Merge branch 'v2.0.x' =x V2.0.6

This commit is contained in:
Graham Jones
2016-08-08 18:11:47 +01:00
37 changed files with 1793 additions and 271 deletions
+3
View File
@@ -1,6 +1,9 @@
build build
.gradle .gradle
.idea .idea
local.properties
*.iml
app/app-release.apk
app/build app/build
app/app.iml app/app.iml
+16 -1
View File
@@ -1,10 +1,25 @@
OpenSeizureDetector Android App - Change Log OpenSeizureDetector Android App - Change Log
============================================ ============================================
V2.0.6 - 25 July 2016
- Added main activity menu option to view log files (via web browser).
- Added options to switch off spectrum display on watch to save battery.
- Changed main screen graph to bar chart and highlights frequency
region of interest.
- Fixed problem with log files not showing on web interface.
- Added system log file to help with de-bugging start-up/shutdown issues.
- Improved handling of watch app settings to make sure
they are loaded correctly without having to re-start app (but I'd still recommend re-starting the watch app manually to be sure :) )
- Reduced ammount of bluetooth comms to the watch to save battery.
- Added support for future watch app features (such as raw mode and digital
filter mode).
- Added watch app to Android phone app package so watch app can be
installed directly from phone rather than using pebble store - to make sure that watch app and Android app are always compatible.
V2.0.3 - 23 April 2016 V2.0.3 - 23 April 2016
Further modification to beep code to avoid occasional crashes Further modification to beep code to avoid occasional crashes
if system tries to beep during a re-start. if system tries to beep during a re-start.
Log faults to alarm log on SD Card. Log faults to alarm log on SD Card.
V2.0.2 - 13 April 2016 V2.0.2 - 13 April 2016
Modified 'beep' code to try to avoid crashes on some systems. Modified 'beep' code to try to avoid crashes on some systems.
Binary file not shown.
Binary file not shown.
+4 -1
View File
@@ -25,7 +25,7 @@ android {
dependencies { dependencies {
compile files('libs/mpandroidchartlibrary-2-0-7.jar') compile files('libs/mpandroidchartlibrary-2-0-7.jar')
compile 'com.getpebble:pebblekit:3.0.0@aar' compile 'com.getpebble:pebblekit:3.1.0@aar'
// Unit testing dependencies // Unit testing dependencies
testCompile 'junit:junit:4.12' testCompile 'junit:junit:4.12'
// Set this dependency if you want to use Mockito // Set this dependency if you want to use Mockito
@@ -34,6 +34,9 @@ dependencies {
testCompile 'org.hamcrest:hamcrest-library:1.1' testCompile 'org.hamcrest:hamcrest-library:1.1'
compile 'com.android.support:appcompat-v7:22.2.1' compile 'com.android.support:appcompat-v7:22.2.1'
compile 'com.android.support:support-v4:22.2.1' compile 'com.android.support:support-v4:22.2.1'
//compile files('libs/JTransforms-3.1-with-dependencies.jar')
compile 'org.apache.commons:commons-math3:3.6.1'
} }
repositories { repositories {
Binary file not shown.
+10 -12
View File
@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="uk.org.openseizuredetector" package="uk.org.openseizuredetector"
android:versionCode="24" android:versionCode="27"
android:versionName="2.0.3a" > android:versionName="2.0.6">
<uses-sdk android:minSdkVersion="14" /> <uses-sdk android:minSdkVersion="14" />
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
@@ -23,30 +23,28 @@
<application <application
android:icon="@drawable/star_of_life_48x48" android:icon="@drawable/star_of_life_48x48"
android:label="@string/app_name" > android:label="@string/app_name">
<activity android:name=".StartupActivity" > <activity android:name=".StartupActivity">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter> </intent-filter>
</activity> </activity>
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"
android:icon="@drawable/star_of_life_48x48"
android:label="@string/app_name"
android:exported="true" android:exported="true"
> android:icon="@drawable/star_of_life_48x48"
</activity> android:label="@string/app_name"></activity>
<activity <activity
android:name=".PrefActivity" android:name=".PrefActivity"
android:label="OpenSeizureDetector Preferences" > android:label="OpenSeizureDetector Preferences"></activity>
</activity>
<service <service
android:name=".SdServer" android:name=".SdServer"
android:exported="false" /> android:exported="false" />
<activity android:name=".LogManagerActivity"></activity>
</application> </application>
</manifest> <!-- android:uiOptions="splitActionBarWhenNarrow" --> </manifest> <!-- android:uiOptions="splitActionBarWhenNarrow" -->
Binary file not shown.
+2 -16
View File
@@ -1,15 +1,13 @@
<html> <html>
<head> <head>
<title>Ben's Pebble Watch Seizure Detector</title> <title>Open Seizure Detector</title>
<script src="js/jquery.js"></script> <script src="js/jquery.js"></script>
<script src="js/jBeep.js"></script> <script src="js/jBeep.js"></script>
<script src="js/Chart.min.js"></script> <script src="js/Chart.min.js"></script>
<script src="js/jquery.mobile-1.4.5.min.js"></script>
<script src="js/osd_main.js"></script> <script src="js/osd_main.js"></script>
<script src="js/osd_logs.js"></script> <script src="js/osd_logs.js"></script>
<link rel="stylesheet" href="css/osd.css" /> <link rel="stylesheet" href="css/osd.css" />
<link rel="stylesheet" href="css/jquery.mobile-1.4.5.min.css" />
</head> </head>
<body> <body>
@@ -77,23 +75,11 @@
</div> </div>
</div> <!-- content --> </div> <!-- content -->
<div data-role="footer"> <div data-role="footer">
<a href="#logs">Logs</a> <a href="logfiles.html">View Log Files</a>
<div id="debugInfo"></div> <div id="debugInfo"></div>
</div> <!--footer--> </div> <!--footer-->
</div> <!--page --> </div> <!--page -->
<div data-role="page" id="logs">
<div data-role="header">
<img src="img/icon_48x48.png" alt="logo"/>
<h1>Open Seizure Detector - Logs</h1>
</div>
<div role="main" class="ui-content">
<div id="logfilelist"> </div>
</div>
<div data-role="footer">
<a href="#home">Home</a>
</div>
</div>
</body> </body>
</html> </html>
+99
View File
@@ -0,0 +1,99 @@
<html>
<head>
<title>Ben's Pebble Watch Seizure Detector</title>
<script src="js/jquery.js"></script>
<script src="js/jBeep.js"></script>
<script src="js/Chart.min.js"></script>
<script src="js/jquery.mobile-1.4.5.min.js"></script>
<script src="js/osd_main.js"></script>
<script src="js/osd_logs.js"></script>
<link rel="stylesheet" href="css/osd.css" />
<link rel="stylesheet" href="css/jquery.mobile-1.4.5.min.css" />
</head>
<body>
<div data-role="page" id="home">
<div id="header" data-role="header">
<img src="img/icon_48x48.png" alt="logo"/>
<h1>Open Seizure Detector</h1>
</div>
<div role="main" class="ui-content">
<div id="benStat">
OK
</div>
<div style="clear:both">
<div id="pebStat1">
<font size="7">Pebble Watch Connected</font>
</div>
<div id="pebStat2">
<font size="7">Pebble App Running</font>
</div>
<div id="pebStat3">
Pebble Battery
</div>
</div>
<div id="chartsDiv">
<canvas id="specChart1" width="400" height="300"></canvas>
<canvas id="specChart2" width="400" height="300"></canvas>
</div>
<div id="dataDiv">
<h2>Seizure Detector Data</h2>
<div id="maxFreq">
Maximum Frequency:
</div>
<div id="maxVal">
Maximum Value:
</div>
<div id="specPow">
Spectrum Power:
</div>
<div id="roiPow">
Region Of Interest Power:
</div>
<div id="alarmState">
Alarm Status:
</div>
<div id="alarmPhrase">
Alarm Phrase:
</div>
</div>
<div id="settingsDiv">
<h2>Seizure Detector Settings</h2>
<button id="muteButton">Mute Alarm</button>
<div id="sdSettings">
SD Settings
</div>
</div>
<div style="clear:both">
<p>
For details see
<a href="http://openseizuredetector.org.uk">
OpenSeizureDetector.org.uk
</a>
</p>
</div>
</div> <!-- content -->
<div data-role="footer">
<a href="#logs">Logs</a>
<div id="debugInfo"></div>
</div> <!--footer-->
</div> <!--page -->
<div data-role="page" id="logs">
<div data-role="header">
<img src="img/icon_48x48.png" alt="logo"/>
<h1>Open Seizure Detector - Logs</h1>
</div>
<div role="main" class="ui-content">
<div id="logfilelist"> </div>
</div>
<div data-role="footer">
<a href="#home">Home</a>
</div>
</div>
</body>
</html>
+1 -1
View File
@@ -21,7 +21,7 @@ function populate_filelist(dataStr) {
$(document).delegate("#logs","pageinit", function() { $(document).ready(function() {
//alert("logs page opened"); //alert("logs page opened");
get_filelist(); get_filelist();
}); });
+28
View File
@@ -0,0 +1,28 @@
<html>
<head>
<title>Open Seizure Detector</title>
<script src="js/jquery.js"></script>
<script src="js/jBeep.js"></script>
<script src="js/Chart.min.js"></script>
<script src="js/osd_main.js"></script>
<script src="js/osd_logs.js"></script>
<link rel="stylesheet" href="css/osd.css" />
</head>
<body>
<div data-role="page" id="logs">
<div data-role="header">
<a href="/"><img src="img/icon_48x48.png" alt="logo"/></a>
<h1>Open Seizure Detector - Logs</h1>
</div>
<div role="main" class="ui-content">
<div id="logfilelist"> </div>
</div>
<div data-role="footer">
<a href="/">Home</a>
</div>
</div>
</body>
</html>
@@ -0,0 +1,85 @@
package uk.org.openseizuredetector;
import android.util.Log;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.TimeZone;
/**
* Created by graham on 27/06/16.
*/
/* From https://github.com/kramimus/pebble-accel-analyzer */
public class AccelData {
private final String TAG = AccelData.class.getSimpleName();
final private int x;
final private int y;
final private int z;
private long timestamp = 0;
final private boolean didVibrate;
public AccelData(byte[] data) {
x = (data[0] & 0xff) | (data[1] << 8);
y = (data[2] & 0xff) | (data[3] << 8);
z = (data[4] & 0xff) | (data[5] << 8);
didVibrate = data[6] != 0;
for (int i = 0; i < 8; i++) {
timestamp |= ((long)(data[i+7] & 0xff)) << (i * 8);
}
}
public JSONObject toJson() {
JSONObject json = new JSONObject();
try {
json.put("x", x);
json.put("y", y);
json.put("z", z);
json.put("ts", timestamp);
json.put("v", didVibrate);
return json;
} catch (JSONException e) {
Log.w(TAG, "problem constructing accel data, skipping " + e);
}
return null;
}
public static List<AccelData> fromDataArray(byte[] data) {
List<AccelData> accels = new ArrayList<AccelData>();
for (int i = 0; i < data.length; i += 15) {
accels.add(new AccelData(Arrays.copyOfRange(data, i, i + 15)));
}
return accels;
}
public long getTimestamp() {
return timestamp;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public int getZ() {
return z;
}
public int getMagnitude() {
return (int)Math.sqrt(x*x + y*y + z*z);
}
public void applyTimezone(TimeZone tz) {
timestamp -= tz.getOffset(timestamp);
}
}
@@ -0,0 +1,107 @@
package uk.org.openseizuredetector;
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.RandomAccess;
/**
* Created by graham on 28/06/16.
*/
public class CircularArrayList<E>
extends AbstractList<E> implements RandomAccess {
/**
* If you use this code, please consider notifying isak at du-preez dot com
* with a brief description of your application.
*
* This is free and unencumbered software released into the public domain.
* Anyone is free to copy, modify, publish, use, compile, sell, or
* distribute this software, either in source code form or as a compiled
* binary, for any purpose, commercial or non-commercial, and by any
* means.
*/
private final int n; // buffer length
private final List<E> buf; // a List implementing RandomAccess
private int head = 0;
private int tail = 0;
public CircularArrayList(int capacity) {
n = capacity + 1;
buf = new ArrayList<E>(Collections.nCopies(n, (E) null));
}
public int capacity() {
return n - 1;
}
private int wrapIndex(int i) {
int m = i % n;
if (m < 0) { // java modulus can be negative
m += n;
}
return m;
}
// This method is O(n) but will never be called if the
// CircularArrayList is used in its typical/intended role.
private void shiftBlock(int startIndex, int endIndex) {
assert (endIndex > startIndex);
for (int i = endIndex - 1; i >= startIndex; i--) {
set(i + 1, get(i));
}
}
@Override
public int size() {
return tail - head + (tail < head ? n : 0);
}
@Override
public E get(int i) {
if (i < 0 || i >= size()) {
throw new IndexOutOfBoundsException();
}
return buf.get(wrapIndex(head + i));
}
@Override
public E set(int i, E e) {
if (i < 0 || i >= size()) {
throw new IndexOutOfBoundsException();
}
return buf.set(wrapIndex(head + i), e);
}
@Override
public void add(int i, E e) {
int s = size();
if (s == n - 1) {
throw new IllegalStateException("Cannot add element."
+ " CircularArrayList is filled to capacity.");
}
if (i < 0 || i > s) {
throw new IndexOutOfBoundsException();
}
tail = wrapIndex(tail + 1);
if (i < s) {
shiftBlock(i, s);
}
set(i, e);
}
@Override
public E remove(int i) {
int s = size();
if (i < 0 || i >= s) {
throw new IndexOutOfBoundsException();
}
E e = get(i);
if (i > 0) {
shiftBlock(0, i);
}
head = wrapIndex(head + 1);
return e;
}
}
@@ -0,0 +1,98 @@
package uk.org.openseizuredetector.EventLogManager;
import java.util.ArrayList;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import uk.org.openseizuredetector.R;
public class EventLogListAdapter extends BaseAdapter {
EventLogManager dm;
ArrayList<LogEntryModel> logEntryModelList;
LayoutInflater inflater;
Context _context;
public EventLogListAdapter(Context context) {
logEntryModelList = new ArrayList<LogEntryModel>();
_context = context;
inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
dm = new EventLogManager(_context);
logEntryModelList = dm.getAllData();
}
@Override
public void notifyDataSetChanged() {
super.notifyDataSetChanged();
//refetching the new data from database
logEntryModelList = dm.getAllData();
}
public void delRow(int delPosition) {
dm.deleteRow(logEntryModelList.get(delPosition).getId());
logEntryModelList.remove(delPosition);
}
@Override
public int getCount() {
return logEntryModelList.size();
}
@Override
public Object getItem(int position) {
return logEntryModelList.get(position);
}
@Override
public long getItemId(int position) {
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder vHolder;
if (convertView == null) {
convertView = inflater.inflate(R.layout.log_entry_layout, null);
vHolder = new ViewHolder();
vHolder.date = (TextView) convertView
.findViewById(R.id.event_date);
vHolder.alarmState = (TextView) convertView
.findViewById(R.id.event_alarmState);
vHolder.note = (TextView) convertView
.findViewById(R.id.event_note);
vHolder.dataJSON = (TextView) convertView
.findViewById(R.id.event_dataJSON);
convertView.setTag(vHolder);
} else {
vHolder = (ViewHolder) convertView.getTag();
}
LogEntryModel eventObj = logEntryModelList.get(position);
//vHolder.date.setText(eventObj.getDate().toString());
vHolder.alarmState.setText(eventObj.getAlarmState());
vHolder.note.setText(eventObj.getNote());
vHolder.dataJSON.setText(eventObj.getDataJSON());
return convertView;
}
class ViewHolder {
TextView date,alarmState,note,dataJSON;
}
}
@@ -0,0 +1,210 @@
/**
* Database manager for logging events and associated seizure detector data.
*/
package uk.org.openseizuredetector.EventLogManager;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Locale;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
public class EventLogManager {
final static String TAG = "EventLogManager";
private SQLiteDatabase db; // a reference to the database manager class.
private static final String DB_NAME = "eventlog"; // the name of our database
private static final int DB_VERSION = 1; // the version of the database
private static final String TABLE_NAME = "events";// table name
// the names for our database columns
private static final String TABLE_ROW_ID = "_id";
private static final String TABLE_ROW_DATE = "event_date";
private static final String TABLE_ROW_ALARM_STATE = "alarm_state";
private static final String TABLE_ROW_DATA_JSON = "data_json";
private static final String TABLE_ROW_NOTE = "note";
private Context context;
public EventLogManager(Context context) {
this.context = context;
// create or open the database
CustomSQLiteOpenHelper helper = new CustomSQLiteOpenHelper(context);
this.db = helper.getWritableDatabase();
helper.onCreate(this.db);
}
// the beginnings our SQLiteOpenHelper class
private class CustomSQLiteOpenHelper extends SQLiteOpenHelper {
public CustomSQLiteOpenHelper(Context context) {
super(context, DB_NAME, null, DB_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
// the SQLite query string that will create our column database
// table.
String newTableQueryString = "create table " + TABLE_NAME + " ("
+ TABLE_ROW_ID
+ " integer primary key autoincrement not null,"
+ TABLE_ROW_DATE + " timestamp not null," + TABLE_ROW_ALARM_STATE
+ " integer not null," + TABLE_ROW_NOTE + " text not null,"
+ TABLE_ROW_DATA_JSON + " text not null" + ");";
// execute the query string to the database.
db.execSQL(newTableQueryString);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// LATER, WE WOULD SPECIFIY HOW TO UPGRADE THE DATABASE
// FROM OLDER VERSIONS.
String DROP_TABLE = "DROP TABLE IF EXISTS " + TABLE_NAME;
db.execSQL(DROP_TABLE);
onCreate(db);
}
}
public void addRow(LogEntryModel eventObj) {
ContentValues values = prepareData(eventObj);
// ask the database object to insert the new data
try {
db.insert(TABLE_NAME, null, values);
} catch (Exception e) {
Log.e("DB ERROR", e.toString()); // prints the error message to
// the log
e.printStackTrace(); // prints the stack trace to the log
}
}
private String getDateTime(Date date) {
SimpleDateFormat dateFormat = new SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault());
if (date==null)
return "";
else
return dateFormat.format(date);
}
private ContentValues prepareData(LogEntryModel eventObj) {
ContentValues values = new ContentValues();
values.put(TABLE_ROW_ALARM_STATE, eventObj.getAlarmState());
values.put(TABLE_ROW_DATE, getDateTime(eventObj.getDate()));
values.put(TABLE_ROW_NOTE, eventObj.getNote());
values.put(TABLE_ROW_DATA_JSON, eventObj.getDataJSON());
return values;
}
// Returns row data in form of LogEntryModel object
public LogEntryModel getRowAsObject(int rowID) {
LogEntryModel rowContactObj = new LogEntryModel();
Cursor cursor;
try {
cursor = db.query(TABLE_NAME, new String[] { TABLE_ROW_ID,
TABLE_ROW_ALARM_STATE, TABLE_ROW_DATE, TABLE_ROW_NOTE,
TABLE_ROW_DATA_JSON }, TABLE_ROW_ID + "=" + rowID, null,
null, null, null, null);
cursor.moveToFirst();
prepareSendObject(rowContactObj, cursor);
} catch (SQLException e) {
Log.e("DB ERROR", e.toString());
e.printStackTrace();
}
return rowContactObj;
}
// Returns all the rows data in form of LogEntryModel object list
public ArrayList<LogEntryModel> getAllData() {
ArrayList<LogEntryModel> allRowsObj = new ArrayList<LogEntryModel>();
Cursor cursor;
LogEntryModel rowContactObj;
String[] columns = new String[] { TABLE_ROW_ID, TABLE_ROW_ALARM_STATE,
TABLE_ROW_DATE, TABLE_ROW_NOTE, TABLE_ROW_DATA_JSON };
try {
cursor = db
.query(TABLE_NAME, columns, null, null, null, null, null);
cursor.moveToFirst();
if (!cursor.isAfterLast()) {
do {
rowContactObj = new LogEntryModel();
rowContactObj.setId(cursor.getInt(0));
prepareSendObject(rowContactObj, cursor);
allRowsObj.add(rowContactObj);
} while (cursor.moveToNext()); // try to move the cursor's
// pointer forward one position.
}
} catch (SQLException e) {
Log.e("DB ERROR", e.toString());
e.printStackTrace();
}
return allRowsObj;
}
private void prepareSendObject(LogEntryModel rowObj, Cursor cursor) {
rowObj.setId(cursor.getInt(cursor.getColumnIndexOrThrow(TABLE_ROW_ID)));
rowObj.setAlarmState(cursor.getInt(cursor
.getColumnIndexOrThrow(TABLE_ROW_ALARM_STATE)));
String dateTimeStr = cursor.getString(cursor
.getColumnIndexOrThrow(TABLE_ROW_DATE));
Log.v(TAG,"dateTimeStr = "+dateTimeStr);
Date dateVal;
try { dateVal = new Date(dateTimeStr); }
catch (IllegalArgumentException e) { dateVal = null; }
rowObj.setDate(dateVal);
rowObj.setNote(cursor.getString(cursor
.getColumnIndexOrThrow(TABLE_ROW_NOTE)));
rowObj.setDataJSON(cursor.getString(cursor
.getColumnIndexOrThrow(TABLE_ROW_DATA_JSON)));
}
public void deleteRow(int rowID) {
// ask the database manager to delete the row of given id
try {
db.delete(TABLE_NAME, TABLE_ROW_ID + "=" + rowID, null);
} catch (Exception e) {
Log.e("DB ERROR", e.toString());
e.printStackTrace();
}
}
public void updateRow(int rowId, LogEntryModel contactObj) {
ContentValues values = prepareData(contactObj);
String whereClause = TABLE_ROW_ID + "=?";
String whereArgs[] = new String[] { String.valueOf(rowId) };
db.update(TABLE_NAME, values, whereClause, whereArgs);
}
}
@@ -0,0 +1,53 @@
package uk.org.openseizuredetector.EventLogManager;
import java.util.Date;
/**
* Our LogEntryModel class which will have fields like id, name, contact number
* and email and corresponding getter and setter methods.
* **/
public class LogEntryModel {
private int id;
private Date date;
private int alarmState;
private String dataJSON;
private String note;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getAlarmState() {
return alarmState;
}
public void setAlarmState(int alarmState) {
this.alarmState = alarmState;
}
public String getNote() {
return note;
}
public void setNote(String note) {
this.note = note;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
public String getDataJSON() { return dataJSON; }
public void setDataJSON(String dataJSON) { this.dataJSON = dataJSON; }
}
@@ -0,0 +1,42 @@
package uk.org.openseizuredetector;
import android.app.Activity;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.ListView;
import java.util.Date;
import uk.org.openseizuredetector.EventLogManager.EventLogListAdapter;
import uk.org.openseizuredetector.EventLogManager.EventLogManager;
import uk.org.openseizuredetector.EventLogManager.LogEntryModel;
public class LogManagerActivity extends Activity {
private EventLogListAdapter mEventLogListAdapter;
private ListView mEventLogListView;
private EventLogManager mElm;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_log_manager);
LogEntryModel lem = new LogEntryModel();
//lem.setDate(new Date());
lem.setNote("Test Entry");
lem.setDataJSON("[]");
lem.setAlarmState(1);
mElm = new EventLogManager(this);
mElm.addRow(lem);
mEventLogListAdapter = new EventLogListAdapter(this);
mEventLogListView = (ListView) findViewById(R.id.eventLogListView);
mEventLogListView.setAdapter(mEventLogListAdapter);
}
}
@@ -49,15 +49,25 @@ import android.widget.TextView;
import android.widget.Button; import android.widget.Button;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.text.DecimalFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Timer; import java.util.Timer;
import java.util.TimerTask; import java.util.TimerTask;
//MPAndroidChart //MPAndroidChart
import com.github.mikephil.charting.charts.BarChart;
import com.github.mikephil.charting.charts.LineChart; import com.github.mikephil.charting.charts.LineChart;
import com.github.mikephil.charting.components.XAxis;
import com.github.mikephil.charting.components.YAxis;
import com.github.mikephil.charting.data.BarData;
import com.github.mikephil.charting.data.BarDataSet;
import com.github.mikephil.charting.data.BarEntry;
import com.github.mikephil.charting.data.Entry; import com.github.mikephil.charting.data.Entry;
import com.github.mikephil.charting.data.LineData; import com.github.mikephil.charting.data.LineData;
import com.github.mikephil.charting.data.LineDataSet; import com.github.mikephil.charting.data.LineDataSet;
import com.github.mikephil.charting.utils.ColorTemplate;
import com.github.mikephil.charting.utils.LargeValueFormatter;
import com.github.mikephil.charting.utils.ValueFormatter;
public class MainActivity extends Activity { public class MainActivity extends Activity {
static final String TAG = "MainActivity"; static final String TAG = "MainActivity";
@@ -86,8 +96,11 @@ public class MainActivity extends Activity {
// Set our custom uncaught exception handler to report issues. // Set our custom uncaught exception handler to report issues.
Thread.setDefaultUncaughtExceptionHandler(new OsdUncaughtExceptionHandler(MainActivity.this)); Thread.setDefaultUncaughtExceptionHandler(new OsdUncaughtExceptionHandler(MainActivity.this));
//int i = 5/0; // Force exception to test handler. //int i = 5/0; // Force exception to test handler.
mUtil = new OsdUtil(this); mUtil = new OsdUtil(this,serverStatusHandler);
mConnection = new SdServiceConnection(this); mConnection = new SdServiceConnection(this);
mUtil.writeToSysLogFile("");
mUtil.writeToSysLogFile("* MainActivity Started *");
mUtil.writeToSysLogFile("MainActivity.onCreate()");
// Initialise the User Interface // Initialise the User Interface
setContentView(R.layout.main); setContentView(R.layout.main);
@@ -160,8 +173,11 @@ public class MainActivity extends Activity {
switch (item.getItemId()) { switch (item.getItemId()) {
case R.id.action_launch_pebble_app: case R.id.action_launch_pebble_app:
Log.v(TAG, "action_launch_pebble_app"); Log.v(TAG, "action_launch_pebble_app");
mUtil.startPebbleApp(); mConnection.mSdServer.mSdDataSource.startPebbleApp();
return true; return true;
case R.id.action_instal_watch_app:
Log.v(TAG, "action_install_watch_app");
mConnection.mSdServer.mSdDataSource.installWatchApp();
case R.id.action_accept_alarm: case R.id.action_accept_alarm:
Log.v(TAG, "action_accept_alarm"); Log.v(TAG, "action_accept_alarm");
@@ -209,6 +225,23 @@ public class MainActivity extends Activity {
mConnection.mSdServer.sendSMSAlarm(); mConnection.mSdServer.sendSMSAlarm();
} }
return true; return true;
case R.id.action_logs:
Log.v(TAG, "action_logs");
try {
String url = "http://"
+ mUtil.getLocalIpAddress()
+ ":8080/logfiles.html";
Intent i = new Intent(Intent.ACTION_VIEW);
i.setData(Uri.parse(url));
startActivity(i);
//Intent prefsIntent = new Intent(
// MainActivity.this,
// LogManagerActivity.class);
//this.startActivity(prefsIntent);
} catch (Exception ex) {
Log.v(TAG, "exception starting log manager activity " + ex.toString());
}
return true;
case R.id.action_settings: case R.id.action_settings:
Log.v(TAG, "action_settings"); Log.v(TAG, "action_settings");
try { try {
@@ -233,6 +266,7 @@ public class MainActivity extends Activity {
@Override @Override
protected void onStart() { protected void onStart() {
super.onStart(); super.onStart();
mUtil.writeToSysLogFile("MainActivity.onStart()");
SharedPreferences SP = PreferenceManager SharedPreferences SP = PreferenceManager
.getDefaultSharedPreferences(getBaseContext()); .getDefaultSharedPreferences(getBaseContext());
boolean audibleAlarm = SP.getBoolean("AudibleAlarm", true); boolean audibleAlarm = SP.getBoolean("AudibleAlarm", true);
@@ -243,18 +277,21 @@ public class MainActivity extends Activity {
String versionName = mUtil.getAppVersionName(); String versionName = mUtil.getAppVersionName();
tv.setText("OpenSeizureDetector Server Version " + versionName); tv.setText("OpenSeizureDetector Server Version " + versionName);
mUtil.writeToSysLogFile("MainActivity.onStart - Binding to Server");
mUtil.bindToServer(this, mConnection); mUtil.bindToServer(this, mConnection);
} }
@Override @Override
protected void onStop() { protected void onStop() {
super.onStop(); super.onStop();
mUtil.writeToSysLogFile("MainActivity.onStop()");
mUtil.unbindFromServer(this, mConnection); mUtil.unbindFromServer(this, mConnection);
} }
private void startServer() { private void startServer() {
mUtil.writeToSysLogFile("MainActivity.startServer()");
Log.v(TAG, "starting Server...");
mUtil.startServer(); mUtil.startServer();
// Change the action bar icon to show the option to stop the service. // Change the action bar icon to show the option to stop the service.
if (mOptionsMenu != null) { if (mOptionsMenu != null) {
@@ -268,6 +305,7 @@ public class MainActivity extends Activity {
} }
private void stopServer() { private void stopServer() {
mUtil.writeToSysLogFile("MainActivity.stopServer()");
Log.v(TAG, "stopping Server..."); Log.v(TAG, "stopping Server...");
mUtil.stopServer(); mUtil.stopServer();
// Change the action bar icon to show the option to start the service. // Change the action bar icon to show the option to start the service.
@@ -499,33 +537,86 @@ public class MainActivity extends Activity {
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// Produce graph // Produce graph
LineChart mChart = (LineChart) findViewById(R.id.chart1); BarChart mChart = (BarChart) findViewById(R.id.chart1);
mChart.setDescription(""); mChart.setDrawBarShadow(false);
mChart.setNoDataTextDescription("You need to provide data for the chart."); mChart.setNoDataTextDescription("You need to provide data for the chart.");
// X Values mChart.setDescription("");
// X and Y Values
ArrayList<String> xVals = new ArrayList<String>(); ArrayList<String> xVals = new ArrayList<String>();
ArrayList<BarEntry> yBarVals = new ArrayList<BarEntry>();
for (int i = 0; i < 10; i++) { for (int i = 0; i < 10; i++) {
xVals.add((i) + ""); xVals.add(i+"-"+(i+1)+" Hz");
} if (mConnection.mSdServer != null) {
// Y Values yBarVals.add(new BarEntry(mConnection.mSdServer.mSdData.simpleSpec[i], i));
ArrayList<Entry> yVals = new ArrayList<Entry>(); }
for (int i = 0; i < 10; i++) { else {
if (mConnection.mSdServer != null) yBarVals.add(new BarEntry(i,i));
yVals.add(new Entry(mConnection.mSdServer.mSdData.simpleSpec[i], i)); }
else
yVals.add(new Entry(i, i));
} }
// create a dataset and give it a type // create a dataset and give it a type
LineDataSet set1 = new LineDataSet(yVals, "DataSet 1"); BarDataSet barDataSet = new BarDataSet(yBarVals,"Spectrum");
set1.setColor(Color.BLACK); try {
set1.setLineWidth(1f); int[] barColours = new int[10];
for (int i = 0; i < 10; i++) {
if ((i < mConnection.mSdServer.mSdData.alarmFreqMin) ||
(i > mConnection.mSdServer.mSdData.alarmFreqMax)) {
barColours[i] = Color.GRAY;
} else {
barColours[i] = Color.RED;
}
}
barDataSet.setColors(barColours);
} catch (NullPointerException e){
Log.v(TAG,"Null pointer exception setting bar colours");
}
barDataSet.setBarSpacePercent(20f);
barDataSet.setBarShadowColor(Color.WHITE);
BarData barData = new BarData(xVals,barDataSet);
barData.setValueFormatter(new ValueFormatter() {
@Override
public String getFormattedValue(float v) {
DecimalFormat format = new DecimalFormat("####");
return format.format(v);
}
});
mChart.setData(barData);
// format the axes
XAxis xAxis = mChart.getXAxis();
xAxis.setPosition(XAxis.XAxisPosition.BOTTOM);
xAxis.setTextSize(10f);
xAxis.setDrawAxisLine(true);
xAxis.setDrawLabels(true);
// Note: the default text colour is BLACK, so does not show up on black background!!!
// This took a lot of finding....
xAxis.setTextColor(Color.WHITE);
xAxis.setDrawGridLines(false);
YAxis yAxis = mChart.getAxisLeft();
yAxis.setAxisMinValue(0f);
yAxis.setAxisMaxValue(3000f);
yAxis.setDrawGridLines(true);
yAxis.setDrawLabels(true);
yAxis.setTextColor(Color.WHITE);
yAxis.setValueFormatter(new ValueFormatter() {
@Override
public String getFormattedValue(float v) {
DecimalFormat format = new DecimalFormat("#####");
return format.format(v);
}
});
YAxis yAxis2 = mChart.getAxisRight();
yAxis2.setDrawGridLines(false);
try {
mChart.getLegend().setEnabled(false);
} catch (NullPointerException e) {
Log.v(TAG,"Null Pointer Exception setting legend");
}
ArrayList<LineDataSet> dataSets = new ArrayList<LineDataSet>();
dataSets.add(set1); // add the datasets
LineData data = new LineData(xVals, dataSets);
//data.setValueTextSize(10f);
mChart.setData(data);
mChart.invalidate(); mChart.invalidate();
} }
}; };
@@ -534,15 +625,18 @@ public class MainActivity extends Activity {
@Override @Override
protected void onPause() { protected void onPause() {
super.onPause(); super.onPause();
mUtil.writeToSysLogFile("MainActivity.onPause()");
} }
@Override @Override
protected void onResume() { protected void onResume() {
super.onResume(); super.onResume();
mUtil.writeToSysLogFile("MainActivity.onResume()");
} }
private void showAbout() { private void showAbout() {
mUtil.writeToSysLogFile("MainActivity.showAbout()");
View aboutView = getLayoutInflater().inflate(R.layout.about_layout, null, false); View aboutView = getLayoutInflater().inflate(R.layout.about_layout, null, false);
String versionName = mUtil.getAppVersionName(); String versionName = mUtil.getAppVersionName();
Log.v(TAG, "showAbout() - version name = " + versionName); Log.v(TAG, "showAbout() - version name = " + versionName);
@@ -554,11 +648,11 @@ public class MainActivity extends Activity {
builder.show(); builder.show();
} }
class ResponseHandler extends Handler { static class ResponseHandler extends Handler {
@Override @Override
public void handleMessage(Message message) { public void handleMessage(Message message) {
Log.v(TAG, "Message=" + message.toString()); Log.v(TAG, "Message=" + message.toString());
} }
} }
} }
@@ -30,35 +30,91 @@ import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.ServiceConnection; import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.content.pm.PackageInfo; import android.content.pm.PackageInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.net.Uri; import android.net.Uri;
import android.os.Environment;
import android.os.Handler;
import android.os.IBinder; import android.os.IBinder;
import android.preference.PreferenceManager;
import android.text.format.Time;
import android.util.Log; import android.util.Log;
import android.view.MenuItem; import android.view.MenuItem;
import android.widget.Toast; import android.widget.Toast;
import org.apache.http.conn.util.InetAddressUtils; import org.apache.http.conn.util.InetAddressUtils;
import java.io.File;
import java.io.FileWriter;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.NetworkInterface; import java.net.NetworkInterface;
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.List;
import java.util.RandomAccess;
import java.util.concurrent.RunnableFuture;
/** /**
* OsdUtil - OpenSeizureDetector Utilities * OsdUtil - OpenSeizureDetector Utilities
* Deals with starting and stopping the background service and binding to it to receive data. * Deals with starting and stopping the background service and binding to it to receive data.
*/ */
public class OsdUtil { public class OsdUtil {
private final String SYSLOG = "SysLog";
private final String ALARMLOG = "AlarmLog";
private final String DATALOG = "DataLog";
/** /**
* Based on http://stackoverflow.com/questions/7440473/android-how-to-check-if-the-intent-service-is-still-running-or-has-stopped-running * 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 Context mContext;
private Handler mHandler;
private String TAG = "OsdUtil"; private String TAG = "OsdUtil";
private boolean mLogAlarms = true;
private boolean mLogSystem = true;
private boolean mLogData = true;
public OsdUtil(Context context) { public OsdUtil(Context context, Handler handler) {
mContext = context; mContext = context;
mHandler = handler;
updatePrefs();
writeToSysLogFile("OsdUtil() - initialised");
} }
/**
* updatePrefs() - update basic settings from the SharedPreferences
* - defined in res/xml/prefs.xml
*/
public void updatePrefs() {
Log.v(TAG, "updatePrefs()");
SharedPreferences SP = PreferenceManager
.getDefaultSharedPreferences(mContext);
try {
mLogAlarms = SP.getBoolean("LogAlarms", true);
Log.v(TAG, "updatePrefs() - mLogAlarms = " + mLogAlarms);
mLogData = SP.getBoolean("LogData", false);
Log.v(TAG, "updatePrefs() - mLogData = " + mLogData);
mLogSystem = SP.getBoolean("LogSystem", true);
Log.v(TAG, "updatePrefs() - mLogSystem = " + mLogSystem);
} catch (Exception ex) {
Log.v(TAG, "updatePrefs() - Problem parsing preferences!");
showToast("Problem Parsing Preferences - Something won't work - Please go back to Settings and correct it!");
}
}
/**
* used to make sure timers etc. run on UI thread
*/
public void runOnUiThread(Runnable runnable) {
mHandler.post(runnable);
}
public boolean isServerRunning() { public boolean isServerRunning() {
//Log.v(TAG,"isServerRunning()................"); //Log.v(TAG,"isServerRunning()................");
ActivityManager manager = ActivityManager manager =
@@ -81,6 +137,8 @@ public class OsdUtil {
*/ */
public void startServer() { public void startServer() {
// Start the server // Start the server
Log.v(TAG,"startServer()");
writeToSysLogFile("startServer() - starting server");
Intent sdServerIntent; Intent sdServerIntent;
sdServerIntent = new Intent(mContext, SdServer.class); sdServerIntent = new Intent(mContext, SdServer.class);
sdServerIntent.setData(Uri.parse("Start")); sdServerIntent.setData(Uri.parse("Start"));
@@ -92,6 +150,7 @@ public class OsdUtil {
*/ */
public void stopServer() { public void stopServer() {
Log.v(TAG, "stopping Server..."); Log.v(TAG, "stopping Server...");
writeToSysLogFile("stopserver() - stopping server");
// then send an Intent to stop the service. // then send an Intent to stop the service.
Intent sdServerIntent; Intent sdServerIntent;
@@ -106,6 +165,7 @@ public class OsdUtil {
*/ */
public void bindToServer(Activity activity, SdServiceConnection sdServiceConnection) { public void bindToServer(Activity activity, SdServiceConnection sdServiceConnection) {
Log.v(TAG, "bindToServer() - binding to SdServer"); Log.v(TAG, "bindToServer() - binding to SdServer");
writeToSysLogFile("bindToServer() - binding to SdServer");
Intent intent = new Intent(sdServiceConnection.mContext, SdServer.class); Intent intent = new Intent(sdServiceConnection.mContext, SdServer.class);
activity.bindService(intent, sdServiceConnection, Context.BIND_AUTO_CREATE); activity.bindService(intent, sdServiceConnection, Context.BIND_AUTO_CREATE);
} }
@@ -117,14 +177,18 @@ public class OsdUtil {
// unbind this activity from the service if it is bound. // unbind this activity from the service if it is bound.
if (sdServiceConnection.mBound) { if (sdServiceConnection.mBound) {
Log.v(TAG, "unbindFromServer() - unbinding"); Log.v(TAG, "unbindFromServer() - unbinding");
writeToSysLogFile("unbindFromServer() - unbinding");
try { try {
activity.unbindService(sdServiceConnection); activity.unbindService(sdServiceConnection);
sdServiceConnection.mBound = false; sdServiceConnection.mBound = false;
} catch (Exception ex) { } catch (Exception ex) {
Log.e(TAG, "unbindFromServer() - error unbinding service - " + ex.toString()); Log.e(TAG, "unbindFromServer() - error unbinding service - " + ex.toString());
writeToSysLogFile("unbindFromServer() - error unbinding service - " +ex.toString());
} }
} else { } else {
Log.v(TAG, "unbindFromServer() - not bound to server - ignoring"); Log.v(TAG, "unbindFromServer() - not bound to server - ignoring");
writeToSysLogFile("unbindFromServer() - not bound to server - ignoring");
} }
} }
@@ -180,55 +244,106 @@ public class OsdUtil {
/** /**
* Display a Toast message on screen. * Display a Toast message on screen.
*
* @param msg - message to display. * @param msg - message to display.
*/ */
public void showToast(String msg) { public void showToast(final String msg) {
Toast.makeText(mContext, msg, runOnUiThread(new Runnable() {
Toast.LENGTH_LONG).show(); public void run() {
} Toast.makeText(mContext, msg,
Toast.LENGTH_LONG).show();
/**
* Open Pebble or Pebble Time app. If it is not installed, open Play store so the user can install it.
*/
public void startPebbleApp() {
// first try to launch the original pebble app
Intent pebbleAppIntent;
PackageManager pm = mContext.getPackageManager();
try {
pebbleAppIntent = pm.getLaunchIntentForPackage("com.getpebble.android");
mContext.startActivity(pebbleAppIntent);
} catch (Exception ex1) {
// and if original pebble app fails, try Pebble Time app...
Log.v(TAG, "exception starting original pebble App - trying pebble time..." + ex1.toString());
try {
pebbleAppIntent = pm.getLaunchIntentForPackage("com.getpebble.android.basalt");
mContext.startActivity(pebbleAppIntent);
} catch (Exception ex2) {
// and if that fails, open play store so the user can install it:
Log.v(TAG, "exception starting Pebble Time App." + ex2.toString());
this.showToast("Error Launching Pebble or Pebble Time App - Please make sure it is installed...");
final String appPackageName = "com.getpebble.android.basalt";
try {
// try using play store app.
mContext.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=" + appPackageName)));
} catch (android.content.ActivityNotFoundException anfe) {
// and if play store app is not installed, use browser to open app page.
mContext.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://play.google.com/store/apps/details?id=" + appPackageName)));
}
} }
} });
}
/**
* Write a message to the system log file, provided mLogSystem is true.
* @param msgStr
*/
public void writeToSysLogFile(String msgStr) {
if (mLogSystem)
writeToLogFile(SYSLOG,msgStr);
else
Log.v(TAG,"writeToSysLogFile - mLogSystem False so not writing");
} }
/** /**
* Install the OpenSeizureDetector watch app onto the watch. * Write a message to the alarm log file, provided mLogAlarms is true.
* based on https://forums.getpebble.com/discussion/13128/install-watch-app-pebble-store-from-android-companion-app * @param msgStr
*/ */
public void installOsdWatchApp() { public void writeToAlarmLogFile(String msgStr) {
Intent myIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("pebble://appstore/54d28a43e4d94c043f000008")); if (mLogAlarms)
myIntent.setFlags( Intent.FLAG_ACTIVITY_CLEAR_TASK|Intent.FLAG_ACTIVITY_NEW_TASK ); writeToLogFile(ALARMLOG,msgStr);
mContext.startActivity(myIntent); else
Log.v(TAG,"writeToAlarmLogFile - mLogAlarms False so not writing");
} }
/**
* Write a message to the data log file, provided mLogData is true.
* @param msgStr
*/
public void writeToDataLogFile(String msgStr) {
if (mLogData)
writeToLogFile(DATALOG,msgStr);
else
Log.v(TAG,"writeToDataLogFile - mLogData False so not writing");
}
/**
* Write data to SD card - writes to data log file unless alarm=true,
* in which case writes to alarm log file.
*/
public void writeToLogFile(String fname, String msgStr) {
Log.v(TAG, "writeToLogFile(" + fname + "," + msgStr + ")");
//showToast("Logging " + msgStr);
Time tnow = new Time(Time.getCurrentTimezone());
tnow.setToNow();
String dateStr = tnow.format("%Y-%m-%d");
fname = fname + "_" + dateStr + ".txt";
// Open output directory on SD Card.
if (isExternalStorageWritable()) {
try {
FileWriter of = new FileWriter(getDataStorageDir().toString()
+ "/" + fname, true);
if (msgStr != null) {
String dateTimeStr = tnow.format("%Y-%m-%d %H:%M:%S");
Log.v(TAG, "writing msgStr");
of.append(dateTimeStr+", "
+tnow.toMillis(true)+", "
+msgStr+"<br/>\n");
}
of.close();
} catch (Exception ex) {
Log.e(TAG, "writeToLogFile - error " + ex.toString());
showToast("ERROR Writing to Log File");
}
} else {
Log.e(TAG, "ERROR - Can not Write to External Folder");
}
}
/* Checks if external storage is available for read and write */
public boolean isExternalStorageWritable() {
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)) {
return true;
}
return false;
}
public File getDataStorageDir() {
// Get the directory for the user's public directory.
File file =
new File(Environment.getExternalStorageDirectory()
, "OpenSeizureDetector");
if (!file.mkdirs()) {
Log.e(TAG, "Directory not created");
}
return file;
}
} }
@@ -28,6 +28,7 @@ package uk.org.openseizuredetector;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.os.Handler;
import android.preference.PreferenceActivity; import android.preference.PreferenceActivity;
import android.os.Bundle; import android.os.Bundle;
import android.preference.PreferenceFragment; import android.preference.PreferenceFragment;
@@ -42,6 +43,7 @@ public class PrefActivity extends PreferenceActivity implements SharedPreference
private OsdUtil mUtil; private OsdUtil mUtil;
private boolean mPrefChanged = false; private boolean mPrefChanged = false;
private Context mContext; private Context mContext;
private Handler mHandler;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
@@ -51,9 +53,11 @@ public class PrefActivity extends PreferenceActivity implements SharedPreference
Thread.setDefaultUncaughtExceptionHandler(new OsdUncaughtExceptionHandler(PrefActivity.this)); Thread.setDefaultUncaughtExceptionHandler(new OsdUncaughtExceptionHandler(PrefActivity.this));
//int i = 5/0; // Force exception to test handler. //int i = 5/0; // Force exception to test handler.
mHandler = new Handler();
mUtil = new OsdUtil(getApplicationContext());
mContext = getApplicationContext(); mContext = getApplicationContext();
mUtil = new OsdUtil(mContext,mHandler);
mUtil.writeToSysLogFile("PrefActvity.onCreate()");
} }
/** /**
@@ -105,6 +109,7 @@ public class PrefActivity extends PreferenceActivity implements SharedPreference
@Override @Override
public void onStart() { public void onStart() {
super.onStart(); super.onStart();
mUtil.writeToSysLogFile("PrefActvity.onStart()");
invalidateHeaders(); invalidateHeaders();
Log.v(TAG, "onStart()"); Log.v(TAG, "onStart()");
} }
@@ -120,6 +125,7 @@ public class PrefActivity extends PreferenceActivity implements SharedPreference
@Override @Override
public void onResume() { public void onResume() {
super.onResume(); super.onResume();
mUtil.writeToSysLogFile("PrefActvity.onResume()");
Log.v(TAG, "onResume()"); Log.v(TAG, "onResume()");
SharedPreferences SP = PreferenceManager SharedPreferences SP = PreferenceManager
.getDefaultSharedPreferences(getBaseContext()); .getDefaultSharedPreferences(getBaseContext());
@@ -129,6 +135,7 @@ public class PrefActivity extends PreferenceActivity implements SharedPreference
@Override @Override
protected void onPause() { protected void onPause() {
super.onPause(); super.onPause();
mUtil.writeToSysLogFile("PrefActvity.onPause()");
SharedPreferences SP = PreferenceManager SharedPreferences SP = PreferenceManager
.getDefaultSharedPreferences(getBaseContext()); .getDefaultSharedPreferences(getBaseContext());
SP.unregisterOnSharedPreferenceChangeListener(this); SP.unregisterOnSharedPreferenceChangeListener(this);
@@ -137,8 +144,10 @@ public class PrefActivity extends PreferenceActivity implements SharedPreference
@Override @Override
protected void onDestroy() { protected void onDestroy() {
super.onDestroy(); super.onDestroy();
mUtil.writeToSysLogFile("PrefActvity.onDestroy()");
Log.v(TAG, "onDestroy. mPrefChanged=" + mPrefChanged); Log.v(TAG, "onDestroy. mPrefChanged=" + mPrefChanged);
if (mPrefChanged) { if (mPrefChanged) {
mUtil.writeToSysLogFile("PrefActvity.onDestroy() - settings changed - re-starting....");
mUtil.showToast("Settings Changed - re-starting OpenSeizureDetector...."); mUtil.showToast("Settings Changed - re-starting OpenSeizureDetector....");
Intent intent = new Intent(getApplicationContext(), StartupActivity.class); Intent intent = new Intent(getApplicationContext(), StartupActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK); intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
@@ -43,6 +43,15 @@ public class SdData implements Parcelable {
/* Analysis settings */ /* Analysis settings */
public boolean haveSettings = false; // flag to say if we have received settings or not. public boolean haveSettings = false; // flag to say if we have received settings or not.
public boolean haveData = false; // flag to say we have received data. public boolean haveData = false; // flag to say we have received data.
public short mDataUpdatePeriod;
public short mMutePeriod;
public short mManAlarmPeriod;
public boolean mFallActive;
public short mFallThreshMin;
public short mFallThreshMax;
public short mFallWindow;
public long mSdMode;
public long mSampleFreq;
public long alarmFreqMin; public long alarmFreqMin;
public long alarmFreqMax; public long alarmFreqMax;
public long nMin; public long nMin;
@@ -141,6 +150,10 @@ public class SdData implements Parcelable {
jsonObj.put("haveSettings", haveSettings); jsonObj.put("haveSettings", haveSettings);
jsonObj.put("alarmState", alarmState); jsonObj.put("alarmState", alarmState);
jsonObj.put("alarmPhrase", alarmPhrase); jsonObj.put("alarmPhrase", alarmPhrase);
jsonObj.put("sdMode",mSdMode);
jsonObj.put("sampleFreq",mSampleFreq);
jsonObj.put("alarmFreqMin",alarmFreqMin);
jsonObj.put("alarmFreqMax",alarmFreqMax);
jsonObj.put("alarmThresh", alarmThresh); jsonObj.put("alarmThresh", alarmThresh);
jsonObj.put("alarmRatioThresh", alarmRatioThresh); jsonObj.put("alarmRatioThresh", alarmRatioThresh);
JSONArray arr = new JSONArray(); JSONArray arr = new JSONArray();
@@ -24,6 +24,7 @@
package uk.org.openseizuredetector; package uk.org.openseizuredetector;
import android.content.Context; import android.content.Context;
import android.os.Handler;
import android.util.Log; import android.util.Log;
import android.widget.Toast; import android.widget.Toast;
@@ -39,13 +40,17 @@ interface SdDataReceiver {
public abstract class SdDataSource { public abstract class SdDataSource {
public SdData mSdData; public SdData mSdData;
public String mName = "undefined"; public String mName = "undefined";
protected OsdUtil mUtil;
protected Context mContext; protected Context mContext;
protected Handler mHandler;
protected SdDataReceiver mSdDataReceiver; protected SdDataReceiver mSdDataReceiver;
private String TAG = "SdDataSource"; private String TAG = "SdDataSource";
public SdDataSource(Context context, SdDataReceiver sdDataReceiver) { public SdDataSource(Context context, Handler handler, SdDataReceiver sdDataReceiver) {
Log.v(TAG, "SdDataSource() Constructor"); Log.v(TAG, "SdDataSource() Constructor");
mContext = context; mContext = context;
mHandler = handler;
mUtil = new OsdUtil(mContext, mHandler);
mSdDataReceiver = sdDataReceiver; mSdDataReceiver = sdDataReceiver;
mSdData = new SdData(); mSdData = new SdData();
} }
@@ -73,6 +78,13 @@ public abstract class SdDataSource {
Log.v(TAG, "stop()"); Log.v(TAG, "stop()");
} }
/**
* Install the watch app on the watch.
*/
public void installWatchApp() { Log.v(TAG,"installWatchApp"); }
public void startPebbleApp() { Log.v(TAG,"startPebbleApp()"); }
/** /**
* Display a Toast message on screen. * Display a Toast message on screen.
* @param msg - message to display. * @param msg - message to display.
@@ -5,6 +5,7 @@ import android.content.SharedPreferences;
import android.net.ConnectivityManager; import android.net.ConnectivityManager;
import android.net.NetworkInfo; import android.net.NetworkInfo;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.os.Handler;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.text.format.Time; import android.text.format.Time;
import android.util.Log; import android.util.Log;
@@ -32,14 +33,15 @@ public class SdDataSourceNetwork extends SdDataSource {
private int ALARM_STATE_NETFAULT = 7; private int ALARM_STATE_NETFAULT = 7;
public SdDataSourceNetwork(Context context, SdDataReceiver sdDataReceiver) { public SdDataSourceNetwork(Context context, Handler handler, SdDataReceiver sdDataReceiver) {
super(context,sdDataReceiver); super(context, handler, sdDataReceiver);
mName = "Network"; mName = "Network";
} }
@Override public void start() { @Override public void start() {
// Update preferences. // Update preferences.
Log.v(TAG,"start(): calling updatePrefs()"); Log.v(TAG,"start(): calling updatePrefs()");
mUtil.writeToSysLogFile("SdDataSourceNetwork().start()");
updatePrefs(); updatePrefs();
// Start timer to retrieve seizure detector data regularly. // Start timer to retrieve seizure detector data regularly.
@@ -62,6 +64,7 @@ public class SdDataSourceNetwork extends SdDataSource {
} }
@Override public void stop() { @Override public void stop() {
mUtil.writeToSysLogFile("SdDataSourceNetwork().stop()");
// Stop the data update timer // Stop the data update timer
if (mDataUpdateTimer !=null) { if (mDataUpdateTimer !=null) {
Log.v(TAG,"stop(): cancelling status timer"); Log.v(TAG,"stop(): cancelling status timer");
@@ -80,6 +83,7 @@ public class SdDataSourceNetwork extends SdDataSource {
*/ */
public void updatePrefs() { public void updatePrefs() {
Log.v(TAG, "updatePrefs()"); Log.v(TAG, "updatePrefs()");
mUtil.writeToSysLogFile("SdDataSourceNetwork().updatePrefs()");
SharedPreferences SP = PreferenceManager SharedPreferences SP = PreferenceManager
.getDefaultSharedPreferences(mContext); .getDefaultSharedPreferences(mContext);
mServerIP = SP.getString("ServerIP","192.168.1.175"); mServerIP = SP.getString("ServerIP","192.168.1.175");
@@ -90,14 +94,14 @@ public class SdDataSourceNetwork extends SdDataSource {
Log.v(TAG,"updatePrefs() - mDataUpdatePeriod = "+mDataUpdatePeriod); Log.v(TAG,"updatePrefs() - mDataUpdatePeriod = "+mDataUpdatePeriod);
} catch (Exception ex) { } catch (Exception ex) {
Log.v(TAG,"updatePrefs() - Problem parsing preferences!"); Log.v(TAG,"updatePrefs() - Problem parsing preferences!");
mUtil.writeToSysLogFile("SdDataSourceNetwork().updatePrefs() - " +ex.toString());
showToast("Problem Parsing Preferences - Something won't work"); showToast("Problem Parsing Preferences - Something won't work");
} }
} }
/** /**
* Retrive the current Seizure Detector Data from the server. * Retrive the current Seizure Detector Data from the server.
* Uses teh DownloadSdDataTask class to download the data in the * Uses the DownloadSdDataTask class to download the data in the
* background. The data is processed in DownloadSdDataTask.onPostExecute(). * background. The data is processed in DownloadSdDataTask.onPostExecute().
*/ */
public void downloadSdData() { public void downloadSdData() {
@@ -3,7 +3,7 @@
See http://openseizuredetector.org for more information. See http://openseizuredetector.org for more information.
Copyright Graham Jones, 2015. Copyright Graham Jones, 2015, 2016
This file is part of pebble_sd. This file is part of pebble_sd.
@@ -24,18 +24,24 @@
package uk.org.openseizuredetector; package uk.org.openseizuredetector;
import android.content.Context; import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Handler; import android.os.Handler;
import android.os.Looper;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.text.format.Time; import android.text.format.Time;
import android.util.Log; import android.util.Log;
import android.widget.Toast; import android.widget.Toast;
import com.getpebble.android.kit.Constants;
import com.getpebble.android.kit.PebbleKit; import com.getpebble.android.kit.PebbleKit;
import com.getpebble.android.kit.util.PebbleDictionary; import com.getpebble.android.kit.util.PebbleDictionary;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.ByteOrder; import java.nio.ByteOrder;
import java.nio.IntBuffer; import java.nio.IntBuffer;
@@ -50,15 +56,16 @@ import java.util.UUID;
* network data source. * network data source.
*/ */
public class SdDataSourcePebble extends SdDataSource { public class SdDataSourcePebble extends SdDataSource {
private Handler mHandler = new Handler();
private Timer mSettingsTimer; private Timer mSettingsTimer;
private Timer mStatusTimer; private Timer mStatusTimer;
private Time mPebbleStatusTime; private Time mPebbleStatusTime;
private boolean mPebbleAppRunningCheck = false; private boolean mPebbleAppRunningCheck = false;
private int mDataPeriod = 5; // Period at which data is sent from watch to phone (sec)
private int mAppRestartTimeout = 10; // Timeout before re-starting watch app (sec) if we have not received private int mAppRestartTimeout = 10; // Timeout before re-starting watch app (sec) if we have not received
// data after mDataPeriod // data after mDataUpdatePeriod
//private Looper mServiceLooper; //private Looper mServiceLooper;
private int mFaultTimerPeriod = 30; // Fault Timer Period in sec private int mFaultTimerPeriod = 30; // Fault Timer Period in sec
private int mSettingsPeriod = 60; // period between requesting settings in seconds.
private PebbleKit.PebbleDataReceiver msgDataHandler = null; private PebbleKit.PebbleDataReceiver msgDataHandler = null;
@@ -94,14 +101,54 @@ public class SdDataSourcePebble extends SdDataSource {
private int KEY_DATA_UPDATE_PERIOD = 25; private int KEY_DATA_UPDATE_PERIOD = 25;
private int KEY_MUTE_PERIOD = 26; private int KEY_MUTE_PERIOD = 26;
private int KEY_MAN_ALARM_PERIOD = 27; private int KEY_MAN_ALARM_PERIOD = 27;
private int KEY_SD_MODE = 28;
private int KEY_SAMPLE_FREQ = 29;
private int KEY_RAW_DATA = 30;
private int KEY_NUM_RAW_DATA = 31;
private int KEY_DEBUG = 32;
private int KEY_DISPLAY_SPECTRUM = 33;
// Values of the KEY_DATA_TYPE entry in a message // Values of the KEY_DATA_TYPE entry in a message
private int DATA_TYPE_RESULTS = 1; // Analysis Results private int DATA_TYPE_RESULTS = 1; // Analysis Results
private int DATA_TYPE_SETTINGS = 2; // Settings private int DATA_TYPE_SETTINGS = 2; // Settings
private int DATA_TYPE_SPEC = 3; // FFT Spectrum (or part of a spectrum) private int DATA_TYPE_SPEC = 3; // FFT Spectrum (or part of a spectrum)
public SdDataSourcePebble(Context context, SdDataReceiver sdDataReceiver) { private int DATA_TYPE_RAW = 4; // raw accelerometer data.
super(context,sdDataReceiver);
// Values for SD_MODE
private int SD_MODE_FFT = 0; // The original OpenSeizureDetector mode (FFT based)
private int SD_MODE_RAW = 1; // Send raw, unprocessed data to the phone.
private int SD_MODE_FILTER = 2; // Use digital filter rather than FFT.
private short mDebug;
private short mDisplaySpectrum;
private short mDataUpdatePeriod;
private short mMutePeriod;
private short mManAlarmPeriod;
private short mPebbleSdMode;
private short mSampleFreq;
private short mAlarmFreqMin;
private short mAlarmFreqMax;
private short mWarnTime;
private short mAlarmTime;
private short mAlarmThresh;
private short mAlarmRatioThresh;
private boolean mFallActive;
private short mFallThreshMin;
private short mFallThreshMax;
private short mFallWindow;
// raw data storage for SD_MODE_RAW
private int MAX_RAW_DATA = 500;
private double[] rawData = new double[MAX_RAW_DATA];
private int nRawData = 0;
public SdDataSourcePebble(Context context, Handler handler,
SdDataReceiver sdDataReceiver) {
super(context, handler, sdDataReceiver);
mName = "Pebble"; mName = "Pebble";
// Set default settings from XML files (mContext is set by super().
PreferenceManager.setDefaultValues(mContext,
R.xml.pebble_datasource_prefs, true);
} }
@@ -111,6 +158,7 @@ public class SdDataSourcePebble extends SdDataSource {
*/ */
public void start() { public void start() {
Log.v(TAG, "start()"); Log.v(TAG, "start()");
mUtil.writeToSysLogFile("SdDataSourcePebble.start()");
updatePrefs(); updatePrefs();
startPebbleServer(); startPebbleServer();
// Start timer to check status of pebble regularly. // Start timer to check status of pebble regularly.
@@ -118,35 +166,38 @@ public class SdDataSourcePebble extends SdDataSource {
// use a timer to check the status of the pebble app on the same frequency // use a timer to check the status of the pebble app on the same frequency
// as we get app data. // as we get app data.
if (mStatusTimer == null) { if (mStatusTimer == null) {
Log.v(TAG, "onCreate(): starting status timer"); Log.v(TAG, "start(): starting status timer");
mUtil.writeToSysLogFile("SdDataSourcePebble.start() - starting status timer");
mStatusTimer = new Timer(); mStatusTimer = new Timer();
mStatusTimer.schedule(new TimerTask() { mStatusTimer.schedule(new TimerTask() {
@Override @Override
public void run() { public void run() {
getPebbleStatus(); getPebbleStatus();
} }
}, 0, mDataPeriod * 1000); }, 0, mDataUpdatePeriod * 1000);
} else { } else {
Log.v(TAG, "onCreate(): status timer already running."); Log.v(TAG, "start(): status timer already running.");
mUtil.writeToSysLogFile("SdDataSourcePebble.start() - status timer already running??");
} }
// make sure we get some data when we first start. // make sure we get some data when we first start.
getPebbleData(); getPebbleData();
// Start timer to retrieve pebble settings regularly. // Start timer to retrieve pebble settings regularly.
getPebbleSdSettings(); getPebbleSdSettings();
if (mSettingsTimer == null) { if (mSettingsTimer == null) {
Log.v(TAG, "onCreate(): starting settings timer"); Log.v(TAG, "start(): starting settings timer");
mUtil.writeToSysLogFile("SdDataSourcePebble.start() - starting settings timer");
mSettingsTimer = new Timer(); mSettingsTimer = new Timer();
mSettingsTimer.schedule(new TimerTask() { mSettingsTimer.schedule(new TimerTask() {
@Override @Override
public void run() { public void run() {
//mUtil.writeToSysLogFile("SdDataSourcePebble.mSettingsTimer timed out.");
getPebbleSdSettings(); getPebbleSdSettings();
} }
}, 0, 1000 * (mDataPeriod + 60)); // ask for settings less frequently than we get data }, 0, 1000 * mSettingsPeriod); // ask for settings less frequently than we get data
} else { } else {
Log.v(TAG, "onCreate(): settings timer already running."); Log.v(TAG, "start(): settings timer already running.");
mUtil.writeToSysLogFile("SdDataSourcePebble.start() - settings timer already running??");
} }
} }
/** /**
@@ -154,30 +205,33 @@ public class SdDataSourcePebble extends SdDataSource {
*/ */
public void stop() { public void stop() {
Log.v(TAG, "stop()"); Log.v(TAG, "stop()");
mUtil.writeToSysLogFile("SdDataSourcePebble.stop()");
try { try {
// Stop the status timer // Stop the status timer
if (mStatusTimer != null) { if (mStatusTimer != null) {
Log.v(TAG, "onDestroy(): cancelling status timer"); Log.v(TAG, "stop(): cancelling status timer");
mUtil.writeToSysLogFile("SdDataSourcePebble.stop() - cancelling status timer");
mStatusTimer.cancel(); mStatusTimer.cancel();
mStatusTimer.purge(); mStatusTimer.purge();
mStatusTimer = null; mStatusTimer = null;
} }
// Stop the settings timer // Stop the settings timer
if (mSettingsTimer != null) { if (mSettingsTimer != null) {
Log.v(TAG, "onDestroy(): cancelling settings timer"); Log.v(TAG, "stop(): cancelling settings timer");
mUtil.writeToSysLogFile("SdDataSourcePebble.stop() - cancelling settings timer");
mSettingsTimer.cancel(); mSettingsTimer.cancel();
mSettingsTimer.purge(); mSettingsTimer.purge();
mSettingsTimer = null; mSettingsTimer = null;
} }
// Stop pebble message handler. // Stop pebble message handler.
Log.v(TAG, "onDestroy(): stopping pebble server"); Log.v(TAG, "stop(): stopping pebble server");
mUtil.writeToSysLogFile("SdDataSourcePebble.stop() - stopping pebble server");
stopPebbleServer(); stopPebbleServer();
} catch (Exception e) { } catch (Exception e) {
Log.v(TAG, "Error in stop() - " + e.toString()); Log.v(TAG, "Error in stop() - " + e.toString());
mUtil.writeToSysLogFile("SdDataSourcePebble.stop() - error - "+e.toString());
} }
} }
/** /**
@@ -186,6 +240,7 @@ public class SdDataSourcePebble extends SdDataSource {
*/ */
public void updatePrefs() { public void updatePrefs() {
Log.v(TAG, "updatePrefs()"); Log.v(TAG, "updatePrefs()");
mUtil.writeToSysLogFile("SdDataSourcePebble.updatePrefs()");
SharedPreferences SP = PreferenceManager SharedPreferences SP = PreferenceManager
.getDefaultSharedPreferences(mContext); .getDefaultSharedPreferences(mContext);
try { try {
@@ -200,17 +255,6 @@ public class SdDataSourcePebble extends SdDataSource {
toast.show(); toast.show();
} }
// Parse the DataPeriod setting.
try {
String dataPeriodStr = SP.getString("DataPeriod", "5");
mDataPeriod = Integer.parseInt(dataPeriodStr);
Log.v(TAG, "updatePrefs() - mDataPeriod = " + mDataPeriod);
} catch (Exception ex) {
Log.v(TAG, "updatePrefs() - Problem with DataPeriod preference!");
Toast toast = Toast.makeText(mContext, "Problem Parsing DataPeriod Preference", Toast.LENGTH_SHORT);
toast.show();
}
// Parse the FaultTimer period setting. // Parse the FaultTimer period setting.
try { try {
String faultTimerPeriodStr = SP.getString("FaultTimerPeriod", "30"); String faultTimerPeriodStr = SP.getString("FaultTimerPeriod", "30");
@@ -224,84 +268,78 @@ public class SdDataSourcePebble extends SdDataSource {
// Watch Settings // Watch Settings
PebbleDictionary setDict = new PebbleDictionary();
short intVal;
String prefStr; String prefStr;
prefStr = SP.getString("DataUpdatePeriod", "5"); prefStr = SP.getString("PebbleDebug", "SET_FROM_XML");
intVal = (short) Integer.parseInt(prefStr); mDebug = (short) Integer.parseInt(prefStr);
Log.v(TAG, "updatePrefs() DataUpdatePeriod = " + intVal); Log.v(TAG, "updatePrefs() Debug = " + mDebug);
setDict.addInt16(KEY_DATA_UPDATE_PERIOD, intVal);
prefStr = SP.getString("MutePeriod", "300"); prefStr = SP.getString("PebbleDisplaySpectrum", "SET_FROM_XML");
intVal = (short) Integer.parseInt(prefStr); mDisplaySpectrum = (short) Integer.parseInt(prefStr);
Log.v(TAG, "updatePrefs() MutePeriod = " + intVal); Log.v(TAG, "updatePrefs() DisplaySpectrum = " + mDisplaySpectrum);
setDict.addInt16(KEY_MUTE_PERIOD, intVal);
prefStr = SP.getString("ManAlarmPeriod", "30"); prefStr = SP.getString("PebbleUpdatePeriod", "SET_FROM_XML");
intVal = (short) Integer.parseInt(prefStr); mDataUpdatePeriod = (short) Integer.parseInt(prefStr);
Log.v(TAG, "updatePrefs() ManAlarmPeriod = " + intVal); Log.v(TAG, "updatePrefs() DataUpdatePeriod = " + mDataUpdatePeriod);
setDict.addInt16(KEY_MAN_ALARM_PERIOD, intVal);
prefStr = SP.getString("MutePeriod", "SET_FROM_XML");
mMutePeriod = (short) Integer.parseInt(prefStr);
Log.v(TAG, "updatePrefs() MutePeriod = " + mMutePeriod);
prefStr = SP.getString("AlarmFreqMin", "5"); prefStr = SP.getString("ManAlarmPeriod", "SET_FROM_XML");
intVal = (short) Integer.parseInt(prefStr); mManAlarmPeriod = (short) Integer.parseInt(prefStr);
Log.v(TAG, "updatePrefs() AlarmFreqMin = " + intVal); Log.v(TAG, "updatePrefs() ManAlarmPeriod = " + mManAlarmPeriod);
setDict.addInt16(KEY_ALARM_FREQ_MIN, intVal);
prefStr = SP.getString("AlarmFreqMax", "10"); prefStr = SP.getString("PebbleSdMode", "SET_FROM_XML");
intVal = (short) Integer.parseInt(prefStr); mPebbleSdMode = (short) Integer.parseInt(prefStr);
Log.v(TAG, "updatePrefs() AlarmFreqMax = " + intVal); Log.v(TAG, "updatePrefs() PebbleSdMode = " + mPebbleSdMode);
setDict.addUint16(KEY_ALARM_FREQ_MAX, (short) intVal);
prefStr = SP.getString("WarnTime", "5"); prefStr = SP.getString("SampleFreq", "SET_FROM_XML");
intVal = (short) Integer.parseInt(prefStr); mSampleFreq = (short) Integer.parseInt(prefStr);
Log.v(TAG, "updatePrefs() WarnTime = " + intVal); Log.v(TAG, "updatePrefs() SampleFreq = " + mSampleFreq);
setDict.addUint16(KEY_WARN_TIME, (short) intVal);
prefStr = SP.getString("AlarmTime", "10"); prefStr = SP.getString("AlarmFreqMin", "SET_FROM_XML");
intVal = (short) Integer.parseInt(prefStr); mAlarmFreqMin = (short) Integer.parseInt(prefStr);
Log.v(TAG, "updatePrefs() AlarmTime = " + intVal); Log.v(TAG, "updatePrefs() AlarmFreqMin = " + mAlarmFreqMin);
setDict.addUint16(KEY_ALARM_TIME, (short) intVal);
prefStr = SP.getString("AlarmThresh", "70"); prefStr = SP.getString("AlarmFreqMax", "SET_FROM_XML");
intVal = (short) Integer.parseInt(prefStr); mAlarmFreqMax = (short) Integer.parseInt(prefStr);
Log.v(TAG, "updatePrefs() AlarmThresh = " + intVal); Log.v(TAG, "updatePrefs() AlarmFreqMax = " + mAlarmFreqMax);
setDict.addUint16(KEY_ALARM_THRESH, (short) intVal);
prefStr = SP.getString("AlarmRatioThresh", "30"); prefStr = SP.getString("WarnTime", "SET_FROM_XML");
intVal = (short) Integer.parseInt(prefStr); mWarnTime = (short) Integer.parseInt(prefStr);
Log.v(TAG, "updatePrefs() AlarmRatioThresh = " + intVal); Log.v(TAG, "updatePrefs() WarnTime = " + mWarnTime);
setDict.addUint16(KEY_ALARM_RATIO_THRESH, (short) intVal);
boolean fallActiveBool = SP.getBoolean("FallActive", false); prefStr = SP.getString("AlarmTime", "SET_FROM_XML");
Log.v(TAG, "updatePrefs() FallActive = " + fallActiveBool); mAlarmTime = (short) Integer.parseInt(prefStr);
if (fallActiveBool) Log.v(TAG, "updatePrefs() AlarmTime = " + mAlarmTime);
setDict.addUint16(KEY_FALL_ACTIVE, (short) 1);
else
setDict.addUint16(KEY_FALL_ACTIVE, (short) 0);
prefStr = SP.getString("FallThreshMin", "200"); prefStr = SP.getString("AlarmThresh", "SET_FROM_XML");
intVal = (short) Integer.parseInt(prefStr); mAlarmThresh = (short) Integer.parseInt(prefStr);
Log.v(TAG, "updatePrefs() FallThreshMin = " + intVal); Log.v(TAG, "updatePrefs() AlarmThresh = " + mAlarmThresh);
setDict.addUint16(KEY_FALL_THRESH_MIN, (short) intVal);
prefStr = SP.getString("FallThreshMax", "1200"); prefStr = SP.getString("AlarmRatioThresh", "SET_FROM_XML");
intVal = (short) Integer.parseInt(prefStr); mAlarmRatioThresh = (short) Integer.parseInt(prefStr);
Log.v(TAG, "updatePrefs() FallThreshMax = " + intVal); Log.v(TAG, "updatePrefs() AlarmRatioThresh = " + mAlarmRatioThresh);
setDict.addUint16(KEY_FALL_THRESH_MAX, (short) intVal);
prefStr = SP.getString("FallWindow", "1500"); mFallActive = SP.getBoolean("FallActive", false);
intVal = (short) Integer.parseInt(prefStr); Log.v(TAG, "updatePrefs() FallActive = " + mFallActive);
Log.v(TAG, "updatePrefs() FallWindow = " + intVal);
setDict.addUint16(KEY_FALL_WINDOW, (short) intVal);
prefStr = SP.getString("FallThreshMin", "SET_FROM_XML");
mFallThreshMin = (short) Integer.parseInt(prefStr);
Log.v(TAG, "updatePrefs() FallThreshMin = " + mFallThreshMin);
prefStr = SP.getString("FallThreshMax", "SET_FROM_XML");
mFallThreshMax = (short) Integer.parseInt(prefStr);
Log.v(TAG, "updatePrefs() FallThreshMax = " + mFallThreshMax);
prefStr = SP.getString("FallWindow", "SET_FROM_XML");
mFallWindow = (short) Integer.parseInt(prefStr);
Log.v(TAG, "updatePrefs() FallWindow = " + mFallWindow);
// Send Watch Settings to Pebble
Log.v(TAG, "updatePrefs() - setDict = " + setDict.toJsonString());
PebbleKit.sendDataToPebble(mContext, SD_UUID, setDict);
} catch (Exception ex) { } catch (Exception ex) {
Log.v(TAG, "updatePrefs() - Problem parsing preferences!"); Log.v(TAG, "updatePrefs() - Problem parsing preferences!");
mUtil.writeToSysLogFile("SdDataSourcePebble.updatePrefs() - ERROR "+ex.toString());
Toast toast = Toast.makeText(mContext, "Problem Parsing Preferences - Something won't work - Please go back to Settings and correct it!", Toast.LENGTH_SHORT); Toast toast = Toast.makeText(mContext, "Problem Parsing Preferences - Something won't work - Please go back to Settings and correct it!", Toast.LENGTH_SHORT);
toast.show(); toast.show();
} }
@@ -314,6 +352,7 @@ public class SdDataSourcePebble extends SdDataSource {
*/ */
private void startPebbleServer() { private void startPebbleServer() {
Log.v(TAG, "StartPebbleServer()"); Log.v(TAG, "StartPebbleServer()");
mUtil.writeToSysLogFile("SdDataSourcePebble.startPebbleServer()");
final Handler handler = new Handler(); final Handler handler = new Handler();
msgDataHandler = new PebbleKit.PebbleDataReceiver(SD_UUID) { msgDataHandler = new PebbleKit.PebbleDataReceiver(SD_UUID) {
@Override @Override
@@ -322,8 +361,8 @@ public class SdDataSourcePebble extends SdDataSource {
final PebbleDictionary data) { final PebbleDictionary data) {
Log.v(TAG, "Received message from Pebble - data type=" Log.v(TAG, "Received message from Pebble - data type="
+ data.getUnsignedIntegerAsLong(KEY_DATA_TYPE)); + data.getUnsignedIntegerAsLong(KEY_DATA_TYPE));
// If we ha ve a message, the app must be running // If we have a message, the app must be running
Log.v(TAG,"Setting mPebbleAppRunningCheck to true"); Log.v(TAG, "Setting mPebbleAppRunningCheck to true");
mPebbleAppRunningCheck = true; mPebbleAppRunningCheck = true;
PebbleKit.sendAckToPebble(context, transactionId); PebbleKit.sendAckToPebble(context, transactionId);
//Log.v(TAG,"Message is: "+data.toJsonString()); //Log.v(TAG,"Message is: "+data.toJsonString());
@@ -342,13 +381,12 @@ public class SdDataSourcePebble extends SdDataSource {
mSdData.alarmPhrase = "Unknown"; mSdData.alarmPhrase = "Unknown";
mSdData.haveData = true; mSdData.haveData = true;
mSdDataReceiver.onSdDataReceived(mSdData); mSdDataReceiver.onSdDataReceived(mSdData);
}
// Read the data that has been sent, and convert it into // Read the data that has been sent, and convert it into
// an integer array. // an integer array.
byte[] byteArr = data.getBytes(KEY_SPEC_DATA); byte[] byteArr = data.getBytes(KEY_SPEC_DATA);
if ((byteArr!=null) && (byteArr.length!=0)) { if ((byteArr != null) && (byteArr.length != 0)) {
IntBuffer intBuf = ByteBuffer.wrap(byteArr) IntBuffer intBuf = ByteBuffer.wrap(byteArr)
.order(ByteOrder.LITTLE_ENDIAN) .order(ByteOrder.LITTLE_ENDIAN)
.asIntBuffer(); .asIntBuffer();
@@ -358,9 +396,9 @@ public class SdDataSourcePebble extends SdDataSource {
mSdData.simpleSpec[i] = intArray[i]; mSdData.simpleSpec[i] = intArray[i];
} }
} else { } else {
Log.v(TAG,"***** zero length spectrum received - error!!!!"); Log.v(TAG, "***** zero length spectrum received - error!!!!");
} }
}
if (data.getUnsignedIntegerAsLong(KEY_DATA_TYPE) if (data.getUnsignedIntegerAsLong(KEY_DATA_TYPE)
== DATA_TYPE_SETTINGS) { == DATA_TYPE_SETTINGS) {
@@ -376,12 +414,45 @@ public class SdDataSourcePebble extends SdDataSource {
mSdData.batteryPc = data.getUnsignedIntegerAsLong(KEY_BATTERY_PC); mSdData.batteryPc = data.getUnsignedIntegerAsLong(KEY_BATTERY_PC);
mSdData.haveSettings = true; mSdData.haveSettings = true;
} }
if (data.getUnsignedIntegerAsLong(KEY_DATA_TYPE)
== DATA_TYPE_RAW) {
Log.v(TAG, "DATA_TYPE = Raw");
long numSamples;
numSamples = data.getUnsignedIntegerAsLong(KEY_NUM_RAW_DATA);
Log.v(TAG, "numSamples = " + numSamples);
byte[] rawDataBytes = data.getBytes(KEY_RAW_DATA);
for (int i = 0; i < rawDataBytes.length - 4; i += 4) { // 4 bytes per sample
int x = (rawDataBytes[i]);
//int y = (rawDataBytes[i+2] & 0xff) | (rawDataBytes[i+3] << 8);
//int z = (rawDataBytes[i+4] & 0xff) | (rawDataBytes[i+5] << 8);
//Log.v(TAG,"x="+x+", y="+y+", z="+z);
Log.v(TAG,"x="+x);
if (nRawData < MAX_RAW_DATA) {
rawData[nRawData] = (int)Math.sqrt(x);
} else {
Log.i(TAG, "WARNING - rawData Buffer Full");
}
}
//for (AccelData reading : AccelData.fromDataArray(rawDataBytes)) {
// if (nRawData < MAX_RAW_DATA) {
// rawData[nRawData] = reading.getMagnitude();
// nRawData++;
// } else {
// Log.i(TAG, "WARNING - rawData Buffer Full");
// }
// }
}
} }
}; };
PebbleKit.registerReceivedDataHandler(mContext, msgDataHandler); PebbleKit.registerReceivedDataHandler(mContext, msgDataHandler);
// We struggle to connect to pebble time if app is already running, so stop app so we can // We struggle to connect to pebble time if app is already running,
// re-connect to it. // so stop app so we can re-connect to it.
stopWatchApp(); //stopWatchApp();
startWatchApp();
} }
/** /**
@@ -390,10 +461,13 @@ public class SdDataSourcePebble extends SdDataSource {
public void stopPebbleServer() { public void stopPebbleServer() {
Log.v(TAG, "stopPebbleServer(): Stopping Pebble Server"); Log.v(TAG, "stopPebbleServer(): Stopping Pebble Server");
Log.v(TAG, "stopPebbleServer(): msgDataHandler = " + msgDataHandler.toString()); Log.v(TAG, "stopPebbleServer(): msgDataHandler = " + msgDataHandler.toString());
mUtil.writeToSysLogFile("SdDataSourcePebble.stopPebbleServer()");
try { try {
mContext.unregisterReceiver(msgDataHandler); mContext.unregisterReceiver(msgDataHandler);
stopWatchApp();
} catch (Exception e) { } catch (Exception e) {
Log.v(TAG, "stopPebbleServer() - error " + e.toString()); Log.v(TAG, "stopPebbleServer() - error " + e.toString());
mUtil.writeToSysLogFile("SdDataSourcePebble.stopPebbleServer() - error " + e.toString());
} }
} }
@@ -402,11 +476,20 @@ public class SdDataSourcePebble extends SdDataSource {
*/ */
public void startWatchApp() { public void startWatchApp() {
Log.v(TAG, "startWatchApp() - closing app first"); Log.v(TAG, "startWatchApp() - closing app first");
mUtil.writeToSysLogFile("SdDataSourcePebble.startWatchApp() - closing app first");
// first close the watch app if it is running. // first close the watch app if it is running.
PebbleKit.closeAppOnPebble(mContext, SD_UUID); PebbleKit.closeAppOnPebble(mContext, SD_UUID);
// then start it. Log.v(TAG, "startWatchApp() - starting watch app after 5 seconds delay...");
Log.v(TAG, "startWatchApp() - starting watch app..."); // Wait 5 seconds then start the app.
PebbleKit.startAppOnPebble(mContext, SD_UUID); Timer appStartTimer = new Timer();
appStartTimer.schedule(new TimerTask() {
@Override
public void run() {
Log.v(TAG, "startWatchApp() - starting watch app...");
mUtil.writeToSysLogFile("SdDataSourcePebble.startWatchApp() - starting watch app");
PebbleKit.startAppOnPebble(mContext, SD_UUID);
}
}, 5000);
} }
/** /**
@@ -414,16 +497,22 @@ public class SdDataSourcePebble extends SdDataSource {
*/ */
public void stopWatchApp() { public void stopWatchApp() {
Log.v(TAG, "stopWatchApp()"); Log.v(TAG, "stopWatchApp()");
mUtil.writeToSysLogFile("SdDataSourcePebble.stopWatchApp()");
PebbleKit.closeAppOnPebble(mContext, SD_UUID); PebbleKit.closeAppOnPebble(mContext, SD_UUID);
} }
/** /**
* Request Pebble App to send us its latest settings. * Send our latest settings to the watch, then request Pebble App to send
* us its latest settings so we can check it has been set up correctly..
* Will be received as a message by the receiveData handler * Will be received as a message by the receiveData handler
*/ */
public void getPebbleSdSettings() { public void getPebbleSdSettings() {
Log.v(TAG, "getPebbleSdSettings() - requesting settings from pebble"); Log.v(TAG, "getPebbleSdSettings() - sending required settings to pebble");
mUtil.writeToSysLogFile("SdDataSourcePebble.getPebbleSdSettings()");
sendPebbleSdSettings();
//Log.v(TAG, "getPebbleSdSettings() - requesting settings from pebble");
//mUtil.writeToSysLogFile("SdDataSourcePebble.getPebbleSdSettings() - and request settings from pebble");
PebbleDictionary data = new PebbleDictionary(); PebbleDictionary data = new PebbleDictionary();
data.addUint8(KEY_SETTINGS, (byte) 1); data.addUint8(KEY_SETTINGS, (byte) 1);
PebbleKit.sendDataToPebble( PebbleKit.sendDataToPebble(
@@ -432,12 +521,114 @@ public class SdDataSourcePebble extends SdDataSource {
data); data);
} }
/**
* Send the pebble watch settings that are stored as class member
* variables to the watch.
*/
public void sendPebbleSdSettings() {
Log.v(TAG, "sendPebblSdSettings() - preparing settings dictionary.. mSampleFreq=" + mSampleFreq);
mUtil.writeToSysLogFile("SdDataSourcePebble.sendPebbleSdSettings()");
// Watch Settings
final PebbleDictionary setDict = new PebbleDictionary();
setDict.addInt16(KEY_DEBUG, mDebug);
setDict.addInt16(KEY_DISPLAY_SPECTRUM, mDisplaySpectrum);
setDict.addInt16(KEY_DATA_UPDATE_PERIOD, mDataUpdatePeriod);
setDict.addInt16(KEY_MUTE_PERIOD, mMutePeriod);
setDict.addInt16(KEY_MAN_ALARM_PERIOD, mManAlarmPeriod);
setDict.addInt16(KEY_SD_MODE, mPebbleSdMode);
setDict.addInt16(KEY_SAMPLE_FREQ, mSampleFreq);
setDict.addInt16(KEY_ALARM_FREQ_MIN, mAlarmFreqMin);
setDict.addInt16(KEY_ALARM_FREQ_MAX, mAlarmFreqMax);
setDict.addUint16(KEY_WARN_TIME, mWarnTime);
setDict.addUint16(KEY_ALARM_TIME, mAlarmTime);
setDict.addUint16(KEY_ALARM_THRESH, mAlarmThresh);
setDict.addUint16(KEY_ALARM_RATIO_THRESH, mAlarmRatioThresh);
if (mFallActive)
setDict.addUint16(KEY_FALL_ACTIVE, (short) 1);
else
setDict.addUint16(KEY_FALL_ACTIVE, (short) 0);
setDict.addUint16(KEY_FALL_THRESH_MIN, mFallThreshMin);
setDict.addUint16(KEY_FALL_THRESH_MAX, mFallThreshMax);
setDict.addUint16(KEY_FALL_WINDOW, mFallWindow);
// Send Watch Settings to Pebble
Log.v(TAG, "sendPebbleSdSettings() - setDict = " + setDict.toJsonString());
PebbleKit.sendDataToPebble(mContext, SD_UUID, setDict);
}
/**
* Compares the watch settings retrieved from the watch (stored in mSdData)
* to the required settings stored as member variables to this class.
*
* @return true if they are all the same, or false if there are discrepancies.
*/
public boolean checkWatchSettings() {
boolean settingsOk = true;
if (mDataUpdatePeriod != mSdData.mDataUpdatePeriod) {
Log.v(TAG, "checkWatchSettings - mDataUpdatePeriod Wrong");
settingsOk = false;
}
if (mMutePeriod != mSdData.mMutePeriod) {
Log.v(TAG, "checkWatchSettings - mMutePeriod Wrong");
settingsOk = false;
}
if (mManAlarmPeriod != mSdData.mManAlarmPeriod) {
Log.v(TAG, "checkWatchSettings - mManAlarmPeriod Wrong");
settingsOk = false;
}
if (mAlarmFreqMin != mSdData.alarmFreqMin) {
Log.v(TAG, "checkWatchSettings - mAlarmFreqMin Wrong");
settingsOk = false;
}
if (mAlarmFreqMax != mSdData.alarmFreqMax) {
Log.v(TAG, "checkWatchSettings - mAlarmFreqMax Wrong");
settingsOk = false;
}
if (mWarnTime != mSdData.warnTime) {
Log.v(TAG, "checkWatchSettings - mWarnTime Wrong");
settingsOk = false;
}
if (mAlarmTime != mSdData.alarmTime) {
Log.v(TAG, "checkWatchSettings - mAlarmTime Wrong");
settingsOk = false;
}
if (mAlarmThresh != mSdData.alarmThresh) {
Log.v(TAG, "checkWatchSettings - mAlarmThresh Wrong");
settingsOk = false;
}
if (mAlarmRatioThresh != mSdData.alarmRatioThresh) {
Log.v(TAG, "checkWatchSettings - mAlarmRatioThresh Wrong");
settingsOk = false;
}
if (mFallActive != mSdData.mFallActive) {
Log.v(TAG, "checkWatchSettings - mAlarmFreqMin Wrong");
settingsOk = false;
}
if (mFallThreshMin != mSdData.mFallThreshMin) {
Log.v(TAG, "checkWatchSettings - mFallThreshMin Wrong");
settingsOk = false;
}
if (mFallThreshMax != mSdData.mFallThreshMax) {
Log.v(TAG, "checkWatchSettings - mFallThreshMax Wrong");
settingsOk = false;
}
if (mFallWindow != mSdData.mFallWindow) {
Log.v(TAG, "checkWatchSettings - mFallWindow Wrong");
settingsOk = false;
}
return settingsOk;
}
/** /**
* Request Pebble App to send us its latest data. * Request Pebble App to send us its latest data.
* Will be received as a message by the receiveData handler * Will be received as a message by the receiveData handler
*/ */
public void getPebbleData() { public void getPebbleData() {
Log.v(TAG, "getPebbleData() - requesting data from pebble"); Log.v(TAG, "getPebbleData() - requesting data from pebble");
mUtil.writeToSysLogFile("SdDataSourcePebble.getPebbleData() - requesting data from pebble");
PebbleDictionary data = new PebbleDictionary(); PebbleDictionary data = new PebbleDictionary();
data.addUint8(KEY_DATA_TYPE, (byte) 1); data.addUint8(KEY_DATA_TYPE, (byte) 1);
PebbleKit.sendDataToPebble( PebbleKit.sendDataToPebble(
@@ -458,7 +649,7 @@ public class SdDataSourcePebble extends SdDataSource {
tnow.setToNow(); tnow.setToNow();
// get time since the last data was received from the Pebble watch. // get time since the last data was received from the Pebble watch.
tdiff = (tnow.toMillis(false) - mPebbleStatusTime.toMillis(false)); tdiff = (tnow.toMillis(false) - mPebbleStatusTime.toMillis(false));
Log.v(TAG, "getPebbleStatus() - mPebbleAppRunningCheck="+mPebbleAppRunningCheck+" tdiff="+tdiff); Log.v(TAG, "getPebbleStatus() - mPebbleAppRunningCheck=" + mPebbleAppRunningCheck + " tdiff=" + tdiff);
// Check we are actually connected to the pebble. // Check we are actually connected to the pebble.
mSdData.pebbleConnected = PebbleKit.isWatchConnected(mContext); mSdData.pebbleConnected = PebbleKit.isWatchConnected(mContext);
if (!mSdData.pebbleConnected) mPebbleAppRunningCheck = false; if (!mSdData.pebbleConnected) mPebbleAppRunningCheck = false;
@@ -467,15 +658,20 @@ public class SdDataSourcePebble extends SdDataSource {
// the app is not talking to us // the app is not talking to us
// mPebbleAppRunningCheck is set to true in the receiveData handler. // mPebbleAppRunningCheck is set to true in the receiveData handler.
if (!mPebbleAppRunningCheck && if (!mPebbleAppRunningCheck &&
(tdiff > (mDataPeriod+mAppRestartTimeout) * 1000)) { (tdiff > (mDataUpdatePeriod + mAppRestartTimeout) * 1000)) {
Log.v(TAG, "getPebbleStatus() - tdiff = " + tdiff); Log.v(TAG, "getPebbleStatus() - tdiff = " + tdiff);
mSdData.pebbleAppRunning = false; mSdData.pebbleAppRunning = false;
Log.v(TAG, "getPebbleStatus() - Pebble App Not Running - Attempting to Re-Start"); //Log.v(TAG, "getPebbleStatus() - Pebble App Not Running - Attempting to Re-Start");
startWatchApp(); //mUtil.writeToSysLogFile("SdDataSourcePebble.getPebbleStatus() - Pebble App not Running - Attempting to Re-Start");
//startWatchApp();
//mPebbleStatusTime = tnow; // set status time to now so we do not re-start app repeatedly. //mPebbleStatusTime = tnow; // set status time to now so we do not re-start app repeatedly.
getPebbleSdSettings(); //getPebbleSdSettings();
// Only make audible warning beep if we have not received data for more than mFaultTimerPeriod seconds. // Only make audible warning beep if we have not received data for more than mFaultTimerPeriod seconds.
if (tdiff > (mDataPeriod+mFaultTimerPeriod) * 1000) { if (tdiff > (mDataUpdatePeriod + mFaultTimerPeriod) * 1000) {
Log.v(TAG, "getPebbleStatus() - Pebble App Not Running - Attempting to Re-Start");
mUtil.writeToSysLogFile("SdDataSourcePebble.getPebbleStatus() - Pebble App not Running - Attempting to Re-Start");
startWatchApp();
mPebbleStatusTime.setToNow();
mSdDataReceiver.onSdDataFault(mSdData); mSdDataReceiver.onSdDataFault(mSdData);
} else { } else {
Log.v(TAG, "getPebbleStatus() - Waiting for mFaultTimerPeriod before issuing audible warning..."); Log.v(TAG, "getPebbleStatus() - Waiting for mFaultTimerPeriod before issuing audible warning...");
@@ -496,10 +692,115 @@ public class SdDataSourcePebble extends SdDataSource {
getPebbleSdSettings(); getPebbleSdSettings();
getPebbleData(); getPebbleData();
} }
if (mPebbleSdMode == SD_MODE_RAW) {
analyseRawData();
}
}
/**
* analyseRawData() - called when raw data is received.
* FIXME - this does not do anything at the moment so raw data is
* ignored!
*/
private void analyseRawData() {
Log.v(TAG,"analyserawData()");
//DoubleFFT_1D fft = new DoubleFFT_1D(MAX_RAW_DATA);
//fft.realForward(rawData);
// FIXME - rawData should really be a circular buffer.
nRawData = 0;
}
/**
* Install the wach app that is bundled in the 'assets' folder of this
* phone app.
* from https://github.com/pebble-examples/pebblekit-android-example/blob/master/android/Eclipse/src/com/getpebble/pebblekitexample/MainActivity.java#L148
*/
@Override
public void installWatchApp() {
Log.v(TAG, "SdDataSourcePebble.installWatchApp()");
mUtil.writeToSysLogFile("SdDataSourcePebble.installWatchApp()");
final String WATCHAPP_FILENAME = "pebble_sd.pbw";
try {
// Read .pbw from assets/
Intent intent = new Intent(Intent.ACTION_VIEW);
File file = new File(mContext.getExternalFilesDir(null), WATCHAPP_FILENAME);
InputStream is = mContext.getResources().getAssets().open(WATCHAPP_FILENAME);
OutputStream os = new FileOutputStream(file);
byte[] pbw = new byte[is.available()];
is.read(pbw);
os.write(pbw);
is.close();
os.close();
// Install via Pebble Android app
intent.setDataAndType(Uri.fromFile(file), "application/pbw");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivity(intent);
} catch (IOException e) {
mUtil.writeToSysLogFile("SdDataSourcePebble.installWatchApp() - app install failed"+e.toString());
Toast.makeText(mContext, "App install failed: " + e.getLocalizedMessage(), Toast.LENGTH_LONG).show();
}
}
/**
* Install the OpenSeizureDetector watch app onto the watch from Pebble AppStore
* based on https://forums.getpebble.com/discussion/13128/install-watch-app-pebble-store-from-android-companion-app
*/
public void installWatchAppFromPebbleAppStore() {
Intent myIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("pebble://appstore/54d28a43e4d94c043f000008"));
myIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivity(myIntent);
} }
/**
* Open Pebble or Pebble Time app. If it is not installed, open Play store so the user can install it.
*/
@Override
public void startPebbleApp() {
mUtil.writeToSysLogFile("SdDataSourcePebble.startPebbleApp()");
// first try to launch the original pebble app
Intent pebbleAppIntent;
PackageManager pm = mContext.getPackageManager();
try {
pebbleAppIntent = pm.getLaunchIntentForPackage("com.getpebble.android");
mContext.startActivity(pebbleAppIntent);
} catch (Exception ex1) {
// and if original pebble app fails, try Pebble Time app...
Log.v(TAG, "exception starting original pebble App - trying pebble time..." + ex1.toString());
mUtil.writeToSysLogFile("SdDataSourcePebble.startPebbleApp() - Error starting original pebble app - trying Pebble Time App instead");
try {
pebbleAppIntent = pm.getLaunchIntentForPackage("com.getpebble.android.basalt");
mContext.startActivity(pebbleAppIntent);
} catch (Exception ex2) {
// and if that fails, open play store so the user can install it:
Log.v(TAG, "exception starting Pebble Time App." + ex2.toString());
mUtil.writeToSysLogFile("SdDataSourcePebble.startPebbleApp() - Error starting Pebble Time App - Is it installed?");
this.showToast("Error Launching Pebble or Pebble Time App - Please make sure it is installed...");
final String appPackageName = "com.getpebble.android.basalt";
try {
mUtil.writeToSysLogFile("SdDataSourcePebble.startPebbleApp() - Opening Play Store to install Pebble App");
// try using play store app.
mContext.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=" + appPackageName)));
} catch (android.content.ActivityNotFoundException anfe) {
// and if play store app is not installed, use browser to open app page.
mContext.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://play.google.com/store/apps/details?id=" + appPackageName)));
}
}
}
}
} }
@@ -130,10 +130,9 @@ public class SdServer extends Service implements SdDataReceiver {
*/ */
public SdServer() { public SdServer() {
super(); super();
Log.v(TAG, "SdServer Created");
mSdData = new SdData(); mSdData = new SdData();
mToneGenerator = new ToneGenerator(AudioManager.STREAM_ALARM, 100); mToneGenerator = new ToneGenerator(AudioManager.STREAM_ALARM, 100);
Log.v(TAG, "SdServer Created");
} }
@@ -144,7 +143,7 @@ public class SdServer extends Service implements SdDataReceiver {
} }
/** /**
* used to make suer timers run on UI thread * used to make sure timers run on UI thread
*/ */
private void runOnUiThread(Runnable runnable) { private void runOnUiThread(Runnable runnable) {
mHandler.post(runnable); mHandler.post(runnable);
@@ -157,6 +156,9 @@ public class SdServer extends Service implements SdDataReceiver {
@Override @Override
public void onCreate() { public void onCreate() {
Log.v(TAG, "onCreate()"); Log.v(TAG, "onCreate()");
mHandler = new Handler();
mUtil = new OsdUtil(getApplicationContext(),mHandler);
mUtil.writeToSysLogFile("SdServer.onCreate()");
// Set our custom uncaught exception handler to report issues. // Set our custom uncaught exception handler to report issues.
Thread.setDefaultUncaughtExceptionHandler( Thread.setDefaultUncaughtExceptionHandler(
@@ -164,9 +166,6 @@ public class SdServer extends Service implements SdDataReceiver {
//int i = 5/0; // Force exception to test handler. //int i = 5/0; // Force exception to test handler.
mHandler = new Handler();
mUtil = new OsdUtil(getApplicationContext());
// Create a wake lock, but don't use it until the service is started. // Create a wake lock, but don't use it until the service is started.
PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE); PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
@@ -181,6 +180,7 @@ public class SdServer extends Service implements SdDataReceiver {
@Override @Override
public int onStartCommand(Intent intent, int flags, int startId) { public int onStartCommand(Intent intent, int flags, int startId) {
Log.v(TAG, "onStartCommand() - SdServer service starting"); Log.v(TAG, "onStartCommand() - SdServer service starting");
mUtil.writeToSysLogFile("SdServer.onStartCommand()");
// Update preferences. // Update preferences.
Log.v(TAG, "onStartCommand() - calling updatePrefs()"); Log.v(TAG, "onStartCommand() - calling updatePrefs()");
@@ -190,23 +190,28 @@ public class SdServer extends Service implements SdDataReceiver {
switch (mSdDataSourceName) { switch (mSdDataSourceName) {
case "Pebble": case "Pebble":
Log.v(TAG, "Selecting Pebble DataSource"); Log.v(TAG, "Selecting Pebble DataSource");
mSdDataSource = new SdDataSourcePebble(this.getApplicationContext(), this); mUtil.writeToSysLogFile("SdServer.onStartCommand() - creating SdDataSourcePebble");
mSdDataSource = new SdDataSourcePebble(this.getApplicationContext(), mHandler, this);
break; break;
case "Network": case "Network":
Log.v(TAG, "Selecting Network DataSource"); Log.v(TAG, "Selecting Network DataSource");
mSdDataSource = new SdDataSourceNetwork(this.getApplicationContext(), this); mUtil.writeToSysLogFile("SdServer.onStartCommand() - creating SdDataSourceNetwork");
mSdDataSource = new SdDataSourceNetwork(this.getApplicationContext(), mHandler, this);
break; break;
default: default:
Log.v(TAG, "Datasource " + mSdDataSourceName + " not recognised - Exiting"); Log.v(TAG, "Datasource " + mSdDataSourceName + " not recognised - Exiting");
mUtil.writeToSysLogFile("SdServer.onStartCommand() - Datasource "+mSdDataSourceName+" not recognised - exiting");
mUtil.showToast("Datasource " + mSdDataSourceName + " not recognised - Exiting"); mUtil.showToast("Datasource " + mSdDataSourceName + " not recognised - Exiting");
return 1; return 1;
} }
mUtil.writeToSysLogFile("SdServer.onStartCommand() - starting SdDataSource");
mSdDataSource.start(); mSdDataSource.start();
// Display a notification icon in the status bar of the phone to // Display a notification icon in the status bar of the phone to
// show the service is running. // show the service is running.
Log.v(TAG, "showing Notification"); Log.v(TAG, "showing Notification");
mUtil.writeToSysLogFile("SdServer.onStartCommand() - showing Notification");
showNotification(0); showNotification(0);
// Record last time we sent an SMS so we can limit rate of SMS // Record last time we sent an SMS so we can limit rate of SMS
@@ -216,7 +221,8 @@ public class SdServer extends Service implements SdDataReceiver {
// Start timer to log data regularly.. // Start timer to log data regularly..
if (dataLogTimer == null) { if (dataLogTimer == null) {
Log.v(TAG, "onCreate(): starting dataLog timer"); Log.v(TAG, "onStartCommand(): starting dataLog timer");
mUtil.writeToSysLogFile("SdServer.onStartCommand() - starting dataLog timer");
dataLogTimer = new Timer(); dataLogTimer = new Timer();
dataLogTimer.schedule(new TimerTask() { dataLogTimer.schedule(new TimerTask() {
@Override @Override
@@ -225,19 +231,23 @@ public class SdServer extends Service implements SdDataReceiver {
} }
}, 0, 1000 * 60); }, 0, 1000 * 60);
} else { } else {
Log.v(TAG, "onCreate(): dataLog timer already running."); Log.v(TAG, "onStartCommand(): dataLog timer already running.");
mUtil.writeToSysLogFile("SdServer.onStartCommand() - dataLog timer already running???");
} }
// Start the web server // Start the web server
mUtil.writeToSysLogFile("SdServer.onStartCommand() - starting web server");
startWebServer(); startWebServer();
// Apply the wake-lock to prevent CPU sleeping (very battery intensive!) // Apply the wake-lock to prevent CPU sleeping (very battery intensive!)
if (mWakeLock != null) { if (mWakeLock != null) {
mWakeLock.acquire(); mWakeLock.acquire();
Log.v(TAG, "Applied Wake Lock to prevent device sleeping"); Log.v(TAG, "Applied Wake Lock to prevent device sleeping");
mUtil.writeToSysLogFile("SdServer.onStartCommand() - applying wake lock");
} else { } else {
Log.d(TAG, "mmm...mWakeLock is null, so not aquiring lock. This shouldn't happen!"); Log.d(TAG, "mmm...mWakeLock is null, so not aquiring lock. This shouldn't happen!");
mUtil.writeToSysLogFile("SdServer.onStartCommand() - mWakeLock is not null - this shouldn't happen???");
} }
return START_STICKY; return START_STICKY;
@@ -246,6 +256,7 @@ public class SdServer extends Service implements SdDataReceiver {
@Override @Override
public void onDestroy() { public void onDestroy() {
Log.v(TAG, "onDestroy(): SdServer Service stopping"); Log.v(TAG, "onDestroy(): SdServer Service stopping");
mUtil.writeToSysLogFile("SdServer.onDestroy() - releasing wakelock");
// release the wake lock to allow CPU to sleep and reduce // release the wake lock to allow CPU to sleep and reduce
// battery drain. // battery drain.
if (mWakeLock != null) { if (mWakeLock != null) {
@@ -254,22 +265,26 @@ public class SdServer extends Service implements SdDataReceiver {
Log.v(TAG, "Released Wake Lock to allow device to sleep."); Log.v(TAG, "Released Wake Lock to allow device to sleep.");
} catch (Exception e) { } catch (Exception e) {
Log.e(TAG, "Error Releasing Wakelock - " + e.toString()); Log.e(TAG, "Error Releasing Wakelock - " + e.toString());
mUtil.writeToSysLogFile("SdServer.onDestroy() - Error releasing wakelock.");
mUtil.showToast("Error Releasing Wakelock"); mUtil.showToast("Error Releasing Wakelock");
} }
} else { } else {
Log.d(TAG, "mmm...mWakeLock is null, so not releasing lock. This shouldn't happen!"); Log.d(TAG, "mmm...mWakeLock is null, so not releasing lock. This shouldn't happen!");
mUtil.writeToSysLogFile("SdServer.onDestroy() - mWakeLock is null so not releasing lock - this Shouldn't happen???");
} }
if (mSdDataSource != null) { if (mSdDataSource != null) {
Log.v(TAG, "stopping mSdDataSource"); Log.v(TAG, "stopping mSdDataSource");
mUtil.writeToSysLogFile("SdServer.onDestroy() - stopping mSdDataSource");
mSdDataSource.stop(); mSdDataSource.stop();
} else { } else {
Log.e(TAG, "ERROR - mSdDataSource is null - why????"); Log.e(TAG, "ERROR - mSdDataSource is null - why????");
mUtil.writeToSysLogFile("SdServer.onDestroy() - mSdDataSource is null - why???");
} }
// Stop the data update timer // Stop the Cancel Audible timer
if (mCancelAudibleTimer != null) { if (mCancelAudibleTimer != null) {
Log.v(TAG, "stop(): cancelling Cancel_Audible timer"); Log.v(TAG, "onDestroy(): cancelling Cancel_Audible timer");
mCancelAudibleTimer.cancel(); mCancelAudibleTimer.cancel();
//mCancelAudibleTimer.purge(); //mCancelAudibleTimer.purge();
mCancelAudibleTimer = null; mCancelAudibleTimer = null;
@@ -279,18 +294,23 @@ public class SdServer extends Service implements SdDataReceiver {
try { try {
// Cancel the notification. // Cancel the notification.
Log.v(TAG, "onDestroy(): cancelling notification"); Log.v(TAG, "onDestroy(): cancelling notification");
mUtil.writeToSysLogFile("SdServer.onDestroy - cancelling notification");
mNM.cancel(NOTIFICATION_ID); mNM.cancel(NOTIFICATION_ID);
// Stop web server // Stop web server
Log.v(TAG, "onDestroy(): stopping web server"); Log.v(TAG, "onDestroy(): stopping web server");
mUtil.writeToSysLogFile("SdServer.onDestroy() - stopping Web Server");
stopWebServer(); stopWebServer();
// stop this service. // stop this service.
Log.v(TAG, "onDestroy(): calling stopSelf()"); Log.v(TAG, "onDestroy(): calling stopSelf()");
mUtil.writeToSysLogFile("SdServer.onDestroy() - stopping self");
stopSelf(); stopSelf();
} catch (Exception e) { } catch (Exception e) {
Log.v(TAG, "Error in onDestroy() - " + e.toString()); Log.v(TAG, "Error in onDestroy() - " + e.toString());
mUtil.writeToSysLogFile("SdServer.onDestroy() -error "+e.toString());
} }
mUtil.writeToSysLogFile("SdServer.onDestroy() - releasing mToneGenerator");
mToneGenerator.release(); mToneGenerator.release();
mToneGenerator = null; mToneGenerator = null;
} }
@@ -336,6 +356,7 @@ public class SdServer extends Service implements SdDataReceiver {
// Show the main activity on the user's screen. // Show the main activity on the user's screen.
private void showMainActivity() { private void showMainActivity() {
Log.v(TAG, "showMainActivity()"); Log.v(TAG, "showMainActivity()");
mUtil.writeToSysLogFile("SdServer.showMainActivity()");
ActivityManager manager = (ActivityManager) getSystemService(ACTIVITY_SERVICE); ActivityManager manager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
List<ActivityManager.RunningTaskInfo> runningTaskInfo = manager.getRunningTasks(1); List<ActivityManager.RunningTaskInfo> runningTaskInfo = manager.getRunningTasks(1);
@@ -343,6 +364,7 @@ public class SdServer extends Service implements SdDataReceiver {
if (componentInfo.getPackageName().equals("uk.org.openseizuredetector")) { if (componentInfo.getPackageName().equals("uk.org.openseizuredetector")) {
Log.v(TAG,"showMainActivity(): OpenSeizureDetector Activity is already shown on top - not doing anything"); Log.v(TAG,"showMainActivity(): OpenSeizureDetector Activity is already shown on top - not doing anything");
mUtil.writeToSysLogFile("SdServer.showMainActivity - Activity is already shown on top, not doing anything");
} else { } else {
Log.v(TAG,"showMainActivity(): Showing Main Activity"); Log.v(TAG,"showMainActivity(): Showing Main Activity");
Intent i = new Intent(getApplicationContext(), MainActivity.class); Intent i = new Intent(getApplicationContext(), MainActivity.class);
@@ -485,6 +507,7 @@ public class SdServer extends Service implements SdDataReceiver {
} else { } else {
mUtil.showToast("Warming mToneGenerator is null - not beeping!!!"); mUtil.showToast("Warming mToneGenerator is null - not beeping!!!");
Log.v(TAG, "beep() - Warming mToneGenerator is null - not beeping!!!"); Log.v(TAG, "beep() - Warming mToneGenerator is null - not beeping!!!");
mUtil.writeToSysLogFile("SdServer.beep() - mToneGenerator is null???");
} }
} }
@@ -499,6 +522,7 @@ public class SdServer extends Service implements SdDataReceiver {
if (mAudibleFaultWarning) { if (mAudibleFaultWarning) {
beep(10); beep(10);
Log.v(TAG, "faultWarningBeep()"); Log.v(TAG, "faultWarningBeep()");
mUtil.writeToSysLogFile("SdServer.faultWarningBeep() - beeping");
} else { } else {
Log.v(TAG, "faultWarningBeep() - silent..."); Log.v(TAG, "faultWarningBeep() - silent...");
} }
@@ -521,6 +545,7 @@ public class SdServer extends Service implements SdDataReceiver {
if (mAudibleAlarm) { if (mAudibleAlarm) {
beep(3000); beep(3000);
Log.v(TAG, "alarmBeep()"); Log.v(TAG, "alarmBeep()");
mUtil.writeToSysLogFile("SdServer.alarmBeep() - beeping");
} else { } else {
Log.v(TAG, "alarmBeep() - silent..."); Log.v(TAG, "alarmBeep() - silent...");
} }
@@ -537,6 +562,7 @@ public class SdServer extends Service implements SdDataReceiver {
if (mAudibleWarning) { if (mAudibleWarning) {
beep(100); beep(100);
Log.v(TAG, "warningBeep()"); Log.v(TAG, "warningBeep()");
mUtil.writeToSysLogFile("SdServer.warningBeep() - beeping");
} else { } else {
Log.v(TAG, "warningBeep() - silent..."); Log.v(TAG, "warningBeep() - silent...");
} }
@@ -550,6 +576,7 @@ public class SdServer extends Service implements SdDataReceiver {
public void sendSMSAlarm() { public void sendSMSAlarm() {
if (mSMSAlarm) { if (mSMSAlarm) {
Log.v(TAG, "sendSMSAlarm() - Sending to " + mSMSNumbers.length + " Numbers"); Log.v(TAG, "sendSMSAlarm() - Sending to " + mSMSNumbers.length + " Numbers");
mUtil.writeToSysLogFile("SdServer.sendSMSAlarm()");
Time tnow = new Time(Time.getCurrentTimezone()); Time tnow = new Time(Time.getCurrentTimezone());
tnow.setToNow(); tnow.setToNow();
String dateStr = tnow.format("%Y-%m-%d %H-%M-%S"); String dateStr = tnow.format("%Y-%m-%d %H-%M-%S");
@@ -614,8 +641,9 @@ public class SdServer extends Service implements SdDataReceiver {
*/ */
protected void startWebServer() { protected void startWebServer() {
Log.v(TAG, "startWebServer()"); Log.v(TAG, "startWebServer()");
mUtil.writeToSysLogFile("SdServer.Start Web Server.");
if (webServer == null) { if (webServer == null) {
webServer = new SdWebServer(getApplicationContext(), getDataStorageDir(), mSdData); webServer = new SdWebServer(getApplicationContext(), mUtil.getDataStorageDir(), mSdData);
try { try {
webServer.start(); webServer.start();
} catch (IOException ioe) { } catch (IOException ioe) {
@@ -631,7 +659,7 @@ public class SdServer extends Service implements SdDataReceiver {
* Stop the web server - FIXME - doesn't seem to do anything! * Stop the web server - FIXME - doesn't seem to do anything!
*/ */
protected void stopWebServer() { protected void stopWebServer() {
Log.v(TAG, "stopWebServer()"); Log.v(TAG, "SdServer.stopWebServer()");
if (webServer != null) { if (webServer != null) {
webServer.stop(); webServer.stop();
if (webServer.isAlive()) { if (webServer.isAlive()) {
@@ -660,6 +688,8 @@ public class SdServer extends Service implements SdDataReceiver {
*/ */
public void updatePrefs() { public void updatePrefs() {
Log.v(TAG, "updatePrefs()"); Log.v(TAG, "updatePrefs()");
mUtil.writeToSysLogFile("SdServer.updatePrefs()");
SharedPreferences SP = PreferenceManager SharedPreferences SP = PreferenceManager
.getDefaultSharedPreferences(getBaseContext()); .getDefaultSharedPreferences(getBaseContext());
try { try {
@@ -698,31 +728,13 @@ public class SdServer extends Service implements SdDataReceiver {
} catch (Exception ex) { } catch (Exception ex) {
Log.v(TAG, "updatePrefs() - Problem parsing preferences!"); Log.v(TAG, "updatePrefs() - Problem parsing preferences!");
mUtil.writeToSysLogFile("SdServer.updatePrefs() - Error "+ex.toString());
Toast toast = Toast.makeText(getApplicationContext(), "Problem Parsing Preferences - Something won't work - Please go back to Settings and correct it!", Toast.LENGTH_SHORT); Toast toast = Toast.makeText(getApplicationContext(), "Problem Parsing Preferences - Something won't work - Please go back to Settings and correct it!", Toast.LENGTH_SHORT);
toast.show(); toast.show();
} }
} }
/* Checks if external storage is available for read and write */
public boolean isExternalStorageWritable() {
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)) {
return true;
}
return false;
}
public File getDataStorageDir() {
// Get the directory for the user's public pictures directory.
File file =
new File(Environment.getExternalStorageDirectory()
, "OpenSeizureDetector");
if (!file.mkdirs()) {
Log.e(TAG, "Directory not created");
}
return file;
}
/** /**
* Write data to SD card alarm log * Write data to SD card alarm log
@@ -757,9 +769,9 @@ public class SdServer extends Service implements SdDataReceiver {
fname = fname + "_" + dateStr + ".txt"; fname = fname + "_" + dateStr + ".txt";
// Open output directory on SD Card. // Open output directory on SD Card.
if (isExternalStorageWritable()) { if (mUtil.isExternalStorageWritable()) {
try { try {
FileWriter of = new FileWriter(getDataStorageDir().toString() FileWriter of = new FileWriter(mUtil.getDataStorageDir().toString()
+ "/" + fname, true); + "/" + fname, true);
if (mSdData != null) { if (mSdData != null) {
Log.v(TAG, "writing mSdData.toString()"); Log.v(TAG, "writing mSdData.toString()");
@@ -112,6 +112,7 @@ public class SdWebServer extends NanoHTTPD {
default: default:
if (uri.startsWith("/index.html") || if (uri.startsWith("/index.html") ||
uri.startsWith("/logfiles.html") ||
uri.startsWith("/favicon.ico") || uri.startsWith("/favicon.ico") ||
uri.startsWith("/js/") || uri.startsWith("/js/") ||
uri.startsWith("/css/") || uri.startsWith("/css/") ||
@@ -35,6 +35,7 @@ import android.os.Handler;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.util.Log; import android.util.Log;
import android.view.View; import android.view.View;
import android.view.WindowManager;
import android.widget.Button; import android.widget.Button;
import android.widget.ProgressBar; import android.widget.ProgressBar;
import android.widget.TextView; import android.widget.TextView;
@@ -61,7 +62,7 @@ public class StartupActivity extends Activity {
private Timer mUiTimer; private Timer mUiTimer;
private SdServiceConnection mConnection; private SdServiceConnection mConnection;
private boolean mStartedMainActivity = false; private boolean mStartedMainActivity = false;
final Handler mServerStatusHandler = new Handler(); // used to update ui from mUiTimer private Handler mHandler = new Handler(); // used to update ui from mUiTimer
@Override @Override
@@ -70,10 +71,26 @@ public class StartupActivity extends Activity {
// Set our custom uncaught exception handler to report issues. // Set our custom uncaught exception handler to report issues.
Thread.setDefaultUncaughtExceptionHandler(new OsdUncaughtExceptionHandler(StartupActivity.this)); Thread.setDefaultUncaughtExceptionHandler(new OsdUncaughtExceptionHandler(StartupActivity.this));
//int i = 5/0; // Force exception to test handler.
mHandler = new Handler();
mUtil = new OsdUtil(this,mHandler);
mUtil.writeToSysLogFile("");
mUtil.writeToSysLogFile("*******************************");
mUtil.writeToSysLogFile("* StartUpActivity Started *");
mUtil.writeToSysLogFile("*******************************");
// Force the screen to stay on when the app is running
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
setContentView(R.layout.startup_activity); setContentView(R.layout.startup_activity);
mUtil = new OsdUtil(this);
// Read the default settings from the xml preferences files, so we do
// not have to use the hard coded ones in the java files.
PreferenceManager.setDefaultValues(this, R.xml.alarm_prefs, true);
PreferenceManager.setDefaultValues(this, R.xml.camera_prefs, true);
PreferenceManager.setDefaultValues(this, R.xml.general_prefs, true);
PreferenceManager.setDefaultValues(this, R.xml.network_datasource_prefs, true);
Button b = (Button)findViewById(R.id.settingsButton); Button b = (Button)findViewById(R.id.settingsButton);
b.setOnClickListener(new View.OnClickListener() { b.setOnClickListener(new View.OnClickListener() {
@@ -81,12 +98,14 @@ public class StartupActivity extends Activity {
public void onClick(View view) { public void onClick(View view) {
Log.v(TAG, "settings button clicked"); Log.v(TAG, "settings button clicked");
try { try {
mUtil.writeToSysLogFile("Starting Settings Activity");
Intent intent = new Intent( Intent intent = new Intent(
StartupActivity.this, StartupActivity.this,
PrefActivity.class); PrefActivity.class);
startActivity(intent); startActivity(intent);
} catch (Exception ex) { } catch (Exception ex) {
Log.v(TAG, "exception starting settings activity " + ex.toString()); Log.v(TAG, "exception starting settings activity " + ex.toString());
mUtil.writeToSysLogFile("ERROR Starting Settings Activity");
} }
} }
@@ -97,7 +116,8 @@ public class StartupActivity extends Activity {
@Override @Override
public void onClick(View view) { public void onClick(View view) {
Log.v(TAG, "pebble button clicked"); Log.v(TAG, "pebble button clicked");
mUtil.startPebbleApp(); mUtil.writeToSysLogFile("Starting Pebble Phone App");
mConnection.mSdServer.mSdDataSource.startPebbleApp();
} }
}); });
@@ -106,7 +126,8 @@ public class StartupActivity extends Activity {
@Override @Override
public void onClick(View view) { public void onClick(View view) {
Log.v(TAG, "install Osd Watch App button clicked"); Log.v(TAG, "install Osd Watch App button clicked");
mUtil.installOsdWatchApp(); mUtil.writeToSysLogFile("Installing Watch App");
mConnection.mSdServer.mSdDataSource.installWatchApp();
} }
}); });
@@ -115,6 +136,8 @@ public class StartupActivity extends Activity {
@Override @Override
protected void onStart() { protected void onStart() {
super.onStart(); super.onStart();
mUtil.writeToSysLogFile("StartupActivity.onStart()");
// Display the DataSource name // Display the DataSource name
SharedPreferences SP = PreferenceManager SharedPreferences SP = PreferenceManager
@@ -134,11 +157,14 @@ public class StartupActivity extends Activity {
if (mUtil.isServerRunning()) { if (mUtil.isServerRunning()) {
Log.v(TAG, "onStart() - server running - stopping it"); Log.v(TAG, "onStart() - server running - stopping it");
mUtil.writeToSysLogFile("StartupActivity.onStart() - server already running - stopping it.");
mUtil.stopServer(); mUtil.stopServer();
} }
mUtil.writeToSysLogFile("StartupActivity.onStart() - starting server");
mUtil.startServer(); mUtil.startServer();
// Bind to the service. // Bind to the service.
mUtil.writeToSysLogFile("StartupActivity.onStart() - binding to server");
mConnection = new SdServiceConnection(this); mConnection = new SdServiceConnection(this);
mUtil.bindToServer(this, mConnection); mUtil.bindToServer(this, mConnection);
@@ -147,7 +173,7 @@ public class StartupActivity extends Activity {
mUiTimer.schedule(new TimerTask() { mUiTimer.schedule(new TimerTask() {
@Override @Override
public void run() { public void run() {
mServerStatusHandler.post(serverStatusRunnable); mHandler.post(serverStatusRunnable);
//updateServerStatus(); //updateServerStatus();
} }
}, 0, 1000); }, 0, 1000);
@@ -156,8 +182,9 @@ public class StartupActivity extends Activity {
@Override @Override
protected void onStop() { protected void onStop() {
Log.v(TAG, "onStop()");
super.onStop(); super.onStop();
Log.v(TAG, "onStop()");
mUtil.writeToSysLogFile("StartupActivity.onStop() - unbinding from server");
mUtil.unbindFromServer(this, mConnection); mUtil.unbindFromServer(this, mConnection);
mUiTimer.cancel(); mUiTimer.cancel();
} }
@@ -285,6 +312,7 @@ public class StartupActivity extends Activity {
if (allOk) { if (allOk) {
if (!mStartedMainActivity) { if (!mStartedMainActivity) {
Log.v(TAG, "starting main activity..."); Log.v(TAG, "starting main activity...");
mUtil.writeToSysLogFile("StartupActivity.serverStatusRunnable - all checks ok - starting main activity.");
try { try {
Intent intent = new Intent( Intent intent = new Intent(
getApplicationContext(), getApplicationContext(),
@@ -296,9 +324,11 @@ public class StartupActivity extends Activity {
} catch (Exception ex) { } catch (Exception ex) {
mStartedMainActivity = false; mStartedMainActivity = false;
Log.v(TAG, "exception starting main activity " + ex.toString()); Log.v(TAG, "exception starting main activity " + ex.toString());
mUtil.writeToSysLogFile("StartupActivity.serverStatusRunnable - exception starting main activity "+ex.toString());
} }
} else { } else {
Log.v(TAG,"allOk, but already started MainActivity so not doing anything"); Log.v(TAG,"allOk, but already started MainActivity so not doing anything");
mUtil.writeToSysLogFile("StartupActivity.serverStatusRunnable - allOk, but already started MainActivity so not doing anything");
} }
} }
} }
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="uk.org.openseizuredetector.LogManager">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="Large Text"
android:id="@+id/textView2"
/>
<ListView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/eventLogListView"
android:layout_marginTop="97dp" />
</LinearLayout>
@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="date"
android:id="@+id/event_date" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="alarm"
android:id="@+id/event_alarmState"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="note"
android:id="@+id/event_note"
/>
</LinearLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="dataJSON"
android:id="@+id/event_dataJSON" />
</LinearLayout>
+1 -1
View File
@@ -131,7 +131,7 @@
android:text="Cancel Audible (temporarily)" /> android:text="Cancel Audible (temporarily)" />
</LinearLayout> </LinearLayout>
<com.github.mikephil.charting.charts.LineChart <com.github.mikephil.charting.charts.BarChart
android:id="@+id/chart1" android:id="@+id/chart1"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" /> android:layout_height="match_parent" />
@@ -5,12 +5,6 @@
android:title="Accept Alarm" /> android:title="Accept Alarm" />
<item
android:id="@+id/action_launch_pebble_app"
android:icon="@drawable/stop_server"
android:showAsAction="never|withText"
android:title="Launch Pebble App" />
<item <item
android:id="@+id/action_start_stop" android:id="@+id/action_start_stop"
android:icon="@drawable/stop_server" android:icon="@drawable/stop_server"
@@ -24,6 +18,16 @@
android:showAsAction="never|withText" android:showAsAction="never|withText"
android:title="Test Fault Beep" /> android:title="Test Fault Beep" />
--> -->
<item
android:id="@+id/action_launch_pebble_app"
android:showAsAction="never|withText"
android:title="Launch Pebble App" />
<item
android:id="@+id/action_instal_watch_app"
android:showAsAction="never|withText"
android:title="Install Watch App" />
<item <item
android:id="@+id/action_test_alarm_beep" android:id="@+id/action_test_alarm_beep"
android:icon="@drawable/stop_server" android:icon="@drawable/stop_server"
@@ -43,11 +47,20 @@
android:title="Test SMS Alarm Notification" /> android:title="Test SMS Alarm Notification" />
<item
android:id="@+id/action_logs"
android:icon="@drawable/ic_action_settings"
android:showAsAction="never|withText"
android:title="View Log Entries"
android:enabled="true"
/>
<item <item
android:id="@+id/action_settings" android:id="@+id/action_settings"
android:icon="@drawable/ic_action_settings" android:icon="@drawable/ic_action_settings"
android:showAsAction="never|withText" android:showAsAction="never|withText"
android:title="Settings" /> android:title="Settings"
/>
<item <item
android:id="@+id/action_about" android:id="@+id/action_about"
@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Arrays used to produce list selections in pebble_datasource_prefs.xml -->
<resources>
<string-array name="pebble_debug_list">
<item>"Debug OFF"</item>
<item>"Debug ON"</item>
</string-array>
<string-array name="pebble_debug_values">
<item>"0"</item>
<item>"1"</item>
</string-array>
<string-array name="pebble_display_spectrum_list">
<item>"Spectrum Display OFF"</item>
<item>"Spectrum Display ON"</item>
</string-array>
<string-array name="pebble_display_spectrum_values">
<item>"0"</item>
<item>"1"</item>
</string-array>
<string-array name="pebble_sd_mode_list">
<item>"Normal - OpenSeizureDetector FFT"</item>
<item>"Raw"</item>
<item>"Digital Filter"</item>
</string-array>
<string-array name="pebble_sd_mode_list_values">
<item>"0"</item>
<item>"1"</item>
<item>"2"</item>
</string-array>
<string-array name="pebble_sample_freq_list">
<item>"100 Hz"</item>
<item>"50 Hz"</item>
<item>"25 Hz"</item>
<item>"10 Hz"</item>
</string-array>
<string-array name="pebble_sample_freq_list_values">
<item>"100"</item>
<item>"50"</item>
<item>"25"</item>
<item>"10"</item>
</string-array>
</resources>
+1
View File
@@ -6,6 +6,7 @@
android:summary="Select whether to use a Pebble Watch or network connection as the seizure detector data source." android:summary="Select whether to use a Pebble Watch or network connection as the seizure detector data source."
android:entries="@array/datasource_list" android:entries="@array/datasource_list"
android:entryValues="@array/datasource_list_values" android:entryValues="@array/datasource_list_values"
android:defaultValue="Pebble"
android:dialogTitle="Select Data Source" /> android:dialogTitle="Select Data Source" />
<CheckBoxPreference <CheckBoxPreference
android:defaultValue="true" android:defaultValue="true"
@@ -1,11 +1,12 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- The ListPreference data is defined in pebble_datasource_values.xml -->
<PreferenceScreen <PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"> xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceCategory android:title="User Interface Settings"> <PreferenceCategory android:title="User Interface Settings">
<EditTextPreference <EditTextPreference
android:defaultValue="5" android:defaultValue="5"
android:key="DataUpdatePeriod" android:key="PebbleUpdatePeriod"
android:summary="Time period at which data is sent to the phone." android:summary="Time period at which data is sent to the phone (increase value to reduce battery consumption)"
android:title="Data Period (sec)" /> android:title="Data Period (sec)" />
<EditTextPreference <EditTextPreference
android:defaultValue="300" android:defaultValue="300"
@@ -19,10 +20,37 @@
android:title="Manual Alarm Period (sec)" /> android:title="Manual Alarm Period (sec)" />
</PreferenceCategory> </PreferenceCategory>
<PreferenceCategory android:title="Seizure Detector Settings"> <PreferenceCategory android:title="Seizure Detector Settings">
<ListPreference
android:key="PebbleDisplaySpectrum"
android:title="Spectrum display Mode"
android:summary="Set Display Spectrum mode on or off."
android:entries="@array/pebble_display_spectrum_list"
android:entryValues="@array/pebble_display_spectrum_values"
android:defaultValue="0"
android:dialogTitle="Select Display Spectrum Mode" />
<ListPreference
android:key="PebbleSdMode"
android:title="Seizure Detector Mode"
android:summary="Select one of the three available modes of operation."
android:entries="@array/pebble_sd_mode_list"
android:entryValues="@array/pebble_sd_mode_list_values"
android:defaultValue="0"
android:dialogTitle="Select Seizure Detector Mode" />
<ListPreference
android:key="SampleFreq"
android:title="Select Sample Frequency"
android:summary="Higher Frequency is more Accurate, but uses more battery power."
android:entries="@array/pebble_sample_freq_list"
android:entryValues="@array/pebble_sample_freq_list_values"
android:defaultValue="100"
android:dialogTitle="Select Sample Frequency"
android:enabled="false"
/>
<EditTextPreference <EditTextPreference
android:defaultValue="5" android:defaultValue="3"
android:key="AlarmFreqMin" android:key="AlarmFreqMin"
android:summary="Minimum Frequency of ROI (Hz) (Default = 5 Hz)" android:summary="Minimum Frequency of ROI (Hz) (Default = 3 Hz)"
android:title="AlarmFreqMin (Hz)" /> android:title="AlarmFreqMin (Hz)" />
<EditTextPreference <EditTextPreference
android:defaultValue="10" android:defaultValue="10"
@@ -47,7 +75,7 @@
<EditTextPreference <EditTextPreference
android:defaultValue="30" android:defaultValue="30"
android:key="AlarmRatioThresh" android:key="AlarmRatioThresh"
android:summary="Alarm Ratio Threshold (Default = 30)" android:summary="Alarm Ratio Threshold (Default = 30). Increase this value to reduce sensitivity if false alarms are a problem."
android:title="AlarmRatioThresh" /> android:title="AlarmRatioThresh" />
</PreferenceCategory> </PreferenceCategory>
@@ -76,6 +104,14 @@
<PreferenceCategory <PreferenceCategory
android:title="Watch Communications Settings"> android:title="Watch Communications Settings">
<ListPreference
android:key="PebbleDebug"
android:title="Seizure Detector Debug Mode"
android:summary="Set Debug mode on or off."
android:entries="@array/pebble_debug_list"
android:entryValues="@array/pebble_debug_values"
android:defaultValue="0"
android:dialogTitle="Select Debug Mode" />
<EditTextPreference <EditTextPreference
android:defaultValue="10" android:defaultValue="10"
android:key="AppRestartTimeout" android:key="AppRestartTimeout"
@@ -0,0 +1,46 @@
package uk.org.openseizuredetector;
import android.content.Context;
import android.util.EventLog;
import android.util.Log;
import junit.framework.TestCase;
import android.test.mock.MockContext;
import org.junit.Test;
import org.mockito.internal.exceptions.ExceptionIncludingMockitoWarnings;
import uk.org.openseizuredetector.EventLogManager.EventLogManager;
import uk.org.openseizuredetector.EventLogManager.LogEntryModel;
/**
* Created by graham on 12/05/16.
*/
public class EventLogManagerTest extends TestCase {
private final static String TAG = "EventLogManagerTest";
Context mContext;
protected void setUp() throws Exception {
super.setUp();
Log.v(TAG,"setUp()");
mContext = new MockContext();
}
@Test
public void testOpenDb() throws Exception {
Log.v(TAG,"testOpenDb()");
EventLogManager em = new EventLogManager(mContext);
assertNotNull(em);
LogEntryModel lem = new LogEntryModel();
//lem.setDate(new Date());
lem.setNote("Test Entry");
lem.setDataJSON("[]");
lem.setAlarmState(1);
em.addRow(lem);
}
}
@@ -1,6 +1,7 @@
package uk.org.openseizuredetector; package uk.org.openseizuredetector;
import android.app.Activity; import android.app.Activity;
import android.os.Handler;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@@ -24,7 +25,8 @@ public class OsdUtilTest {
@Test @Test
public void testStartServer() throws Exception { public void testStartServer() throws Exception {
//Activity a = new Activity(); //Activity a = new Activity();
OsdUtil util = new OsdUtil(null); Handler handler = new Handler();
OsdUtil util = new OsdUtil(null,handler);
assertThat(util.isServerRunning(), is(true)); assertThat(util.isServerRunning(), is(true));
assertThat(true, is (true)); assertThat(true, is (true));
//assertThat(true, is(false)); //assertThat(true, is(false));