Merge branch 'V2.6_new' into V2.6 - Addes updated SMS sending code and network datasource passive

This commit is contained in:
Graham Jones
2018-12-27 09:48:37 +00:00
16 changed files with 209 additions and 44 deletions

View File

@@ -1,9 +1,13 @@
OpenSeizureDetector Android App - Change Log
============================================
V2.6.0 - 01 Sep 2017
Added Support for Wifi data source (initially to be used for ESP8266_SD)
and Android Wear datasource
V2.6.0 - 26dec2018
- Changed SMS code to comply with new Google Play Store requirements.
- Added Support for Wifi data source (initially to be used for Garmin_SD)
V2.5.5 - 23feb2018 - Improved logging to help diagnose network problems
that result in 'net fault' warnings from network data source
('wifi-storms').
V2.5.4 - 03dec2017 - Added option to use either tone generator or MP3 alarm sound, as a user reported problem with tone generator on high end samsung phone.

14
DEV_NOTES.txt Normal file
View File

@@ -0,0 +1,14 @@
Graham's Development Notes
==========================
V2.6
- We had a V2.6 started, but I can't remember what it did (but it does include
the NetworkPassive Datasource that I want).
- Start V2.6_new to add in the changes needed for SMS.
- Merge V2.6_new into V2.6, and resolve conflicts.
- Change the gradle dependencies from 'compile' to 'implementation' to get rid
of build warnings.
- clean project and re-build.
- Suddenly got an error "com.android.builder.dexing.DexArchiveMergerException: Error while merging dex archives: <lots of .jar files listed>
The number of method references in a .dex file cannot exceed 64K."
- Added multidex support library to build.gradle dependencies and it seemed to compile....

View File

@@ -23,22 +23,23 @@ android {
}
dependencies {
compile files('libs/mpandroidchartlibrary-2-0-7.jar')
compile 'com.getpebble:pebblekit:3.1.0@aar'
implementation 'com.android.support:multidex:1.0.3'
implementation files('libs/mpandroidchartlibrary-2-0-7.jar')
implementation 'com.getpebble:pebblekit:3.1.0@aar'
// Unit testing dependencies
testCompile 'junit:junit:4.12'
testImplementation 'junit:junit:4.12'
// Set this dependency if you want to use Mockito
testCompile 'org.mockito:mockito-core:1.10.19'
testImplementation 'org.mockito:mockito-core:1.10.19'
// Set this dependency if you want to use Hamcrest matching
testCompile 'org.hamcrest:hamcrest-library:1.1'
compile 'com.android.support:appcompat-v7:22.2.1'
compile 'com.android.support:support-v4:22.2.1'
testImplementation 'org.hamcrest:hamcrest-library:1.1'
implementation 'com.android.support:appcompat-v7:22.2.1'
implementation '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'
implementation 'org.apache.commons:commons-math3:3.6.1'
// google play services used for location finding for SMS alerts.
compile 'com.google.android.gms:play-services-location:10.0.0'
compile 'com.google.android.gms:play-services:10.0.1'
compile 'com.github.wendykierp:JTransforms:3.0'
implementation 'com.google.android.gms:play-services:10.0.1'
implementation 'com.github.wendykierp:JTransforms:3.0'
implementation 'com.google.android.gms:play-services-location:10.0.0'
}

View File

@@ -1 +1 @@
[{"outputType":{"type":"APK"},"apkInfo":{"type":"MAIN","splits":[],"versionCode":38},"path":"app-release.apk","properties":{"packageId":"uk.org.openseizuredetector","split":"","minSdkVersion":"14"}}]
[{"outputType":{"type":"APK"},"apkInfo":{"type":"MAIN","splits":[],"versionCode":41},"path":"app-release.apk","properties":{"packageId":"uk.org.openseizuredetector","split":"","minSdkVersion":"14"}}]

View File

@@ -1,11 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="uk.org.openseizuredetector"
android:versionCode="39"
android:versionCode="42"
android:versionName="2.6.0">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.SEND_SMS" />

View File

@@ -28,6 +28,8 @@ public class SdDataSourceNetwork extends SdDataSource {
private Time mStatusTime;
private Timer mDataUpdateTimer;
private int mDataUpdatePeriod = 2000;
private int mConnnectTimeoutPeriod = 5000;
private int mReadTimeoutPeriod = 5000;
private String mServerIP = "unknown";
private int ALARM_STATE_NETFAULT = 7;
@@ -92,6 +94,12 @@ public class SdDataSourceNetwork extends SdDataSource {
String dataUpdatePeriodStr = SP.getString("DataUpdatePeriod","2000");
mDataUpdatePeriod = Integer.parseInt(dataUpdatePeriodStr);
Log.v(TAG,"updatePrefs() - mDataUpdatePeriod = "+mDataUpdatePeriod);
String connectTimeoutPeriodStr = SP.getString("ConnectTimeoutPeriod","5000");
mConnnectTimeoutPeriod = Integer.parseInt(connectTimeoutPeriodStr);
Log.v(TAG,"updatePrefs() - mConnectTimeoutPeriod = "+mConnnectTimeoutPeriod);
String readTimeoutPeriodStr = SP.getString("ReadTimeoutPeriod","5000");
mReadTimeoutPeriod = Integer.parseInt(readTimeoutPeriodStr);
Log.v(TAG,"updatePrefs() - mReadTimeoutPeriod = "+mReadTimeoutPeriod);
} catch (Exception ex) {
Log.v(TAG,"updatePrefs() - Problem parsing preferences!");
mUtil.writeToSysLogFile("SdDataSourceNetwork().updatePrefs() - " +ex.toString());
@@ -156,9 +164,7 @@ public class SdDataSourceNetwork extends SdDataSource {
}
/**
* Retrive the current Seizure Detector Data from the server.
* Uses the DownloadSdDataTask class to download the data in the
* background. The data is processed in DownloadSdDataTask.onPostExecute().
* Accept an alarm remotely using a http GET request.
*/
@Override
public void acceptAlarm() {
@@ -203,8 +209,8 @@ public class SdDataSourceNetwork extends SdDataSource {
try {
URL url = new URL(myurl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setReadTimeout(5000 /* milliseconds */);
conn.setConnectTimeout(5000 /* milliseconds */);
conn.setReadTimeout(mReadTimeoutPeriod /* milliseconds */);
conn.setConnectTimeout(mConnnectTimeoutPeriod /* milliseconds */);
conn.setRequestMethod("GET");
conn.setDoInput(true);
// Starts the query

View File

@@ -245,7 +245,7 @@ public class SdDataSourcePebble extends SdDataSource {
*/
public void updatePrefs() {
Log.v(TAG, "updatePrefs()");
mUtil.writeToSysLogFile("SdDataSourcePebble.updatePrefs()");
//mUtil.writeToSysLogFile("SdDataSourcePebble.updatePrefs()");
SharedPreferences SP = PreferenceManager
.getDefaultSharedPreferences(mContext);
try {
@@ -527,7 +527,7 @@ public class SdDataSourcePebble extends SdDataSource {
*/
public void getPebbleSdSettings() {
Log.v(TAG, "getWatchSdSettings() - sending required settings to pebble");
mUtil.writeToSysLogFile("SdDataSourcePebble.getWatchSdSettings()");
//mUtil.writeToSysLogFile("SdDataSourcePebble.getPebbleSdSettings()");
sendPebbleSdSettings();
//Log.v(TAG, "getWatchSdSettings() - requesting settings from pebble");
//mUtil.writeToSysLogFile("SdDataSourcePebble.getWatchSdSettings() - and request settings from pebble");
@@ -545,7 +545,7 @@ public class SdDataSourcePebble extends SdDataSource {
*/
public void sendPebbleSdSettings() {
Log.v(TAG, "sendPebblSdSettings() - preparing settings dictionary.. mSampleFreq=" + mSampleFreq);
mUtil.writeToSysLogFile("SdDataSourcePebble.sendWatchSdSettings()");
//mUtil.writeToSysLogFile("SdDataSourcePebble.sendPebbleSdSettings()");
// Watch Settings
final PebbleDictionary setDict = new PebbleDictionary();

View File

@@ -41,6 +41,7 @@ import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.AssetManager;
import android.content.SharedPreferences;
import android.graphics.drawable.Drawable;
@@ -48,6 +49,8 @@ import android.location.Location;
import android.media.AudioManager;
import android.media.RingtoneManager;
import android.media.ToneGenerator;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.Uri;
import android.os.CountDownTimer;
import android.os.Environment;
@@ -124,6 +127,8 @@ public class SdServer extends Service implements SdDataReceiver, SdLocationRecei
private Handler mHandler;
private ToneGenerator mToneGenerator;
private NetworkBroadcastReceiver mNetworkBroadcastReceiver;
private final IBinder mBinder = new SdBinder();
/**
@@ -554,12 +559,12 @@ public class SdServer extends Service implements SdDataReceiver, SdLocationRecei
} else {
if (mAudibleFaultWarning) {
if (mMp3Alarm) {
Log.v(TAG,"making MP3 alarm beep");
Log.v(TAG, "making MP3 alarm beep");
// From https://stackoverflow.com/questions/4441334/how-to-play-an-android-notification-sound
// This plays an audio file as a notification, using the notification sound channel.
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
Uri soundUri = Uri.parse("android.resource://"+getPackageName()+"/raw/fault");
Uri soundUri = Uri.parse("android.resource://" + getPackageName() + "/raw/fault");
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(getApplicationContext())
.setSound(soundUri); //This sets the sound to play
@@ -576,6 +581,7 @@ public class SdServer extends Service implements SdDataReceiver, SdLocationRecei
} else {
startFaultTimer();
Log.v(TAG, "faultWarningBeep() - starting Fault Timer");
mUtil.writeToSysLogFile("faultWarningBeep() - starting Fault Timer");
}
}
@@ -590,12 +596,12 @@ public class SdServer extends Service implements SdDataReceiver, SdLocationRecei
} else {
if (mAudibleAlarm) {
if (mMp3Alarm) {
Log.v(TAG,"making MP3 alarm beep");
Log.v(TAG, "making MP3 alarm beep");
// From https://stackoverflow.com/questions/4441334/how-to-play-an-android-notification-sound
// This plays an audio file as a notification, using the notification sound channel.
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
Uri soundUri = Uri.parse("android.resource://"+getPackageName()+"/raw/alarm");
Uri soundUri = Uri.parse("android.resource://" + getPackageName() + "/raw/alarm");
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(getApplicationContext())
.setSound(soundUri); //This sets the sound to play
@@ -620,12 +626,12 @@ public class SdServer extends Service implements SdDataReceiver, SdLocationRecei
} else {
if (mAudibleWarning) {
if (mMp3Alarm) {
Log.v(TAG,"making MP3 alarm beep");
Log.v(TAG, "making MP3 alarm beep");
// From https://stackoverflow.com/questions/4441334/how-to-play-an-android-notification-sound
// This plays an audio file as a notification, using the notification sound channel.
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
Uri soundUri = Uri.parse("android.resource://"+getPackageName()+"/raw/warning");
Uri soundUri = Uri.parse("android.resource://" + getPackageName() + "/raw/warning");
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(getApplicationContext())
.setSound(soundUri); //This sets the sound to play
@@ -663,10 +669,19 @@ public class SdServer extends Service implements SdDataReceiver, SdLocationRecei
Time tnow = new Time(Time.getCurrentTimezone());
tnow.setToNow();
String dateStr = tnow.format("%H:%M:%S %d/%m/%Y");
SmsManager sm = SmsManager.getDefault();
// 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);
// sm.sendTextMessage(mSMSNumbers[i], null, mSMSMsgStr + " - " + dateStr, null, null);
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setDataAndType(Uri.parse("smsto:"), "vnd.android-dir/mms-sms");
intent.putExtra("sms_body", mSMSMsgStr + " - " + dateStr);
intent.putExtra("address", new String(mSMSNumbers[i]));
if (intent.resolveActivity(getPackageManager()) != null) {
startActivity(intent);
} else {
Log.v(TAG, "sendSMSAlarm() - Failed to send SMS.");
}
}
} else {
Log.v(TAG, "sendSMSAlarm() - SMS Alarms Disabled - not doing anything!");
@@ -776,7 +791,7 @@ public class SdServer extends Service implements SdDataReceiver, SdLocationRecei
// Start timer to remove the cancel audible flag
// after the required period.
if (mCancelAudibleTimer != null) {
Log.v(TAG, "onCreate(): cancel audible timer already running - cancelling it.");
Log.v(TAG, "cancelAudible(): cancel audible timer already running - cancelling it.");
mCancelAudibleTimer.cancel();
mCancelAudibleTimer = null;
mCancelAudible = false;
@@ -804,7 +819,8 @@ public class SdServer extends Service implements SdDataReceiver, SdLocationRecei
/**
* Start the web server (on port 8080)
* Start the web server (on port 8080), and register for network connectivity events so we can log
* problems.
*/
protected void startWebServer() {
Log.v(TAG, "startWebServer()");
@@ -820,10 +836,16 @@ public class SdServer extends Service implements SdDataReceiver, SdLocationRecei
} else {
Log.v(TAG, "startWebServer(): server already running???");
}
mNetworkBroadcastReceiver = new NetworkBroadcastReceiver();
IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
//filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
getApplicationContext().registerReceiver(mNetworkBroadcastReceiver, filter);
}
/**
* Stop the web server - FIXME - doesn't seem to do anything!
* And de-register for network connectivity events.
*/
protected void stopWebServer() {
Log.v(TAG, "SdServer.stopWebServer()");
@@ -836,8 +858,49 @@ public class SdServer extends Service implements SdDataReceiver, SdLocationRecei
}
webServer = null;
}
getApplicationContext().unregisterReceiver(mNetworkBroadcastReceiver);
}
private class NetworkBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Log.v(TAG, "NetworkBroadCastReceiver.onReceive");
//mUtil.writeToSysLogFile("Network State Changed" + intent.getAction());
//mUtil.showToast("Network State Changed" + intent.getAction());
ConnectivityManager cm =
(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetwork = null;
try {
activeNetwork = cm.getActiveNetworkInfo();
} catch (Exception e) {
Log.v(TAG, "NetworkBroadcastReceiver - failed to retrieve active network info");
mUtil.writeToSysLogFile("NetworkBroadcastReceiver - failed to retrieve active network info");
Log.v(TAG, e.toString());
}
boolean isConnected = activeNetwork != null &&
activeNetwork.isConnectedOrConnecting();
if (isConnected) {
boolean isWiFi = activeNetwork.getType() == ConnectivityManager.TYPE_WIFI;
if (!isWiFi) {
Log.v(TAG, "NetworkBroadcastReceiver - no Wifi Connection");
mUtil.writeToSysLogFile("Network State Changed - no Wifi Connection");
mUtil.showToast("Network State Changed - no Wifi Connection");
} else {
Log.v(TAG, "NetworkBroadcastReceiver - Wifi Connected");
mUtil.writeToSysLogFile("Network State Changed - Wifi Connected");
mUtil.showToast("Network State Changed - Wifi Connected");
}
} else {
Log.v(TAG, "NetworkBroadcastReceiver - No Active Network");
mUtil.writeToSysLogFile("Network State Changed - No Active Network");
mUtil.showToast("Network State Changed - No Active Network");
}
}
}
/**
* Log data to SD card if mLogData is set in preferences.
*/
@@ -1022,8 +1085,10 @@ public class SdServer extends Service implements SdDataReceiver, SdLocationRecei
public void startFaultTimer() {
if (mFaultTimer != null) {
Log.v(TAG, "startFaultTimer(): fault timer already running - not doing anything.");
mUtil.writeToSysLogFile("startFaultTimer() - fault timer already running");
} else {
Log.v(TAG, "startFaultTimer(): starting fault timer.");
mUtil.writeToSysLogFile("startFaultTimer() - starting fault timer");
runOnUiThread(new Runnable() {
public void run() {
mFaultTimerCompleted = false;
@@ -1039,11 +1104,13 @@ public class SdServer extends Service implements SdDataReceiver, SdLocationRecei
public void stopFaultTimer() {
if (mFaultTimer != null) {
Log.v(TAG, "stopFaultTimer(): fault timer already running - cancelling it.");
mUtil.writeToSysLogFile("stopFaultTimer() - stopping fault timer");
mFaultTimer.cancel();
mFaultTimer = null;
mFaultTimerCompleted = false;
} else {
Log.v(TAG, "stopFaultTimer(): fault timer not running - not doing anything.");
//mUtil.writeToSysLogFile("stopFaultTimer() - fault timer not running");
}
}

View File

@@ -496,6 +496,8 @@ public class StartupActivity extends Activity {
+ "so I can get in touch if necessary.\nThank you! Graham \ngraham@openseizuredetector.org.uk "
+ "\n\nChanges in this version:"
+ "\n- Added support for 'Wifi Datasources' - initially for the experimental ESP8266 based seizure detector."
+ "\n- Improved logging of network status to help debugging network data source issues."
+ "\n- "
);
// This makes the links display as links, but they do not respond to clicks for some reason...
Linkify.addLinks(s, Linkify.ALL);

View File

@@ -12,15 +12,15 @@
android:summary="Period between server data requests in miliseconds."
android:title="Data Update Period (ms)" />
<EditTextPreference
android:defaultValue="2000"
android:key="ConnTimeout"
android:defaultValue="5000"
android:key="ConnectTimeoutPeriod"
android:numeric="integer"
android:summary=""
android:title="Connection Timeout (ms)" />
android:title="Connection Timeout Period (ms)" />
<EditTextPreference
android:defaultValue="2000"
android:key="SoTimeout"
android:defaultValue="5000"
android:key="ReadTimeoutPeriod"
android:numeric="integer"
android:summary=""
android:title="So Timeout (ms)" />
android:title="Read Timeout Period (ms)" />
</PreferenceScreen>

View File

@@ -2,14 +2,22 @@
buildscript {
repositories {
jcenter()
maven {
url 'https://maven.google.com/'
name 'Google'
}
}
dependencies {
classpath 'com.android.tools.build:gradle:3.0.1'
classpath 'com.android.tools.build:gradle:3.2.1'
}
}
allprojects {
repositories {
jcenter()
maven {
url 'https://maven.google.com/'
name 'Google'
}
}
}

Binary file not shown.

Binary file not shown.

62
doc/Developer_Guide.txt Normal file
View File

@@ -0,0 +1,62 @@
OpenSeizureDetector Developer Guide (for V3.0 and higher)
The OpenSeizureDetector main app is the alarm system. It monitors one
or more data sources which send it seizure detector data using broadcast
itents. If alarm conditions are experienced it will raise audible alarms
and SMS alarms if configured in the settings.
If seizure detector data is not received at the expected time, it will raise
fault alarms to warn the user of a problem.
The OpenSeizureDetector StartUpActivity does the following:
- Start the SdServer background service that does the seizure detector
monitoring.
- Monitors SdServer for a number of conditions to be met, which shows that it
is running correctly.
- Once it is running correctly, StartUpActivity exits, and MainActivity starts
to provide user display of seizure detector data.
The MainActivity does the following:
- Monitor the status of the SdServer background service, and display data
relating to the server on the screen for the user.
- Provide user interface to cancel audible alarms, accept alarms, and
open settings editing screens to configure OpenSeizureDetector.
The SdServer background service does the following.
- Reads configuration data from local stored preferences, including which
data sources are to be used.
- Sends a broadcast intent to the required data sources asking them to start.
- Monitors for broadcast intents from the data sources which contain seizure
detector data.
- Checks the time since the last data was received from the data source, and
if it is longer than a specified period, attempts to re-start the data
source. If data is still not received, raises a system fault alarm.
- Checks the seizure detector data received from the data source, and raises
audible and SMS alarms if an alarm state is detected.
- Provieds a web interface to allow users to monitor the seizure detector
status using a web browser or other http client.
Indidual Data Source apps are separate .apk packages. They provide:
- A broadcast receiver that will receive start/stop requests from the
main OpenSeizureDetector SdServer process.
- A background SdDataSourceService service that interfaces with the seizure
detector hardware (e.g. a smart watch) and receives data from the hardware.
It carries out the necessary processing to determine if an alarm condition
is present, and sends a broadcast intent to the OpenSeizureDetector SdServer
service with the data when it has been processed.
- A configuration user interface to allow the data source to be configured.
Version V3.0 will initially provide two data sources that will reproduce the
functionality of V2.5.x:
- SdDataSourcePebble - pebble watch data source
- SdDataSourceNetwork - actively request data from the web interface of another
OpenSeizureDetector instance.
These will be packages uk.org.openseizuredetector.datasource.pebble and
uk.org.openseizuredetector.datasource.network
Future data sources will be:
- SdDataSourceGarmin - uses a Garmin ConnectIQ smart watch.
- SdDataSourceAndroidWear - Uses an Android Wear smart watch.
- SdDataSourceAudio - uses the microphone on the phone to detect abnormal sounds.

View File

@@ -1,6 +1,6 @@
#Sun Dec 03 09:39:36 GMT 2017
#Wed Dec 26 18:31:40 GMT 2018
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip