Added data logging preferences to settings page
This commit is contained in:
@@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
52
app/src/main/res/xml/logging_prefs.xml
Normal file
52
app/src/main/res/xml/logging_prefs.xml
Normal 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>
|
||||||
@@ -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"
|
||||||
|
|||||||
Reference in New Issue
Block a user