Added time limit for NDA logging so it stopps logging after a given period - needs checking though as it might not work...

This commit is contained in:
Graham Jones
2022-10-23 22:47:25 +01:00
parent 7a977ea54e
commit ce5e1b4074
5 changed files with 175 additions and 21 deletions

View File

@@ -2,8 +2,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
package="uk.org.openseizuredetector" package="uk.org.openseizuredetector"
android:versionCode="103" android:versionCode="113"
android:versionName="4.0.7"> android:versionName="4.0.8b">
<!-- android:allowBackup="false" --> <!-- android:allowBackup="false" -->
<uses-permission android:name="android.permission.BLUETOOTH" /> <uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />

View File

@@ -24,6 +24,7 @@ package uk.org.openseizuredetector;
import android.content.ContentValues; import android.content.ContentValues;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences;
import android.database.Cursor; import android.database.Cursor;
import android.database.DatabaseUtils; import android.database.DatabaseUtils;
import android.database.SQLException; import android.database.SQLException;
@@ -32,6 +33,8 @@ import android.database.sqlite.SQLiteOpenHelper;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.os.CountDownTimer; import android.os.CountDownTimer;
import android.os.Handler; import android.os.Handler;
import android.preference.PreferenceManager;
import android.text.format.Time;
import android.util.Log; import android.util.Log;
import org.json.JSONArray; import org.json.JSONArray;
@@ -63,6 +66,20 @@ import java.util.HashMap;
* - Query the local database to return all datapoints within +/- EventDuration/2 minutes of the event. * - Query the local database to return all datapoints within +/- EventDuration/2 minutes of the event.
* - Upload the datapoints, linking them to the new eventID. * - Upload the datapoints, linking them to the new eventID.
* - Mark all the uploaded datapoints as uploaded. * - Mark all the uploaded datapoints as uploaded.
*
* Event statuses:
* 0 - OK
* 1 - WARNING
* 2 - ALARM
* 3 - FALL
* 4 - FAULT
* 5 - Manual Alarm
* 6 - NDA (Normal Daily Activities)
*
* NDA Timer creates an event periodically to record Normal Daily Activities (NDA),
* irrespective of the alarm state. This will upload a lot of data, so it will only run
* for 24 hours after being activated before shutting down requring the user to re-select
* the option to log NDA to re-start it.
*/ */
public class LogManager { public class LogManager {
static final private String TAG = "LogManager"; static final private String TAG = "LogManager";
@@ -74,6 +91,9 @@ public class LogManager {
private String mAuthToken; private String mAuthToken;
static private SQLiteDatabase mOsdDb = null; // SQLite Database for data and log entries. static private SQLiteDatabase mOsdDb = null; // SQLite Database for data and log entries.
private RemoteLogTimer mRemoteLogTimer; private RemoteLogTimer mRemoteLogTimer;
private boolean mLogNDA;
private NDATimer mNDATimer;
private long mNDATimerStartTime;
private static Context mContext; private static Context mContext;
private OsdUtil mUtil; private OsdUtil mUtil;
public static WebApiConnection mWac; public static WebApiConnection mWac;
@@ -90,6 +110,7 @@ public class LogManager {
private long mAutoPrunePeriod = 3600; // Prune the database every hour private long mAutoPrunePeriod = 3600; // Prune the database every hour
private boolean mAutoPruneDb; private boolean mAutoPruneDb;
private AutoPruneTimer mAutoPruneTimer; private AutoPruneTimer mAutoPruneTimer;
private SdData mSdSettingsData;
public interface CursorCallback { public interface CursorCallback {
void accept(Cursor retVal); void accept(Cursor retVal);
@@ -102,7 +123,9 @@ public class LogManager {
public LogManager(Context context, public LogManager(Context context,
boolean logRemote, boolean logRemoteMobile, String authToken, boolean logRemote, boolean logRemoteMobile, String authToken,
long eventDuration, long remoteLogPeriod, long eventDuration, long remoteLogPeriod,
boolean autoPruneDb, long dataRetentionPeriod) { boolean logNDA,
boolean autoPruneDb, long dataRetentionPeriod,
SdData sdSettingsData) {
Log.d(TAG, "LogManger Constructor"); Log.d(TAG, "LogManger Constructor");
mContext = context; mContext = context;
Handler handler = new Handler(); Handler handler = new Handler();
@@ -114,9 +137,12 @@ public class LogManager {
mAutoPruneDb = autoPruneDb; mAutoPruneDb = autoPruneDb;
mDataRetentionPeriod = dataRetentionPeriod; mDataRetentionPeriod = dataRetentionPeriod;
mRemoteLogPeriod = remoteLogPeriod; mRemoteLogPeriod = remoteLogPeriod;
mLogNDA = logNDA;
mSdSettingsData = sdSettingsData;
Log.v(TAG, "mLogRemote=" + mLogRemote); Log.v(TAG, "mLogRemote=" + mLogRemote);
Log.v(TAG, "mLogRemoteMobile=" + mLogRemoteMobile); Log.v(TAG, "mLogRemoteMobile=" + mLogRemoteMobile);
Log.v(TAG, "mEventDuration=" + mEventDuration); Log.v(TAG, "mEventDuration=" + mEventDuration);
Log.v(TAG, "mLogNDA=" + mLogNDA);
Log.v(TAG, "mAutoPruneDb=" + mAutoPruneDb); Log.v(TAG, "mAutoPruneDb=" + mAutoPruneDb);
Log.v(TAG, "mDataRetentionPeriod=" + mDataRetentionPeriod); Log.v(TAG, "mDataRetentionPeriod=" + mDataRetentionPeriod);
Log.v(TAG, "mRemoteLogPeriod=" + mRemoteLogPeriod); Log.v(TAG, "mRemoteLogPeriod=" + mRemoteLogPeriod);
@@ -146,6 +172,13 @@ public class LogManager {
Log.i(TAG, "AutoPruneDB is not set - not starting Auto Prune Timer"); Log.i(TAG, "AutoPruneDB is not set - not starting Auto Prune Timer");
} }
if (mLogNDA) {
Log.i(TAG, "Starting Normal Daily Activity Log Timer");
startNDATimer();
} else {
Log.i(TAG, "mLogNDA is false - not starting Normal Daily Activity Log timer");
}
} }
/** /**
@@ -325,17 +358,6 @@ public class LogManager {
// Expects dataTime to be in format: SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); // Expects dataTime to be in format: SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Log.d(TAG, "createLocalEvent() - dataTime=" + dataTime + ", status=" + status + ", dataJSON="+dataJSON); Log.d(TAG, "createLocalEvent() - dataTime=" + dataTime + ", status=" + status + ", dataJSON="+dataJSON);
// Write Event to database // Write Event to database
//String SQLStr = "INSERT INTO " + mEventsTableName
// + "(dataTime, status, type, subtype, notes, dataJSON)"
// + " VALUES("
// + "'" + dataTime + "',"
// + status + ","
// + "'" + type + "',"
// + "'" + subType + "',"
// + "'" + desc + "',"
// + "'" + dataJSON + "'"
// + ")";
//mOsdDb.execSQL(SQLStr);
ContentValues values = new ContentValues(); ContentValues values = new ContentValues();
values.put("dataTime", dataTime); values.put("dataTime", dataTime);
values.put("status", status); values.put("status", status);
@@ -345,7 +367,7 @@ public class LogManager {
values.put("dataJSON", dataJSON); values.put("dataJSON", dataJSON);
long newRowId = mOsdDb.insert(mEventsTableName, null, values); long newRowId = mOsdDb.insert(mEventsTableName, null, values);
Log.d(TAG, "Created Row ID"+newRowId); Log.d(TAG, "createLocalEvent(): Created Row ID"+newRowId);
return true; return true;
} }
@@ -556,7 +578,7 @@ public class LogManager {
// Do not try to upload very recent events so that we have chance to record the post-event data before uploading it. // Do not try to upload very recent events so that we have chance to record the post-event data before uploading it.
long currentDateMillis = new Date().getTime(); long currentDateMillis = new Date().getTime();
long endDateMillis = currentDateMillis - 1000 * mEventDuration; long endDateMillis = currentDateMillis - 1000 * mEventDuration / 2;
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String endDateStr = dateFormat.format(new Date(endDateMillis)); String endDateStr = dateFormat.format(new Date(endDateMillis));
String whereClauseUploaded = "uploaded is null"; String whereClauseUploaded = "uploaded is null";
@@ -732,21 +754,41 @@ public class LogManager {
private String getEventWhereClause(boolean includeWarnings) { private String getEventWhereClause(boolean includeWarnings) {
/**
* * Event statuses:
* * 0 - OK
* * 1 - WARNING
* * 2 - ALARM
* * 3 - FALL
* * 4 - FAULT
* * 5 - Manual Alarm
* * 6 - NDA (Normal Daily Activities)
*/
String whereClause; String whereClause;
if (includeWarnings) { if (includeWarnings) {
whereClause = "Status in (?, ?, ?, ?)"; whereClause = "Status in (?, ?, ?, ?, ?)";
} else { } else {
whereClause = "Status in (?, ?, ?)"; whereClause = "Status in (?, ?, ?, ?)";
} }
return (whereClause); return (whereClause);
} }
private String[] getEventWhereArgs(boolean includeWarnings) { private String[] getEventWhereArgs(boolean includeWarnings) {
/**
* * Event statuses:
* * 0 - OK
* * 1 - WARNING
* * 2 - ALARM
* * 3 - FALL
* * 4 - FAULT
* * 5 - Manual Alarm
* * 6 - NDA (Normal Daily Activities)
*/
String[] whereArgs; String[] whereArgs;
if (includeWarnings) { if (includeWarnings) {
whereArgs = new String[]{"1", "2", "3", "5"}; whereArgs = new String[]{"1", "2", "3", "5", "6"};
} else { } else {
whereArgs = new String[]{"2", "3", "5"}; whereArgs = new String[]{"2", "3", "5", "6"};
} }
return (whereArgs); return (whereArgs);
} }
@@ -1010,6 +1052,7 @@ public class LogManager {
// Stop the timers and shutdown the remote API connection. // Stop the timers and shutdown the remote API connection.
stopRemoteLogTimer(); stopRemoteLogTimer();
stopAutoPruneTimer(); stopAutoPruneTimer();
stopNDATimer();
} }
/* /*
@@ -1039,6 +1082,47 @@ public class LogManager {
} }
} }
/*
* Start the timer that will log Normal Daily Activity continuously.
*/
private void startNDATimer() {
if (mNDATimer != null) {
Log.i(TAG, "startNDATimer -timer already running - cancelling it");
mNDATimer.cancel();
mNDATimer = null;
}
Log.i(TAG, "startNDATimer() - starting NDATimer");
// We set the timer to timeout after the event duration, so that we record all data
// without a gap.
mNDATimer =
new NDATimer(mEventDuration * 1000, 1000);
mNDATimer.start();
// If we do not have a stored start time for NDA logging, set it to current time
// and store it.
SharedPreferences SP = PreferenceManager
.getDefaultSharedPreferences(mContext);
mNDATimerStartTime = SP.getLong("NDATimerStartTime", 0);
if (mNDATimerStartTime == 0) {
mNDATimerStartTime = new Time(Time.getCurrentTimezone()).toMillis(true);
SharedPreferences.Editor editor = SP.edit();
editor.putLong("NDATimerStartTime", mNDATimerStartTime);
editor.apply();
}
}
/*
* Cancel the Normal Daily Actity Log timer
*/
public void stopNDATimer() {
if (mNDATimer != null) {
Log.i(TAG, "stopNDATimer(): cancelling Normal Daily Activity timer");
mNDATimer.cancel();
mNDATimer = null;
}
}
/* /*
* Start the timer that will Auto Prune the database * Start the timer that will Auto Prune the database
@@ -1068,6 +1152,21 @@ public class LogManager {
} }
public void createNDAEvent() {
Log.i(TAG,"createNDAEvent()");
Date curDate = new Date();
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateStr = dateFormat.format(curDate);
createLocalEvent(dateStr,6,"nda", null, null,
mSdSettingsData.toSettingsJSON());
}
public void updateSdData(SdData sdData) {
mSdSettingsData = sdData;
}
public static class OsdDbHelper extends SQLiteOpenHelper { public static class OsdDbHelper extends SQLiteOpenHelper {
// If you change the database schema, you must increment the database version. // If you change the database schema, you must increment the database version.
public static final int DATABASE_VERSION = 1; public static final int DATABASE_VERSION = 1;
@@ -1141,6 +1240,48 @@ public class LogManager {
} }
/**
* Log Normal Daily Activities periodically.
*/
private class NDATimer extends CountDownTimer {
// FIXME - NDA Log Period hard coded!
private double mNDALogPeriodHours = 0.1;
public NDATimer(long startTime, long interval) {
super(startTime, interval);
}
@Override
public void onTick(long l) {
// Do Nothing
}
@Override
public void onFinish() {
Log.d(TAG, "mNDATimer - onFinish - Recording a Normal Daily Activity Event");
createNDAEvent();
// Check if we have been logging NDA events for more than the set limit.
long tNow = new Time(Time.getCurrentTimezone()).toMillis(true);
double tDiffHrs = (tNow - mNDATimerStartTime) / (3600.*1000.);
if (tDiffHrs >= mNDALogPeriodHours) {
Log.i(TAG, "mNDATimer - onFinish - NDA logging period completed - switching off NDA Logging");
SharedPreferences SP = PreferenceManager
.getDefaultSharedPreferences(mContext);
SharedPreferences.Editor editor = SP.edit();
editor.putLong("NDATimerStartTime", 0);
editor.putBoolean("LogNDA", false);
editor.apply();
} else {
// Restart this timer.
Log.i(TAG,"NDATimer - tdiffHrs = "+tDiffHrs+ ", tnow="+tNow+", tstrt="+mNDATimerStartTime+", NDALogPeriod="+mNDALogPeriodHours);
Log.i(TAG,"NDATimer - re-starting NDA timer");
start();
}
}
}
/** /**
* Prune the database periodically. * Prune the database periodically.
*/ */

View File

@@ -134,6 +134,8 @@ public class SdServer extends Service implements SdDataReceiver {
public boolean mLogData = false; public boolean mLogData = false;
public boolean mLogDataRemote = false; public boolean mLogDataRemote = false;
public boolean mLogDataRemoteMobile = false; public boolean mLogDataRemoteMobile = false;
public boolean mLogNDA = false;
private String mAuthToken = null; private String mAuthToken = null;
private long mEventsTimerPeriod = 60; // Number of seconds between checks to see if there are unvalidated remote events. 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. private long mEventDuration = 120; // event duration in seconds - uploads datapoints that cover this time range centred on the event time.
@@ -273,7 +275,7 @@ public class SdServer extends Service implements SdDataReceiver {
// Create our log manager. // Create our log manager.
mLm = new LogManager(this, mLogDataRemote, mLogDataRemoteMobile, mAuthToken, mEventDuration, mLm = new LogManager(this, mLogDataRemote, mLogDataRemoteMobile, mAuthToken, mEventDuration,
mRemoteLogPeriod, mAutoPruneDb, mDataRetentionPeriod); mRemoteLogPeriod, mLogNDA ,mAutoPruneDb, mDataRetentionPeriod, mSdData);
if (mSMSAlarm) { if (mSMSAlarm) {
Log.v(TAG, "Creating LocationFinder"); Log.v(TAG, "Creating LocationFinder");
@@ -562,6 +564,7 @@ public class SdServer extends Service implements SdDataReceiver {
SdData sdData = mSdData; SdData sdData = mSdData;
sdData.alarmState = 5; sdData.alarmState = 5;
onSdDataReceived(sdData); onSdDataReceived(sdData);
mLm.updateSdData(sdData); // Make sure the data time is up to date in the log manager - only relevant for NDA logging.
} }
/** /**
@@ -1229,6 +1232,8 @@ public class SdServer extends Service implements SdDataReceiver {
mUtil.writeToSysLogFile("updatePrefs() - mLogDataRemote = " + mLogDataRemote); mUtil.writeToSysLogFile("updatePrefs() - mLogDataRemote = " + mLogDataRemote);
mLogDataRemoteMobile = SP.getBoolean("LogDataRemoteMobile", false); mLogDataRemoteMobile = SP.getBoolean("LogDataRemoteMobile", false);
Log.v(TAG, "updatePrefs() - mLogDataRemoteMobile = " + mLogDataRemoteMobile); Log.v(TAG, "updatePrefs() - mLogDataRemoteMobile = " + mLogDataRemoteMobile);
mLogNDA = SP.getBoolean("LogNDA", false);
Log.v(TAG, "updatePrefs() - mLogNDA = " + mLogNDA);
mUtil.writeToSysLogFile("updatePrefs() - mLogDataRemoteMobile = " + mLogDataRemoteMobile); mUtil.writeToSysLogFile("updatePrefs() - mLogDataRemoteMobile = " + mLogDataRemoteMobile);
mAuthToken = SP.getString("webApiAuthToken", null); mAuthToken = SP.getString("webApiAuthToken", null);
Log.v(TAG, "updatePrefs() - mAuthToken = " + mAuthToken); Log.v(TAG, "updatePrefs() - mAuthToken = " + mAuthToken);

View File

@@ -438,4 +438,7 @@
<string name="not_logged_in_dialog_title">Not Logged in to Data Sharing</string> <string name="not_logged_in_dialog_title">Not Logged in to Data Sharing</string>
<string name="not_logged_in_dialog_message">You must be logged in to the Data Sharing system to be able to report seizures.</string> <string name="not_logged_in_dialog_message">You must be logged in to the Data Sharing system to be able to report seizures.</string>
<string name="include_warnings">Include Warnings</string> <string name="include_warnings">Include Warnings</string>
<string name="LogNDASummary">Continuously log data to the data sharing system to provide background \'normal daily activity\' data to help reduce false alarms.</string>
<string name="LogNDATitle">Log Normal Daily Activities (NDA)</string>
<string name="NDATimerStartTimeParseError">Error Parsing NDATimerStartTime</string>
</resources> </resources>

View File

@@ -35,6 +35,11 @@
android:key="LogDataRemoteMobile" android:key="LogDataRemoteMobile"
android:summary="@string/log_data_remote_mobile_summary" android:summary="@string/log_data_remote_mobile_summary"
android:title="@string/log_data_remote_mobile_title" /> android:title="@string/log_data_remote_mobile_title" />
<CheckBoxPreference
android:defaultValue="false"
android:key="LogNDA"
android:summary="@string/LogNDASummary"
android:title="@string/LogNDATitle" />
<!--<EditTextPreference <!--<EditTextPreference
android:defaultValue="60" android:defaultValue="60"
android:key="RemoteLogPeriod" android:key="RemoteLogPeriod"