Started v2.0 of android app - re-factored so the service uses a datasource to populate the SdData class - so that we can make different data sources in the future.

This commit is contained in:
Graham Jones
2015-11-16 23:03:20 +00:00
parent c4712c19e8
commit f5e5c7e093
9 changed files with 1046 additions and 887 deletions

5
.gitignore vendored Normal file
View File

@@ -0,0 +1,5 @@
build
.gradle
.idea
app/build

View File

@@ -13,7 +13,7 @@
<content url="file://$MODULE_DIR$"> <content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.gradle" /> <excludeFolder url="file://$MODULE_DIR$/.gradle" />
</content> </content>
<orderEntry type="jdk" jdkName="1.8" jdkType="JavaSDK" /> <orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="sourceFolder" forTests="false" />
</component> </component>
</module> </module>

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<module external.linked.project.id=":app" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/.." external.system.id="GRADLE" external.system.module.group="Android_Pebble_SD_AS" external.system.module.version="unspecified" type="JAVA_MODULE" version="4"> <module external.linked.project.id=":app" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/.." external.system.id="GRADLE" external.system.module.group="Android_Pebble_SD" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
<component name="FacetManager"> <component name="FacetManager">
<facet type="android-gradle" name="Android-Gradle"> <facet type="android-gradle" name="Android-Gradle">
<configuration> <configuration>

View File

@@ -1,8 +1,8 @@
<?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="16" android:versionCode="17"
android:versionName="1.12"> android:versionName="2.0a">
<uses-sdk android:minSdkVersion="11" /> <uses-sdk android:minSdkVersion="11" />
<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" />

View File

@@ -25,9 +25,7 @@
package uk.org.openseizuredetector; package uk.org.openseizuredetector;
import android.app.ActionBar;
import android.app.Activity; import android.app.Activity;
import android.app.IntentService;
import android.app.ActivityManager; import android.app.ActivityManager;
import android.app.ActivityManager.RunningServiceInfo; import android.app.ActivityManager.RunningServiceInfo;
import android.content.ComponentName; import android.content.ComponentName;
@@ -35,22 +33,15 @@ import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.pm.PackageInfo; import android.content.pm.PackageInfo;
import android.preference.Preference;
import android.content.ServiceConnection; import android.content.ServiceConnection;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.content.Context;
import android.graphics.Color; import android.graphics.Color;
import android.media.AudioManager;
import android.media.ToneGenerator;
import android.net.Uri; import android.net.Uri;
import android.net.wifi.WifiManager;
import android.net.wifi.WifiInfo;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.os.IBinder; import android.os.IBinder;
import android.os.Message; import android.os.Message;
import android.os.Messenger; import android.os.Messenger;
import android.os.RemoteException;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.util.Log; import android.util.Log;
import android.view.Menu; import android.view.Menu;
@@ -58,7 +49,6 @@ import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.ViewConfiguration; import android.view.ViewConfiguration;
import android.view.WindowManager; import android.view.WindowManager;
import android.widget.LinearLayout;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Button; import android.widget.Button;
import java.lang.reflect.Field; import java.lang.reflect.Field;
@@ -69,28 +59,12 @@ import java.util.Enumeration;
import java.util.Timer; import java.util.Timer;
import java.util.TimerTask; import java.util.TimerTask;
import org.apache.http.conn.util.InetAddressUtils; import org.apache.http.conn.util.InetAddressUtils;
import java.lang.CharSequence;
import android.util.AttributeSet;
//MPAndroidChart //MPAndroidChart
import com.github.mikephil.charting.charts.LineChart; import com.github.mikephil.charting.charts.LineChart;
import com.github.mikephil.charting.components.Legend;
import com.github.mikephil.charting.components.Legend.LegendForm;
import com.github.mikephil.charting.components.LimitLine;
import com.github.mikephil.charting.components.LimitLine.LimitLabelPosition;
import com.github.mikephil.charting.components.XAxis;
import com.github.mikephil.charting.components.YAxis;
import com.github.mikephil.charting.data.DataSet;
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.data.filter.Approximator;
import com.github.mikephil.charting.data.filter.Approximator.ApproximatorType;
import com.github.mikephil.charting.listener.OnChartGestureListener;
import com.github.mikephil.charting.listener.OnChartValueSelectedListener;
import com.github.mikephil.charting.utils.Highlight;
import uk.org.openseizuredetector.SdServer;
public class MainActivity extends Activity public class MainActivity extends Activity
{ {
@@ -466,31 +440,31 @@ public class MainActivity extends Activity
try { try {
if (mBound) { if (mBound) {
tv = (TextView) findViewById(R.id.alarmTv); tv = (TextView) findViewById(R.id.alarmTv);
if ((mSdServer.sdData.alarmState==0) if ((mSdServer.mSdData.alarmState==0)
&& !mSdServer.sdData.alarmStanding && !mSdServer.mSdData.alarmStanding
&& !mSdServer.sdData.fallAlarmStanding) { && !mSdServer.mSdData.fallAlarmStanding) {
tv.setText("OK"); tv.setText("OK");
tv.setBackgroundColor(okColour); tv.setBackgroundColor(okColour);
} }
if ((mSdServer.sdData.alarmState==1) if ((mSdServer.mSdData.alarmState==1)
&& !mSdServer.sdData.alarmStanding && !mSdServer.mSdData.alarmStanding
&& !mSdServer.sdData.fallAlarmStanding) { && !mSdServer.mSdData.fallAlarmStanding) {
tv.setText("WARNING"); tv.setText("WARNING");
tv.setBackgroundColor(warnColour); tv.setBackgroundColor(warnColour);
} }
if (mSdServer.sdData.alarmStanding) { if (mSdServer.mSdData.alarmStanding) {
tv.setText("**ALARM**"); tv.setText("**ALARM**");
tv.setBackgroundColor(alarmColour); tv.setBackgroundColor(alarmColour);
} }
if (mSdServer.sdData.fallAlarmStanding) { if (mSdServer.mSdData.fallAlarmStanding) {
tv.setText("**FALL**"); tv.setText("**FALL**");
tv.setBackgroundColor(alarmColour); tv.setBackgroundColor(alarmColour);
} }
tv = (TextView) findViewById(R.id.pebTimeTv); tv = (TextView) findViewById(R.id.pebTimeTv);
tv.setText(mSdServer.mPebbleStatusTime.format("%H:%M:%S")); tv.setText(mSdServer.mSdData.dataTime.format("%H:%M:%S"));
// Pebble Connected Phrase // Pebble Connected Phrase
tv = (TextView) findViewById(R.id.pebbleTv); tv = (TextView) findViewById(R.id.pebbleTv);
if (mSdServer.sdData.pebbleConnected) { if (mSdServer.mSdData.pebbleConnected) {
tv.setText("Pebble Watch Connected OK"); tv.setText("Pebble Watch Connected OK");
tv.setBackgroundColor(okColour); tv.setBackgroundColor(okColour);
} else { } else {
@@ -498,7 +472,7 @@ public class MainActivity extends Activity
tv.setBackgroundColor(alarmColour); tv.setBackgroundColor(alarmColour);
} }
tv = (TextView) findViewById(R.id.appTv); tv = (TextView) findViewById(R.id.appTv);
if (mSdServer.sdData.pebbleAppRunning) { if (mSdServer.mSdData.pebbleAppRunning) {
tv.setText("Pebble App OK"); tv.setText("Pebble App OK");
tv.setBackgroundColor(okColour); tv.setBackgroundColor(okColour);
} else { } else {
@@ -506,19 +480,19 @@ public class MainActivity extends Activity
tv.setBackgroundColor(alarmColour); tv.setBackgroundColor(alarmColour);
} }
tv = (TextView) findViewById(R.id.battTv); tv = (TextView) findViewById(R.id.battTv);
tv.setText("Pebble Battery = "+String.valueOf(mSdServer.sdData.batteryPc)+"%"); tv.setText("Pebble Battery = "+String.valueOf(mSdServer.mSdData.batteryPc)+"%");
if (mSdServer.sdData.batteryPc<=20) if (mSdServer.mSdData.batteryPc<=20)
tv.setBackgroundColor(alarmColour); tv.setBackgroundColor(alarmColour);
if (mSdServer.sdData.batteryPc>20) if (mSdServer.mSdData.batteryPc>20)
tv.setBackgroundColor(warnColour); tv.setBackgroundColor(warnColour);
if (mSdServer.sdData.batteryPc>=40) if (mSdServer.mSdData.batteryPc>=40)
tv.setBackgroundColor(okColour); tv.setBackgroundColor(okColour);
tv = (TextView) findViewById(R.id.debugTv); tv = (TextView) findViewById(R.id.debugTv);
String specStr = ""; String specStr = "";
for (int i=0;i<10;i++) for (int i=0;i<10;i++)
specStr = specStr specStr = specStr
+ mSdServer.sdData.simpleSpec[i] + mSdServer.mSdData.simpleSpec[i]
+ ", "; + ", ";
tv.setText("Spec = "+specStr); tv.setText("Spec = "+specStr);
} }
@@ -544,7 +518,7 @@ public class MainActivity extends Activity
ArrayList<Entry> yVals = new ArrayList<Entry>(); ArrayList<Entry> yVals = new ArrayList<Entry>();
for (int i = 0; i < 10; i++) { for (int i = 0; i < 10; i++) {
if (mSdServer!=null) if (mSdServer!=null)
yVals.add(new Entry(mSdServer.sdData.simpleSpec[i], i)); yVals.add(new Entry(mSdServer.mSdData.simpleSpec[i], i));
else else
yVals.add(new Entry(i, i)); yVals.add(new Entry(i, i));
} }

View File

@@ -125,7 +125,7 @@ public class SdData implements Parcelable {
jsonObj.put("dataTimeStr","00000000T000000"); jsonObj.put("dataTimeStr","00000000T000000");
jsonObj.put("dataTime","00-00-00 00:00:00"); jsonObj.put("dataTime","00-00-00 00:00:00");
} }
Log.v(TAG,"sdData.dataTime = "+dataTime); Log.v(TAG,"mSdData.dataTime = "+dataTime);
jsonObj.put("maxVal",maxVal); jsonObj.put("maxVal",maxVal);
jsonObj.put("maxFreq",maxFreq); jsonObj.put("maxFreq",maxFreq);
jsonObj.put("specPower",specPower); jsonObj.put("specPower",specPower);

View File

@@ -0,0 +1,74 @@
/*
Android_Pebble_sd - Android alarm client for openseizuredetector..
See http://openseizuredetector.org for more information.
Copyright Graham Jones, 2015.
This file is part of pebble_sd.
Android_Pebble_sd is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Android_Pebble_sd is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Android_pebble_sd. If not, see <http://www.gnu.org/licenses/>.
*/
package uk.org.openseizuredetector;
import android.content.Context;
import android.util.Log;
interface SdDataReceiver {
public void onSdDataReceived(SdData sdData);
public void onSdDataFault(SdData sdData);
}
/**
* Abstract class for a seizure detector data source. Subclasses include a pebble smart watch data source and a
* network data source.
*/
public abstract class SdDataSource {
public SdData mSdData;
protected Context mContext;
protected SdDataReceiver mSdDataReceiver;
private String TAG = "SdDataSource";
public SdDataSource(Context context, SdDataReceiver sdDataReceiver) {
Log.v(TAG, "SdDataSource() Constructor");
mContext = context;
mSdDataReceiver = sdDataReceiver;
mSdData = new SdData();
}
/**
* Returns the SdData object stored by this class.
* @return
*/
public SdData getSdData() {
return mSdData;
}
/**
* Start the datasource updating - initialises from sharedpreferences first to
* make sure any changes to preferences are taken into account.
*/
public void start() {
Log.v(TAG, "start()");
}
/**
* Stop the datasource from updating
*/
public void stop() {
Log.v(TAG, "stop()");
}
}

View File

@@ -0,0 +1,441 @@
/*
Android_Pebble_sd - Android alarm client for openseizuredetector..
See http://openseizuredetector.org for more information.
Copyright Graham Jones, 2015.
This file is part of pebble_sd.
Android_Pebble_sd is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Android_Pebble_sd is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Android_pebble_sd. If not, see <http://www.gnu.org/licenses/>.
*/
package uk.org.openseizuredetector;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Handler;
import android.os.Looper;
import android.preference.PreferenceManager;
import android.text.format.Time;
import android.util.Log;
import android.widget.Toast;
import com.getpebble.android.kit.Constants;
import com.getpebble.android.kit.PebbleKit;
import com.getpebble.android.kit.util.PebbleDictionary;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.IntBuffer;
import java.util.Timer;
import java.util.TimerTask;
import java.util.UUID;
/**
* Abstract class for a seizure detector data source. Subclasses include a pebble smart watch data source and a
* network data source.
*/
public class SdDataSourcePebble extends SdDataSource {
private Timer mSettingsTimer;
private Timer mStatusTimer;
private Time mPebbleStatusTime;
private boolean mPebbleAppRunningCheck = false;
private int mAppRestartTimeout = 10; // Timeout before re-starting watch app (sec).
//private Looper mServiceLooper;
private int mFaultTimerPeriod = 30; // Fault Timer Period in sec
private PebbleKit.PebbleDataReceiver msgDataHandler = null;
private String TAG = "SdDataSourcePebble";
private UUID SD_UUID = UUID.fromString("03930f26-377a-4a3d-aa3e-f3b19e421c9d");
private int NSAMP = 512; // Number of samples in fft input dataset.
private int KEY_DATA_TYPE = 1;
private int KEY_ALARMSTATE = 2;
private int KEY_MAXVAL = 3;
private int KEY_MAXFREQ = 4;
private int KEY_SPECPOWER = 5;
private int KEY_SETTINGS = 6;
private int KEY_ALARM_FREQ_MIN = 7;
private int KEY_ALARM_FREQ_MAX = 8;
private int KEY_WARN_TIME = 9;
private int KEY_ALARM_TIME = 10;
private int KEY_ALARM_THRESH = 11;
private int KEY_POS_MIN = 12; // position of first data point in array
private int KEY_POS_MAX = 13; // position of last data point in array.
private int KEY_SPEC_DATA = 14; // Spectrum data
private int KEY_ROIPOWER = 15;
private int KEY_NMIN = 16;
private int KEY_NMAX = 17;
private int KEY_ALARM_RATIO_THRESH = 18;
private int KEY_BATTERY_PC = 19;
//private int KEY_SET_SETTINGS =20; // Phone is asking us to update watch app settings.
private int KEY_FALL_THRESH_MIN = 21;
private int KEY_FALL_THRESH_MAX = 22;
private int KEY_FALL_WINDOW = 23;
private int KEY_FALL_ACTIVE = 24;
// Values of the KEY_DATA_TYPE entry in a message
private int DATA_TYPE_RESULTS = 1; // Analysis Results
private int DATA_TYPE_SETTINGS = 2; // Settings
private int DATA_TYPE_SPEC = 3; // FFT Spectrum (or part of a spectrum)
public SdDataSourcePebble(Context context, SdDataReceiver sdDataReceiver) {
super(context,sdDataReceiver);
}
/**
* Start the datasource updating - initialises from sharedpreferences first to
* make sure any changes to preferences are taken into account.
*/
public void start() {
Log.v(TAG, "start()");
updatePrefs();
startPebbleServer();
// Start timer to check status of pebble regularly.
mPebbleStatusTime = new Time(Time.getCurrentTimezone());
//getPebbleStatus();
if (mStatusTimer == null) {
Log.v(TAG, "onCreate(): starting status timer");
mStatusTimer = new Timer();
mStatusTimer.schedule(new TimerTask() {
@Override
public void run() {
getPebbleStatus();
}
}, 0, 1000);
} else {
Log.v(TAG, "onCreate(): status timer already running.");
}
// Start timer to retrieve pebble settings regularly.
getPebbleSdSettings();
if (mSettingsTimer == null) {
Log.v(TAG, "onCreate(): starting settings timer");
mSettingsTimer = new Timer();
mSettingsTimer.schedule(new TimerTask() {
@Override
public void run() {
getPebbleSdSettings();
}
}, 0, 1000 * 60);
} else {
Log.v(TAG, "onCreate(): settings timer already running.");
}
}
/**
* Stop the datasource from updating
*/
public void stop() {
Log.v(TAG, "stop()");
try {
// Stop the status timer
if (mStatusTimer != null) {
Log.v(TAG, "onDestroy(): cancelling status timer");
mStatusTimer.cancel();
mStatusTimer.purge();
mStatusTimer = null;
}
// Stop the settings timer
if (mSettingsTimer != null) {
Log.v(TAG, "onDestroy(): cancelling settings timer");
mSettingsTimer.cancel();
mSettingsTimer.purge();
mSettingsTimer = null;
}
// Stop pebble message handler.
Log.v(TAG, "onDestroy(): stopping pebble server");
stopPebbleServer();
} catch (Exception e) {
Log.v(TAG, "Error in stop() - " + e.toString());
}
}
/**
* updatePrefs() - update basic settings from the SharedPreferences
* - defined in res/xml/SdDataSourcePebblePrefs.xml
*/
public void updatePrefs() {
Log.v(TAG, "updatePrefs()");
SharedPreferences SP = PreferenceManager
.getDefaultSharedPreferences(mContext);
try {
// Parse the AppRestartTimeout period setting.
try {
String appRestartTimeoutStr = SP.getString("AppRestartTimeout", "10");
mAppRestartTimeout = Integer.parseInt(appRestartTimeoutStr);
Log.v(TAG, "updatePrefs() - mAppRestartTimeout = " + mAppRestartTimeout);
} catch (Exception ex) {
Log.v(TAG, "updatePrefs() - Problem with AppRestartTimeout preference!");
Toast toast = Toast.makeText(mContext, "Problem Parsing AppRestartTimeout Preference", Toast.LENGTH_SHORT);
toast.show();
}
// Parse the FaultTimer period setting.
try {
String faultTimerPeriodStr = SP.getString("FaultTimerPeriod", "30");
mFaultTimerPeriod = Integer.parseInt(faultTimerPeriodStr);
Log.v(TAG, "updatePrefs() - mFaultTimerPeriod = " + mFaultTimerPeriod);
} catch (Exception ex) {
Log.v(TAG, "updatePrefs() - Problem with FaultTimerPeriod preference!");
Toast toast = Toast.makeText(mContext, "Problem Parsing FaultTimerPeriod Preference", Toast.LENGTH_SHORT);
toast.show();
}
// Watch Settings
PebbleDictionary setDict = new PebbleDictionary();
short intVal;
String prefStr;
prefStr = SP.getString("AlarmFreqMin", "5");
intVal = (short) Integer.parseInt(prefStr);
Log.v(TAG, "updatePrefs() AlarmFreqMin = " + intVal);
setDict.addInt16(KEY_ALARM_FREQ_MIN, intVal);
prefStr = SP.getString("AlarmFreqMax", "10");
intVal = (short) Integer.parseInt(prefStr);
Log.v(TAG, "updatePrefs() AlarmFreqMax = " + intVal);
setDict.addUint16(KEY_ALARM_FREQ_MAX, (short) intVal);
prefStr = SP.getString("WarnTime", "5");
intVal = (short) Integer.parseInt(prefStr);
Log.v(TAG, "updatePrefs() WarnTime = " + intVal);
setDict.addUint16(KEY_WARN_TIME, (short) intVal);
prefStr = SP.getString("AlarmTime", "10");
intVal = (short) Integer.parseInt(prefStr);
Log.v(TAG, "updatePrefs() AlarmTime = " + intVal);
setDict.addUint16(KEY_ALARM_TIME, (short) intVal);
prefStr = SP.getString("AlarmThresh", "100");
intVal = (short) Integer.parseInt(prefStr);
Log.v(TAG, "updatePrefs() AlarmThresh = " + intVal);
setDict.addUint16(KEY_ALARM_THRESH, (short) intVal);
prefStr = SP.getString("AlarmRatioThresh", "30");
intVal = (short) Integer.parseInt(prefStr);
Log.v(TAG, "updatePrefs() AlarmRatioThresh = " + intVal);
setDict.addUint16(KEY_ALARM_RATIO_THRESH, (short) intVal);
boolean fallActiveBool = SP.getBoolean("FallActive", false);
Log.v(TAG, "updatePrefs() FallActive = " + fallActiveBool);
if (fallActiveBool)
setDict.addUint16(KEY_FALL_ACTIVE, (short) 1);
else
setDict.addUint16(KEY_FALL_ACTIVE, (short) 0);
prefStr = SP.getString("FallThreshMin", "200");
intVal = (short) Integer.parseInt(prefStr);
Log.v(TAG, "updatePrefs() FallThreshMin = " + intVal);
setDict.addUint16(KEY_FALL_THRESH_MIN, (short) intVal);
prefStr = SP.getString("FallThreshMax", "1200");
intVal = (short) Integer.parseInt(prefStr);
Log.v(TAG, "updatePrefs() FallThreshMax = " + intVal);
setDict.addUint16(KEY_FALL_THRESH_MAX, (short) intVal);
prefStr = SP.getString("FallWindow", "1500");
intVal = (short) Integer.parseInt(prefStr);
Log.v(TAG, "updatePrefs() FallWindow = " + intVal);
setDict.addUint16(KEY_FALL_WINDOW, (short) intVal);
// Send Watch Settings to Pebble
Log.v(TAG, "updatePrefs() - setDict = " + setDict.toJsonString());
PebbleKit.sendDataToPebble(mContext, SD_UUID, setDict);
} catch (Exception ex) {
Log.v(TAG, "updatePrefs() - Problem parsing preferences!");
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();
}
}
/**
* Set this server to receive pebble data by registering it as
* A PebbleDataReceiver
*/
private void startPebbleServer() {
Log.v(TAG, "StartPebbleServer()");
final Handler handler = new Handler();
msgDataHandler = new PebbleKit.PebbleDataReceiver(SD_UUID) {
@Override
public void receiveData(final Context context,
final int transactionId,
final PebbleDictionary data) {
Log.v(TAG, "Received message from Pebble - data type="
+ data.getUnsignedIntegerAsLong(KEY_DATA_TYPE));
// If we ha ve a message, the app must be running
mPebbleAppRunningCheck = true;
PebbleKit.sendAckToPebble(context, transactionId);
//Log.v(TAG,"Message is: "+data.toJsonString());
if (data.getUnsignedIntegerAsLong(KEY_DATA_TYPE)
== DATA_TYPE_RESULTS) {
Log.v(TAG, "DATA_TYPE = Results");
mSdData.dataTime.setToNow();
Log.v(TAG, "mSdData.dataTime=" + mSdData.dataTime);
mSdData.alarmState = data.getUnsignedIntegerAsLong(
KEY_ALARMSTATE);
mSdData.maxVal = data.getUnsignedIntegerAsLong(KEY_MAXVAL);
mSdData.maxFreq = data.getUnsignedIntegerAsLong(KEY_MAXFREQ);
mSdData.specPower = data.getUnsignedIntegerAsLong(KEY_SPECPOWER);
mSdData.roiPower = data.getUnsignedIntegerAsLong(KEY_ROIPOWER);
mSdData.alarmPhrase = "Unknown";
mSdDataReceiver.onSdDataReceived(mSdData);
}
// Read the data that has been sent, and convert it into
// an integer array.
byte[] byteArr = data.getBytes(KEY_SPEC_DATA);
if ((byteArr!=null) && (byteArr.length!=0)) {
IntBuffer intBuf = ByteBuffer.wrap(byteArr)
.order(ByteOrder.LITTLE_ENDIAN)
.asIntBuffer();
int[] intArray = new int[intBuf.remaining()];
intBuf.get(intArray);
for (int i = 0; i < intArray.length; i++) {
mSdData.simpleSpec[i] = intArray[i];
}
} else {
Log.v(TAG,"***** zero length spectrum received - error!!!!");
}
if (data.getUnsignedIntegerAsLong(KEY_DATA_TYPE)
== DATA_TYPE_SETTINGS) {
Log.v(TAG, "DATA_TYPE = Settings");
mSdData.alarmFreqMin = data.getUnsignedIntegerAsLong(KEY_ALARM_FREQ_MIN);
mSdData.alarmFreqMax = data.getUnsignedIntegerAsLong(KEY_ALARM_FREQ_MAX);
mSdData.nMin = data.getUnsignedIntegerAsLong(KEY_NMIN);
mSdData.nMax = data.getUnsignedIntegerAsLong(KEY_NMAX);
mSdData.warnTime = data.getUnsignedIntegerAsLong(KEY_WARN_TIME);
mSdData.alarmTime = data.getUnsignedIntegerAsLong(KEY_ALARM_TIME);
mSdData.alarmThresh = data.getUnsignedIntegerAsLong(KEY_ALARM_THRESH);
mSdData.alarmRatioThresh = data.getUnsignedIntegerAsLong(KEY_ALARM_RATIO_THRESH);
mSdData.batteryPc = data.getUnsignedIntegerAsLong(KEY_BATTERY_PC);
mSdData.haveSettings = true;
}
}
};
PebbleKit.registerReceivedDataHandler(mContext, msgDataHandler);
}
/**
* De-register this server from receiving pebble data
*/
public void stopPebbleServer() {
Log.v(TAG, "stopPebbleServer(): Stopping Pebble Server");
Log.v(TAG, "stopPebbleServer(): msgDataHandler = " + msgDataHandler.toString());
try {
mContext.unregisterReceiver(msgDataHandler);
} catch (Exception e) {
Log.v(TAG, "stopPebbleServer() - error " + e.toString());
}
}
/**
* Attempt to start the pebble_sd watch app on the pebble watch.
*/
public void startWatchApp() {
PebbleKit.startAppOnPebble(mContext, SD_UUID);
}
/**
* stop the pebble_sd watch app on the pebble watch.
*/
public void stopWatchApp() {
PebbleKit.closeAppOnPebble(mContext, SD_UUID);
}
/**
* Request Pebble App to send us its latest settings.
* Will be received as a message by the receiveData handler
*/
public void getPebbleSdSettings() {
Log.v(TAG, "getPebbleSdSettings() - requesting settings from pebble");
PebbleDictionary data = new PebbleDictionary();
data.addUint8(KEY_SETTINGS, (byte) 1);
PebbleKit.sendDataToPebble(
mContext,
SD_UUID,
data);
}
/**
* Checks the status of the connection to the pebble watch,
* and sets class variables for use by other functions.
* If the watch app is not running, it attempts to re-start it.
*/
public void getPebbleStatus() {
Time tnow = new Time(Time.getCurrentTimezone());
long tdiff;
tnow.setToNow();
tdiff = (tnow.toMillis(false) - mPebbleStatusTime.toMillis(false));
// Check we are actually connected to the pebble.
mSdData.pebbleConnected = PebbleKit.isWatchConnected(mContext);
// And is the pebble_sd app running?
// set mPebbleAppRunningCheck has been false for more than 10 seconds
// the app is not talking to us
// mPebbleAppRunningCheck is set to true in the receiveData handler.
if (!mPebbleAppRunningCheck &&
(tdiff > mAppRestartTimeout * 1000)) {
Log.v(TAG, "getPebbleStatus() - tdiff = " + tdiff);
mSdData.pebbleAppRunning = false;
Log.v(TAG, "getPebbleStatus() - Pebble App Not Running - Attempting to Re-Start");
startWatchApp();
getPebbleSdSettings();
// Only make audible warning beep if we have not received data for more than mFaultTimerPeriod seconds.
if (tdiff > mFaultTimerPeriod * 1000) {
mSdDataReceiver.onSdDataFault(mSdData);
} else {
Log.v(TAG, "getPebbleStatus() - Waiting for mFaultTimerPeriod before issuing audible warning...");
}
} else {
mSdData.pebbleAppRunning = true;
}
// if we have confirmation that the app is running, reset the
// status time to now and initiate another check.
if (mPebbleAppRunningCheck) {
mPebbleAppRunningCheck = false;
mPebbleStatusTime.setToNow();
}
if (!mSdData.haveSettings) {
Log.v(TAG, "getPebbleStatus() - no settings received yet - requesting");
getPebbleSdSettings();
}
}
}

View File

@@ -27,11 +27,9 @@
package uk.org.openseizuredetector; package uk.org.openseizuredetector;
import java.util.Map; import java.util.Map;
import fi.iki.elonen.NanoHTTPD; import fi.iki.elonen.NanoHTTPD;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityManager.RunningServiceInfo;
import android.app.Notification; import android.app.Notification;
import android.app.NotificationManager; import android.app.NotificationManager;
import android.app.PendingIntent; import android.app.PendingIntent;
@@ -39,46 +37,31 @@ import android.app.Service;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.res.AssetManager; import android.content.res.AssetManager;
import android.content.res.AssetFileDescriptor;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.media.AudioManager; import android.media.AudioManager;
import android.media.ToneGenerator; import android.media.ToneGenerator;
import android.os.Bundle;
import android.os.Environment; import android.os.Environment;
import android.os.Handler;
import android.os.HandlerThread; import android.os.HandlerThread;
import android.os.Binder; import android.os.Binder;
import android.os.CountDownTimer;
import android.os.IBinder; import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.PowerManager; import android.os.PowerManager;
import android.os.PowerManager.WakeLock; import android.os.PowerManager.WakeLock;
import android.os.Process;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.telephony.SmsManager; import android.telephony.SmsManager;
import android.telephony.SmsMessage;
import android.util.Log; import android.util.Log;
import android.widget.Toast; import android.widget.Toast;
import java.util.Timer; import java.util.Timer;
import java.util.TimerTask; import java.util.TimerTask;
import java.io.*; import java.io.*;
import java.util.*; import java.util.*;
import java.util.UUID;
import java.util.StringTokenizer; import java.util.StringTokenizer;
import java.net.URL;
import android.net.Uri;
import java.nio.ByteBuffer;
import java.nio.ShortBuffer;
import java.nio.IntBuffer;
import java.nio.ByteOrder;
import android.text.format.Time; import android.text.format.Time;
import org.json.JSONObject; import org.json.JSONObject;
import org.json.JSONArray; import org.json.JSONArray;
import com.getpebble.android.kit.Constants;
import com.getpebble.android.kit.PebbleKit;
import com.getpebble.android.kit.util.PebbleDictionary;
/** /**
@@ -87,41 +70,7 @@ import com.getpebble.android.kit.util.PebbleDictionary;
* and * and
* http://developer.android.com/guide/components/services.html#ExtendingService * http://developer.android.com/guide/components/services.html#ExtendingService
*/ */
public class SdServer extends Service public class SdServer extends Service implements SdDataReceiver {
{
private UUID SD_UUID = UUID.fromString("03930f26-377a-4a3d-aa3e-f3b19e421c9d");
private int NSAMP = 512; // Number of samples in fft input dataset.
private int KEY_DATA_TYPE = 1;
private int KEY_ALARMSTATE = 2;
private int KEY_MAXVAL = 3;
private int KEY_MAXFREQ = 4;
private int KEY_SPECPOWER = 5;
private int KEY_SETTINGS = 6;
private int KEY_ALARM_FREQ_MIN =7;
private int KEY_ALARM_FREQ_MAX =8;
private int KEY_WARN_TIME = 9;
private int KEY_ALARM_TIME = 10;
private int KEY_ALARM_THRESH = 11;
private int KEY_POS_MIN = 12; // position of first data point in array
private int KEY_POS_MAX = 13; // position of last data point in array.
private int KEY_SPEC_DATA = 14; // Spectrum data
private int KEY_ROIPOWER = 15;
private int KEY_NMIN = 16;
private int KEY_NMAX = 17;
private int KEY_ALARM_RATIO_THRESH = 18;
private int KEY_BATTERY_PC = 19;
//private int KEY_SET_SETTINGS =20; // Phone is asking us to update watch app settings.
private int KEY_FALL_THRESH_MIN = 21;
private int KEY_FALL_THRESH_MAX = 22;
private int KEY_FALL_WINDOW = 23;
private int KEY_FALL_ACTIVE =24;
// Values of the KEY_DATA_TYPE entry in a message
private int DATA_TYPE_RESULTS = 1; // Analysis Results
private int DATA_TYPE_SETTINGS = 2; // Settings
private int DATA_TYPE_SPEC = 3; // FFT Spectrum (or part of a spectrum)
// Notification ID // Notification ID
private int NOTIFICATION_ID = 1; private int NOTIFICATION_ID = 1;
@@ -129,18 +78,11 @@ public class SdServer extends Service
private WebServer webServer = null; private WebServer webServer = null;
private final static String TAG = "SdServer"; private final static String TAG = "SdServer";
private Looper mServiceLooper;
public Time mPebbleStatusTime;
private boolean mPebbleAppRunningCheck = false;
private Timer statusTimer = null;
private int mFaultTimerPeriod = 30; // Fault Timer Period in sec
private int mAppRestartTimeout = 10; // Timeout before re-starting watch app (sec).
private Timer settingsTimer = null;
private Timer dataLogTimer = null; private Timer dataLogTimer = null;
private HandlerThread thread; private HandlerThread thread;
private WakeLock mWakeLock = null; private WakeLock mWakeLock = null;
public SdData sdData; public SdDataSource mSdDataSource;
private PebbleKit.PebbleDataReceiver msgDataHandler = null; public SdData mSdData;
private boolean mLatchAlarms = false; private boolean mLatchAlarms = false;
private boolean mCancelAudible = false; private boolean mCancelAudible = false;
private boolean mAudibleAlarm = false; private boolean mAudibleAlarm = false;
@@ -158,7 +100,7 @@ public class SdServer extends Service
/** /**
* class to handle binding the MainApp activity to this service * class to handle binding the MainApp activity to this service
* so it can access sdData. * so it can access mSdData.
*/ */
public class SdBinder extends Binder { public class SdBinder extends Binder {
SdServer getService() { SdServer getService() {
@@ -171,7 +113,7 @@ public class SdServer extends Service
*/ */
public SdServer() { public SdServer() {
super(); super();
sdData = new SdData(); mSdData = new SdData();
Log.v(TAG, "SdServer Created"); Log.v(TAG, "SdServer Created");
} }
@@ -183,7 +125,6 @@ public class SdServer extends Service
} }
/** /**
* onCreate() - called when services is created. Starts message * onCreate() - called when services is created. Starts message
* handler process to listen for messages from other processes. * handler process to listen for messages from other processes.
@@ -192,6 +133,7 @@ public class SdServer extends Service
public void onCreate() { public void onCreate() {
Log.v(TAG, "onCreate()"); Log.v(TAG, "onCreate()");
// 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);
mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
@@ -209,6 +151,9 @@ public class SdServer extends Service
// Update preferences. // Update preferences.
Log.v(TAG, "onStartCommand() - calling updatePrefs()"); Log.v(TAG, "onStartCommand() - calling updatePrefs()");
updatePrefs(); updatePrefs();
mSdDataSource = new SdDataSourcePebble(this.getApplicationContext(), this);
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.
@@ -220,35 +165,6 @@ public class SdServer extends Service
mSMSTime = new Time(Time.getCurrentTimezone()); mSMSTime = new Time(Time.getCurrentTimezone());
// Start receiving data from the pebble watch
startPebbleServer();
// Start timer to check status of pebble regularly.
mPebbleStatusTime = new Time(Time.getCurrentTimezone());
//getPebbleStatus();
if (statusTimer==null) {
Log.v(TAG,"onCreate(): starting status timer");
statusTimer = new Timer();
statusTimer.schedule(new TimerTask() {
@Override
public void run() {getPebbleStatus();}
}, 0, 1000);
} else {
Log.v(TAG,"onCreate(): status timer already running.");
}
// Start timer to retrieve pebble settings regularly.
getPebbleSdSettings();
if (settingsTimer == null) {
Log.v(TAG,"onCreate(): starting settings timer");
settingsTimer = new Timer();
settingsTimer.schedule(new TimerTask() {
@Override
public void run() {getPebbleSdSettings();}
}, 0, 1000*60);
} else {
Log.v(TAG,"onCreate(): settings timer already running.");
}
// Start timer to log data regularly.. // Start timer to log data regularly..
if (dataLogTimer == null) { if (dataLogTimer == null) {
@@ -256,7 +172,9 @@ public class SdServer extends Service
dataLogTimer = new Timer(); dataLogTimer = new Timer();
dataLogTimer.schedule(new TimerTask() { dataLogTimer.schedule(new TimerTask() {
@Override @Override
public void run() {logData();} public void run() {
logData();
}
}, 0, 1000 * 60); }, 0, 1000 * 60);
} else { } else {
Log.v(TAG, "onCreate(): dataLog timer already running."); Log.v(TAG, "onCreate(): dataLog timer already running.");
@@ -289,30 +207,15 @@ public class SdServer extends Service
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!");
} }
mSdDataSource.stop();
try { try {
// Stop the status timer
if (statusTimer!=null) {
Log.v(TAG,"onDestroy(): cancelling status timer");
statusTimer.cancel();
statusTimer.purge();
statusTimer = null;
}
// Stop the settings timer
if (settingsTimer!=null) {
Log.v(TAG,"onDestroy(): cancelling settings timer");
settingsTimer.cancel();
settingsTimer.purge();
settingsTimer = null;
}
// Cancel the notification. // Cancel the notification.
Log.v(TAG, "onDestroy(): cancelling notification"); Log.v(TAG, "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");
stopWebServer(); stopWebServer();
// Stop pebble message handler.
Log.v(TAG,"onDestroy(): stopping pebble server");
stopPebbleServer();
// stop this service. // stop this service.
Log.v(TAG, "onDestroy(): calling stopSelf()"); Log.v(TAG, "onDestroy(): calling stopSelf()");
stopSelf(); stopSelf();
@@ -323,7 +226,6 @@ public class SdServer extends Service
} }
/** /**
* Show a notification while this service is running. * Show a notification while this service is running.
*/ */
@@ -343,122 +245,12 @@ public class SdServer extends Service
} }
/* from http://stackoverflow.com/questions/12154940/how-to-make-a-beep-in-android */
/** /**
* beep for duration miliseconds, but only if mAudibleAlarm is set. * Process the data received from the SdData source.
* @param sdData
*/ */
private void beep(int duration) { public void onSdDataReceived(SdData sdData) {
ToneGenerator toneG = new ToneGenerator(AudioManager.STREAM_ALARM, 100); Log.v(TAG, "onSdDataReceived()");
toneG.startTone(ToneGenerator.TONE_CDMA_ALERT_CALL_GUARD, duration);
Log.v(TAG,"beep()");
}
/*
* beep, provided mAudibleAlarm is set
*/
public void faultWarningBeep() {
if (mCancelAudible) {
Log.v(TAG, "faultWarningBeep() - CancelAudible Active - silent beep...");
} else {
if (mAudibleFaultWarning) {
beep(10);
Log.v(TAG, "faultWarningBeep()");
} else {
Log.v(TAG, "faultWarningBeep() - silent...");
}
}
}
/*
* beep, provided mAudibleAlarm is set
*/
public void alarmBeep() {
if (mCancelAudible) {
Log.v(TAG,"alarmBeep() - CancelAudible Active - silent beep...");
} else {
if (mAudibleAlarm) {
beep(1000);
Log.v(TAG,"alarmBeep()");
} else {
Log.v(TAG,"alarmBeep() - silent...");
}
}
}
/*
* beep, provided mAudibleWarning is set
*/
public void warningBeep() {
if (mCancelAudible) {
Log.v(TAG,"warningBeep() - CancelAudible Active - silent beep...");
} else {
if (mAudibleWarning) {
beep(100);
Log.v(TAG,"warningBeep()");
} else {
Log.v(TAG,"warningBeep() - silent...");
}
}
}
/**
* Sends SMS Alarms to the telephone numbers specified in mSMSNumbers[]
*/
public void sendSMSAlarm() {
if (mSMSAlarm) {
Log.v(TAG,"sendSMSAlarm() - Sending to "+mSMSNumbers.length+" Numbers");
Time tnow = new Time(Time.getCurrentTimezone());
tnow.setToNow();
String dateStr = tnow.format("%Y-%m-%d %H-%M-%S");
SmsManager sm = SmsManager.getDefault();
for (int i=0;i<mSMSNumbers.length;i++) {
Log.v(TAG,"sendSMSAlarm() - Sending to "+mSMSNumbers[i]);
sm.sendTextMessage(mSMSNumbers[i], null, mSMSMsgStr+" - "+dateStr, null, null);
}
} else {
Log.v(TAG,"sendSMSAlarm() - SMS Alarms Disabled - not doing anything!");
Toast toast = Toast.makeText(getApplicationContext(),
"SMS Alarms Disabled - not doing anything!",
Toast.LENGTH_SHORT);
toast.show();
}
}
/**
* Set this server to receive pebble data by registering it as
* A PebbleDataReceiver
*/
private void startPebbleServer() {
Log.v(TAG, "StartPebbleServer()");
final Handler handler = new Handler();
msgDataHandler = new PebbleKit.PebbleDataReceiver(SD_UUID) {
@Override
public void receiveData(final Context context,
final int transactionId,
final PebbleDictionary data) {
Log.v(TAG, "Received message from Pebble - data type="
+ data.getUnsignedIntegerAsLong(KEY_DATA_TYPE));
// If we ha ve a message, the app must be running
mPebbleAppRunningCheck = true;
PebbleKit.sendAckToPebble(context, transactionId);
//Log.v(TAG,"Message is: "+data.toJsonString());
if (data.getUnsignedIntegerAsLong(KEY_DATA_TYPE)
== DATA_TYPE_RESULTS) {
Log.v(TAG, "DATA_TYPE = Results");
sdData.dataTime.setToNow();
Log.v(TAG, "sdData.dataTime=" + sdData.dataTime);
sdData.alarmState = data.getUnsignedIntegerAsLong(
KEY_ALARMSTATE);
sdData.maxVal = data.getUnsignedIntegerAsLong(KEY_MAXVAL);
sdData.maxFreq = data.getUnsignedIntegerAsLong(KEY_MAXFREQ);
sdData.specPower = data.getUnsignedIntegerAsLong(KEY_SPECPOWER);
sdData.roiPower = data.getUnsignedIntegerAsLong(KEY_ROIPOWER);
sdData.alarmPhrase = "Unknown";
if (sdData.alarmState == 0) { if (sdData.alarmState == 0) {
if ((!mLatchAlarms) || if ((!mLatchAlarms) ||
(mLatchAlarms && (mLatchAlarms &&
@@ -534,78 +326,110 @@ public class SdServer extends Service
mSMSTime = tnow; mSMSTime = tnow;
} }
} }
}
mSdData = sdData;
}
public void onSdDataFault(SdData sdData) {
Log.v(TAG,"onSdDataFault()");
if (mAudibleFaultWarning) {
faultWarningBeep();
}
}
/* from http://stackoverflow.com/questions/12154940/how-to-make-a-beep-in-android */
/**
* beep for duration miliseconds, but only if mAudibleAlarm is set.
*/
private void beep(int duration) {
ToneGenerator toneG = new ToneGenerator(AudioManager.STREAM_ALARM, 100);
toneG.startTone(ToneGenerator.TONE_CDMA_ALERT_CALL_GUARD, duration);
Log.v(TAG, "beep()");
}
/*
* beep, provided mAudibleAlarm is set
*/
public void faultWarningBeep() {
if (mCancelAudible) {
Log.v(TAG, "faultWarningBeep() - CancelAudible Active - silent beep...");
} else {
if (mAudibleFaultWarning) {
beep(10);
Log.v(TAG, "faultWarningBeep()");
} else {
Log.v(TAG, "faultWarningBeep() - silent...");
}
}
} }
// Read the data that has been sent, and convert it into /*
// an integer array. * beep, provided mAudibleAlarm is set
byte[] byteArr = data.getBytes(KEY_SPEC_DATA); */
IntBuffer intBuf = ByteBuffer.wrap(byteArr) public void alarmBeep() {
.order(ByteOrder.LITTLE_ENDIAN) if (mCancelAudible) {
.asIntBuffer(); Log.v(TAG, "alarmBeep() - CancelAudible Active - silent beep...");
int[] intArray = new int[intBuf.remaining()]; } else {
intBuf.get(intArray); if (mAudibleAlarm) {
for (int i=0;i<intArray.length;i++) { beep(1000);
sdData.simpleSpec[i] = intArray[i]; Log.v(TAG, "alarmBeep()");
} else {
Log.v(TAG, "alarmBeep() - silent...");
}
}
}
/*
* beep, provided mAudibleWarning is set
*/
public void warningBeep() {
if (mCancelAudible) {
Log.v(TAG, "warningBeep() - CancelAudible Active - silent beep...");
} else {
if (mAudibleWarning) {
beep(100);
Log.v(TAG, "warningBeep()");
} else {
Log.v(TAG, "warningBeep() - silent...");
}
}
} }
/**
* Sends SMS Alarms to the telephone numbers specified in mSMSNumbers[]
*/
public void sendSMSAlarm() {
if (mSMSAlarm) {
Log.v(TAG, "sendSMSAlarm() - Sending to " + mSMSNumbers.length + " Numbers");
Time tnow = new Time(Time.getCurrentTimezone());
tnow.setToNow();
String dateStr = tnow.format("%Y-%m-%d %H-%M-%S");
SmsManager sm = SmsManager.getDefault();
for (int i = 0; i < mSMSNumbers.length; i++) {
Log.v(TAG, "sendSMSAlarm() - Sending to " + mSMSNumbers[i]);
sm.sendTextMessage(mSMSNumbers[i], null, mSMSMsgStr + " - " + dateStr, null, null);
} }
if (data.getUnsignedIntegerAsLong(KEY_DATA_TYPE) } else {
==DATA_TYPE_SETTINGS) { Log.v(TAG, "sendSMSAlarm() - SMS Alarms Disabled - not doing anything!");
Log.v(TAG,"DATA_TYPE = Settings"); Toast toast = Toast.makeText(getApplicationContext(),
sdData.alarmFreqMin = data.getUnsignedIntegerAsLong(KEY_ALARM_FREQ_MIN); "SMS Alarms Disabled - not doing anything!",
sdData.alarmFreqMax = data.getUnsignedIntegerAsLong(KEY_ALARM_FREQ_MAX); Toast.LENGTH_SHORT);
sdData.nMin = data.getUnsignedIntegerAsLong(KEY_NMIN); toast.show();
sdData.nMax = data.getUnsignedIntegerAsLong(KEY_NMAX);
sdData.warnTime = data.getUnsignedIntegerAsLong(KEY_WARN_TIME);
sdData.alarmTime = data.getUnsignedIntegerAsLong(KEY_ALARM_TIME);
sdData.alarmThresh = data.getUnsignedIntegerAsLong(KEY_ALARM_THRESH);
sdData.alarmRatioThresh = data.getUnsignedIntegerAsLong(KEY_ALARM_RATIO_THRESH);
sdData.batteryPc = data.getUnsignedIntegerAsLong(KEY_BATTERY_PC);
sdData.haveSettings = true;
} }
} }
};
PebbleKit.registerReceivedDataHandler(this,msgDataHandler);
}
/** /**
* set the alarm standing flags to false to allow alarm phase to reset to current value. * set the alarm standing flags to false to allow alarm phase to reset to current value.
*/ */
public void acceptAlarm() { public void acceptAlarm() {
Log.v(TAG, "acceptAlarm()"); Log.v(TAG, "acceptAlarm()");
sdData.alarmStanding = false; mSdData.alarmStanding = false;
sdData.fallAlarmStanding = false; mSdData.fallAlarmStanding = false;
}
/**
* De-register this server from receiving pebble data
*/
public void stopPebbleServer() {
Log.v(TAG,"stopPebbleServer(): Stopping Pebble Server");
Log.v(TAG,"stopPebbleServer(): msgDataHandler = "+msgDataHandler.toString());
try {
unregisterReceiver(msgDataHandler);
} catch (Exception e) {
Log.v(TAG,"stopPebbleServer() - error "+e.toString());
}
}
/**
* Attempt to start the pebble_sd watch app on the pebble watch.
*/
public void startWatchApp() {
PebbleKit.startAppOnPebble(getApplicationContext(),
SD_UUID);
}
/**
* stop the pebble_sd watch app on the pebble watch.
*/
public void stopWatchApp() {
PebbleKit.closeAppOnPebble(getApplicationContext(),
SD_UUID);
} }
@@ -653,68 +477,6 @@ public class SdServer extends Service
} }
} }
/**
* Checks the status of the connection to the pebble watch,
* and sets class variables for use by other functions.
* If the watch app is not running, it attempts to re-start it.
*/
public void getPebbleStatus() {
Time tnow = new Time(Time.getCurrentTimezone());
long tdiff;
tnow.setToNow();
tdiff = (tnow.toMillis(false) - mPebbleStatusTime.toMillis(false));
// Check we are actually connected to the pebble.
sdData.pebbleConnected = PebbleKit.isWatchConnected(this);
// And is the pebble_sd app running?
// set mPebbleAppRunningCheck has been false for more than 10 seconds
// the app is not talking to us
// mPebbleAppRunningCheck is set to true in the receiveData handler.
if (!mPebbleAppRunningCheck &&
(tdiff > mAppRestartTimeout * 1000)) {
Log.v(TAG, "getPebbleStatus() - tdiff = " + tdiff);
sdData.pebbleAppRunning = false;
Log.v(TAG, "getPebbleStatus() - Pebble App Not Running - Attempting to Re-Start");
startWatchApp();
getPebbleSdSettings();
// Only make audible warning beep if we have not received data for more than mFaultTimerPeriod seconds.
if ((tdiff > mFaultTimerPeriod * 1000)
&& (mAudibleFaultWarning)
) {
faultWarningBeep();
} else {
Log.v(TAG, "getPebbleStatus() - Waiting for mFaultTimerPeriod before issuing audible warning...");
}
} else {
sdData.pebbleAppRunning = true;
}
// if we have confirmation that the app is running, reset the
// status time to now and initiate another check.
if (mPebbleAppRunningCheck) {
mPebbleAppRunningCheck = false;
mPebbleStatusTime.setToNow();
}
if (!sdData.haveSettings) {
Log.v(TAG, "getPebbleStatus() - no settings received yet - requesting");
getPebbleSdSettings();
}
}
/**
* Request Pebble App to send us its latest settings.
* Will be received as a message by the receiveData handler
*/
public void getPebbleSdSettings() {
Log.v(TAG,"getPebbleSdSettings() - requesting settings from pebble");
PebbleDictionary data = new PebbleDictionary();
data.addUint8(KEY_SETTINGS, (byte)1);
PebbleKit.sendDataToPebble(
getApplicationContext(),
SD_UUID,
data);
}
/** /**
* updatePrefs() - update basic settings from the SharedPreferences * updatePrefs() - update basic settings from the SharedPreferences
@@ -745,90 +507,6 @@ public class SdServer extends Service
mLogData = SP.getBoolean("LogData", false); mLogData = SP.getBoolean("LogData", false);
Log.v(TAG, "updatePrefs() - mLogData = " + mLogData); Log.v(TAG, "updatePrefs() - mLogData = " + mLogData);
// Parse the AppRestartTimeout period setting.
try {
String appRestartTimeoutStr = SP.getString("AppRestartTimeout", "10");
mAppRestartTimeout = Integer.parseInt(appRestartTimeoutStr);
Log.v(TAG, "onStart() - mAppRestartTimeout = " + mAppRestartTimeout);
} catch (Exception ex) {
Log.v(TAG, "onStart() - Problem with AppRestartTimeout preference!");
Toast toast = Toast.makeText(getApplicationContext(), "Problem Parsing AppRestartTimeout Preference", Toast.LENGTH_SHORT);
toast.show();
}
// Parse the FaultTimer period setting.
try {
String faultTimerPeriodStr = SP.getString("FaultTimerPeriod", "30");
mFaultTimerPeriod = Integer.parseInt(faultTimerPeriodStr);
Log.v(TAG, "onStart() - mFaultTimerPeriod = " + mFaultTimerPeriod);
} catch (Exception ex) {
Log.v(TAG, "onStart() - Problem with FaultTimerPeriod preference!");
Toast toast = Toast.makeText(getApplicationContext(), "Problem Parsing FaultTimerPeriod Preference", Toast.LENGTH_SHORT);
toast.show();
}
// Watch Settings
PebbleDictionary setDict = new PebbleDictionary();
short intVal;
String prefStr;
prefStr = SP.getString("AlarmFreqMin","5");
intVal = (short)Integer.parseInt(prefStr);
Log.v(TAG, "updatePrefs() AlarmFreqMin = " + intVal);
setDict.addInt16(KEY_ALARM_FREQ_MIN,intVal);
prefStr = SP.getString("AlarmFreqMax","10");
intVal = (short)Integer.parseInt(prefStr);
Log.v(TAG, "updatePrefs() AlarmFreqMax = " + intVal);
setDict.addUint16(KEY_ALARM_FREQ_MAX, (short) intVal);
prefStr = SP.getString("WarnTime","5");
intVal = (short)Integer.parseInt(prefStr);
Log.v(TAG, "updatePrefs() WarnTime = " + intVal);
setDict.addUint16(KEY_WARN_TIME,(short)intVal);
prefStr = SP.getString("AlarmTime","10");
intVal = (short)Integer.parseInt(prefStr);
Log.v(TAG, "updatePrefs() AlarmTime = " + intVal);
setDict.addUint16(KEY_ALARM_TIME,(short)intVal);
prefStr = SP.getString("AlarmThresh","100");
intVal = (short)Integer.parseInt(prefStr);
Log.v(TAG, "updatePrefs() AlarmThresh = " + intVal);
setDict.addUint16(KEY_ALARM_THRESH,(short)intVal);
prefStr = SP.getString("AlarmRatioThresh","30");
intVal = (short)Integer.parseInt(prefStr);
Log.v(TAG, "updatePrefs() AlarmRatioThresh = " + intVal);
setDict.addUint16(KEY_ALARM_RATIO_THRESH, (short) intVal);
boolean fallActiveBool = SP.getBoolean("FallActive",false);
Log.v(TAG, "updatePrefs() FallActive = " + fallActiveBool);
if (fallActiveBool)
setDict.addUint16(KEY_FALL_ACTIVE,(short)1);
else
setDict.addUint16(KEY_FALL_ACTIVE,(short)0);
prefStr = SP.getString("FallThreshMin","200");
intVal = (short)Integer.parseInt(prefStr);
Log.v(TAG,"updatePrefs() FallThreshMin = "+intVal);
setDict.addUint16(KEY_FALL_THRESH_MIN,(short)intVal);
prefStr = SP.getString("FallThreshMax","1200");
intVal = (short)Integer.parseInt(prefStr);
Log.v(TAG,"updatePrefs() FallThreshMax = "+intVal);
setDict.addUint16(KEY_FALL_THRESH_MAX,(short)intVal);
prefStr = SP.getString("FallWindow","1500");
intVal = (short)Integer.parseInt(prefStr);
Log.v(TAG,"updatePrefs() FallWindow = "+intVal);
setDict.addUint16(KEY_FALL_WINDOW,(short)intVal);
// Send Watch Settings to Pebble
Log.v(TAG,"updatePrefs() - setDict = "+setDict.toJsonString());
PebbleKit.sendDataToPebble(getApplicationContext(), SD_UUID, setDict);
} catch (Exception ex) { } catch (Exception ex) {
Log.v(TAG, "updatePrefs() - Problem parsing preferences!"); Log.v(TAG, "updatePrefs() - Problem parsing preferences!");
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);
@@ -894,9 +572,9 @@ public class SdServer extends Service
try { try {
FileWriter of = new FileWriter(getDataStorageDir().toString() FileWriter of = new FileWriter(getDataStorageDir().toString()
+ "/" + fname, true); + "/" + fname, true);
if (sdData!=null) { if (mSdData != null) {
Log.v(TAG,"writing sdData.toString()"); Log.v(TAG, "writing mSdData.toString()");
of.append(sdData.toString()+"\n"); of.append(mSdData.toString() + "\n");
} }
of.close(); of.close();
} catch (Exception ex) { } catch (Exception ex) {
@@ -913,8 +591,8 @@ public class SdServer extends Service
*/ */
private class WebServer extends NanoHTTPD { private class WebServer extends NanoHTTPD {
private String TAG = "WebServer"; private String TAG = "WebServer";
public WebServer()
{ public WebServer() {
// Set the port to listen on (8080) // Set the port to listen on (8080)
super(8080); super(8080);
} }
@@ -939,17 +617,7 @@ public class SdServer extends Service
case "/data": case "/data":
//Log.v(TAG,"WebServer.serve() - Returning data"); //Log.v(TAG,"WebServer.serve() - Returning data");
try { try {
//JSONObject jsonObj = new JSONObject(); answer = mSdData.toString();
//jsonObj.put("Time",mPebbleStatusTime.format("%H:%M:%S"));
//jsonObj.put("alarmState",sdData.alarmState);
//jsonObj.put("alarmPhrase",sdData.alarmPhrase);
//jsonObj.put("maxVal",sdData.maxVal);
//jsonObj.put("maxFreq",sdData.maxFreq);
//jsonObj.put("specPower",sdData.specPower);
//jsonObj.put("roiPower",sdData.roiPower);
//jsonObj.put("pebCon",mPebbleConnected);
//jsonObj.put("pebAppRun",mPebbleAppRunning);
answer = sdData.toString();
} catch (Exception ex) { } catch (Exception ex) {
Log.v(TAG, "Error Creating Data Object - " + ex.toString()); Log.v(TAG, "Error Creating Data Object - " + ex.toString());
answer = "Error Creating Data Object"; answer = "Error Creating Data Object";
@@ -960,15 +628,15 @@ public class SdServer extends Service
//Log.v(TAG,"WebServer.serve() - Returning settings"); //Log.v(TAG,"WebServer.serve() - Returning settings");
try { try {
JSONObject jsonObj = new JSONObject(); JSONObject jsonObj = new JSONObject();
jsonObj.put("alarmFreqMin",sdData.alarmFreqMin); jsonObj.put("alarmFreqMin", mSdData.alarmFreqMin);
jsonObj.put("alarmFreqMax",sdData.alarmFreqMax); jsonObj.put("alarmFreqMax", mSdData.alarmFreqMax);
jsonObj.put("nMin",sdData.nMin); jsonObj.put("nMin", mSdData.nMin);
jsonObj.put("nMax",sdData.nMax); jsonObj.put("nMax", mSdData.nMax);
jsonObj.put("warnTime",sdData.warnTime); jsonObj.put("warnTime", mSdData.warnTime);
jsonObj.put("alarmTime",sdData.alarmTime); jsonObj.put("alarmTime", mSdData.alarmTime);
jsonObj.put("alarmThresh",sdData.alarmThresh); jsonObj.put("alarmThresh", mSdData.alarmThresh);
jsonObj.put("alarmRatioThresh",sdData.alarmRatioThresh); jsonObj.put("alarmRatioThresh", mSdData.alarmRatioThresh);
jsonObj.put("batteryPc",sdData.batteryPc); jsonObj.put("batteryPc", mSdData.batteryPc);
answer = jsonObj.toString(); answer = jsonObj.toString();
} catch (Exception ex) { } catch (Exception ex) {
Log.v(TAG, "Error Creating Data Object - " + ex.toString()); Log.v(TAG, "Error Creating Data Object - " + ex.toString());
@@ -981,10 +649,10 @@ public class SdServer extends Service
try { try {
JSONObject jsonObj = new JSONObject(); JSONObject jsonObj = new JSONObject();
Log.v(TAG, "WebServer.serve() - Returning spectrum - 2"); Log.v(TAG, "WebServer.serve() - Returning spectrum - 2");
// Initialised it this way because one phone was ok with JSONArray(sdData.simpleSpec), and the other crashed... // Initialised it this way because one phone was ok with JSONArray(mSdData.simpleSpec), and the other crashed...
JSONArray arr = new JSONArray(); JSONArray arr = new JSONArray();
for (int i=0;i<sdData.simpleSpec.length;i++) { for (int i = 0; i < mSdData.simpleSpec.length; i++) {
arr.put(sdData.simpleSpec[i]); arr.put(mSdData.simpleSpec[i]);
} }
Log.v(TAG, "WebServer.serve() - Returning spectrum - 3"); Log.v(TAG, "WebServer.serve() - Returning spectrum - 3");
@@ -1006,8 +674,7 @@ public class SdServer extends Service
uri.startsWith("/img/")) { uri.startsWith("/img/")) {
//Log.v(TAG,"Serving File"); //Log.v(TAG,"Serving File");
return serveFile(uri); return serveFile(uri);
} } else if (uri.startsWith("/logs")) {
else if (uri.startsWith("/logs")) {
Log.v(TAG, "WebServer.serve() - serving data logs - uri=" + uri); Log.v(TAG, "WebServer.serve() - serving data logs - uri=" + uri);
NanoHTTPD.Response resp = serveLogFile(uri); NanoHTTPD.Response resp = serveLogFile(uri);
Log.v(TAG, "WebServer.serve() - response = " + resp.toString()); Log.v(TAG, "WebServer.serve() - response = " + resp.toString());
@@ -1023,8 +690,6 @@ public class SdServer extends Service
} }
/** /**
* Return a file from the external storage folder * Return a file from the external storage folder
*/ */