Added data logging preferences to settings page

This commit is contained in:
Graham Jones
2022-01-07 22:05:30 +00:00
parent 5294353bcf
commit 276f14afba
6 changed files with 179 additions and 18 deletions

View File

@@ -81,13 +81,19 @@ public class LogManager implements AuthCallbackInterface, EventCallbackInterface
public WebApiConnection mWac; public WebApiConnection mWac;
private boolean mUploadInProgress; private boolean mUploadInProgress;
private long eventDuration = 1; // event duration in minutes - 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.
private long mLocaDbTimeLimitDays = 1; // Prunes the local db so it only retains data younger than this duration. private long mDataRetentionPeriod = 1; // Prunes the local db so it only retains data younger than this duration (in days)
private long mRemoteLogPeriod = 60; // Period in seconds between uploads to the remote server.
private ArrayList<JSONObject> mDatapointsToUploadList; private ArrayList<JSONObject> mDatapointsToUploadList;
private int mCurrentEventId; private int mCurrentEventId;
private int mCurrentDatapointId; private int mCurrentDatapointId;
private long mAutoPrunePeriod = 3600; // Prune the database every hour
private boolean mAutoPruneDb;
private AutoPruneTimer mAutoPruneTimer;
public LogManager(Context context) { public LogManager(Context context) {
String prefVal;
Log.d(TAG,"LogManger Constructor"); Log.d(TAG,"LogManger Constructor");
mContext = context; mContext = context;
Handler handler = new Handler(); Handler handler = new Handler();
@@ -99,6 +105,22 @@ public class LogManager implements AuthCallbackInterface, EventCallbackInterface
mLogRemoteMobile = (prefs.getBoolean("LogDataRemoteMobile", false)); mLogRemoteMobile = (prefs.getBoolean("LogDataRemoteMobile", false));
Log.v(TAG,"mLogRemoteMobile="+mLogRemoteMobile); Log.v(TAG,"mLogRemoteMobile="+mLogRemoteMobile);
prefVal = prefs.getString("EventDurationSec", "300");
mEventDuration = Integer.parseInt(prefVal);
Log.v(TAG,"mEventDuration="+mEventDuration);
mAutoPruneDb = prefs.getBoolean("AutoPruneDb", false);
Log.v(TAG,"mAutoPruneDb="+mAutoPruneDb);
prefVal = prefs.getString("DataRetentionPeriod", "28");
mDataRetentionPeriod = Integer.parseInt(prefVal);
Log.v(TAG,"mDataRetentionPeriod="+mDataRetentionPeriod);
prefVal = prefs.getString("RemoteLogPeriod", "60");
mRemoteLogPeriod = Integer.parseInt(prefVal);
Log.v(TAG,"mRemoteLogPeriod="+mRemoteLogPeriod);
mUtil = new OsdUtil(mContext, handler); mUtil = new OsdUtil(mContext, handler);
openDb(); openDb();
@@ -106,6 +128,13 @@ public class LogManager implements AuthCallbackInterface, EventCallbackInterface
startRemoteLogTimer(); startRemoteLogTimer();
if (mAutoPruneDb) {
Log.v(TAG,"Starting Auto Prune Timer");
startAutoPruneTimer();
} else {
Log.v(TAG,"AutoPruneDB is not set");
}
} }
/** /**
@@ -307,7 +336,7 @@ public class LogManager implements AuthCallbackInterface, EventCallbackInterface
// Return an array list of objects representing the events in the database. // Return an array list of objects representing the events in the database.
// Based on https://www.tutlane.com/tutorial/android/android-sqlite-listview-with-examples // Based on https://www.tutlane.com/tutorial/android/android-sqlite-listview-with-examples
public ArrayList<HashMap<String, String>> getEventsList(boolean includeWarnings) { public ArrayList<HashMap<String, String>> getEventsList(boolean includeWarnings) {
Log.v(TAG,"getEventsList()"); //Log.v(TAG,"getEventsList()");
SQLiteDatabase db = mOSDDb.getWritableDatabase(); SQLiteDatabase db = mOSDDb.getWritableDatabase();
ArrayList<HashMap<String, String>> eventsList = new ArrayList<>(); ArrayList<HashMap<String, String>> eventsList = new ArrayList<>();
String statusListStr, sqlStr; String statusListStr, sqlStr;
@@ -348,7 +377,7 @@ public class LogManager implements AuthCallbackInterface, EventCallbackInterface
//event.put("dataJSON", cursor.getString(cursor.getColumnIndex("dataJSON"))); //event.put("dataJSON", cursor.getString(cursor.getColumnIndex("dataJSON")));
eventsList.add(event); eventsList.add(event);
} }
Log.v(TAG,"getEventsList() - returning "+eventsList); //Log.v(TAG,"getEventsList() - returning "+eventsList);
return eventsList; return eventsList;
} }
@@ -360,8 +389,8 @@ public class LogManager implements AuthCallbackInterface, EventCallbackInterface
Cursor c = null; Cursor c = null;
int retVal; int retVal;
long currentDateMillis = new Date().getTime(); long currentDateMillis = new Date().getTime();
//long endDateMillis = currentDateMillis - 24*3600*1000* mLocaDbTimeLimitDays; long endDateMillis = currentDateMillis - 24*3600*1000* mDataRetentionPeriod;
long endDateMillis = currentDateMillis - 3600*1000* mLocaDbTimeLimitDays; // Using hours rather than days for testing //long endDateMillis = currentDateMillis - 3600*1000* mDataRetentionPeriod; // Using hours rather than days for testing
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));
@@ -383,7 +412,7 @@ public class LogManager implements AuthCallbackInterface, EventCallbackInterface
* Return the ID of the next event (alarm, warning, fall etc that needs to be uploaded (alarm or warning condition and has not yet been uploaded. * Return the ID of the next event (alarm, warning, fall etc that needs to be uploaded (alarm or warning condition and has not yet been uploaded.
*/ */
public int getNextEventToUpload(boolean includeWarnings) { public int getNextEventToUpload(boolean includeWarnings) {
Log.v(TAG, "getNextEventToUpload()"); Log.v(TAG, "getNextEventToUpload("+includeWarnings+")");
Time tnow = new Time(Time.getCurrentTimezone()); Time tnow = new Time(Time.getCurrentTimezone());
tnow.setToNow(); tnow.setToNow();
String dateStr = tnow.format("%Y-%m-%d"); String dateStr = tnow.format("%Y-%m-%d");
@@ -397,10 +426,14 @@ public class LogManager implements AuthCallbackInterface, EventCallbackInterface
} else { } else {
statusListStr = "2,3,5"; // Alarm, Fall, Manual Alarm statusListStr = "2,3,5"; // Alarm, Fall, Manual Alarm
} }
// 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 endDateMillis = currentDateMillis - 1000* mEventDuration;
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String endDateStr = dateFormat.format(new Date(endDateMillis));
try { try {
//FIXME: We need to exclude very recent records from this, otherwise the system might upload SQLStr = "SELECT * from "+ mDbTableName + " where uploaded=false and Status in ("+statusListStr+") and DataTime<'"+endDateStr+"';";
// a seizure while it is still occurring and we will miss out on the post-seizure date.
SQLStr = "SELECT * from "+ mDbTableName + " where uploaded=false and Status in ("+statusListStr+");";
Cursor resultSet = mOSDDb.getWritableDatabase().rawQuery(SQLStr,null); Cursor resultSet = mOSDDb.getWritableDatabase().rawQuery(SQLStr,null);
resultSet.moveToFirst(); resultSet.moveToFirst();
if (resultSet.getCount() == 0) { if (resultSet.getCount() == 0) {
@@ -460,7 +493,7 @@ public class LogManager implements AuthCallbackInterface, EventCallbackInterface
* Return the number of events stored in the local database * Return the number of events stored in the local database
*/ */
public int getLocalEventsCount(boolean includeWarnings) { public int getLocalEventsCount(boolean includeWarnings) {
Log.v(TAG, "getLocalEventsCount()"); //Log.v(TAG, "getLocalEventsCount()");
String SQLStr = "SQLStr"; String SQLStr = "SQLStr";
String statusListStr; String statusListStr;
@@ -485,7 +518,7 @@ public class LogManager implements AuthCallbackInterface, EventCallbackInterface
* Return the number of datapoints stored in the local database * Return the number of datapoints stored in the local database
*/ */
public int getLocalDatapointsCount() { public int getLocalDatapointsCount() {
Log.v(TAG, "getLocalDatapointsCount()"); //Log.v(TAG, "getLocalDatapointsCount()");
String SQLStr = "SQLStr"; String SQLStr = "SQLStr";
String statusListStr; String statusListStr;
@@ -645,8 +678,8 @@ public class LogManager implements AuthCallbackInterface, EventCallbackInterface
Log.v(TAG,"eventCallback() EventId="+eventId+", eventDateStr="+eventDateStr+", eventDate="+eventDate.toString()); Log.v(TAG,"eventCallback() EventId="+eventId+", eventDateStr="+eventDateStr+", eventDate="+eventDate.toString());
long eventDateMillis = eventDate.getTime(); long eventDateMillis = eventDate.getTime();
long startDateMillis = eventDateMillis - 1000*60* eventDuration/2; long startDateMillis = eventDateMillis - 1000* mEventDuration /2;
long endDateMillis = eventDateMillis + 1000*60*eventDuration/2; long endDateMillis = eventDateMillis + 1000* mEventDuration /2;
dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String datapointsJsonStr = getDatapointsbyDate( String datapointsJsonStr = getDatapointsbyDate(
@@ -732,7 +765,7 @@ public class LogManager implements AuthCallbackInterface, EventCallbackInterface
} }
Log.v(TAG, "startRemoteLogTimer() - starting RemoteLogTimer"); Log.v(TAG, "startRemoteLogTimer() - starting RemoteLogTimer");
mRemoteLogTimer = mRemoteLogTimer =
new RemoteLogTimer(10 * 1000, 1000); new RemoteLogTimer(mRemoteLogPeriod * 1000, 1000);
mRemoteLogTimer.start(); mRemoteLogTimer.start();
} }
@@ -749,6 +782,33 @@ public class LogManager implements AuthCallbackInterface, EventCallbackInterface
} }
/*
* Start the timer that will Auto Prune the database
*/
private void startAutoPruneTimer() {
if (mAutoPruneTimer != null) {
Log.v(TAG, "startAutoPruneTimer -timer already running - cancelling it");
mAutoPruneTimer.cancel();
mAutoPruneTimer = null;
}
Log.v(TAG, "startAutoPruneTimer() - starting AutoPruneTimer");
mAutoPruneTimer =
new AutoPruneTimer(mAutoPrunePeriod * 1000, 1000);
mAutoPruneTimer.start();
}
/*
* Cancel the auto prune timer to prevent attempts to upload to remote database.
*/
public void stopAutoPruneTimer() {
if (mAutoPruneTimer != null) {
Log.v(TAG, "stopAutoPruneTimer(): cancelling Auto Prune timer");
mAutoPruneTimer.cancel();
mAutoPruneTimer = null;
}
}
public class OsdDbHelper extends SQLiteOpenHelper { public 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.
@@ -811,4 +871,26 @@ public class LogManager implements AuthCallbackInterface, EventCallbackInterface
} }
/**
* Prune the database periodically.
*/
private class AutoPruneTimer extends CountDownTimer {
public AutoPruneTimer(long startTime, long interval) {
super(startTime, interval);
}
@Override
public void onTick(long l) { }
@Override
public void onFinish() {
Log.v(TAG, "mAutoPruneTimer - onFinish - Pruning Local Database");
pruneLocalDb();
// Restart this timer.
start();
}
}
} }

View File

@@ -119,11 +119,12 @@ public class LogManagerControlActivity extends AppCompatActivity {
@Override @Override
public void onClick(View view) { public void onClick(View view) {
Log.v(TAG, "onPruneBtn"); Log.v(TAG, "onPruneBtn");
// Confirmation dialog based on: https://stackoverflow.com/a/12213536/2104584
AlertDialog.Builder builder = new AlertDialog.Builder(mContext); AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
builder.setTitle("Prune Database"); builder.setTitle("Prune Database");
builder.setMessage("This will remove all data from the database that is more than xxx days old.\nAre you sure?"); builder.setMessage("This will remove all data from the database that is more than xxx days old."
+"\nThis can NOT be undone.\nAre you sure?");
builder.setPositiveButton("YES", new DialogInterface.OnClickListener() { builder.setPositiveButton("YES", new DialogInterface.OnClickListener() {
@Override @Override
public void onClick(DialogInterface dialog, int which) { public void onClick(DialogInterface dialog, int which) {
@@ -178,7 +179,7 @@ public class LogManagerControlActivity extends AppCompatActivity {
} }
Log.v(TAG, "startRemoteLogTimer() - starting RemoteLogTimer"); Log.v(TAG, "startRemoteLogTimer() - starting RemoteLogTimer");
mUiTimer = mUiTimer =
new UiTimer(1000, 1000); new UiTimer(5000, 1000);
mUiTimer.start(); mUiTimer.start();
} }

View File

@@ -276,6 +276,17 @@ public class PrefActivity extends PreferenceActivity implements SharedPreference
} }
} }
public static class LoggingPrefsFragment extends PreferenceFragment {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Load the preferences from an XML resource
addPreferencesFromResource(R.xml.logging_prefs);
}
}
public static class SeizureDetectorPrefsFragment extends PreferenceFragment { public static class SeizureDetectorPrefsFragment extends PreferenceFragment {
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {

View File

@@ -308,4 +308,14 @@
<string name="EventsInLocalDb">Events in Local Database</string> <string name="EventsInLocalDb">Events in Local Database</string>
<string name="createdNewEvent">Created new Manual Alarm Event</string> <string name="createdNewEvent">Created new Manual Alarm Event</string>
<string name="DatapointNotFound">Datapoint not found - not doing anything</string> <string name="DatapointNotFound">Datapoint not found - not doing anything</string>
<string name="logging_settings_title">Data Logging Settings</string>
<string name="logging_settings_summary">Settings that control how data is recorded on the phone and uploaded to the Open Seizure Database</string>
<string name="eventDurationSummary">The time (in seconds) before and after a seizure event that we record data.</string>
<string name="eventDurationTitle">Event Duration (seconds)</string>
<string name="dataRetentionPeriodTitle">Data Retention Period (days)</string>
<string name="dataRetentionPeriodSummary">The period (in days) that data will be retained and is protected from deletion by the \'Prune Database\' Option.</string>
<string name="AutoPruneDbTitle">Automatically Prune (Trim) Database</string>
<string name="AutoPruneDbSummary">Automatically Prune (Trim) the Database periodically to prevent excessive storage capacity (memory) usage.</string>
<string name="remoteLogPeriodSummary">The period (in seconds) between attempts to upload data to the remote server. Each attempt only uploads a single event, not all the available data.</string>
<string name="remoteLogPeriodTitle">Remote Log Period (seconds)</string>
</resources> </resources>

View File

@@ -0,0 +1,52 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<CheckBoxPreference
android:defaultValue="true"
android:key="LogAlarms"
android:summary="@string/log_alarms_summary"
android:title="@string/log_alarms_title" />
<CheckBoxPreference
android:defaultValue="true"
android:key="LogData"
android:summary="@string/log_data_summary"
android:title="@string/log_data_title" />
<EditTextPreference
android:defaultValue="150"
android:key="EventDurationSec"
android:summary="@string/eventDurationSummary"
android:title="@string/eventDurationTitle" />
<CheckBoxPreference
android:defaultValue="false"
android:key="AutoPruneDb"
android:summary="@string/AutoPruneDbSummary"
android:title="@string/AutoPruneDbTitle" />
<EditTextPreference
android:defaultValue="28"
android:key="DataRetentionPeriod"
android:summary="@string/dataRetentionPeriodSummary"
android:title="@string/dataRetentionPeriodTitle" />
<CheckBoxPreference
android:defaultValue="false"
android:key="LogDataRemote"
android:summary="@string/log_data_remote_summary"
android:title="@string/log_data_remote_title" />
<CheckBoxPreference
android:defaultValue="false"
android:key="LogDataRemoteMobile"
android:summary="@string/log_data_remote_mobile_summary"
android:title="@string/log_data_remote_mobile_title" />
<EditTextPreference
android:defaultValue="60"
android:key="RemoteLogPeriod"
android:summary="@string/remoteLogPeriodSummary"
android:title="@string/remoteLogPeriodTitle" />
<EditTextPreference
android:defaultValue="https://osdapi.ddns.net/"
android:key="OSDUrl"
android:summary="@string/remote_url_summary"
android:title="@string/remote_url_title" />
</PreferenceScreen>

View File

@@ -17,6 +17,11 @@
android:title="@string/alarms_settings_title" android:title="@string/alarms_settings_title"
android:summary="@string/alarms_settings_summary" /> android:summary="@string/alarms_settings_summary" />
<header android:fragment="uk.org.openseizuredetector.PrefActivity$LoggingPrefsFragment"
android:icon="@drawable/icon_24x24"
android:title="@string/logging_settings_title"
android:summary="@string/logging_settings_summary" />
<header android:fragment="uk.org.openseizuredetector.PrefActivity$SeizureDetectorPrefsFragment" <header android:fragment="uk.org.openseizuredetector.PrefActivity$SeizureDetectorPrefsFragment"
android:icon="@drawable/icon_24x24" android:icon="@drawable/icon_24x24"
android:title="@string/seizure_detector_settings_title" android:title="@string/seizure_detector_settings_title"