diff --git a/app/src/main/java/uk/org/openseizuredetector/LogManager.java b/app/src/main/java/uk/org/openseizuredetector/LogManager.java index 56c47cb..f8bd954 100644 --- a/app/src/main/java/uk/org/openseizuredetector/LogManager.java +++ b/app/src/main/java/uk/org/openseizuredetector/LogManager.java @@ -81,13 +81,19 @@ public class LogManager implements AuthCallbackInterface, EventCallbackInterface public WebApiConnection mWac; 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 mLocaDbTimeLimitDays = 1; // Prunes the local db so it only retains data younger than this duration. + private long mEventDuration = 120; // event duration in seconds - uploads datapoints that cover this time range centred on the event time. + 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 mDatapointsToUploadList; private int mCurrentEventId; private int mCurrentDatapointId; + private long mAutoPrunePeriod = 3600; // Prune the database every hour + private boolean mAutoPruneDb; + private AutoPruneTimer mAutoPruneTimer; + public LogManager(Context context) { + String prefVal; Log.d(TAG,"LogManger Constructor"); mContext = context; Handler handler = new Handler(); @@ -99,6 +105,22 @@ public class LogManager implements AuthCallbackInterface, EventCallbackInterface mLogRemoteMobile = (prefs.getBoolean("LogDataRemoteMobile", false)); 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); openDb(); @@ -106,6 +128,13 @@ public class LogManager implements AuthCallbackInterface, EventCallbackInterface 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. // Based on https://www.tutlane.com/tutorial/android/android-sqlite-listview-with-examples public ArrayList> getEventsList(boolean includeWarnings) { - Log.v(TAG,"getEventsList()"); + //Log.v(TAG,"getEventsList()"); SQLiteDatabase db = mOSDDb.getWritableDatabase(); ArrayList> eventsList = new ArrayList<>(); String statusListStr, sqlStr; @@ -348,7 +377,7 @@ public class LogManager implements AuthCallbackInterface, EventCallbackInterface //event.put("dataJSON", cursor.getString(cursor.getColumnIndex("dataJSON"))); eventsList.add(event); } - Log.v(TAG,"getEventsList() - returning "+eventsList); + //Log.v(TAG,"getEventsList() - returning "+eventsList); return eventsList; } @@ -360,8 +389,8 @@ public class LogManager implements AuthCallbackInterface, EventCallbackInterface Cursor c = null; int retVal; long currentDateMillis = new Date().getTime(); - //long endDateMillis = currentDateMillis - 24*3600*1000* mLocaDbTimeLimitDays; - long endDateMillis = currentDateMillis - 3600*1000* mLocaDbTimeLimitDays; // Using hours rather than days for testing + long endDateMillis = currentDateMillis - 24*3600*1000* mDataRetentionPeriod; + //long endDateMillis = currentDateMillis - 3600*1000* mDataRetentionPeriod; // Using hours rather than days for testing SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 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. */ public int getNextEventToUpload(boolean includeWarnings) { - Log.v(TAG, "getNextEventToUpload()"); + Log.v(TAG, "getNextEventToUpload("+includeWarnings+")"); Time tnow = new Time(Time.getCurrentTimezone()); tnow.setToNow(); String dateStr = tnow.format("%Y-%m-%d"); @@ -397,10 +426,14 @@ public class LogManager implements AuthCallbackInterface, EventCallbackInterface } else { 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 { - //FIXME: We need to exclude very recent records from this, otherwise the system might upload - // 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+");"; + SQLStr = "SELECT * from "+ mDbTableName + " where uploaded=false and Status in ("+statusListStr+") and DataTime<'"+endDateStr+"';"; Cursor resultSet = mOSDDb.getWritableDatabase().rawQuery(SQLStr,null); resultSet.moveToFirst(); if (resultSet.getCount() == 0) { @@ -460,7 +493,7 @@ public class LogManager implements AuthCallbackInterface, EventCallbackInterface * Return the number of events stored in the local database */ public int getLocalEventsCount(boolean includeWarnings) { - Log.v(TAG, "getLocalEventsCount()"); + //Log.v(TAG, "getLocalEventsCount()"); String SQLStr = "SQLStr"; String statusListStr; @@ -485,7 +518,7 @@ public class LogManager implements AuthCallbackInterface, EventCallbackInterface * Return the number of datapoints stored in the local database */ public int getLocalDatapointsCount() { - Log.v(TAG, "getLocalDatapointsCount()"); + //Log.v(TAG, "getLocalDatapointsCount()"); String SQLStr = "SQLStr"; String statusListStr; @@ -645,8 +678,8 @@ public class LogManager implements AuthCallbackInterface, EventCallbackInterface Log.v(TAG,"eventCallback() EventId="+eventId+", eventDateStr="+eventDateStr+", eventDate="+eventDate.toString()); long eventDateMillis = eventDate.getTime(); - long startDateMillis = eventDateMillis - 1000*60* eventDuration/2; - long endDateMillis = eventDateMillis + 1000*60*eventDuration/2; + long startDateMillis = eventDateMillis - 1000* mEventDuration /2; + long endDateMillis = eventDateMillis + 1000* mEventDuration /2; dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String datapointsJsonStr = getDatapointsbyDate( @@ -732,7 +765,7 @@ public class LogManager implements AuthCallbackInterface, EventCallbackInterface } Log.v(TAG, "startRemoteLogTimer() - starting RemoteLogTimer"); mRemoteLogTimer = - new RemoteLogTimer(10 * 1000, 1000); + new RemoteLogTimer(mRemoteLogPeriod * 1000, 1000); 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 { // 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(); + } + + } + + } diff --git a/app/src/main/java/uk/org/openseizuredetector/LogManagerControlActivity.java b/app/src/main/java/uk/org/openseizuredetector/LogManagerControlActivity.java index 8492700..061221c 100644 --- a/app/src/main/java/uk/org/openseizuredetector/LogManagerControlActivity.java +++ b/app/src/main/java/uk/org/openseizuredetector/LogManagerControlActivity.java @@ -119,11 +119,12 @@ public class LogManagerControlActivity extends AppCompatActivity { @Override public void onClick(View view) { Log.v(TAG, "onPruneBtn"); + // Confirmation dialog based on: https://stackoverflow.com/a/12213536/2104584 AlertDialog.Builder builder = new AlertDialog.Builder(mContext); 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() { @Override public void onClick(DialogInterface dialog, int which) { @@ -178,7 +179,7 @@ public class LogManagerControlActivity extends AppCompatActivity { } Log.v(TAG, "startRemoteLogTimer() - starting RemoteLogTimer"); mUiTimer = - new UiTimer(1000, 1000); + new UiTimer(5000, 1000); mUiTimer.start(); } diff --git a/app/src/main/java/uk/org/openseizuredetector/PrefActivity.java b/app/src/main/java/uk/org/openseizuredetector/PrefActivity.java index 9620c7c..66f49a9 100644 --- a/app/src/main/java/uk/org/openseizuredetector/PrefActivity.java +++ b/app/src/main/java/uk/org/openseizuredetector/PrefActivity.java @@ -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 { @Override public void onCreate(Bundle savedInstanceState) { diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 8d28647..eabcdd4 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -308,4 +308,14 @@ Events in Local Database Created new Manual Alarm Event Datapoint not found - not doing anything + Data Logging Settings + Settings that control how data is recorded on the phone and uploaded to the Open Seizure Database + The time (in seconds) before and after a seizure event that we record data. + Event Duration (seconds) + Data Retention Period (days) + The period (in days) that data will be retained and is protected from deletion by the \'Prune Database\' Option. + Automatically Prune (Trim) Database + Automatically Prune (Trim) the Database periodically to prevent excessive storage capacity (memory) usage. + 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. + Remote Log Period (seconds) diff --git a/app/src/main/res/xml/logging_prefs.xml b/app/src/main/res/xml/logging_prefs.xml new file mode 100644 index 0000000..483d19b --- /dev/null +++ b/app/src/main/res/xml/logging_prefs.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/xml/preference_headers.xml b/app/src/main/res/xml/preference_headers.xml index c205cc3..829de47 100644 --- a/app/src/main/res/xml/preference_headers.xml +++ b/app/src/main/res/xml/preference_headers.xml @@ -17,6 +17,11 @@ android:title="@string/alarms_settings_title" android:summary="@string/alarms_settings_summary" /> +
+