Moved system logging to use sqlite database rather than file - removed need for access external strage permission.
This commit is contained in:
@@ -68,17 +68,15 @@ import java.util.function.Consumer;
|
||||
public class LogManager {
|
||||
static final private String TAG = "LogManager";
|
||||
//private String mDbName = "osdData";
|
||||
final private String mDpTableName = "datapoints";
|
||||
final private String mSysLogTableName = "syslog";
|
||||
final static private String mDpTableName = "datapoints";
|
||||
private boolean mLogRemote;
|
||||
private boolean mLogRemoteMobile;
|
||||
private String mAuthToken;
|
||||
static private OsdDbHelper mDpDb; // Datapoints table helper.
|
||||
private OsdDbHelper mSysLogDb; // Datapoints table helper.
|
||||
static private SQLiteDatabase mOsdDb = null; // SQLite Database for data and log entries.
|
||||
private RemoteLogTimer mRemoteLogTimer;
|
||||
private Context mContext;
|
||||
private static Context mContext;
|
||||
private OsdUtil mUtil;
|
||||
public WebApiConnection mWac;
|
||||
public static WebApiConnection mWac;
|
||||
|
||||
private boolean mUploadInProgress;
|
||||
private long mEventDuration = 120; // event duration in seconds - uploads datapoints that cover this time range centred on the event time.
|
||||
@@ -116,16 +114,22 @@ public class LogManager {
|
||||
|
||||
mUtil = new OsdUtil(mContext, handler);
|
||||
openDb();
|
||||
Log.i(TAG,"Starting Remote Database Interface");
|
||||
mWac = new WebApiConnection(mContext);
|
||||
mWac.setStoredToken(mAuthToken);
|
||||
|
||||
startRemoteLogTimer();
|
||||
if (mLogRemote) {
|
||||
Log.i(TAG,"Starting Remote Log Timer");
|
||||
startRemoteLogTimer();
|
||||
} else {
|
||||
Log.i(TAG,"mLogRemote is false - not starting remote log timer");
|
||||
}
|
||||
|
||||
if (mAutoPruneDb) {
|
||||
Log.v(TAG, "Starting Auto Prune Timer");
|
||||
Log.i(TAG, "Starting Auto Prune Timer");
|
||||
startAutoPruneTimer();
|
||||
} else {
|
||||
Log.v(TAG, "AutoPruneDB is not set");
|
||||
Log.i(TAG, "AutoPruneDB is not set - not starting Auto Prune Timer");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -168,43 +172,34 @@ public class LogManager {
|
||||
}
|
||||
|
||||
|
||||
private boolean openDb() {
|
||||
private static boolean openDb() {
|
||||
Log.d(TAG, "openDb");
|
||||
try {
|
||||
mDpDb = new OsdDbHelper(mDpTableName, mContext);
|
||||
if (!checkTableExists(mDpDb, mDpTableName)) {
|
||||
Log.e(TAG, "ERROR - Table does not exist");
|
||||
if (mOsdDb == null) {
|
||||
Log.i(TAG,"openDb: mOsdDb is null - initialising");
|
||||
mOsdDb = new OsdDbHelper(mContext).getWritableDatabase();
|
||||
} else {
|
||||
Log.i(TAG,"openDb: mOsdDb has been initialised already so not doing anything");
|
||||
}
|
||||
if (!checkTableExists(mOsdDb, mDpTableName)) {
|
||||
Log.e(TAG, "ERROR - Table "+mDpTableName+" does not exist");
|
||||
return false;
|
||||
} else {
|
||||
Log.d(TAG, "table " + mDpTableName + " exists ok");
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
Log.e(TAG, "Failed to open Database: " + e.toString());
|
||||
mDpDb = null;
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
mSysLogDb = new OsdDbHelper(mSysLogTableName, mContext);
|
||||
if (!checkTableExists(mSysLogDb, mSysLogTableName)) {
|
||||
Log.e(TAG, "ERROR - SysLog table does not exist");
|
||||
return false;
|
||||
} else {
|
||||
Log.d(TAG, "table " + mSysLogTableName + " exists ok");
|
||||
}
|
||||
return true;
|
||||
} catch (SQLException e) {
|
||||
Log.e(TAG, "Failed to open Syslog Database: " + e.toString());
|
||||
mSysLogDb = null;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean checkTableExists(OsdDbHelper osdDb, String osdTableName) {
|
||||
private static boolean checkTableExists(SQLiteDatabase osdDb, String osdTableName) {
|
||||
Cursor c = null;
|
||||
boolean tableExists = false;
|
||||
Log.d(TAG, "checkTableExists()");
|
||||
try {
|
||||
c = osdDb.getWritableDatabase().query(osdTableName, null,
|
||||
c = osdDb.query(osdTableName, null,
|
||||
null, null, null, null, null);
|
||||
tableExists = true;
|
||||
c.close();
|
||||
@@ -239,7 +234,7 @@ public class LogManager {
|
||||
+ DatabaseUtils.sqlEscapeString(sdData.toJSON(true)) + ","
|
||||
+ 0
|
||||
+ ")";
|
||||
mDpDb.getWritableDatabase().execSQL(SQLStr);
|
||||
mOsdDb.execSQL(SQLStr);
|
||||
Log.v(TAG, "data written to database");
|
||||
|
||||
} catch (SQLException e) {
|
||||
@@ -249,37 +244,6 @@ public class LogManager {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Write syslog string to local database
|
||||
* FIXME - I am sure we should not be using raw SQL Srings to do this!
|
||||
*/
|
||||
public void writeLogEntryToLocalDb(String logText, int statusVal) {
|
||||
Log.v(TAG, "writeLogEntryToLocalDb()");
|
||||
Date curDate = new Date();
|
||||
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
|
||||
String dateStr = dateFormat.format(curDate);
|
||||
String SQLStr = "SQLStr";
|
||||
|
||||
try {
|
||||
SQLStr = "INSERT INTO " + mSysLogTableName
|
||||
+ "(dataTime, status, dataJSON, uploaded)"
|
||||
+ " VALUES("
|
||||
+ "'" + dateStr + "',"
|
||||
+ statusVal + ","
|
||||
+ DatabaseUtils.sqlEscapeString(logText) + ","
|
||||
+ 0
|
||||
+ ")";
|
||||
mSysLogDb.getWritableDatabase().execSQL(SQLStr);
|
||||
Log.v(TAG, "syslog entry written to database: "+logText);
|
||||
|
||||
} catch (SQLException e) {
|
||||
Log.e(TAG, "writeToLocalDb(): Error Writing Data: " + e.toString());
|
||||
Log.e(TAG, "SQLStr was " + SQLStr);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a json representation of datapoint 'id'.
|
||||
@@ -296,7 +260,7 @@ public class LogManager {
|
||||
//String[] selectArgs = new String[]{String.format("%d", id)};
|
||||
//c = mOSDDb.getWritableDatabase().query(mDbTableName, null,
|
||||
// selectStr, selectArgs, null, null, null);
|
||||
c = mDpDb.getWritableDatabase().rawQuery(selectStr, null);
|
||||
c = mOsdDb.rawQuery(selectStr, null);
|
||||
retVal = cursor2Json(c);
|
||||
} catch (Exception e) {
|
||||
Log.d(TAG, "getDatapointById(): Error Querying Database: " + e.getLocalizedMessage());
|
||||
@@ -317,7 +281,7 @@ public class LogManager {
|
||||
Log.d(TAG, "setDatapointToUploaded() - id=" + id);
|
||||
ContentValues cv = new ContentValues();
|
||||
cv.put("uploaded", eventId);
|
||||
int nRowsUpdated = mDpDb.getWritableDatabase().update(mDpTableName, cv, "id = ?",
|
||||
int nRowsUpdated = mOsdDb.update(mDpTableName, cv, "id = ?",
|
||||
new String[]{String.format("%d", id)});
|
||||
|
||||
return (nRowsUpdated == 1);
|
||||
@@ -336,7 +300,7 @@ public class LogManager {
|
||||
//Cursor c = null;
|
||||
ContentValues cv = new ContentValues();
|
||||
cv.put("status", statusVal);
|
||||
int nRowsUpdated = mDpDb.getWritableDatabase().update(mDpTableName, cv, "id = ?",
|
||||
int nRowsUpdated = mOsdDb.update(mDpTableName, cv, "id = ?",
|
||||
new String[]{String.format("%d", id)});
|
||||
|
||||
return (nRowsUpdated == 1);
|
||||
@@ -419,7 +383,7 @@ public class LogManager {
|
||||
try {
|
||||
String selectStr = "DataTime<=?";
|
||||
String[] selectArgs = {endDateStr};
|
||||
retVal = mDpDb.getWritableDatabase().delete(mDpTableName, selectStr, selectArgs);
|
||||
retVal = mOsdDb.delete(mDpTableName, selectStr, selectArgs);
|
||||
} catch (Exception e) {
|
||||
Log.d(TAG, "Error deleting datapoints" + e.toString());
|
||||
retVal = 0;
|
||||
@@ -599,7 +563,7 @@ public class LogManager {
|
||||
+ ", mHaving =" + mHaving + ", mOrderBy=" + mOrderBy);
|
||||
|
||||
try {
|
||||
Cursor resultSet = mDpDb.getWritableDatabase().query(mTable, mColumns, mSelection,
|
||||
Cursor resultSet = mOsdDb.query(mTable, mColumns, mSelection,
|
||||
mSelectionArgs, mGroupBy, mHaving, mOrderBy);
|
||||
resultSet.moveToFirst();
|
||||
return (resultSet);
|
||||
@@ -826,26 +790,36 @@ public class LogManager {
|
||||
|
||||
/**
|
||||
* close() - shut down the logging system
|
||||
* WARNING - this should only be called by the final destructor of the app (not individual class destructors)
|
||||
* because it will close the DB for all instances of LogManger, not just the one on which it is called.
|
||||
* FIXME: If I was keen I would keep a count of how many instances of LogManager there are, and have this function do nothing
|
||||
* unless it was the last instance.
|
||||
*/
|
||||
public void close() {
|
||||
mDpDb.close();
|
||||
stopRemoteLogTimer();
|
||||
public static void close() {
|
||||
mOsdDb.close();
|
||||
mOsdDb = null;
|
||||
if (mWac != null) {
|
||||
Log.i(TAG,"Stopping Remote Database");
|
||||
Log.i(TAG,"Stopping Remote Database Interface");
|
||||
mWac.close();
|
||||
}
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
// Stop the timers and shutdown the remote API connection.
|
||||
stopRemoteLogTimer();
|
||||
stopAutoPruneTimer();
|
||||
}
|
||||
|
||||
/*
|
||||
* Start the timer that will upload data to the remote server after a given period.
|
||||
*/
|
||||
private void startRemoteLogTimer() {
|
||||
if (mRemoteLogTimer != null) {
|
||||
Log.v(TAG, "startRemoteLogTimer -timer already running - cancelling it");
|
||||
Log.i(TAG, "startRemoteLogTimer -timer already running - cancelling it");
|
||||
mRemoteLogTimer.cancel();
|
||||
mRemoteLogTimer = null;
|
||||
}
|
||||
Log.v(TAG, "startRemoteLogTimer() - starting RemoteLogTimer");
|
||||
Log.i(TAG, "startRemoteLogTimer() - starting RemoteLogTimer");
|
||||
mRemoteLogTimer =
|
||||
new RemoteLogTimer(mRemoteLogPeriod * 1000, 1000);
|
||||
mRemoteLogTimer.start();
|
||||
@@ -857,7 +831,7 @@ public class LogManager {
|
||||
*/
|
||||
public void stopRemoteLogTimer() {
|
||||
if (mRemoteLogTimer != null) {
|
||||
Log.v(TAG, "stopRemoteLogTimer(): cancelling Remote Log timer");
|
||||
Log.i(TAG, "stopRemoteLogTimer(): cancelling Remote Log timer");
|
||||
mRemoteLogTimer.cancel();
|
||||
mRemoteLogTimer = null;
|
||||
}
|
||||
@@ -869,11 +843,11 @@ public class LogManager {
|
||||
*/
|
||||
private void startAutoPruneTimer() {
|
||||
if (mAutoPruneTimer != null) {
|
||||
Log.v(TAG, "startAutoPruneTimer -timer already running - cancelling it");
|
||||
Log.i(TAG, "startAutoPruneTimer -timer already running - cancelling it");
|
||||
mAutoPruneTimer.cancel();
|
||||
mAutoPruneTimer = null;
|
||||
}
|
||||
Log.v(TAG, "startAutoPruneTimer() - starting AutoPruneTimer");
|
||||
Log.i(TAG, "startAutoPruneTimer() - starting AutoPruneTimer");
|
||||
mAutoPruneTimer =
|
||||
new AutoPruneTimer(mAutoPrunePeriod * 1000, 1000);
|
||||
mAutoPruneTimer.start();
|
||||
@@ -885,47 +859,46 @@ public class LogManager {
|
||||
*/
|
||||
public void stopAutoPruneTimer() {
|
||||
if (mAutoPruneTimer != null) {
|
||||
Log.v(TAG, "stopAutoPruneTimer(): cancelling Auto Prune timer");
|
||||
Log.i(TAG, "stopAutoPruneTimer(): cancelling Auto Prune timer");
|
||||
mAutoPruneTimer.cancel();
|
||||
mAutoPruneTimer = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static public class OsdDbHelper extends SQLiteOpenHelper {
|
||||
public static class OsdDbHelper extends SQLiteOpenHelper {
|
||||
// If you change the database schema, you must increment the database version.
|
||||
public static final int DATABASE_VERSION = 1;
|
||||
public static final String DATABASE_NAME = "OsdData.db";
|
||||
private final String mOsdTableName;
|
||||
private static final String TAG = "LogManager.OsdDbHelper";
|
||||
|
||||
public OsdDbHelper(String osdTableName, Context context) {
|
||||
public OsdDbHelper(Context context) {
|
||||
super(context, DATABASE_NAME, null, DATABASE_VERSION);
|
||||
Log.d(TAG, "OsdDbHelper constructor");
|
||||
mOsdTableName = osdTableName;
|
||||
}
|
||||
|
||||
public void onCreate(SQLiteDatabase db) {
|
||||
Log.v(TAG, "onCreate - TableName=" + mOsdTableName);
|
||||
String SQLStr = "CREATE TABLE IF NOT EXISTS " + mOsdTableName + "("
|
||||
Log.i(TAG, "onCreate - TableName=" + mDpTableName);
|
||||
String SQLStr = "CREATE TABLE IF NOT EXISTS " + mDpTableName + "("
|
||||
+ "id INTEGER PRIMARY KEY,"
|
||||
+ "dataTime DATETIME,"
|
||||
+ "Status INT,"
|
||||
+ "dataJSON TEXT,"
|
||||
+ "uploaded INT"
|
||||
+ ");";
|
||||
|
||||
db.execSQL(SQLStr);
|
||||
}
|
||||
|
||||
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||
// This database is only a cache for online data, so its upgrade policy is
|
||||
// to simply to discard the data and start over
|
||||
db.execSQL("Drop table if exists " + mOsdTableName + ";");
|
||||
Log.i(TAG,"onUpgrade()");
|
||||
db.execSQL("Drop table if exists " + mDpTableName + ";");
|
||||
onCreate(db);
|
||||
}
|
||||
|
||||
public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||
Log.i(TAG,"onDowngrade()");
|
||||
onUpgrade(db, oldVersion, newVersion);
|
||||
}
|
||||
}
|
||||
@@ -947,7 +920,7 @@ public class LogManager {
|
||||
|
||||
@Override
|
||||
public void onFinish() {
|
||||
Log.v(TAG, "mRemoteLogTimer - onFinish - uploading data to remote database");
|
||||
Log.d(TAG, "mRemoteLogTimer - onFinish - uploading data to remote database");
|
||||
writeToRemoteServer();
|
||||
// Restart this timer.
|
||||
start();
|
||||
@@ -969,7 +942,7 @@ public class LogManager {
|
||||
|
||||
@Override
|
||||
public void onFinish() {
|
||||
Log.v(TAG, "mAutoPruneTimer - onFinish - Pruning Local Database");
|
||||
Log.d(TAG, "mAutoPruneTimer - onFinish - Pruning Local Database");
|
||||
pruneLocalDb();
|
||||
// Restart this timer.
|
||||
start();
|
||||
|
||||
@@ -51,16 +51,16 @@ public class LogManagerControlActivity extends AppCompatActivity {
|
||||
private UiTimer mUiTimer;
|
||||
private ArrayList<HashMap<String, String>> mEventsList;
|
||||
private ArrayList<HashMap<String, String>> mRemoteEventsList;
|
||||
private ArrayList<HashMap<String, String>> mSysLogList;
|
||||
private SdServiceConnection mConnection;
|
||||
private OsdUtil mUtil;
|
||||
final Handler serverStatusHandler = new Handler();
|
||||
private Integer mUiTimerPeriodFast = 2000; // 2 seconds - we use fast updating while UI is blank and we are waiting for first data
|
||||
private Integer mUiTimerPeriodSlow = 60000; // 60 seconds - once data has been received and UI populated we only update once per minute.
|
||||
|
||||
private Integer UI_MODE_LOCAL = 0;
|
||||
private Integer UI_MODE_SHARED = 1;
|
||||
|
||||
private Integer mUiMode = UI_MODE_SHARED;
|
||||
private boolean mUpdateSysLog = true;
|
||||
//private Integer UI_MODE_LOCAL = 0;
|
||||
//private Integer UI_MODE_SHARED = 1;
|
||||
//private Integer mUiMode = UI_MODE_SHARED;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
@@ -198,7 +198,11 @@ public class LogManagerControlActivity extends AppCompatActivity {
|
||||
Log.v(TAG, "initialiseServiceConnection() - set mEventsList - Updating UI");
|
||||
updateUi();
|
||||
});
|
||||
//mEventsList = mLm.getEventsList(true);
|
||||
mUtil.getSysLogList((ArrayList<HashMap<String, String>> syslogList) -> {
|
||||
mSysLogList = syslogList;
|
||||
Log.v(TAG, "initialiseServiceConnection() - set mSysLogList - Updating UI");
|
||||
updateUi();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -275,6 +279,16 @@ public class LogManagerControlActivity extends AppCompatActivity {
|
||||
} else {
|
||||
stopUpdating = false;
|
||||
}
|
||||
// SysLog ListView
|
||||
if (mSysLogList != null && mUpdateSysLog) {
|
||||
ListView lv = (ListView) findViewById(R.id.sysLogListView);
|
||||
ListAdapter adapter = new SimpleAdapter(LogManagerControlActivity.this, mSysLogList, R.layout.syslog_entry_layout,
|
||||
new String[]{"dataTime", "logLevel", "dataJSON"},
|
||||
new int[]{R.id.syslog_entry_date_tv, R.id.syslog_level_tv, R.id.syslog_entry_text_tv});
|
||||
lv.setAdapter(adapter);
|
||||
//Log.v(TAG,"eventsList="+mEventsList);
|
||||
mUpdateSysLog = false;
|
||||
}
|
||||
// Remote Database List View
|
||||
if (mRemoteEventsList != null) {
|
||||
ListView lv = (ListView) findViewById(R.id.remoteEventsLv);
|
||||
@@ -316,8 +330,9 @@ public class LogManagerControlActivity extends AppCompatActivity {
|
||||
} //updateUi();
|
||||
|
||||
public void onRadioButtonClicked(View view) {
|
||||
LinearLayout localDataLl = (LinearLayout) findViewById(R.id.local_data_ll);;
|
||||
LinearLayout sharedDataLl = (LinearLayout) findViewById(R.id.shared_data_ll);;;
|
||||
LinearLayout localDataLl = (LinearLayout) findViewById(R.id.local_data_ll);
|
||||
LinearLayout sharedDataLl = (LinearLayout) findViewById(R.id.shared_data_ll);
|
||||
LinearLayout syslogLl = (LinearLayout) findViewById(R.id.syslog_ll);
|
||||
// Is the button now checked?
|
||||
boolean checked = ((RadioButton) view).isChecked();
|
||||
|
||||
@@ -328,6 +343,7 @@ public class LogManagerControlActivity extends AppCompatActivity {
|
||||
// Switch to the local data view
|
||||
localDataLl.setVisibility(View.VISIBLE);
|
||||
sharedDataLl.setVisibility(View.GONE);
|
||||
syslogLl.setVisibility(View.GONE);
|
||||
}
|
||||
break;
|
||||
case R.id.shared_data_rb:
|
||||
@@ -335,8 +351,17 @@ public class LogManagerControlActivity extends AppCompatActivity {
|
||||
// Switch to the local data view
|
||||
localDataLl.setVisibility(View.GONE);
|
||||
sharedDataLl.setVisibility(View.VISIBLE);
|
||||
syslogLl.setVisibility(View.GONE);
|
||||
}
|
||||
break;
|
||||
case R.id.syslog_rb:
|
||||
if (checked) {
|
||||
// Switch to the local data view
|
||||
localDataLl.setVisibility(View.GONE);
|
||||
sharedDataLl.setVisibility(View.GONE);
|
||||
syslogLl.setVisibility(View.VISIBLE);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -306,7 +306,7 @@ public class MainActivity extends AppCompatActivity {
|
||||
}
|
||||
return true;
|
||||
*/
|
||||
case R.id.action_logs:
|
||||
/* case R.id.action_logs:
|
||||
Log.i(TAG, "action_logs");
|
||||
try {
|
||||
String url = "http://"
|
||||
@@ -323,6 +323,7 @@ public class MainActivity extends AppCompatActivity {
|
||||
Log.i(TAG, "exception starting log manager activity " + ex.toString());
|
||||
}
|
||||
return true;
|
||||
*/
|
||||
case R.id.action_logmanager:
|
||||
Log.i(TAG, "action_logmanager");
|
||||
try {
|
||||
|
||||
@@ -27,60 +27,43 @@ package uk.org.openseizuredetector;
|
||||
import android.Manifest;
|
||||
import android.app.Activity;
|
||||
import android.app.ActivityManager;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.ServiceConnection;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.FeatureInfo;
|
||||
import android.content.pm.InstrumentationInfo;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageInstaller;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PermissionGroupInfo;
|
||||
import android.content.pm.PermissionInfo;
|
||||
import android.content.pm.ProviderInfo;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.content.pm.ServiceInfo;
|
||||
import android.content.res.Resources;
|
||||
import android.content.res.XmlResourceParser;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.database.Cursor;
|
||||
import android.database.DatabaseUtils;
|
||||
import android.database.SQLException;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteOpenHelper;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.NetworkInfo;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Build;
|
||||
import android.os.Environment;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.UserHandle;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.app.ActivityCompat;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.text.format.Time;
|
||||
import android.util.Log;
|
||||
import android.view.MenuItem;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.apache.http.conn.util.InetAddressUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.NetworkInterface;
|
||||
import java.util.AbstractList;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
import java.util.RandomAccess;
|
||||
import java.util.concurrent.RunnableFuture;
|
||||
import java.util.HashMap;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* OsdUtil - OpenSeizureDetector Utilities
|
||||
@@ -92,7 +75,7 @@ public class OsdUtil implements ActivityCompat.OnRequestPermissionsResultCallbac
|
||||
private final String DATALOG = "DataLog";
|
||||
|
||||
private final String[] REQUIRED_PERMISSIONS = {
|
||||
Manifest.permission.WRITE_EXTERNAL_STORAGE,
|
||||
//Manifest.permission.WRITE_EXTERNAL_STORAGE,
|
||||
Manifest.permission.WAKE_LOCK,
|
||||
};
|
||||
|
||||
@@ -107,14 +90,19 @@ public class OsdUtil implements ActivityCompat.OnRequestPermissionsResultCallbac
|
||||
/**
|
||||
* Based on http://stackoverflow.com/questions/7440473/android-how-to-check-if-the-intent-service-is-still-running-or-has-stopped-running
|
||||
*/
|
||||
private Context mContext;
|
||||
private static Context mContext;
|
||||
private Handler mHandler;
|
||||
private String TAG = "OsdUtil";
|
||||
private static String TAG = "OsdUtil";
|
||||
private boolean mLogAlarms = true;
|
||||
private boolean mLogSystem = true;
|
||||
private boolean mLogData = true;
|
||||
private boolean mPermissionsRequested = false;
|
||||
private boolean mSMSPermissionsRequested = false;
|
||||
private static final String mSysLogTableName = "SysLog";
|
||||
//private LogManager mLm;
|
||||
static private SQLiteDatabase mSysLogDb = null; // SQLite Database for data and log entries.
|
||||
private final static Long mMinPruneInterval = new Long(5 * 60 * 1000); // minimum time between syslog pruning is 5 minutes
|
||||
private static Long mLastPruneMillis = new Long(0); // Record of the last time we pruned the syslog db.
|
||||
|
||||
private static int mNbound = 0;
|
||||
|
||||
@@ -122,6 +110,9 @@ public class OsdUtil implements ActivityCompat.OnRequestPermissionsResultCallbac
|
||||
mContext = context;
|
||||
mHandler = handler;
|
||||
updatePrefs();
|
||||
//Log.i(TAG,"Creating Log Manager instance");
|
||||
//mLm = new LogManager(mContext,false,false,null,0,0,false,0);
|
||||
openDb();
|
||||
writeToSysLogFile("OsdUtil() - initialised");
|
||||
|
||||
}
|
||||
@@ -171,7 +162,7 @@ public class OsdUtil implements ActivityCompat.OnRequestPermissionsResultCallbac
|
||||
}
|
||||
}
|
||||
if (nServers != 0) {
|
||||
Log.v(TAG, "isServerRunning() - " + nServers + " instances are running");
|
||||
//Log.v(TAG, "isServerRunning() - " + nServers + " instances are running");
|
||||
return true;
|
||||
} else
|
||||
return false;
|
||||
@@ -337,16 +328,18 @@ public class OsdUtil implements ActivityCompat.OnRequestPermissionsResultCallbac
|
||||
|
||||
|
||||
/**
|
||||
* Write a message to the system log file, provided mLogSystem is true.
|
||||
* Write a message to the system log database.
|
||||
*
|
||||
* @param msgStr
|
||||
*/
|
||||
public void writeToSysLogFile(String msgStr) {
|
||||
if (mLogSystem)
|
||||
writeToLogFile(SYSLOG, msgStr);
|
||||
else
|
||||
Log.v(TAG, "writeToSysLogFile - mLogSystem False so not writing");
|
||||
public void writeToSysLogFile(String msgStr,String logType) {
|
||||
writeLogEntryToLocalDb(msgStr,logType);
|
||||
}
|
||||
public void writeToSysLogFile(String msgStr) {
|
||||
writeLogEntryToLocalDb(msgStr,"v");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Write a message to the alarm log file, provided mLogAlarms is true.
|
||||
@@ -572,4 +565,238 @@ public class OsdUtil implements ActivityCompat.OnRequestPermissionsResultCallbac
|
||||
}
|
||||
return(retVal);
|
||||
}
|
||||
|
||||
private static boolean openDb() {
|
||||
Log.d(TAG, "openDb");
|
||||
try {
|
||||
if (mSysLogDb == null) {
|
||||
Log.i(TAG,"openDb: mSysLogDb is null - initialising");
|
||||
mSysLogDb = new OsdSysLogHelper(mContext).getWritableDatabase();
|
||||
} else {
|
||||
Log.i(TAG,"openDb: mSysLogDb has been initialised already so not doing anything");
|
||||
}
|
||||
if (!checkTableExists(mSysLogDb, mSysLogTableName)) {
|
||||
Log.e(TAG, "ERROR - Table "+mSysLogTableName+" does not exist");
|
||||
return false;
|
||||
} else {
|
||||
Log.d(TAG, "table " + mSysLogTableName + " exists ok");
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
Log.e(TAG, "Failed to open Database: " + e.toString());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean checkTableExists(SQLiteDatabase osdDb, String osdTableName) {
|
||||
Cursor c = null;
|
||||
boolean tableExists = false;
|
||||
Log.d(TAG, "checkTableExists()");
|
||||
try {
|
||||
c = osdDb.query(osdTableName, null,
|
||||
null, null, null, null, null);
|
||||
tableExists = true;
|
||||
c.close();
|
||||
} catch (Exception e) {
|
||||
Log.d(TAG, osdTableName + " doesn't exist :(((");
|
||||
}
|
||||
return tableExists;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write syslog string to local database
|
||||
* FIXME - I am sure we should not be using raw SQL Srings to do this!
|
||||
*/
|
||||
public void writeLogEntryToLocalDb(String logText, String statusVal) {
|
||||
Log.v(TAG, "writeLogEntryToLocalDb()");
|
||||
Date curDate = new Date();
|
||||
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
|
||||
String dateStr = dateFormat.format(curDate);
|
||||
String SQLStr = "SQLStr";
|
||||
|
||||
try {
|
||||
SQLStr = "INSERT INTO " + mSysLogTableName
|
||||
+ "(dataTime, logLevel, dataJSON, uploaded)"
|
||||
+ " VALUES("
|
||||
+ "'" + dateStr + "',"
|
||||
+ DatabaseUtils.sqlEscapeString(statusVal) + ","
|
||||
+ DatabaseUtils.sqlEscapeString(logText) + ","
|
||||
+ 0
|
||||
+ ")";
|
||||
mSysLogDb.execSQL(SQLStr);
|
||||
Log.v(TAG, "syslog entry written to database: "+logText);
|
||||
pruneSysLogDb();
|
||||
|
||||
} catch (SQLException e) {
|
||||
Log.e(TAG, "writeLogEngryToLocalDb(): Error Writing Data: " + e.toString());
|
||||
Log.e(TAG, "SQLStr was " + SQLStr);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array list of objects representing the syslog entries in the database by calling the specified callback function.
|
||||
*
|
||||
* @return True on successful start or false if call fails.
|
||||
*/
|
||||
public boolean getSysLogList(Consumer<ArrayList<HashMap<String, String>>> callback) {
|
||||
Log.v(TAG, "getSysLogList");
|
||||
ArrayList<HashMap<String, String>> eventsList = new ArrayList<>();
|
||||
|
||||
String whereClause = "";
|
||||
String[] whereArgs = {};
|
||||
String[] columns = {"*"};
|
||||
new SelectQueryTask(mSysLogTableName, columns, null, null,
|
||||
null, null, "dataTime DESC", (Cursor cursor) -> {
|
||||
Log.v(TAG, "getSysLogList - returned " + cursor);
|
||||
if (cursor != null) {
|
||||
Log.v(TAG, "getSysLogList - returned " + cursor.getCount() + " records");
|
||||
while (!cursor.isAfterLast()) {
|
||||
HashMap<String, String> event = new HashMap<>();
|
||||
//event.put("id", cursor.getString(cursor.getColumnIndex("id")));
|
||||
event.put("dataTime", cursor.getString(cursor.getColumnIndex("dataTime")));
|
||||
String loglevel = cursor.getString(cursor.getColumnIndex("logLevel"));
|
||||
event.put("loglevel", loglevel);
|
||||
event.put("dataJSON", cursor.getString(cursor.getColumnIndex("dataJSON")));
|
||||
//event.put("dataJSON", cursor.getString(cursor.getColumnIndex("dataJSON")));
|
||||
eventsList.add(event);
|
||||
cursor.moveToNext();
|
||||
}
|
||||
}
|
||||
callback.accept(eventsList);
|
||||
}).execute();
|
||||
return (true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the sqlite query (=SELECT statement)
|
||||
* Use as new SelectQueryTask(xxx,xxx,xx,xxxx).execute()
|
||||
*
|
||||
*/
|
||||
static private class SelectQueryTask extends AsyncTask<Void, Void, Cursor> {
|
||||
// Based on https://stackoverflow.com/a/21120199/2104584
|
||||
String mTable;
|
||||
String[] mColumns;
|
||||
String mSelection;
|
||||
String[] mSelectionArgs;
|
||||
String mGroupBy;
|
||||
String mHaving;
|
||||
String mOrderBy;
|
||||
Consumer<Cursor> mCallback;
|
||||
|
||||
//query(String table, String[] columns, String selection, String[] selectionArgs,
|
||||
// String groupBy, String having, String orderBy)
|
||||
SelectQueryTask(String table, String[] columns, String selection, String[] selectionArgs,
|
||||
String groupBy, String having, String orderBy, Consumer<Cursor> callback) {
|
||||
// list all the parameters like in normal class define
|
||||
this.mTable = table;
|
||||
this.mColumns = columns;
|
||||
this.mSelection = selection;
|
||||
this.mSelectionArgs = selectionArgs;
|
||||
this.mGroupBy = groupBy;
|
||||
this.mHaving = having;
|
||||
this.mOrderBy = orderBy;
|
||||
this.mCallback = callback;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Cursor doInBackground(Void... params) {
|
||||
Log.v(TAG, "runSelect.doInBackground()");
|
||||
Log.v(TAG, "SelectQueryTask.doInBackground: mTable=" + mTable + ", mColumns=" + Arrays.toString(mColumns)
|
||||
+ ", mSelection=" + mSelection + ", mSelectionArgs=" + Arrays.toString(mSelectionArgs) + ", mGroupBy=" + mGroupBy
|
||||
+ ", mHaving =" + mHaving + ", mOrderBy=" + mOrderBy);
|
||||
|
||||
try {
|
||||
Cursor resultSet = mSysLogDb.query(mTable, mColumns, mSelection,
|
||||
mSelectionArgs, mGroupBy, mHaving, mOrderBy);
|
||||
resultSet.moveToFirst();
|
||||
return (resultSet);
|
||||
} catch (SQLException e) {
|
||||
Log.e(TAG, "SelectQueryTask.doInBackground(): Error selecting Data: " + e.toString());
|
||||
return (null);
|
||||
} catch (IllegalArgumentException e) {
|
||||
Log.e(TAG, "SelectQueryTask.doInBackground(): Illegal Argument Exception: " + e.toString());
|
||||
return (null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(final Cursor result) {
|
||||
mCallback.accept(result);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* pruneSysLogDb() removes data that is older than 7 days
|
||||
*/
|
||||
public int pruneSysLogDb() {
|
||||
//Log.v(TAG, "pruneSysLogDb()");
|
||||
int retVal;
|
||||
long currentDateMillis = new Date().getTime();
|
||||
if (currentDateMillis > mLastPruneMillis + mMinPruneInterval) {
|
||||
mLastPruneMillis = currentDateMillis;
|
||||
// FIXME - change this to something sensible like 7 days after testing
|
||||
long endDateMillis = currentDateMillis - 5 * 60 * 1000;
|
||||
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
String endDateStr = dateFormat.format(new Date(endDateMillis));
|
||||
Log.v(TAG, "pruneSysLogDb - endDateStr=" + endDateStr);
|
||||
try {
|
||||
String selectStr = "DataTime<=?";
|
||||
String[] selectArgs = {endDateStr};
|
||||
retVal = mSysLogDb.delete(mSysLogTableName, selectStr, selectArgs);
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Error deleting log entries" + e.toString());
|
||||
retVal = 0;
|
||||
}
|
||||
if (retVal > 0) {
|
||||
Log.v(TAG, String.format("pruneSysLogDb() - deleted %d records", retVal));
|
||||
}
|
||||
return (retVal);
|
||||
} else {
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class OsdSysLogHelper extends SQLiteOpenHelper {
|
||||
// If you change the database schema, you must increment the database version.
|
||||
public static final int DATABASE_VERSION = 1;
|
||||
public static final String DATABASE_NAME = "OsdSysLog.db";
|
||||
private static final String TAG = "LogManager.OsdSysLogHelper";
|
||||
|
||||
public OsdSysLogHelper(Context context) {
|
||||
super(context, DATABASE_NAME, null, DATABASE_VERSION);
|
||||
Log.d(TAG, "OsdSysLogHelper constructor");
|
||||
}
|
||||
|
||||
public void onCreate(SQLiteDatabase db) {
|
||||
Log.i(TAG, "onCreate - TableName=" + mSysLogTableName);
|
||||
String SQLStr = "CREATE TABLE IF NOT EXISTS " + mSysLogTableName + "("
|
||||
+ "id INTEGER PRIMARY KEY,"
|
||||
+ "dataTime DATETIME,"
|
||||
+ "logLevel TEXT,"
|
||||
+ "dataJSON TEXT,"
|
||||
+ "uploaded INT"
|
||||
+ ");";
|
||||
db.execSQL(SQLStr);
|
||||
}
|
||||
|
||||
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||
// This database is only a cache for online data, so its upgrade policy is
|
||||
// to simply to discard the data and start over
|
||||
Log.i(TAG,"onUpgrade()");
|
||||
db.execSQL("Drop table if exists " + mSysLogTableName + ";");
|
||||
onCreate(db);
|
||||
}
|
||||
|
||||
public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||
Log.i(TAG,"onDowngrade()");
|
||||
onUpgrade(db, oldVersion, newVersion);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -439,6 +439,7 @@ public class SdServer extends Service implements SdDataReceiver {
|
||||
|
||||
if (mLm != null) {
|
||||
Log.d(TAG, "Closing Down Log Manager");
|
||||
mLm.stop();
|
||||
mLm.close();
|
||||
}
|
||||
|
||||
@@ -590,7 +591,7 @@ public class SdServer extends Service implements SdDataReceiver {
|
||||
}
|
||||
if (mLogAlarms) {
|
||||
Log.v(TAG, "WARNING - Logging to SD Card");
|
||||
writeAlarmToSD();
|
||||
//writeAlarmToSD();
|
||||
} else {
|
||||
Log.v(TAG, "WARNING");
|
||||
}
|
||||
@@ -603,7 +604,7 @@ public class SdServer extends Service implements SdDataReceiver {
|
||||
sdData.alarmStanding = true;
|
||||
if (mLogAlarms) {
|
||||
Log.v(TAG, "***ALARM*** - Logging to SD Card");
|
||||
writeAlarmToSD();
|
||||
//writeAlarmToSD();
|
||||
} else {
|
||||
Log.v(TAG, "***ALARM***");
|
||||
}
|
||||
@@ -641,7 +642,7 @@ public class SdServer extends Service implements SdDataReceiver {
|
||||
sdData.fallAlarmStanding = true;
|
||||
if (mLogAlarms) {
|
||||
Log.v(TAG, "***FALL*** - Logging to SD Card");
|
||||
writeAlarmToSD();
|
||||
//writeAlarmToSD();
|
||||
showNotification(2);
|
||||
} else {
|
||||
Log.v(TAG, "***FALL***");
|
||||
@@ -675,7 +676,7 @@ public class SdServer extends Service implements SdDataReceiver {
|
||||
sdData.alarmPhrase = "HR ABNORMAL";
|
||||
if (mLogAlarms) {
|
||||
Log.v(TAG, "***HEART RATE*** - Logging to SD Card");
|
||||
writeAlarmToSD();
|
||||
//writeAlarmToSD();
|
||||
} else {
|
||||
Log.v(TAG, "***HEART RATE***");
|
||||
}
|
||||
@@ -709,7 +710,7 @@ public class SdServer extends Service implements SdDataReceiver {
|
||||
sdData.alarmPhrase = "Oxygen Saturation ABNORMAL";
|
||||
if (mLogAlarms) {
|
||||
Log.v(TAG, "***OXYGEN SATURATION*** - Logging to SD Card");
|
||||
writeAlarmToSD();
|
||||
//writeAlarmToSD();
|
||||
} else {
|
||||
Log.v(TAG, "***OXYGEN SATURATION***");
|
||||
}
|
||||
@@ -742,7 +743,7 @@ public class SdServer extends Service implements SdDataReceiver {
|
||||
// Fault
|
||||
if ((sdData.alarmState) == 4 || (sdData.alarmState == 7) || (sdData.mHRFaultStanding)) {
|
||||
sdData.alarmPhrase = "FAULT";
|
||||
writeAlarmToSD();
|
||||
//writeAlarmToSD();
|
||||
faultWarningBeep();
|
||||
showNotification(-1);
|
||||
} else {
|
||||
@@ -1259,62 +1260,6 @@ public class SdServer extends Service implements SdDataReceiver {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Write data to SD card alarm log
|
||||
*/
|
||||
public void writeAlarmToSD() {
|
||||
writeToSD(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write to data log file on SD Card
|
||||
*/
|
||||
public void writeToSD() {
|
||||
writeToSD(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write data to SD card - writes to data log file unless alarm=true,
|
||||
* in which case writes to alarm log file.
|
||||
*/
|
||||
public void writeToSD(boolean alarm) {
|
||||
//Log.v(TAG, "writeToSD(" + alarm + ")");
|
||||
Time tnow = new Time(Time.getCurrentTimezone());
|
||||
tnow.setToNow();
|
||||
String dateStr = tnow.format("%Y-%m-%d");
|
||||
|
||||
// Select filename depending on 'alarm' parameter.
|
||||
String fname;
|
||||
if (alarm)
|
||||
fname = "AlarmLog";
|
||||
else
|
||||
fname = "DataLog";
|
||||
|
||||
fname = fname + "_" + dateStr + ".txt";
|
||||
// Open output directory on SD Card.
|
||||
if (mUtil.isExternalStorageWritable()) {
|
||||
try {
|
||||
FileWriter of = new FileWriter(getExternalFilesDir(null).toString()
|
||||
+ "/" + fname, true);
|
||||
if (mSdData != null) {
|
||||
if (alarm) {
|
||||
//Log.v(TAG, "writeToSD() - logging mSdData.toString()");
|
||||
of.append(mSdData.toString() + "\n");
|
||||
} else {
|
||||
//Log.v(TAG, "writeToSD() - logging mSdData.toCSVString()");
|
||||
of.append(mSdData.toCSVString(true) + "\n");
|
||||
}
|
||||
}
|
||||
of.close();
|
||||
} catch (Exception ex) {
|
||||
Log.e(TAG, "writeAlarmToSD - error " + ex.toString());
|
||||
}
|
||||
} else {
|
||||
Log.e(TAG, "ERROR - Can not Write to External Folder");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void sendPhoneAlarm() {
|
||||
/**
|
||||
* Use the separate OpenSeizureDetector Dialler app to generate a phone call alarm to the numbers selected for SMS Alarms.
|
||||
|
||||
Reference in New Issue
Block a user