From 2124dc321418cd4be1c59140af8f697b07dd6fcf Mon Sep 17 00:00:00 2001 From: ktind Date: Sun, 7 Sep 2014 19:45:00 -0500 Subject: [PATCH] -Added a special notification for monitor errors (MQTT disconnect, mongo disconnect). I'm thinking this will need to be moved into the Android Notification and make Android notification monitor a required monitor. -General code cleanup -Stabilization of the MQTT Manager (specific conditions caused it to loose the ping timer) -Added some event correlation in the analyzer to remove duplicate/redundant/known/inferred messages -Fixed a bug that caused the incorrect last download for a monitor to be retrieved -Added more useful messages in the notification for each device -Removed Special value as a download status - didn't make sense. Moved the detection of special value to the G4 analyzer -Added ACRA code to report IO errors to Dexcom G4's -Removed unnecessary "isNew" attribute from EGV records --- mobile/build.gradle | 4 +- .../com/ktind/cgm/bgscout/AbstractDevice.java | 59 ++---- .../cgm/bgscout/AbstractDownloadAnalyzer.java | 6 +- .../ktind/cgm/bgscout/AbstractMonitor.java | 21 +-- .../ktind/cgm/bgscout/AbstractPollDevice.java | 1 - .../ktind/cgm/bgscout/AbstractPushDevice.java | 2 - .../com/ktind/cgm/bgscout/AlertMessage.java | 38 +++- .../ktind/cgm/bgscout/AnalyzedDownload.java | 169 +++++++++++------ .../bgscout/AndroidNotificationMonitor.java | 32 +--- .../java/com/ktind/cgm/bgscout/BGScout.java | 6 +- .../cgm/bgscout/CGMDownloadAnalyzer.java | 173 +++++++++--------- .../com/ktind/cgm/bgscout/Conditions.java | 3 +- .../com/ktind/cgm/bgscout/DexcomG4/G4.java | 7 - .../cgm/bgscout/DexcomG4/G4Constants.java | 13 +- .../com/ktind/cgm/bgscout/DownloadObject.java | 3 - .../com/ktind/cgm/bgscout/DownloadStatus.java | 2 +- .../java/com/ktind/cgm/bgscout/EGVRecord.java | 32 ++-- .../com/ktind/cgm/bgscout/G4CGMDevice.java | 57 ++---- .../ktind/cgm/bgscout/G4DownloadAnalyzer.java | 47 +++-- .../com/ktind/cgm/bgscout/MainActivity.java | 18 +- .../com/ktind/cgm/bgscout/MockDevice.java | 2 +- .../ktind/cgm/bgscout/MongoUploadMonitor.java | 63 ++++--- .../ktind/cgm/bgscout/NightScoutUpload.java | 4 +- .../com/ktind/cgm/bgscout/NotifHelper.java | 83 +++++++++ .../com/ktind/cgm/bgscout/PebbleMonitor.java | 4 +- .../ktind/cgm/bgscout/RemoteMQTTDevice.java | 1 + .../java/com/ktind/cgm/bgscout/TimeTools.java | 59 ++++++ .../com/ktind/cgm/bgscout/mqtt/MQTTMgr.java | 50 +++-- mobile/src/main/res/layout/activity_main.xml | 2 +- mobile/src/main/res/values/strings.xml | 4 +- mobile/src/main/res/xml/app_tracker.xml | 2 +- 31 files changed, 575 insertions(+), 392 deletions(-) create mode 100644 mobile/src/main/java/com/ktind/cgm/bgscout/NotifHelper.java create mode 100644 mobile/src/main/java/com/ktind/cgm/bgscout/TimeTools.java diff --git a/mobile/build.gradle b/mobile/build.gradle index e180926..4d7b922 100644 --- a/mobile/build.gradle +++ b/mobile/build.gradle @@ -8,8 +8,8 @@ android { applicationId "com.ktind.cgm.bgscout" minSdkVersion 16 targetSdkVersion 20 - versionCode 6 - versionName "1.0.6" + versionCode 8 + versionName "0.0.8" } buildTypes { release { diff --git a/mobile/src/main/java/com/ktind/cgm/bgscout/AbstractDevice.java b/mobile/src/main/java/com/ktind/cgm/bgscout/AbstractDevice.java index 9ce6933..8607c55 100644 --- a/mobile/src/main/java/com/ktind/cgm/bgscout/AbstractDevice.java +++ b/mobile/src/main/java/com/ktind/cgm/bgscout/AbstractDevice.java @@ -8,11 +8,12 @@ import android.database.Cursor; import android.net.Uri; import android.os.BatteryManager; -import android.os.Looper; import android.preference.PreferenceManager; import android.provider.ContactsContract; import android.util.Log; +import com.google.android.gms.analytics.GoogleAnalytics; + import java.io.IOException; import java.util.ArrayList; import java.util.Date; @@ -73,10 +74,8 @@ public AbstractDevice(String name, int deviceID, Context context, String driver) this.driver=driver; this.setDeviceID(deviceID); this.setContext(context); -// this.setHandler(mH); this.deviceIDStr = "device_" + String.valueOf(getDeviceID()); sharedPref=PreferenceManager.getDefaultSharedPreferences(context); -// monitors=new ArrayList(); state=State.STOPPED; String contactDataUri=sharedPref.getString(deviceIDStr+"_contact_data_uri",Uri.EMPTY.toString()); @@ -144,16 +143,6 @@ public void start(){ context.registerReceiver(uiQuery,intentFilter); } - -// public void mainloop(){ -// while(started){ -// -// } -// } -// public void setHandler(Handler mH){ -// this.mHandler=mH; -// } - public float getUploaderBattery(){ IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED); Intent batteryStatus = context.registerReceiver(null, ifilter); @@ -212,14 +201,8 @@ public void fireMonitors(DownloadObject dl) { // FIXME why is monitors set to null here sometimes? if (monitors==null) return; - for (AbstractMonitor monitor:monitors){ -// try { -// monitor.process(getLastDownloadObject()); - monitor.process(dl); -// } catch (DeviceException e) { -// Log.w(TAG,e.getMessage()); -// } - } + for (AbstractMonitor monitor:monitors) + monitor.process(dl); stats.stopMonitorTimer(); } @@ -308,20 +291,12 @@ public Trend getLastTrend() throws NoDataException { protected void onDownload(DownloadObject dl){ sendToUI(); -// try { - if (Looper.getMainLooper().getThread()==Thread.currentThread()) - Log.d(TAG,"ON THE MAIN Thread!!!"); - else - Log.d(TAG, "Not on the MAIN Thread ("+Thread.currentThread().getName()+"/"+Thread.currentThread().getState()+")"); - SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(context); - SharedPreferences.Editor editor = sharedPref.edit(); - editor.putLong(deviceIDStr +"_last_"+driver, dl.getLastReadingDate().getTime()); - editor.apply(); -// } catch (NoDataException e) { -// Log.i(TAG,"No data on download"); -//// e.printStackTrace(); -// } +// SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(context); +// SharedPreferences.Editor editor = sharedPref.edit(); +// editor.putLong(deviceIDStr +"_last_"+driver, dl.getLastReadingDate().getTime()); +// editor.apply(); fireMonitors(dl); + GoogleAnalytics.getInstance(context.getApplicationContext()).dispatchLocalHits(); } public void sendToUI(){ @@ -334,17 +309,13 @@ public void sendToUI(){ } catch (NoDataException e) { downloadObject=new DownloadObject(); Log.e(TAG,"Sending empty DownloadObject",e); -// e.printStackTrace(); } finally { if (downloadObject!=null) { downloadObject.setDeviceID(deviceIDStr); downloadObject.setDeviceName(getName()); -// downloadObject.buildMessage(); uiIntent.putExtra("download", downloadObject); } } -// Log.d(TAG,"Sending broadcast to UI: "+uiIntent.getExtras().getString("download","")); - context.sendBroadcast(uiIntent); } @@ -354,8 +325,8 @@ public void setRemote(boolean remote) { @Override public void stop() { - if (state==State.STOPPED) { - Log.w(TAG,getName()+"/"+getDeviceType()+" has already been stopped"); + if (state==State.STOPPED || state==State.STOPPING) { + Log.w(TAG,getName()+"/"+getDeviceType()+" has already been stopped or is being stopped"); return; } state=State.STOPPING; @@ -365,13 +336,6 @@ public void stop() { started=false; } -// public enum State{ -// STARTING, -// STARTED, -// STOPPING, -// STOPPED -// } - public class AlarmReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { @@ -390,7 +354,6 @@ private String getPhone(Uri dataUri){ String id=dataUri.getLastPathSegment(); Log.d(TAG,"id="+id); Log.d(TAG,"URI="+dataUri); - // TODO Limit fields returned to specific field that we want? Phone? Cursor cursor = context.getContentResolver().query(ContactsContract.Data.CONTENT_URI, null, ContactsContract.Data._ID + " = ?", new String[]{id}, null); int numIdx = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER); Log.d(TAG, "cursor.getCount(): " + cursor.getCount()); diff --git a/mobile/src/main/java/com/ktind/cgm/bgscout/AbstractDownloadAnalyzer.java b/mobile/src/main/java/com/ktind/cgm/bgscout/AbstractDownloadAnalyzer.java index 528a7ff..a01248c 100644 --- a/mobile/src/main/java/com/ktind/cgm/bgscout/AbstractDownloadAnalyzer.java +++ b/mobile/src/main/java/com/ktind/cgm/bgscout/AbstractDownloadAnalyzer.java @@ -26,10 +26,6 @@ package com.ktind.cgm.bgscout; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Set; - /** * Created by klee24 on 8/28/14. */ @@ -51,4 +47,6 @@ public AnalyzedDownload analyze() { return this.downloadObject; } + abstract protected void correlateMessages(); + } diff --git a/mobile/src/main/java/com/ktind/cgm/bgscout/AbstractMonitor.java b/mobile/src/main/java/com/ktind/cgm/bgscout/AbstractMonitor.java index 9c9e506..3903868 100644 --- a/mobile/src/main/java/com/ktind/cgm/bgscout/AbstractMonitor.java +++ b/mobile/src/main/java/com/ktind/cgm/bgscout/AbstractMonitor.java @@ -43,15 +43,12 @@ abstract public class AbstractMonitor implements MonitorInterface { protected String name; protected boolean allowVirtual=false; protected String monitorType="generic"; -// protected int highThreshold=180; -// protected int lowThreshold=60; protected int deviceID; protected String deviceIDStr; protected Context context; protected SharedPreferences sharedPref; protected long lastSuccessDate; protected State state; -// protected EGVLimits egvLimits; public AbstractMonitor(String n,int devID,Context context, String monitorName){ this.setName(n); @@ -61,7 +58,7 @@ public AbstractMonitor(String n,int devID,Context context, String monitorName){ this.monitorType=monitorName; sharedPref = PreferenceManager.getDefaultSharedPreferences(context); // Default to the last 2.5 hours as the "last successful download" - this.lastSuccessDate=sharedPref.getLong(deviceIDStr+monitorType,new Date().getTime()-900000L); + this.lastSuccessDate=sharedPref.getLong("last_"+deviceIDStr+"_"+monitorType,new Date().getTime()-900000L); Log.d(TAG,"Setting lastSuccessDate to: "+new Date(lastSuccessDate)); } @@ -108,7 +105,7 @@ final public void process(DownloadObject d) { long startTime=System.currentTimeMillis(); Log.d(TAG,"Monitor "+name+" has fired for "+monitorType); if (isAllowVirtual() || ! d.isRemoteDevice()){ - lastSuccessDate=sharedPref.getLong(deviceIDStr+monitorType,new Date().getTime()-900000L); + lastSuccessDate=sharedPref.getLong("last_"+deviceIDStr+"_"+monitorType,new Date().getTime()-900000L); Log.d(TAG, "Trimming data for monitor "+name+"/"+monitorType); final DownloadObject dl=new DownloadObject(d); dl.setEgvRecords(trimReadingsAfter(getlastSuccessDate(), d.getEgvArrayListRecords())); @@ -139,7 +136,7 @@ public long getlastSuccessDate(){ // It is up to each implementation to save the last successful date. public void savelastSuccessDate(long date){ SharedPreferences.Editor editor=sharedPref.edit(); - editor.putLong(deviceIDStr+monitorType,date); + editor.putLong("last_"+deviceIDStr+"_"+monitorType,date); editor.apply(); } @@ -173,16 +170,4 @@ public ArrayList trimReadingsAfter(Long afterDateLong, ArrayList= Build.VERSION_CODES.KITKAT) alarmMgr.setExact(AlarmManager.RTC_WAKEUP,getNextReadingTime().getTime(),alarmIntent); else diff --git a/mobile/src/main/java/com/ktind/cgm/bgscout/AbstractPushDevice.java b/mobile/src/main/java/com/ktind/cgm/bgscout/AbstractPushDevice.java index 6701ae8..cac12c5 100644 --- a/mobile/src/main/java/com/ktind/cgm/bgscout/AbstractPushDevice.java +++ b/mobile/src/main/java/com/ktind/cgm/bgscout/AbstractPushDevice.java @@ -32,8 +32,6 @@ public AbstractPushDevice(String n, int deviceID, Context appContext, String dri super(n, deviceID, appContext, driver); } -// abstract void onDataReady(DownloadObject ddo); - @Override public void onDownload(DownloadObject dl){ stats.addDownload(); diff --git a/mobile/src/main/java/com/ktind/cgm/bgscout/AlertMessage.java b/mobile/src/main/java/com/ktind/cgm/bgscout/AlertMessage.java index 3dbefea..7e174c5 100644 --- a/mobile/src/main/java/com/ktind/cgm/bgscout/AlertMessage.java +++ b/mobile/src/main/java/com/ktind/cgm/bgscout/AlertMessage.java @@ -32,10 +32,12 @@ public class AlertMessage { public AlertLevels alertLevel; public String message; + public Conditions condition; - public AlertMessage(AlertLevels aL,String msg){ - alertLevel=aL; - message=msg; + public AlertMessage(AlertLevels aL,String msg,Conditions condition){ + this.alertLevel=aL; + this.message=msg; + this.condition=condition; } public AlertLevels getAlertLevel() { @@ -53,4 +55,34 @@ public String getMessage() { public void setMessage(String message) { this.message = message; } + + public Conditions getCondition() { + return condition; + } + + public void setCondition(Conditions condition) { + this.condition = condition; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + AlertMessage that = (AlertMessage) o; + + if (alertLevel != that.alertLevel) return false; + if (condition != that.condition) return false; + if (!message.equals(that.message)) return false; + + return true; + } + + @Override + public int hashCode() { + int result = alertLevel.hashCode(); + result = 31 * result + message.hashCode(); + result = 31 * result + condition.hashCode(); + return result; + } } diff --git a/mobile/src/main/java/com/ktind/cgm/bgscout/AnalyzedDownload.java b/mobile/src/main/java/com/ktind/cgm/bgscout/AnalyzedDownload.java index 9d7c062..d672235 100644 --- a/mobile/src/main/java/com/ktind/cgm/bgscout/AnalyzedDownload.java +++ b/mobile/src/main/java/com/ktind/cgm/bgscout/AnalyzedDownload.java @@ -26,20 +26,24 @@ package com.ktind.cgm.bgscout; +import android.util.Log; + import java.util.ArrayList; +import java.util.Iterator; /** * Created by klee24 on 8/28/14. */ public class AnalyzedDownload extends DownloadObject { + protected static final String TAG = AnalyzedDownload.class.getSimpleName(); protected ArrayList messages=new ArrayList(); - protected boolean hasCritical=false; - protected boolean hasInfo=false; - protected boolean hasWarn=false; - protected boolean criticalHigh=false; - protected boolean criticalLow=false; - protected boolean warnHigh=false; - protected boolean warnLow=false; +// protected boolean hasCritical=false; +// protected boolean hasInfo=false; +// protected boolean hasWarn=false; +// protected boolean criticalHigh=false; +// protected boolean criticalLow=false; +// protected boolean warnHigh=false; +// protected boolean warnLow=false; protected ArrayList conditions=new ArrayList(); AnalyzedDownload(DownloadObject dl){ @@ -50,33 +54,34 @@ public ArrayList getMessages() { return messages; } - public void addMessage(AlertMessage message,Conditions condition){ - if (! conditions.contains(condition) && condition!=Conditions.NONE) - conditions.add(condition); - if (message.getAlertLevel()==AlertLevels.INFO) - hasInfo=true; - if (message.getAlertLevel()==AlertLevels.WARN) - hasWarn=true; - if (message.getAlertLevel()==AlertLevels.CRITICAL) - hasCritical=true; - this.messages.add(message); + public void addMessage(AlertMessage message){ + if (! conditions.contains(message.getCondition()) && message.getCondition()!=Conditions.NONE) + conditions.add(message.getCondition()); +// if (message.getAlertLevel()==AlertLevels.INFO) +// hasInfo=true; +// if (message.getAlertLevel()==AlertLevels.WARN) +// hasWarn=true; +// if (message.getAlertLevel()==AlertLevels.CRITICAL) +// hasCritical=true; + if (!messages.contains(message)) + this.messages.add(message); } public void setMessages(ArrayList messages) { this.messages = messages; } - public boolean hasCritical() { - return hasCritical; - } - - public boolean hasInfo() { - return hasInfo; - } - - public boolean hasWarn() { - return hasWarn; - } +// public boolean hasCritical() { +// return hasCritical; +// } +// +// public boolean hasInfo() { +// return hasInfo; +// } +// +// public boolean hasWarn() { +// return hasWarn; +// } public ArrayList getAlertsForLevel(AlertLevels alertLevel){ ArrayList response=new ArrayList(); @@ -87,43 +92,101 @@ public ArrayList getAlertsForLevel(AlertLevels alertLevel){ return response; } - public boolean isCriticalHigh() { - return criticalHigh; - } - - public void setCriticalHigh(boolean criticalHigh) { - this.criticalHigh = criticalHigh; - } - - public boolean isCriticalLow() { - return criticalLow; - } +// public boolean isCriticalHigh() { +// return criticalHigh; +// } +// +// public void setCriticalHigh(boolean criticalHigh) { +// this.criticalHigh = criticalHigh; +// } +// +// public boolean isCriticalLow() { +// return criticalLow; +// } +// +// public void setCriticalLow(boolean criticalLow) { +// this.criticalLow = criticalLow; +// } +// +// public boolean isWarnHigh() { +// return warnHigh; +// } +// +// public void setWarnHigh(boolean warnHigh) { +// this.warnHigh = warnHigh; +// } +// +// public boolean isWarnLow() { +// return warnLow; +// } +// +// public void setWarnLow(boolean warnLow) { +// this.warnLow = warnLow; +// } - public void setCriticalLow(boolean criticalLow) { - this.criticalLow = criticalLow; + public ArrayList getConditions() { + return conditions; } - public boolean isWarnHigh() { - return warnHigh; + public ArrayList getMessagesByCondition(Conditions... conditions){ + ArrayList result=new ArrayList(); + for (AlertMessage msg:messages){ + for (Conditions condition:conditions) { + if (msg.getCondition() == condition) + result.add(msg); + } + } + return result; } - public void setWarnHigh(boolean warnHigh) { - this.warnHigh = warnHigh; + public ArrayList getMessagesByCriticality(AlertLevels... levels){ + ArrayList result=new ArrayList(); + for (AlertMessage msg:messages){ + for (AlertLevels level:levels) { + if (msg.getAlertLevel() == level) + result.add(msg); + } + } + return result; } - public boolean isWarnLow() { - return warnLow; - } + public int removeMessageByCondition(Conditions... conditions){ + int count=0; - public void setWarnLow(boolean warnLow) { - this.warnLow = warnLow; - } + for (Iterator iterator = messages.iterator(); iterator.hasNext(); ) { + for (Conditions condition:conditions) { + AlertMessage record = iterator.next(); + if (record.condition == condition) { + Log.d(TAG, "Removed message: "+record.getMessage()); + Log.d(TAG, "Search condition: "+condition+" Message condition: "+record.condition); + iterator.remove(); + } + } + } - public ArrayList getConditions() { - return conditions; +// for (AlertMessage message:messages){ +// for (Conditions condition:conditions) { +// if (message.condition == condition){ +// messages.remove(message); +// count+=1; +// } +// } +// } + return count; } public void addCondition(Conditions condition) { this.conditions.add(condition); } + +// public void deDup(){ +// for (int index=0;index0) lastKnownGood = dl; - // TODO add devicetype to the download object so that we can instantiate the proper analyzer - AbstractDownloadAnalyzer downloadAnalyzer=new G4DownloadAnalyzer(dl, context); - analyzedDownload=downloadAnalyzer.analyze(); + // FIXME violates the open/closed principle... have to change this class if any new devices are added. Look into DI + if (dl.getDriver().equals(G4Constants.DRIVER)) { + AbstractDownloadAnalyzer downloadAnalyzer = new G4DownloadAnalyzer(dl, context); + analyzedDownload = downloadAnalyzer.analyze(); + } else { + Log.w(TAG,"Driver unknown by the analyzer: "+dl.getDriver()); + } if (isSilenced){ long duration=new Date().getTime()-timeSilenced.getTime(); @@ -189,7 +194,7 @@ private void syncTickCounter(){ Log.d(TAG, "Setting tickCounter to " + tickCounter); } } catch (NoDataException e) { - e.printStackTrace(); +// e.printStackTrace(); } } @@ -269,7 +274,6 @@ protected void setSound(AnalyzedDownload dl){ break; } notifBuilder.setSound(uri); - } public void setTicker(AnalyzedDownload dl){ @@ -504,16 +508,9 @@ public void onReceive(Context mContext, Intent intent) { if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) { updateNotification(); isScreenOn=true; -// tickReceiver=new tickReceiver(); -// IntentFilter intentFilter = new IntentFilter("android.intent.action.TIME_TICK"); -// context.registerReceiver(tickReceiver, intentFilter); Log.d(TAG, "Kicking off tick timer"); } else if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) { -// IntentFilter intentFilter = new IntentFilter("android.intent.action.TIME_TICK"); -// context.unregisterReceiver(tickReceiver); -// tickReceiver=null; isScreenOn=false; -// Log.d(TAG, "Canceling tick timer"); } } } @@ -546,7 +543,7 @@ public void onReceive(Context mContext, Intent intent) { } tickCounter+=1; } catch (NoDataException e) { - e.printStackTrace(); +// e.printStackTrace(); } } @@ -555,13 +552,6 @@ public void onReceive(Context mContext, Intent intent) { private Bitmap getThumbnailByPhoneDataUri(Uri phoneDataUri){ String id=phoneDataUri.getLastPathSegment(); -// Cursor cursor = getContentResolver().query(ContactsContract.Data.CONTENT_URI,null, ContactsContract.Data._ID+" = ? ",new String[]{id},null); -// int rawContactIdx=cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.RAW_CONTACT_ID); -// String rawContactId=null; -// if (cursor.moveToFirst()){ -// rawContactId=cursor.getString(rawContactIdx); -// } -// cursor.close(); Cursor cursor = context.getContentResolver().query(ContactsContract.Data.CONTENT_URI,null, ContactsContract.Data._ID+" = ? ",new String[]{id},null); int thumbnailUriIdx=cursor.getColumnIndex(ContactsContract.Data.PHOTO_ID); String thumbnailId=null; @@ -579,8 +569,6 @@ private Bitmap getThumbnailByPhoneDataUri(Uri phoneDataUri){ } } cursor.close(); -// InputStream photoDataStream = ContactsContract.Contacts.openContactPhotoInputStream(getContentResolver(),uri); -// Bitmap photo=BitmapFactory.decodeStream(photoDataStream); return thumbnail; } diff --git a/mobile/src/main/java/com/ktind/cgm/bgscout/BGScout.java b/mobile/src/main/java/com/ktind/cgm/bgscout/BGScout.java index 5614e30..b756fdd 100644 --- a/mobile/src/main/java/com/ktind/cgm/bgscout/BGScout.java +++ b/mobile/src/main/java/com/ktind/cgm/bgscout/BGScout.java @@ -5,8 +5,9 @@ import com.google.android.gms.analytics.GoogleAnalytics; import com.google.android.gms.analytics.Tracker; -import org.acra.*; -import org.acra.annotation.*; +import org.acra.ACRA; +import org.acra.ReportingInteractionMode; +import org.acra.annotation.ReportsCrashes; import org.acra.sender.HttpSender; /** @@ -53,7 +54,6 @@ public class BGScout extends Application { public void onCreate() { super.onCreate(); ACRA.init(this); - } synchronized public Tracker getTracker() { diff --git a/mobile/src/main/java/com/ktind/cgm/bgscout/CGMDownloadAnalyzer.java b/mobile/src/main/java/com/ktind/cgm/bgscout/CGMDownloadAnalyzer.java index ecf8667..01e72c3 100644 --- a/mobile/src/main/java/com/ktind/cgm/bgscout/CGMDownloadAnalyzer.java +++ b/mobile/src/main/java/com/ktind/cgm/bgscout/CGMDownloadAnalyzer.java @@ -32,7 +32,6 @@ import android.preference.PreferenceManager; import android.util.Log; -import java.text.SimpleDateFormat; import java.util.Date; /** @@ -45,8 +44,6 @@ public abstract class CGMDownloadAnalyzer extends AbstractDownloadAnalyzer { protected final int DEVICEBATTERYCRITICAL =20; protected final int MAXRECORDAGE=310000; protected EGVLimits egvLimits=new EGVLimits(); -// protected EGVThresholdsEnum conditions=EGVThresholdsEnum.INRANGE; - CGMDownloadAnalyzer(DownloadObject dl,Context context) { super(dl); @@ -70,133 +67,127 @@ public abstract class CGMDownloadAnalyzer extends AbstractDownloadAnalyzer { } public AnalyzedDownload analyze() { - try { - super.analyze(); - checkDownloadStatus(); - checkUploaderBattery(); - checkCGMBattery(); - checkRecordAge(); - checkThresholdholds(); - checkLastRecordTime(); - } catch (NoDataException e) { - downloadObject.addMessage(new AlertMessage(AlertLevels.WARN,"Download did not contain any data"),Conditions.NODATA); -// e.printStackTrace(); - } + super.analyze(); + checkDownloadStatus(); + checkRecordAge(); + checkUploaderBattery(); + checkCGMBattery(); + checkThresholdholds(); + checkLastRecordTime(); + correlateMessages(); +// downloadObject.deDup(); return this.downloadObject; } protected void checkUploaderBattery(){ - if (downloadObject.getUploaderBattery() < UPLOADERBATTERYWARN) { - downloadObject.addMessage(new AlertMessage(AlertLevels.WARN, "Uploader battery is low: "+(int) downloadObject.getUploaderBattery()),Conditions.UPLOADERLOW); - } else if (downloadObject.getUploaderBattery() < UPLOADERBATTERYCRITICAL) { - downloadObject.addMessage(new AlertMessage(AlertLevels.CRITICAL, "Uploader battery is critically low: "+(int) downloadObject.getUploaderBattery()),Conditions.UPLOADERCRITICALLOW); + // FIXME this breaks i18n possibilties + String verb=(downloadObject.getConditions().contains(Conditions.STALEDATA))?"was":"is"; + if (downloadObject.getUploaderBattery() < UPLOADERBATTERYCRITICAL){ + downloadObject.addMessage(new AlertMessage(AlertLevels.CRITICAL, "Uploader battery " + verb + " critically low: " + (int) downloadObject.getUploaderBattery(), Conditions.UPLOADERCRITICALLOW)); + }else if (downloadObject.getUploaderBattery() < UPLOADERBATTERYWARN) { + downloadObject.addMessage(new AlertMessage(AlertLevels.WARN, "Uploader battery "+verb+" low: "+(int) downloadObject.getUploaderBattery(),Conditions.UPLOADERLOW)); } } protected void checkCGMBattery(){ if (downloadObject.getStatus()==DownloadStatus.SUCCESS) { - if (downloadObject.getDeviceBattery() < DEVICEBATTERYWARN) { - downloadObject.addMessage(new AlertMessage(AlertLevels.WARN, "CGM battery is low: "+downloadObject.getDeviceBattery()),Conditions.DEVICELOW); - } else if (downloadObject.getDeviceBattery() < DEVICEBATTERYCRITICAL) { - downloadObject.addMessage(new AlertMessage(AlertLevels.CRITICAL, "CGM battery is critically low"+downloadObject.getDeviceBattery()),Conditions.DEVICECRITICALLOW); + String verb=(downloadObject.getConditions().contains(Conditions.STALEDATA))?"was":"is"; + if (downloadObject.getDeviceBattery() < DEVICEBATTERYCRITICAL) { + downloadObject.addMessage(new AlertMessage(AlertLevels.CRITICAL, "CGM battery " + verb + " critically low" + downloadObject.getDeviceBattery(), Conditions.DEVICECRITICALLOW)); + }else if (downloadObject.getDeviceBattery() < DEVICEBATTERYWARN) { + downloadObject.addMessage(new AlertMessage(AlertLevels.WARN, "CGM battery "+verb+" low: "+downloadObject.getDeviceBattery(),Conditions.DEVICELOW)); } } } - protected void checkRecordAge() throws NoDataException { - Long recordAge=new Date().getTime() - downloadObject.getLastRecordReadingDate().getTime(); - if (recordAge > MAXRECORDAGE) - downloadObject.addMessage(new AlertMessage(AlertLevels.CRITICAL,"Last record is greater than "+((recordAge/1000)/60)+" minutes old"),Conditions.STALEDATA); + protected void checkRecordAge(){ + Long recordAge= null; Long downloadAge=new Date().getTime() - downloadObject.getDownloadDate().getTime(); + try { + recordAge = new Date().getTime() - downloadObject.getLastRecordReadingDate().getTime(); + // Cutdown on clutter in the notification bar... + // Only show the message for a missed reading or that the uploader isn't communicating + if (recordAge > MAXRECORDAGE && downloadAge <= MAXRECORDAGE) { + //FIXME if the record is over a month old then it will only show the date and it won't make sense to the user. Need to add a special condition. + downloadObject.addMessage(new AlertMessage(AlertLevels.CRITICAL, "CGM out of range/missed reading for " + TimeTools.getTimeDiffStr(downloadObject.getLastRecordReadingDate(),new Date()), Conditions.MISSEDREADING)); +// downloadObject.addMessage(new AlertMessage(AlertLevels.CRITICAL, "CGM out of range or missed reading for more than " + ((recordAge / 1000) / 60) + " minutes old", Conditions.MISSEDREADING)); + } + } catch (NoDataException e) { + downloadObject.addMessage(new AlertMessage(AlertLevels.WARN,"Download did not contain any data",Conditions.NODATA)); + } if (downloadAge > MAXRECORDAGE) - downloadObject.addMessage(new AlertMessage(AlertLevels.CRITICAL,"Have not heard from remote CGM for more than "+((downloadAge/1000)/60)+" minutes"),Conditions.STALEDATA); + downloadObject.addMessage(new AlertMessage(AlertLevels.CRITICAL,"Uploader inactive for "+TimeTools.getTimeDiffStr(downloadObject.getDownloadDate(),new Date()),Conditions.STALEDATA)); } protected void checkDownloadStatus(){ DownloadStatus status=downloadObject.getStatus(); switch (status){ case DEVICENOTFOUND: - downloadObject.addMessage(new AlertMessage(AlertLevels.CRITICAL,"No CGM device found"),Conditions.DEVICEDISCONNECTED); + downloadObject.addMessage(new AlertMessage(AlertLevels.CRITICAL,"No CGM device found",Conditions.DEVICEDISCONNECTED)); break; case IOERROR: - downloadObject.addMessage(new AlertMessage(AlertLevels.CRITICAL,"Unable to read or write to the CGM"),Conditions.DOWNLOADFAILED); + downloadObject.addMessage(new AlertMessage(AlertLevels.CRITICAL,"Unable to read or write to the CGM",Conditions.DOWNLOADFAILED)); break; case NODATA: - downloadObject.addMessage(new AlertMessage(AlertLevels.CRITICAL,"No data in download"),Conditions.NODATA); + downloadObject.addMessage(new AlertMessage(AlertLevels.CRITICAL,"No data in download",Conditions.NODATA)); break; case APPLICATIONERROR: - downloadObject.addMessage(new AlertMessage(AlertLevels.CRITICAL,"Unknown application error"),Conditions.UNKNOWN); + downloadObject.addMessage(new AlertMessage(AlertLevels.CRITICAL,"Unknown application error",Conditions.UNKNOWN)); break; case UNKNOWN: - downloadObject.addMessage(new AlertMessage(AlertLevels.CRITICAL,"Unknown error while trying to retrieve data from CGM"),Conditions.UNKNOWN); + downloadObject.addMessage(new AlertMessage(AlertLevels.CRITICAL,"Unknown error while trying to retrieve data from CGM",Conditions.UNKNOWN)); break; case REMOTEDISCONNECTED: - downloadObject.addMessage(new AlertMessage(AlertLevels.CRITICAL,"Unable to connect to remote devices"),Conditions.REMOTEDISCONNECTED); + downloadObject.addMessage(new AlertMessage(AlertLevels.CRITICAL,"Unable to connect to remote devices",Conditions.REMOTEDISCONNECTED)); default: break; } } - protected void checkThresholdholds() throws NoDataException { - int egv=downloadObject.getLastReading(); - Trend trend=downloadObject.getLastTrend(); - GlucoseUnit unit=downloadObject.getUnit(); - AlertLevels alertLevel=AlertLevels.INFO; - Conditions condition= Conditions.INRANGE; - if (egv > egvLimits.getCriticalHigh()) { - condition=Conditions.CRITICALHIGH; - alertLevel = AlertLevels.CRITICAL; - }else if (egv < egvLimits.getCriticalLow()) { - condition=Conditions.CRITICALLOW; - alertLevel = AlertLevels.CRITICAL; - }else if (egv > egvLimits.getWarnHigh()) { - condition=Conditions.WARNHIGH; - alertLevel = AlertLevels.WARN; - }else if (egv < egvLimits.getWarnLow()) { - condition=Conditions.WARNLOW; - alertLevel = AlertLevels.WARN; + protected void checkThresholdholds(){ + try { + int egv=0; + egv = downloadObject.getLastReading(); + Trend trend=downloadObject.getLastTrend(); + GlucoseUnit unit=downloadObject.getUnit(); + AlertLevels alertLevel=AlertLevels.INFO; + Conditions condition=Conditions.INRANGE; + if (egv > egvLimits.getCriticalHigh()) { + condition=Conditions.CRITICALHIGH; + alertLevel = AlertLevels.CRITICAL; + }else if (egv < egvLimits.getCriticalLow()) { + condition=Conditions.CRITICALLOW; + alertLevel = AlertLevels.CRITICAL; + }else if (egv > egvLimits.getWarnHigh()) { + condition=Conditions.WARNHIGH; + alertLevel = AlertLevels.WARN; + }else if (egv < egvLimits.getWarnLow()) { + condition=Conditions.WARNLOW; + alertLevel = AlertLevels.WARN; + } + String preamble=(downloadObject.getConditions().contains(Conditions.MISSEDREADING) || downloadObject.getConditions().contains(Conditions.STALEDATA))?"Last reading: ":""; + downloadObject.addMessage(new AlertMessage(alertLevel,preamble+egv+" "+unit+" "+trend,condition)); + } catch (NoDataException e) { + downloadObject.addMessage(new AlertMessage(AlertLevels.WARN,"Download did not contain any data",Conditions.NODATA)); } - downloadObject.addMessage(new AlertMessage(alertLevel,egv+" "+unit+" "+trend),condition); } - protected void checkLastRecordTime() throws NoDataException { -// String msg=new SimpleDateFormat("HH:mm:ss MM/dd").format(downloadObject.getLastRecordReadingDate()); - String msg="~"; - int timeDiff=(int) (new Date().getTime()-downloadObject.getLastRecordReadingDate().getTime()); - Log.d("XXX","Time difference: "+timeDiff); - if (timeDiff<60000) { - msg += "Now"; - }else if (timeDiff>60000 && timeDiff<3600000){ - msg += String.valueOf((timeDiff/1000)/60); - msg += "m"; - }else if (timeDiff>3600000 && timeDiff<86400000){ - msg += String.valueOf(((timeDiff/1000)/60)/24); - msg += "h"; - }else if (timeDiff>86400000 && timeDiff<604800000){ - msg += String.valueOf((((timeDiff/1000)/60)/24)/7); - msg += "w"; - }else { - msg=new SimpleDateFormat("HH:mm:ss MM/dd").format(downloadObject.getLastRecordReadingDate()); + protected void checkLastRecordTime(){ + String msg; + try { + msg=TimeTools.getTimeDiffStr(downloadObject.getLastRecordReadingDate(),new Date()); + downloadObject.addMessage(new AlertMessage(AlertLevels.CRITICAL,msg,Conditions.READINGTIME)); + } catch (NoDataException e) { + downloadObject.addMessage(new AlertMessage(AlertLevels.WARN,"Download did not contain any data",Conditions.NODATA)); } - msg+="\n"+new SimpleDateFormat("HH:mm:ss MM/dd").format(downloadObject.getLastRecordReadingDate()); - downloadObject.addMessage(new AlertMessage(AlertLevels.CRITICAL,msg),Conditions.NONE); -// msg="Download: ~"; -// timeDiff=(int) (new Date().getTime()-downloadObject.getDownloadDate().getTime()); -// Log.d("XXX","Time difference: "+timeDiff); -// if (timeDiff<60000) { -// msg += "Now"; -// }else if (timeDiff>60000 && timeDiff<3600000){ -// msg += String.valueOf((timeDiff/1000)/60); -// msg += "m"; -// }else if (timeDiff>3600000 && timeDiff<86400000){ -// msg += String.valueOf(((timeDiff/1000)/60)/24); -// msg += "h"; -// }else if (timeDiff>86400000 && timeDiff<604800000){ -// msg += String.valueOf((((timeDiff/1000)/60)/24)/7); -// msg += "w"; -// }else { -// msg=new SimpleDateFormat("HH:mm:ss MM/dd").format(downloadObject.getLastRecordReadingDate()); -// } -// downloadObject.addMessage(new AlertMessage(AlertLevels.CRITICAL,msg),Conditions.NONE); } + + @Override + protected void correlateMessages(){ + if (downloadObject.getConditions().contains(Conditions.NODATA) && downloadObject.getConditions().contains(Conditions.DEVICEDISCONNECTED)) + downloadObject.removeMessageByCondition(Conditions.NODATA); + if (downloadObject.getConditions().contains(Conditions.MISSEDREADING)) + downloadObject.removeMessageByCondition(Conditions.READINGTIME); + } + } \ No newline at end of file diff --git a/mobile/src/main/java/com/ktind/cgm/bgscout/Conditions.java b/mobile/src/main/java/com/ktind/cgm/bgscout/Conditions.java index a9d36b5..975777c 100644 --- a/mobile/src/main/java/com/ktind/cgm/bgscout/Conditions.java +++ b/mobile/src/main/java/com/ktind/cgm/bgscout/Conditions.java @@ -48,5 +48,6 @@ public enum Conditions { NONE, REMOTEDISCONNECTED, MISSEDREADING, - SPECIALVALUE + SPECIALVALUE, + READINGTIME } diff --git a/mobile/src/main/java/com/ktind/cgm/bgscout/DexcomG4/G4.java b/mobile/src/main/java/com/ktind/cgm/bgscout/DexcomG4/G4.java index 9b8c664..5a02ca8 100644 --- a/mobile/src/main/java/com/ktind/cgm/bgscout/DexcomG4/G4.java +++ b/mobile/src/main/java/com/ktind/cgm/bgscout/DexcomG4/G4.java @@ -65,17 +65,10 @@ public class G4 { CGMTransportAbstract cgmTransport; protected GlucoseUnit unit; protected Context context; -// TimeZone tz; -// long timeZoneOffset; public G4(Context context){ this.context=context; cgmTransport=new G4USBSerialTransport(context); -// Calendar cal = Calendar.getInstance(); -// tz = cal.getTimeZone(); -// timeZoneOffset=tz.getRawOffset()/1000; -// if (tz.inDaylightTime(new Date())) -// timeZoneOffset+=3600; // 1 hour for daylight time if it is observed } public int getDeviceBattery() throws OperationNotSupportedException, NoDeviceFoundException, DeviceIOException { diff --git a/mobile/src/main/java/com/ktind/cgm/bgscout/DexcomG4/G4Constants.java b/mobile/src/main/java/com/ktind/cgm/bgscout/DexcomG4/G4Constants.java index ef63774..710291e 100644 --- a/mobile/src/main/java/com/ktind/cgm/bgscout/DexcomG4/G4Constants.java +++ b/mobile/src/main/java/com/ktind/cgm/bgscout/DexcomG4/G4Constants.java @@ -28,9 +28,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ public class G4Constants extends Constants { - final static int READING_INTERVAL= 60*5; // 5 minutes in seconds (60 seconds * 5 minutes) - final static int defaultReadings=10; - final static int defaultReadTimeout=200; - final static int defaultWriteTimeout=200; - final static long RECEIVERBASEDATE=1230789600000L; + public final static int READING_INTERVAL= 60*5; // 5 minutes in seconds (60 seconds * 5 minutes) + public final static int defaultReadings=10; + public final static int defaultReadTimeout=200; + public final static int defaultWriteTimeout=200; + public final static long RECEIVERBASEDATE=1230789600000L; + public final static int MINEGV=39; + public final static int MAXEGV=401; + public final static String DRIVER="DexcomG4"; } diff --git a/mobile/src/main/java/com/ktind/cgm/bgscout/DownloadObject.java b/mobile/src/main/java/com/ktind/cgm/bgscout/DownloadObject.java index 3ce2632..148e945 100644 --- a/mobile/src/main/java/com/ktind/cgm/bgscout/DownloadObject.java +++ b/mobile/src/main/java/com/ktind/cgm/bgscout/DownloadObject.java @@ -58,9 +58,6 @@ public Date getDownloadDate(){ return new Date(downloadDate); } -// private Date adjustForLocal(Date date){ -// } - private long adjustForLocal(long date){ Calendar cal = Calendar.getInstance(); TimeZone tz = cal.getTimeZone(); diff --git a/mobile/src/main/java/com/ktind/cgm/bgscout/DownloadStatus.java b/mobile/src/main/java/com/ktind/cgm/bgscout/DownloadStatus.java index a05bd98..d23e41e 100644 --- a/mobile/src/main/java/com/ktind/cgm/bgscout/DownloadStatus.java +++ b/mobile/src/main/java/com/ktind/cgm/bgscout/DownloadStatus.java @@ -32,7 +32,7 @@ public enum DownloadStatus { DEVICENOTFOUND("Device does not appear to be connected.",2), IOERROR("Read or write error",3), APPLICATIONERROR("Encountered an unknown error in application",4), - SPECIALVALUE("Has a special value",5), +// SPECIALVALUE("Has a special value",5), NONE("No download has been performed",6), UNKNOWN("Unknown error",7), REMOTEDISCONNECTED("Disconnected from device",8); diff --git a/mobile/src/main/java/com/ktind/cgm/bgscout/EGVRecord.java b/mobile/src/main/java/com/ktind/cgm/bgscout/EGVRecord.java index 32d6c14..9e9293c 100644 --- a/mobile/src/main/java/com/ktind/cgm/bgscout/EGVRecord.java +++ b/mobile/src/main/java/com/ktind/cgm/bgscout/EGVRecord.java @@ -40,14 +40,14 @@ public class EGVRecord implements Parcelable { protected Long date; protected Trend trend=Trend.NONE; protected GlucoseUnit unit=GlucoseUnit.MGDL; - protected boolean isNew=true; +// protected boolean isNew=true; EGVRecord(int egv,long date,Trend trend,boolean isNew){ super(); this.setEgv(egv); this.setDate(date); this.setTrend(trend); - this.setNew(isNew); +// this.setNew(isNew); } EGVRecord(EGVRecord record){ @@ -55,7 +55,7 @@ public class EGVRecord implements Parcelable { this.date=record.date; this.trend=record.getTrend(); this.unit=record.getUnit(); - this.isNew=record.isNew; +// this.isNew=record.isNew; } public EGVRecord(){ @@ -98,13 +98,13 @@ public void setTrend(Trend trend) { this.trend = trend; } - public boolean isNew() { - return isNew; - } +// public boolean isNew() { +// return isNew; +// } - public void setNew(boolean isNew) { - this.isNew = isNew; - } +// public void setNew(boolean isNew) { +// this.isNew = isNew; +// } @Override public int describeContents() { @@ -117,7 +117,7 @@ public void writeToParcel(Parcel dest, int flags) { dest.writeLong(date); dest.writeInt(trend.getVal()); dest.writeInt(unit.getValue()); - dest.writeByte((byte) (isNew ? 1 : 0)); +// dest.writeByte((byte) (isNew ? 1 : 0)); } public static final Parcelable.Creator CREATOR @@ -136,7 +136,7 @@ private EGVRecord(Parcel in) { date=in.readLong(); trend=Trend.values()[in.readInt()]; unit=GlucoseUnit.values()[in.readInt()]; - isNew = in.readByte() != 0; +// isNew = in.readByte() != 0; } @Override @@ -150,10 +150,10 @@ public boolean equals(Object o) { Log.d(TAG, "EGV Record failed on comparison egv"); return false; } - if (isNew != record.isNew){ - Log.d(TAG, "EGV Record failed on comparison isNew"); - return false; - } +// if (isNew != record.isNew){ +// Log.d(TAG, "EGV Record failed on comparison isNew"); +// return false; +// } // if (!date.equals(record.date)){ // Log.d(TAG, "EGV Record failed on comparison date"); // return false; @@ -182,7 +182,7 @@ public int hashCode() { result = 31 * result + date.hashCode(); result = 31 * result + trend.hashCode(); result = 31 * result + unit.hashCode(); - result = 31 * result + (isNew ? 1 : 0); +// result = 31 * result + (isNew ? 1 : 0); return result; } } diff --git a/mobile/src/main/java/com/ktind/cgm/bgscout/G4CGMDevice.java b/mobile/src/main/java/com/ktind/cgm/bgscout/G4CGMDevice.java index 61455fa..f1689a7 100644 --- a/mobile/src/main/java/com/ktind/cgm/bgscout/G4CGMDevice.java +++ b/mobile/src/main/java/com/ktind/cgm/bgscout/G4CGMDevice.java @@ -8,7 +8,8 @@ import com.google.android.gms.analytics.Tracker; import com.ktind.cgm.bgscout.DexcomG4.G4; import com.ktind.cgm.bgscout.DexcomG4.G4EGVRecord; -import com.ktind.cgm.bgscout.DexcomG4.G4EGVSpecialValue; + +import org.acra.ACRA; import java.util.ArrayList; import java.util.Date; @@ -42,8 +43,6 @@ */ public class G4CGMDevice extends AbstractPollDevice { -// protected String serialNum; -// protected String receiverID; protected int cgmBattery=-1; private static final String TAG = G4CGMDevice.class.getSimpleName(); @@ -53,8 +52,6 @@ public G4CGMDevice(String name,int devID,Context context){ super(name,devID,context,"DexcomG4"); device=new G4(context); remote = false; -// driver="DexcomG4"; -// cgmTransport=new G4USBSerialTransport(context); this.deviceType="Dexcom G4"; } @@ -77,7 +74,6 @@ public void start() { @Override protected DownloadObject doDownload() { -// String specialMessage=""; int deviceBattery=-1; float uploaderBattery=getUploaderBattery()*100.0f; @@ -88,11 +84,13 @@ protected DownloadObject doDownload() { int unitID=Integer.parseInt(sharedPref.getString(deviceIDStr+"_units","0")); GlucoseUnit g_unit; g_unit=GlucoseUnit.values()[unitID]; + Tracker t = ((BGScout) context.getApplicationContext()).getTracker(); if (g_unit==GlucoseUnit.NONE) g_unit=GlucoseUnit.MGDL; try { device.connect(); device.setup(); + egvList = G4RecordAdapter.convertToEGVRecordArrayList((ArrayList) device.getLastRecords()); Log.d(TAG,"Display Time: "+device.getDisplayTime()+ " Current time: "+new Date()); if (sharedPref.getBoolean(deviceIDStr+"_time_sync",true)) @@ -103,32 +101,31 @@ protected DownloadObject doDownload() { batteryBalance(deviceBattery, uploaderBattery); device.disconnect(); status = DownloadStatus.SUCCESS; - - if (egvList.size()>0) { - int lastBG = egvList.get(egvList.size()-1).getEgv(); - for (G4EGVSpecialValue specialValue : G4EGVSpecialValue.values()) { - if (lastBG == specialValue.getValue()) { - status = DownloadStatus.SPECIALVALUE; -// specialMessage=G4EGVSpecialValue.getEGVSpecialValue(lastBG).toString(); - break; - } - } - } else { + if (egvList.size()==0){ status=DownloadStatus.NODATA; } } catch (OperationNotSupportedException e) { Log.e(TAG,"Application error",e); + ACRA.getErrorReporter().handleException(e); + t.send(new HitBuilders.ExceptionBuilder() + .setDescription("Application error: "+e.getMessage()) + .setFatal(false) + .build()); status=DownloadStatus.APPLICATIONERROR; } catch (DeviceIOException e) { Log.e(TAG,"Unable to read/write to the device",e); - Tracker t = ((BGScout) context.getApplicationContext()).getTracker(); + ACRA.getErrorReporter().handleException(e); t.send(new HitBuilders.ExceptionBuilder() - .setDescription("IO Error: "+e.getMessage()+" "+e) + .setDescription("IO error: "+e.getMessage()) .setFatal(false) .build()); status=DownloadStatus.IOERROR; } catch (NoDeviceFoundException e) { status=DownloadStatus.DEVICENOTFOUND; + t.send(new HitBuilders.ExceptionBuilder() + .setDescription("Device not found error: "+e.getMessage()) + .setFatal(false) + .build()); } DownloadObject ddo=new DownloadObject(); // Default to the last 2.5 hours at max - it may be less due to the way that the library pulls the data from the @@ -138,15 +135,13 @@ protected DownloadObject doDownload() { SharedPreferences.Editor editor = sharedPref.edit(); // Filter Log.d(TAG,"egvList: "+egvList.size()); -// egvList=filter(lastReadingDate, egvList); // Then set the new last reading date - if (egvList!=null && egvList.size()>0) + if (egvList.size()>0) lastReadingDateRecord=egvList.get(egvList.size()-1).getDate().getTime(); else lastReadingDateRecord=new Date().getTime()-9000000L; - // FIXME this is an awkward transition from Array to ArrayList. There is too much converting and casting going on. - if (egvList==null) - egvList=new ArrayList(); +// if (egvList==null) +// egvList=new ArrayList(); // ddo => Device Download Object.. ddo.setDeviceBattery(deviceBattery) .setLastReadingDate(new Date(lastReadingDateRecord)) @@ -157,26 +152,12 @@ protected DownloadObject doDownload() { .setEgvRecords(egvList) .setDriver(driver) .setDownloadDate(new Date()); -// .setSpecialValueMessage(specialMessage); -// .addAlertMessages(alerts); editor.putLong(deviceIDStr+"_lastG4Download",lastReadingDateRecord); editor.apply(); -// Log.d("XXX","downloadDate=>"+ddo.getDownloadDate()); setLastDownloadObject(ddo); return ddo; } -// public ArrayList filter(Long afterDateLong,ArrayList egvRecords){ -// Log.d(TAG,"in Filter egvList: "+egvRecords.size()); -// Date afterDate=new Date(afterDateLong); -// for (Iterator iterator = egvRecords.iterator(); iterator.hasNext(); ) { -// EGVRecord record = iterator.next(); -// if (! record.getDate().after(afterDate)) -// iterator.remove(); -// } -// return egvRecords; -// } - public void syncTime(){ if (!device.isConnected()) return; diff --git a/mobile/src/main/java/com/ktind/cgm/bgscout/G4DownloadAnalyzer.java b/mobile/src/main/java/com/ktind/cgm/bgscout/G4DownloadAnalyzer.java index 837bb7c..2f96d5a 100644 --- a/mobile/src/main/java/com/ktind/cgm/bgscout/G4DownloadAnalyzer.java +++ b/mobile/src/main/java/com/ktind/cgm/bgscout/G4DownloadAnalyzer.java @@ -28,14 +28,15 @@ import android.content.Context; +import com.ktind.cgm.bgscout.DexcomG4.G4Constants; import com.ktind.cgm.bgscout.DexcomG4.G4EGVSpecialValue; /** * Created by klee24 on 8/28/14. */ public class G4DownloadAnalyzer extends CGMDownloadAnalyzer { - protected final int MINEGV=39; - protected final int MAXEGV=401; +// protected final int MINEGV=39; +// protected final int MAXEGV=401; G4DownloadAnalyzer(DownloadObject dl, Context context) { @@ -46,6 +47,7 @@ public class G4DownloadAnalyzer extends CGMDownloadAnalyzer { public AnalyzedDownload analyze() { super.analyze(); checkSpecialValues(); +// correlateMessages(); return this.downloadObject; } @@ -58,28 +60,45 @@ protected void checkSpecialValues() { return; } - if (egvValue=MAXEGV) { - downloadObject.addMessage(new AlertMessage(AlertLevels.CRITICAL, "EGV is too high to read"),Conditions.CRITICALHIGH); - return; - } else if (egv<=MINEGV && ! G4EGVSpecialValue.isSpecialValue(egv)) { - downloadObject.addMessage(new AlertMessage(AlertLevels.CRITICAL, "EGV is too low to read"),Conditions.CRITICALLOW); - return; + protected void checkThresholdholds(){ + int egv=0; + try { + egv = downloadObject.getLastReading(); + if (egv>=G4Constants.MAXEGV) { + downloadObject.addMessage(new AlertMessage(AlertLevels.CRITICAL, "EGV is too high to read",Conditions.CRITICALHIGH)); + return; + } else if (egv<=G4Constants.MINEGV && ! G4EGVSpecialValue.isSpecialValue(egv)) { + downloadObject.addMessage(new AlertMessage(AlertLevels.CRITICAL, "EGV is too low to read",Conditions.CRITICALLOW)); + return; + } + } catch (NoDataException e) { +// e.printStackTrace(); } + super.checkThresholdholds(); } + + @Override + protected void correlateMessages(){ + // Special values are < 39. + Conditions[] conditions={Conditions.CRITICALLOW,Conditions.WARNLOW}; + if (downloadObject.getConditions().contains(Conditions.SPECIALVALUE)){ + downloadObject.removeMessageByCondition(Conditions.CRITICALLOW,Conditions.WARNLOW); + } + super.correlateMessages(); + } + } diff --git a/mobile/src/main/java/com/ktind/cgm/bgscout/MainActivity.java b/mobile/src/main/java/com/ktind/cgm/bgscout/MainActivity.java index 0e50197..bb6a442 100644 --- a/mobile/src/main/java/com/ktind/cgm/bgscout/MainActivity.java +++ b/mobile/src/main/java/com/ktind/cgm/bgscout/MainActivity.java @@ -30,21 +30,19 @@ import android.view.View; import android.widget.AdapterView; import android.widget.ArrayAdapter; -import android.widget.Button; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.ListView; -import android.widget.QuickContactBadge; import android.widget.TextView; import android.widget.Toast; import com.google.android.gms.analytics.HitBuilders; import com.google.android.gms.analytics.Tracker; +import com.ktind.cgm.bgscout.DexcomG4.G4Constants; import com.ktind.cgm.bgscout.model.Battery; import com.ktind.cgm.bgscout.model.DownloadDataSource; import com.ktind.cgm.bgscout.model.EGV; -import java.io.InputStream; import java.sql.SQLException; import java.util.ArrayList; import java.util.Date; @@ -484,6 +482,8 @@ public UIDevice(ImageView main, ImageView dir, TextView reading, TextView n, Ima setDeviceBatteryLabel(dbatl); deviceBattery.setImageResource(R.drawable.battery); uploaderBattery.setImageResource(R.drawable.battery); + deviceBattery.setImageLevel(100); + uploaderBattery.setImageLevel(100); } public TextView getUploaderBatteryLabel() { @@ -539,7 +539,15 @@ public void update(DownloadObject dl){ } mainBGColor=currentBGColor; main_display.setBackgroundColor(mainBGColor); - bg.setText(String.valueOf(r)); + //FIXME G4 specific code + if (r> G4Constants.MINEGV) + bg.setText(String.valueOf(r)); + else if (r==G4Constants.MINEGV) + bg.setText("Too low"); + else if (r>G4Constants.MAXEGV) + bg.setText("Too high"); + else + bg.setText("---"); int dbat=dl.getDeviceBattery(); deviceBatteryLabel.setText(String.valueOf(dbat)); @@ -552,7 +560,7 @@ public void update(DownloadObject dl){ } catch (NoDataException e) { - Log.d(TAG,"No data in previous download",e); + Log.d(TAG,"No data in previous download"); } } diff --git a/mobile/src/main/java/com/ktind/cgm/bgscout/MockDevice.java b/mobile/src/main/java/com/ktind/cgm/bgscout/MockDevice.java index 89f9cad..2f6f541 100644 --- a/mobile/src/main/java/com/ktind/cgm/bgscout/MockDevice.java +++ b/mobile/src/main/java/com/ktind/cgm/bgscout/MockDevice.java @@ -182,7 +182,7 @@ private EGVRecord generateEGV(int lastBG,Trend lastTrend,Date date,boolean isNew Trend trend=this.generateNextTrend(lastTrend); record.setTrend(trend); record.setDate(date); - record.setNew(isNew); +// record.setNew(isNew); int changeRate=1; boolean negTrend=false; switch (lastTrend){ diff --git a/mobile/src/main/java/com/ktind/cgm/bgscout/MongoUploadMonitor.java b/mobile/src/main/java/com/ktind/cgm/bgscout/MongoUploadMonitor.java index 44dfab8..749642c 100644 --- a/mobile/src/main/java/com/ktind/cgm/bgscout/MongoUploadMonitor.java +++ b/mobile/src/main/java/com/ktind/cgm/bgscout/MongoUploadMonitor.java @@ -60,19 +60,23 @@ protected void doProcess(DownloadObject d) { DBCollection deviceData; -// SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(context); - // FIXME there has to be a better way than this?! -// String[] device_list={"device_1","device_2","device_3","device_4"}; - for (String dev:Constants.DEVICES) { - if (sharedPref.getString(dev+"_name","").equals(getName())){ - mongoURI=sharedPref.getString(dev+"_mongo_uri",""); - collectionName=sharedPref.getString(dev+"_mongo_col",""); - break; - } - } + mongoURI=sharedPref.getString(deviceIDStr+"_mongo_uri",""); + collectionName=sharedPref.getString(deviceIDStr+"_mongo_col",""); MongoClientURI uri=null; - if (mongoURI!=null) + if (mongoURI!=null && ! mongoURI.equals("")) { uri = new MongoClientURI(mongoURI); + Log.w(TAG,"Mongo URI not set"); + NotifHelper.notify(context,"Mongo URI not set"); + } else { + NotifHelper.clearMessage(context,"Mongo URI not set"); + } + + if (uri==null){ + NotifHelper.notify(context,"Bad mongo URI"); + return; + } else { + NotifHelper.clearMessage(context,"Bad mongo URI"); + } DB db; @@ -84,21 +88,19 @@ protected void doProcess(DownloadObject d) { int uploadCount=0; for (EGVRecord sr:r) { BasicDBObject data = new BasicDBObject(); -// if (sr.isNew()) { - data.put("name", d.getDeviceName()); - data.put("trend", sr.getTrend().getVal()); - - // NightScout comptability - data.put("device", "dexcom"); - data.put("date", sr.getDate().getTime()); - data.put("dateString", new SimpleDateFormat("MM/dd/yyy hh:mm:ss aa").format(sr.getDate())); - data.put("sgv", sr.getEgv()); - data.put("direction", sr.getTrend().getNsString()); - - deviceData.update(data, data, true, false, WriteConcern.UNACKNOWLEDGED); - uploadCount+=1; - Log.v(TAG, "Added Record - EGV: " + sr.getEgv() + " Trend: " + sr.getTrend().getNsString() + " Date: " + new SimpleDateFormat("MM/dd/yyy hh:mm:ss aa").format(sr.getDate())); -// } + data.put("name", d.getDeviceName()); + data.put("trend", sr.getTrend().getVal()); + + // NightScout comptability + data.put("device", "dexcom"); + data.put("date", sr.getDate().getTime()); + data.put("dateString", new SimpleDateFormat("MM/dd/yyy hh:mm:ss aa").format(sr.getDate())); + data.put("sgv", sr.getEgv()); + data.put("direction", sr.getTrend().getNsString()); + + deviceData.update(data, data, true, false, WriteConcern.UNACKNOWLEDGED); + uploadCount+=1; + Log.v(TAG, "Added Record - EGV: " + sr.getEgv() + " Trend: " + sr.getTrend().getNsString() + " Date: " + new SimpleDateFormat("MM/dd/yyy hh:mm:ss aa").format(sr.getDate())); } Log.i(TAG,"Records processed: "+r.size()+" Records Uploaded: "+uploadCount); if (!d.isRemoteDevice()) { @@ -112,17 +114,25 @@ protected void doProcess(DownloadObject d) { deviceData.update(data, data, true, false, WriteConcern.UNACKNOWLEDGED); } mongoClient.close(); + // Feels like a hack - need to figure out a better way to handle monitor error messages for the user + NotifHelper.clearMessage(context,"Unable to upload to mongoDB"); + NotifHelper.clearMessage(context,"Mongo timeout"); + NotifHelper.clearMessage(context,"Mongo error"); try { savelastSuccessDate(d.getLastRecordReadingDate().getTime()); } catch (NoDataException e) { Log.v(TAG,"No data in download to update last success time"); } + //TODO Alert user when connection to mongo is unsuccessful } catch (UnknownHostException e) { Log.e(TAG,"Unable to upload to mongoDB",e); + NotifHelper.notify(context,"Unable to upload to mongoDB"); } catch (MongoTimeoutException e){ Log.w(TAG,"Mongo timeout"); + NotifHelper.notify(context,"Mongo timeout"); } catch (MongoException e){ Log.w(TAG, "Mongo catch all exception: ",e); + NotifHelper.notify(context,"Mongo error"); } } @@ -130,4 +140,5 @@ protected void doProcess(DownloadObject d) { public void stop() { Log.i(TAG, "Stopping monitor " + monitorType + " for " + name); } + } \ No newline at end of file diff --git a/mobile/src/main/java/com/ktind/cgm/bgscout/NightScoutUpload.java b/mobile/src/main/java/com/ktind/cgm/bgscout/NightScoutUpload.java index fbf4652..c97fdd2 100644 --- a/mobile/src/main/java/com/ktind/cgm/bgscout/NightScoutUpload.java +++ b/mobile/src/main/java/com/ktind/cgm/bgscout/NightScoutUpload.java @@ -78,8 +78,8 @@ protected void doProcess(DownloadObject d) { int numRecs=d.getEgvArrayListRecords().size(); int index=0; for (EGVRecord record : d.getEgvArrayListRecords()) { - if (!record.isNew()) - continue; +// if (!record.isNew()) +// continue; // hack to only send the last record for now... if (index < numRecs) continue; diff --git a/mobile/src/main/java/com/ktind/cgm/bgscout/NotifHelper.java b/mobile/src/main/java/com/ktind/cgm/bgscout/NotifHelper.java new file mode 100644 index 0000000..10d458a --- /dev/null +++ b/mobile/src/main/java/com/ktind/cgm/bgscout/NotifHelper.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2014. , Kevin Lee (klee24@gmail.com) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.ktind.cgm.bgscout; + +import android.app.Notification; +import android.app.NotificationManager; +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; + +import java.util.ArrayList; + +/** + * Created by klee24 on 9/7/14. + */ +public class NotifHelper { + static private ArrayList messages=new ArrayList(); + + static public void notify(Context context,String message){ + messages.add(message); + notify(context,messages); + } + + static public void clearMessage(Context context,String msg){ + if (messages.contains(msg)) + messages.remove(msg); + else + return; + NotificationManager mNotifyMgr = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); + if (messages.size()==0) + mNotifyMgr.cancel(153); + else { + notify(context,messages); + } + + } + + static private void notify(Context context,ArrayList msgs){ + String msg=""; + for (String m:msgs){ + if (!msg.equals("")) + msg+="\n"; + msg+=m; + } + NotificationManager mNotifyMgr = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); + Notification.Builder notifBuilder=new Notification.Builder(context); + Bitmap bm = BitmapFactory.decodeResource(context.getResources(), R.drawable.exclamationmarkicon); + notifBuilder.setPriority(Notification.PRIORITY_HIGH) + .setContentTitle("Sugarcast Errors") + .setDefaults(Notification.DEFAULT_ALL) + .setTicker(msg) + .setContentText(msg) + .setLargeIcon(bm) + .setSmallIcon(R.drawable.exclamationmarkicon); + Notification notification=notifBuilder.build(); + mNotifyMgr.notify(153,notification); + } + +} diff --git a/mobile/src/main/java/com/ktind/cgm/bgscout/PebbleMonitor.java b/mobile/src/main/java/com/ktind/cgm/bgscout/PebbleMonitor.java index e4386e0..9e6ba5a 100644 --- a/mobile/src/main/java/com/ktind/cgm/bgscout/PebbleMonitor.java +++ b/mobile/src/main/java/com/ktind/cgm/bgscout/PebbleMonitor.java @@ -31,9 +31,7 @@ import com.getpebble.android.kit.PebbleKit; import com.getpebble.android.kit.util.PebbleDictionary; -import com.ktind.cgm.bgscout.DexcomG4.G4Constants; -import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; @@ -142,7 +140,7 @@ protected PebbleDictionary buildMsg(DownloadObject dl){ data.addString(BATT, String.valueOf((int) dl.getUploaderBattery())); data.addString(NAME, dl.getDeviceName()); } catch (NoDataException e) { - e.printStackTrace(); +// e.printStackTrace(); } return data; } diff --git a/mobile/src/main/java/com/ktind/cgm/bgscout/RemoteMQTTDevice.java b/mobile/src/main/java/com/ktind/cgm/bgscout/RemoteMQTTDevice.java index 045138b..95f7027 100644 --- a/mobile/src/main/java/com/ktind/cgm/bgscout/RemoteMQTTDevice.java +++ b/mobile/src/main/java/com/ktind/cgm/bgscout/RemoteMQTTDevice.java @@ -104,6 +104,7 @@ public void disconnect() { public void stop() { super.stop(); disconnect(); + state=State.STOPPED; } @Override diff --git a/mobile/src/main/java/com/ktind/cgm/bgscout/TimeTools.java b/mobile/src/main/java/com/ktind/cgm/bgscout/TimeTools.java new file mode 100644 index 0000000..8d0ecdf --- /dev/null +++ b/mobile/src/main/java/com/ktind/cgm/bgscout/TimeTools.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2014. , Kevin Lee (klee24@gmail.com) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.ktind.cgm.bgscout; + +import java.text.SimpleDateFormat; +import java.util.Date; + +/** + * Created by klee24 on 9/7/14. + */ +public class TimeTools { + + static public String getTimeDiffStr(Date start,Date end){ + long timeDiff = (int) (end.getTime()-start.getTime()); + String msg="~"; +// Log.d("XXX", "Start: " + start); +// Log.d("XXX","End: "+end); +// Log.d("XXX","Time difference: "+timeDiff); + if (timeDiff<60000) { + msg += "Now"; + }else if (timeDiff>60000 && timeDiff<3600000){ + msg += String.valueOf((timeDiff/1000)/60); + msg += "m"; + }else if (timeDiff>3600000 && timeDiff<86400000){ + msg += String.valueOf(((timeDiff/1000)/60)/60); + msg += "h"; + }else if (timeDiff>86400000 && timeDiff<604800000){ + msg += String.valueOf((((timeDiff/1000)/60)/60)/24); + msg += "d"; + }else { + msg=new SimpleDateFormat("HH:mm:ss MM/dd").format(start); + } + return msg; + } +} diff --git a/mobile/src/main/java/com/ktind/cgm/bgscout/mqtt/MQTTMgr.java b/mobile/src/main/java/com/ktind/cgm/bgscout/mqtt/MQTTMgr.java index 8eb7d4a..157f408 100644 --- a/mobile/src/main/java/com/ktind/cgm/bgscout/mqtt/MQTTMgr.java +++ b/mobile/src/main/java/com/ktind/cgm/bgscout/mqtt/MQTTMgr.java @@ -12,8 +12,8 @@ import android.provider.Settings; import android.util.Log; -import com.google.android.gms.analytics.GoogleAnalytics; import com.ktind.cgm.bgscout.BGScout; +import com.ktind.cgm.bgscout.NotifHelper; import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken; import org.eclipse.paho.client.mqttv3.MqttCallback; @@ -142,12 +142,13 @@ public void connect(String url, String lwt) { Log.d(TAG, "Connecting to URL: " + url); mClient = new MqttClient(url, mDeviceId, mDataStore); mClient.connect(mOpts); + NotifHelper.clearMessage(context,"Disconnected from MQTT"); // connected=true; setNextKeepAlive(); + state=State.CONNECTED; } catch (MqttException e) { Log.e(TAG, "Error while connecting: ", e); } - state=State.CONNECTED; } private void setupOpts(String lwt){ @@ -223,7 +224,6 @@ public void publish(String message,String topic){ // Likely due to disconnected that wasn't detected earlier? Should not happen unless connect was called without initConnect reconnectDelayed(); } - GoogleAnalytics.getInstance(context.getApplicationContext()).dispatchLocalHits(); // mClient.publish("/entries/sgv",jsonString.getBytes(),MQTT_QOS_1,true); } @@ -261,17 +261,19 @@ public void notifyObservers(String topic, MqttMessage message) { @Override public void notifyDisconnect() { Log.d(TAG,"In notifyDisconnect()"); - for (MQTTMgrObserverInterface observer:observers){ - Log.v(TAG,"Calling back to registered users"); - try { - observer.onDisconnect(); - } catch (Exception e){ - // TODO add more specific error handling here for the exceptions that we do know about. perhaps add a way for clients to define their own exception handlers? - // Horrible catch all but I don't want the manager to die and reconnect - // and we really know what all exceptions will be thrown - Log.e(TAG,"Caught an exception: "+e.getMessage(),e); - } - } + if (state!=State.DISCONNECTED && state!=State.DISCONNECTING) + NotifHelper.notify(context,"Disconnected from MQTT"); +// for (MQTTMgrObserverInterface observer:observers){ +// Log.v(TAG,"Calling back to registered users"); +// try { +// observer.onDisconnect(); +// } catch (Exception e){ +// // TODO add more specific error handling here for the exceptions that we do know about. perhaps add a way for clients to define their own exception handlers? +// // Horrible catch all but I don't want the manager to die and reconnect +// // and we really know what all exceptions will be thrown +// Log.e(TAG,"Caught an exception: "+e.getMessage(),e); +// } +// } } protected boolean isConnected(){ @@ -285,7 +287,7 @@ public void connectionLost(Throwable throwable) { return; } stats.addLostConnections(); -// notifyDisconnect(); + notifyDisconnect(); Log.w(TAG,"The connection was lost"); if (mqttUrl==null || mqTopics==null){ Log.e(TAG,"Somehow lost the connection and mqttUrl and/or mqTopics have not been set. Make sure to use connect() and subscribe() methods of this class"); @@ -319,6 +321,8 @@ public void messageArrived(String s, MqttMessage mqttMessage) throws Exception { } private void setNextKeepAlive() { + if (state!=State.CONNECTED) + return; Log.d(TAG,"Canceling previous alarm"); alarmMgr.cancel(keepAlivePendingIntent); Log.d(TAG,"Setting next keep alive to trigger in "+(KEEPALIVE_INTERVAL-3000)/1000+" seconds"); @@ -350,10 +354,10 @@ public void sendKeepalive() { } catch (MqttException e) { Log.wtf(TAG,"Exception during ping",e); Log.wtf(TAG,"Reason code:"+e.getReasonCode()); -// notifyDisconnect(); + notifyDisconnect(); reconnectDelayed(5000); } - setNextKeepAlive(); +// setNextKeepAlive(); } public void reconnectDelayed(){ @@ -362,6 +366,11 @@ public void reconnectDelayed(){ public void reconnectDelayed(long delay_ms){ Log.i(TAG, "Attempting to reconnect again in "+delay_ms/1000+" seconds"); +// reconnectReceiver=new ReconnectReceiver(); + reconnectIntent = new Intent(RECONNECT_INTENT_FILTER); + reconnectIntent.putExtra("device",deviceIDStr); + reconnectPendingIntent=PendingIntent.getBroadcast(context, 61, reconnectIntent, 0); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) alarmMgr.setExact(AlarmManager.RTC_WAKEUP,new Date().getTime()+delay_ms,reconnectPendingIntent); else @@ -370,6 +379,7 @@ public void reconnectDelayed(long delay_ms){ private void reconnect(){ if (isOnline()) { + state=State.RECONNECTING; Log.d(TAG, "Reconnecting"); alarmMgr.cancel(reconnectPendingIntent); stats.addReconnect(); @@ -389,11 +399,13 @@ public enum State { CONNECTING, CONNECTED, DISCONNECTING, - DISCONNECTED + DISCONNECTED, + RECONNECTING } public void disconnect(){ - + if (state==State.DISCONNECTING || state==State.DISCONNECTED) + return; stats.addDisconnect(); try { if (mClient!=null && mClient.isConnected()) { diff --git a/mobile/src/main/res/layout/activity_main.xml b/mobile/src/main/res/layout/activity_main.xml index d622f8e..8f5b89e 100644 --- a/mobile/src/main/res/layout/activity_main.xml +++ b/mobile/src/main/res/layout/activity_main.xml @@ -55,7 +55,7 @@ android:gravity="center" android:layout_alignRight="@+id/direction_image" android:layout_alignLeft="@+id/direction_image" - android:textSize="40sp" + android:textSize="35sp" android:textStyle="bold" /> Nightscout API settings Thresholds lastG4Download - -% - -% + % + % --- --- G4 Options diff --git a/mobile/src/main/res/xml/app_tracker.xml b/mobile/src/main/res/xml/app_tracker.xml index 9b7161f..93014b2 100644 --- a/mobile/src/main/res/xml/app_tracker.xml +++ b/mobile/src/main/res/xml/app_tracker.xml @@ -4,7 +4,7 @@ true - true + false