From 3e9ec5ed8185f436a6d45e5fba8128c3a4138cb4 Mon Sep 17 00:00:00 2001 From: Graham Jones Date: Mon, 11 Apr 2022 23:47:15 +0100 Subject: [PATCH] Added dataJSON field to events table so we can store watch app version etc. with the event rather than every datapoint. --- app/src/main/AndroidManifest.xml | 2 +- .../org/openseizuredetector/LogManager.java | 60 ++++++++++++++----- .../LogManagerControlActivity.java | 6 +- .../ReportSeizureActivity.java | 4 +- .../uk/org/openseizuredetector/SdData.java | 48 +++++++++++++++ .../org/openseizuredetector/SdDataSource.java | 4 ++ .../uk/org/openseizuredetector/SdServer.java | 2 +- .../openseizuredetector/WebApiConnection.java | 3 +- .../WebApiConnection_firebase.java | 9 ++- .../WebApiConnection_osdapi.java | 6 +- app/src/main/res/values/strings.xml | 1 + 11 files changed, 119 insertions(+), 26 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 910a93b..5d70e36 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -3,7 +3,7 @@ xmlns:tools="http://schemas.android.com/tools" package="uk.org.openseizuredetector" android:versionCode="100" - android:versionName="4.0.3"> + android:versionName="4.0.4"> diff --git a/app/src/main/java/uk/org/openseizuredetector/LogManager.java b/app/src/main/java/uk/org/openseizuredetector/LogManager.java index 2f905b3..3739a01 100644 --- a/app/src/main/java/uk/org/openseizuredetector/LogManager.java +++ b/app/src/main/java/uk/org/openseizuredetector/LogManager.java @@ -207,6 +207,10 @@ public class LogManager { event.put("id", c.getString(c.getColumnIndex("id"))); event.put("dataTime", c.getString(c.getColumnIndex("dataTime"))); event.put("status", c.getString(c.getColumnIndex("status"))); + event.put("type", c.getString(c.getColumnIndex("type"))); + event.put("subType", c.getString(c.getColumnIndex("subType"))); + event.put("desc", c.getString(c.getColumnIndex("notes"))); + event.put("dataJSON", c.getString(c.getColumnIndex("dataJSON"))); event.put("uploaded", c.getString(c.getColumnIndex("uploaded"))); c.moveToNext(); eventsArray.put(i, event); @@ -293,7 +297,7 @@ public class LogManager { if (sdData.alarmState != 0) { Log.i(TAG, "writeDatapointToLocalDb(): adding event to local DB"); - createLocalEvent(dateStr, sdData.alarmState); + createLocalEvent(dateStr,sdData.alarmState,null, null, null, sdData.toSettingsJSON()); } } catch (SQLException e) { Log.e(TAG, "writeToLocalDb(): Error Writing Data: " + e.toString()); @@ -304,14 +308,22 @@ public class LogManager { } public boolean createLocalEvent(String dataTime, long status) { + return (createLocalEvent(dataTime, status, null, null, null, null)); + } + + public boolean createLocalEvent(String dataTime, long status, String type, String subType, String desc, String dataJSON) { // Expects dataTime to be in format: SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); - Log.d(TAG,"createLocalEvent() - dataTime="+dataTime+", status="+status); + Log.d(TAG, "createLocalEvent() - dataTime=" + dataTime + ", status=" + status + ", dataJSON="+dataJSON); // Write Datapoint to database String SQLStr = "INSERT INTO " + mEventsTableName - + "(dataTime, status)" + + "(dataTime, status, type, subtype, notes, dataJSON)" + " VALUES(" + "'" + dataTime + "'," - + status + + status + "," + + "'" + type + "'," + + "'" + subType + "'," + + "'" + desc + "'," + + "'" + dataJSON + "'" + ")"; mOsdDb.execSQL(SQLStr); return true; @@ -371,7 +383,7 @@ public class LogManager { public boolean setDatapointToUploaded(int id, String eventId) { Log.d(TAG, "setDatapointToUploaded() - id=" + id); if (mOsdDb == null) { - Log.e(TAG,"setDatapointToUploaded() - mOsdDb is null - not doing anything"); + Log.e(TAG, "setDatapointToUploaded() - mOsdDb is null - not doing anything"); return false; } ContentValues cv = new ContentValues(); @@ -491,14 +503,14 @@ public class LogManager { /** * setEventToUploaded * - * @param localEventId - local Event ID to change + * @param localEventId - local Event ID to change * @param remoteEventId - the remote eventId associated with the uploaded datapoint - the 'uploaded' field is set to this value. * @return True on success or False on failure. */ public boolean setEventToUploaded(long localEventId, String remoteEventId) { - Log.d(TAG, "setEventToUploaded() - local id=" + localEventId + " remote id="+remoteEventId); + Log.d(TAG, "setEventToUploaded() - local id=" + localEventId + " remote id=" + remoteEventId); if (mOsdDb == null) { - Log.e(TAG,"setEventToUploaded() - mOsdDb is null - not doing anything"); + Log.e(TAG, "setEventToUploaded() - mOsdDb is null - not doing anything"); return false; } ContentValues cv = new ContentValues(); @@ -784,32 +796,46 @@ public class LogManager { int eventAlarmStatus; String eventDateStr; Date eventDate; + String eventType; + String eventSubType; + String eventDesc; + String eventDataJSON; try { JSONArray datapointJsonArr = new JSONArray(eventJsonStr); eventObj = datapointJsonArr.getJSONObject(0); // We only look at the first (and hopefully only) item in the array. eventAlarmStatus = Integer.parseInt(eventObj.getString("status")); eventDateStr = eventObj.getString("dataTime"); + eventType = eventObj.getString("type"); + eventSubType = eventObj.getString("subType"); + if (eventObj.has("desc")) + eventDesc = eventObj.getString("desc"); + else + eventDesc = ""; + eventDataJSON = eventObj.getString("dataJSON"); Log.d(TAG, "uploadSdData - data from local DB is:" + eventJsonStr + ", eventAlarmStatus=" + eventAlarmStatus + ", eventDateStr=" + eventDateStr); } catch (JSONException e) { Log.e(TAG, "uploadSdData(): ERROR parsing event JSON Data" + eventJsonStr); e.printStackTrace(); + mUploadInProgress = false; return; } catch (NullPointerException e) { - Log.e(TAG, "uploadSdData(): ERROR null pointer exception parsing event JSON Data" + eventJsonStr); + Log.e(TAG, "uploadSdData(): ERROR null pointer exception parsing event JSON Data: " + eventJsonStr); e.printStackTrace(); + mUploadInProgress = false; return; } try { eventDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(eventDateStr); } catch (ParseException e) { Log.e(TAG, "UploadSdData(): Error parsing date " + eventDateStr); + mUploadInProgress = false; return; } Log.i(TAG, "uploadSdData - calling mWac.createEvent"); mCurrentEventLocalId = eventId; - mWac.createEvent(eventAlarmStatus, eventDate, "", this::createEventCallback); + mWac.createEvent(eventAlarmStatus, eventDate, eventType, eventSubType, eventDesc, eventDataJSON, this::createEventCallback); } else { Log.v(TAG, "uploadSdData - no data to upload "); //(warnings="+warningsVal+")"); mUploadInProgress = false; @@ -839,14 +865,14 @@ public class LogManager { @Override public void accept(JSONObject eventObj) { if (eventObj == null) { - Log.e(TAG,"createEventCallback() - eventObj is null - failed to create event"); + Log.e(TAG, "createEventCallback() - eventObj is null - failed to create event"); mUtil.showToast("Error Creating Remote Event"); } else { Log.v(TAG, "createEventCallback() - eventObj=" + eventObj.toString()); Date eventDate; String eventDateStr = ""; try { - String dateStr= eventObj.getString("dataTime"); + String dateStr = eventObj.getString("dataTime"); eventDate = mUtil.string2date(dateStr); } catch (JSONException e) { Log.e(TAG, "createEventCallback() - Error parsing JSONObject: " + eventObj.toString()); @@ -888,7 +914,7 @@ public class LogManager { }); } else { - Log.e(TAG,"createEventCallback() - Error - event date is null - not doing anything"); + Log.e(TAG, "createEventCallback() - Error - event date is null - not doing anything"); mUtil.showToast("Error uploading event - date is null"); finishUpload(); } @@ -922,7 +948,7 @@ public class LogManager { finishUpload(); } } else { - Log.w(TAG,"uploadNextDatapoint - mDatapointsToUploadList is null - I don't thin this should have happened!"); + Log.w(TAG, "uploadNextDatapoint - mDatapointsToUploadList is null - I don't thin this should have happened!"); } } @@ -930,13 +956,13 @@ public class LogManager { // a datapoint based on mDatapointsToUploadList(0) so removes that from the list and calls UploadDatapoint() // to upload the next one. public void datapointCallback(String datapointStr) { - Log.v(TAG, "datapointCallback() dataPointId="+mCurrentDatapointId+" remote datapointID=" + datapointStr + ", mCurrentEventId=" + mCurrentEventRemoteId); + Log.v(TAG, "datapointCallback() dataPointId=" + mCurrentDatapointId + " remote datapointID=" + datapointStr + ", mCurrentEventId=" + mCurrentEventRemoteId); if (mDatapointsToUploadList != null) { if (mDatapointsToUploadList.size() > 0) { mDatapointsToUploadList.remove(0); } } else { - Log.w(TAG,"datapointCallback - mDatapointsToUploadList is null - I don't thin this should have happened!"); + Log.w(TAG, "datapointCallback - mDatapointsToUploadList is null - I don't thin this should have happened!"); } setDatapointToUploaded(mCurrentDatapointId, mCurrentEventRemoteId); uploadNextDatapoint(); @@ -1049,6 +1075,8 @@ public class LogManager { + "status INT," + "type TEXT," + "subType TEXT," + + "notes TEXT," // avoiding using 'desc' as that is an sql name. + + "dataJSON TEXT," + "uploaded TEXT" // stores the id of the event in the remote dabase if uploaded, otherwise empty + ");"; db.execSQL(SQLStr); diff --git a/app/src/main/java/uk/org/openseizuredetector/LogManagerControlActivity.java b/app/src/main/java/uk/org/openseizuredetector/LogManagerControlActivity.java index ef1e59a..18a3a55 100644 --- a/app/src/main/java/uk/org/openseizuredetector/LogManagerControlActivity.java +++ b/app/src/main/java/uk/org/openseizuredetector/LogManagerControlActivity.java @@ -427,7 +427,7 @@ public class LogManagerControlActivity extends AppCompatActivity { } return true; case R.id.action_mark_unknown: - Log.i(TAG,"action_mark_unknown"); + Log.i(TAG, "action_mark_unknown"); new AlertDialog.Builder(this) .setTitle(R.string.mark_unverified_events_unknown_dialog_title) .setMessage(R.string.mark_unverified_events_unknown_dialog_message) @@ -435,7 +435,8 @@ public class LogManagerControlActivity extends AppCompatActivity { .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { mLm.mWac.markUnverifiedEventsAsUnknown(); - }}) + } + }) .setNegativeButton(android.R.string.no, null) .show(); default: @@ -624,6 +625,7 @@ public class LogManagerControlActivity extends AppCompatActivity { Log.v(TAG, "getView() " + dataItem.toString()); switch (dataItem.get("type").toString()) { case "null": + case "": v.setBackgroundColor(Color.parseColor("#ffaaaa")); break; case "Seizure": diff --git a/app/src/main/java/uk/org/openseizuredetector/ReportSeizureActivity.java b/app/src/main/java/uk/org/openseizuredetector/ReportSeizureActivity.java index 2ffa351..bac3253 100644 --- a/app/src/main/java/uk/org/openseizuredetector/ReportSeizureActivity.java +++ b/app/src/main/java/uk/org/openseizuredetector/ReportSeizureActivity.java @@ -147,7 +147,9 @@ public class ReportSeizureActivity extends AppCompatActivity { //SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String dateStr=String.format("%4d-%02d-%02d %02d:%02d:30",mYear,mMonth+1,mDay, mHour, mMinute); Log.v(TAG, "onOk() - dateSTr="+dateStr); - mLm.createLocalEvent(dateStr,5); + // FIXME - make new version of SdData.toJSON that gives watch details for in the event. + mLm.createLocalEvent(dateStr,5,null, null, null, + mConnection.mSdServer.mSdData.toSettingsJSON()); mUtil.showToast("Seizure Event Created"); finish(); } diff --git a/app/src/main/java/uk/org/openseizuredetector/SdData.java b/app/src/main/java/uk/org/openseizuredetector/SdData.java index 559a8d6..efcc2d1 100644 --- a/app/src/main/java/uk/org/openseizuredetector/SdData.java +++ b/app/src/main/java/uk/org/openseizuredetector/SdData.java @@ -71,6 +71,12 @@ public class SdData implements Parcelable { public boolean mO2SatNullAsAlarm = false; public double mO2SatThreshMin = 80.0; + /* Watch App Settings */ + public String watchPartNo = ""; + public String watchFwVersion = ""; + public String watchSdVersion = ""; + public String watchSdName = ""; + public double rawData[]; int mNsamp = 0; @@ -164,6 +170,48 @@ public class SdData implements Parcelable { return toDataString(includeRawData); } + public String toSettingsJSON() { + String retval; + retval = "SdData.toSettingsJSON() Output"; + try { + JSONObject jsonObj = new JSONObject(); + if (dataTime != null) { + jsonObj.put("dataTime", dataTime.format("%d-%m-%Y %H:%M:%S")); + jsonObj.put("dataTimeStr", dataTime.format("%Y%m%dT%H%M%S")); + }else{ + jsonObj.put("dataTimeStr", "00000000T000000"); + jsonObj.put("dataTime", "00-00-00 00:00:00"); + } + jsonObj.put("batteryPc", batteryPc); + jsonObj.put("alarmState", alarmState); + jsonObj.put("alarmPhrase", alarmPhrase); + jsonObj.put("sdMode",mSdMode); + jsonObj.put("sampleFreq",mSampleFreq); + jsonObj.put("analysisPeriod",analysisPeriod); + jsonObj.put("alarmFreqMin",alarmFreqMin); + jsonObj.put("alarmFreqMax",alarmFreqMax); + jsonObj.put("alarmThresh", alarmThresh); + jsonObj.put("alarmRatioThresh", alarmRatioThresh); + jsonObj.put("hrAlarmActive", mHRAlarmActive); + jsonObj.put("hrAlarmStanding", mHRAlarmStanding); + jsonObj.put("hrThreshMin",mHRThreshMin); + jsonObj.put("hrThreshMax", mHRThreshMax); + jsonObj.put("o2SatAlarmActive", mO2SatAlarmActive); + jsonObj.put("o2SatAlarmStanding", mO2SatAlarmStanding); + jsonObj.put("o2SatThreshMin",mO2SatThreshMin); + jsonObj.put("watchPartNo",watchPartNo); + jsonObj.put("watchSdName",watchSdName); + jsonObj.put("watchFwVersion",watchFwVersion); + jsonObj.put("watchSdVersion",watchSdVersion); + + retval = jsonObj.toString(); + } catch (Exception ex) { + Log.e(TAG, "toSettingsJSON(): Error Creating Data Object - " + ex.toString()); + retval = "Error Creating Data Object - " + ex.toString(); + } + return (retval); + } + public String toDataString(boolean includeRawData) { String retval; retval = "SdData.toDataString() Output"; diff --git a/app/src/main/java/uk/org/openseizuredetector/SdDataSource.java b/app/src/main/java/uk/org/openseizuredetector/SdDataSource.java index 24757cc..2a64439 100644 --- a/app/src/main/java/uk/org/openseizuredetector/SdDataSource.java +++ b/app/src/main/java/uk/org/openseizuredetector/SdDataSource.java @@ -318,6 +318,10 @@ public abstract class SdDataSource { sdName = dataObject.getString("sdName"); mUtil.writeToSysLogFile(" * sdName = " + sdName + " version " + sdVersion); mUtil.writeToSysLogFile(" * watchPartNo = " + watchPartNo + " fwVersion " + watchFwVersion); + mSdData.watchPartNo = watchPartNo; + mSdData.watchFwVersion = watchFwVersion; + mSdData.watchSdVersion = sdVersion; + mSdData.watchSdName = sdName; } catch (Exception e) { Log.e(TAG, "updateFromJSON - Error Parsing V3.2 JSON String - " + e.toString()); mUtil.writeToSysLogFile("updateFromJSON - Error Parsing V3.2 JSON String - " + jsonStr + " - " + e.toString()); diff --git a/app/src/main/java/uk/org/openseizuredetector/SdServer.java b/app/src/main/java/uk/org/openseizuredetector/SdServer.java index 96421e8..bc8f4c2 100644 --- a/app/src/main/java/uk/org/openseizuredetector/SdServer.java +++ b/app/src/main/java/uk/org/openseizuredetector/SdServer.java @@ -138,7 +138,7 @@ public class SdServer extends Service implements SdDataReceiver { private long mEventsTimerPeriod = 60; // Number of seconds between checks to see if there are unvalidated remote events. private long mEventDuration = 120; // event duration in seconds - uploads datapoints that cover this time range centred on the event time. public long mDataRetentionPeriod = 1; // Prunes the local db so it only retains data younger than this duration (in days) - private long mRemoteLogPeriod = 20; // Period in seconds between uploads to the remote server. + private long mRemoteLogPeriod = 6; // Period in seconds between uploads to the remote server. private long mAutoPrunePeriod = 3600; // Prune the database every hour private boolean mAutoPruneDb; diff --git a/app/src/main/java/uk/org/openseizuredetector/WebApiConnection.java b/app/src/main/java/uk/org/openseizuredetector/WebApiConnection.java index 00776fd..b261bec 100644 --- a/app/src/main/java/uk/org/openseizuredetector/WebApiConnection.java +++ b/app/src/main/java/uk/org/openseizuredetector/WebApiConnection.java @@ -76,7 +76,8 @@ public abstract class WebApiConnection { // Create a new event in the remote database, based on the provided parameters. // passes the newly created documentId to function callback on successful completion, or null on error. - public abstract boolean createEvent(final int osdAlarmState, final Date eventDate, final String eventDesc, StringCallback callback); + public abstract boolean createEvent(final int osdAlarmState, final Date eventDate, final String type, final String subType, + final String eventDesc, final String dataJSON, StringCallback callback); // calls function callback with a JSONObject representation of the event with id 'eventId' public abstract boolean getEvent(String eventId, JSONObjectCallback callback); diff --git a/app/src/main/java/uk/org/openseizuredetector/WebApiConnection_firebase.java b/app/src/main/java/uk/org/openseizuredetector/WebApiConnection_firebase.java index 30a060c..426f2ea 100644 --- a/app/src/main/java/uk/org/openseizuredetector/WebApiConnection_firebase.java +++ b/app/src/main/java/uk/org/openseizuredetector/WebApiConnection_firebase.java @@ -119,7 +119,9 @@ public class WebApiConnection_firebase extends WebApiConnection { // Create a new event in the remote database, based on the provided parameters. // passes the newly created documentId to function callback on successful completion, or null on error. - public boolean createEvent(final int osdAlarmState, final Date eventDate, final String eventDesc, StringCallback callback) { + public boolean createEvent(final int osdAlarmState, final Date eventDate, final String type, final String subType, + final String eventDesc, final String dataJSON, StringCallback callback) { + // FIXME - save type, subtype, eventDesc and dataJSON Log.v(TAG, "createEvent()"); String userId = null; @@ -138,8 +140,9 @@ public class WebApiConnection_firebase extends WebApiConnection { event.put("dataTime", eventDate.getTime()); event.put("osdAlarmState", osdAlarmState); event.put("desc", eventDesc); - event.put("type", null); - event.put("subType", null); + event.put("type", type); + event.put("subType", subType); + event.put("dataJSON", dataJSON); event.put("userId", userId); mDb.collection("Events") diff --git a/app/src/main/java/uk/org/openseizuredetector/WebApiConnection_osdapi.java b/app/src/main/java/uk/org/openseizuredetector/WebApiConnection_osdapi.java index 57aa908..0e01565 100644 --- a/app/src/main/java/uk/org/openseizuredetector/WebApiConnection_osdapi.java +++ b/app/src/main/java/uk/org/openseizuredetector/WebApiConnection_osdapi.java @@ -127,7 +127,8 @@ public class WebApiConnection_osdapi extends WebApiConnection { // Create a new event in the remote database, based on the provided parameters. - public boolean createEvent(final int osdAlarmState, final Date eventDate, final String eventDesc, StringCallback callback) { + public boolean createEvent(final int osdAlarmState, final Date eventDate, final String type, final String subType, + final String eventDesc, final String dataJSON, StringCallback callback) { Log.v(TAG, "createEvent()"); String urlStr = mUrlBase + "/api/events/"; Log.v(TAG, "urlStr=" + urlStr); @@ -142,7 +143,10 @@ public class WebApiConnection_osdapi extends WebApiConnection { try { jsonObject.put("osdAlarmState", String.valueOf(osdAlarmState)); jsonObject.put("dataTime", dateFormat.format(eventDate)); + jsonObject.put("type", type); + jsonObject.put("subType", subType); jsonObject.put("desc", eventDesc); + jsonObject.put("dataJSON", dataJSON); } catch (JSONException e) { Log.e(TAG, "Error generating event JSON string"); } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 6623440..b1641e6 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -3,6 +3,7 @@ OpenSeizureDetector "\n + \nV4.0.4 - Added watch info to events data \nV4.0.3 - Changed remote database to be compatible with either OSD webAPI or future Firebase database.
- Performance improvement by having separate events and datapoints tables in local database \nV4.0.1, 4.0.2, - fixed repoted crashes