diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Overview/Notification.java b/app/src/main/java/info/nightscout/androidaps/plugins/Overview/Notification.java index a857153c73..e464ec6418 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/Overview/Notification.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/Overview/Notification.java @@ -51,6 +51,8 @@ public class Notification { public static final int TOAST_ALARM = 22; public static final int WRONGBASALSTEP = 23; public static final int BOLUS_DELIVERY_ERROR = 24; + public static final int PUMP_UNREACHABLE = 26; + public static final int BG_READINGS_MISSED = 27; public int id; public Date date; diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Overview/NotificationStore.java b/app/src/main/java/info/nightscout/androidaps/plugins/Overview/NotificationStore.java index 8c70d3eea6..58978eeead 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/Overview/NotificationStore.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/Overview/NotificationStore.java @@ -1,6 +1,14 @@ package info.nightscout.androidaps.plugins.Overview; +import android.app.NotificationManager; +import android.content.Context; import android.content.Intent; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.media.AudioAttributes; +import android.media.RingtoneManager; +import android.net.Uri; +import android.support.v4.app.NotificationCompat; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -8,14 +16,13 @@ import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; -import java.util.Date; import java.util.List; import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.R; import info.nightscout.androidaps.Services.AlarmSoundService; import info.nightscout.androidaps.plugins.Wear.WearPlugin; -//Added by Rumen for snooze time +//Added by Rumen for snooze time import info.nightscout.utils.SP; /** @@ -49,11 +56,16 @@ public class NotificationStore { return; } } - if (n.soundId != null) { + + if (SP.getBoolean(MainApp.sResources.getString(R.string.key_raise_urgent_alarms_as_android_notification), false) + && n.level == Notification.URGENT) { + raiseSystemNotification(n); + } else if (n.soundId != null) { Intent alarm = new Intent(MainApp.instance().getApplicationContext(), AlarmSoundService.class); alarm.putExtra("soundid", n.soundId); MainApp.instance().startService(alarm); } + store.add(n); WearPlugin wearPlugin = MainApp.getSpecificPlugin(WearPlugin.class); @@ -64,6 +76,23 @@ public class NotificationStore { Collections.sort(store, new NotificationComparator()); } + private void raiseSystemNotification(Notification n) { + Context context = MainApp.instance().getApplicationContext(); + NotificationManager mgr = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); + Bitmap largeIcon = BitmapFactory.decodeResource(context.getResources(), R.mipmap.blueowl); + Uri sound = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM); + NotificationCompat.Builder notificationBuilder = + new NotificationCompat.Builder(context) + .setSmallIcon(R.drawable.ic_notification) + .setLargeIcon(largeIcon) + .setContentTitle("Urgent alarm") + .setContentText(n.text) + .setPriority(NotificationCompat.PRIORITY_HIGH) + .setVibrate(new long[] { 1000, 1000, 1000, 1000}) + .setSound(sound, AudioAttributes.USAGE_ALARM); + mgr.notify(n.id, notificationBuilder.build()); + } + public boolean remove(int id) { for (int i = 0; i < store.size(); i++) { if (get(i).id == id) { diff --git a/app/src/main/java/info/nightscout/androidaps/receivers/KeepAliveReceiver.java b/app/src/main/java/info/nightscout/androidaps/receivers/KeepAliveReceiver.java index e3c77d0122..7e81b950c7 100644 --- a/app/src/main/java/info/nightscout/androidaps/receivers/KeepAliveReceiver.java +++ b/app/src/main/java/info/nightscout/androidaps/receivers/KeepAliveReceiver.java @@ -20,39 +20,76 @@ import java.util.Date; import info.nightscout.androidaps.Constants; import info.nightscout.androidaps.MainApp; -import info.nightscout.androidaps.interfaces.PumpInterface; +import info.nightscout.androidaps.R; import info.nightscout.androidaps.data.Profile; +import info.nightscout.androidaps.db.BgReading; +import info.nightscout.androidaps.db.DatabaseHelper; +import info.nightscout.androidaps.interfaces.PumpInterface; +import info.nightscout.androidaps.plugins.Overview.Notification; +import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification; +import info.nightscout.utils.SP; public class KeepAliveReceiver extends BroadcastReceiver { + public static final long STATUS_UPDATE_FREQUENCY = 15 * 60 * 1000L; private static Logger log = LoggerFactory.getLogger(KeepAliveReceiver.class); + // TODO consider moving this into an Alarms plugin that works offline and can be configured + // (e.g. override silent mode at night only) + public static final int ALARM_FREQUENCY = 25 * 60 * 1000; + private static long nextPumpDisconnectedAlarm = System.currentTimeMillis() + ALARM_FREQUENCY; + private static long nextMissedReadingsAlarm = System.currentTimeMillis() + ALARM_FREQUENCY; + @Override public void onReceive(Context context, Intent rIntent) { PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE); PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, ""); wl.acquire(); + checkBg(); + checkPump(); + log.debug("KeepAlive received"); + wl.release(); + } + + private void checkBg() { + BgReading bgReading = DatabaseHelper.lastBg(); + if (SP.getBoolean(MainApp.sResources.getString(R.string.key_enable_missed_bg_readings_alert), false) + && bgReading != null && bgReading.date + ALARM_FREQUENCY < System.currentTimeMillis() + && nextMissedReadingsAlarm < System.currentTimeMillis()) { + Notification n = new Notification(Notification.BG_READINGS_MISSED, MainApp.sResources.getString(R.string.missed_bg_readings), Notification.URGENT); + n.soundId = R.raw.alarm; + nextMissedReadingsAlarm = System.currentTimeMillis() + ALARM_FREQUENCY; + MainApp.bus().post(new EventNewNotification(n)); + } + } + + private void checkPump() { final PumpInterface pump = MainApp.getConfigBuilder(); final Profile profile = MainApp.getConfigBuilder().getProfile(); if (pump != null && profile != null && profile.getBasal() != null) { - boolean isBasalOutdated = false; - boolean isStatusOutdated = false; - Date lastConnection = pump.lastDataTime(); - if (lastConnection.getTime() + 30 * 60 * 1000L < System.currentTimeMillis()) - isStatusOutdated = true; - if (Math.abs(profile.getBasal() - pump.getBaseBasalRate()) > pump.getPumpDescription().basalStep) - isBasalOutdated = true; + + boolean isStatusOutdated = lastConnection.getTime() + STATUS_UPDATE_FREQUENCY < System.currentTimeMillis(); + boolean isBasalOutdated = Math.abs(profile.getBasal() - pump.getBaseBasalRate()) > pump.getPumpDescription().basalStep; + + boolean alarmTimeoutExpired = lastConnection.getTime() + ALARM_FREQUENCY < System.currentTimeMillis(); + boolean nextAlarmOccurrenceReached = nextPumpDisconnectedAlarm < System.currentTimeMillis(); SharedPreferences SP = PreferenceManager.getDefaultSharedPreferences(MainApp.instance().getApplicationContext()); - if (SP.getBoolean("syncprofiletopump", false) && !pump.isThisProfileSet(profile)) { + if (SP.getBoolean(MainApp.sResources.getString(R.string.key_enable_pump_unreachable_alert), false) + && isStatusOutdated && alarmTimeoutExpired && nextAlarmOccurrenceReached) { + Notification n = new Notification(Notification.PUMP_UNREACHABLE, MainApp.sResources.getString(R.string.pump_unreachable), Notification.URGENT); + n.soundId = R.raw.alarm; + nextPumpDisconnectedAlarm = System.currentTimeMillis() + ALARM_FREQUENCY; + MainApp.bus().post(new EventNewNotification(n)); + } else if (SP.getBoolean("syncprofiletopump", false) && !pump.isThisProfileSet(profile)) { Thread t = new Thread(new Runnable() { @Override public void run() { pump.setNewBasalProfile(profile); } - }); + }, "pump-update-basal-profile"); t.start(); } else if (isStatusOutdated && !pump.isBusy()) { Thread t = new Thread(new Runnable() { @@ -60,7 +97,7 @@ public class KeepAliveReceiver extends BroadcastReceiver { public void run() { pump.refreshDataFromPump("KeepAlive. Status outdated."); } - }); + }, "pump-refresh"); t.start(); } else if (isBasalOutdated && !pump.isBusy()) { Thread t = new Thread(new Runnable() { @@ -68,13 +105,10 @@ public class KeepAliveReceiver extends BroadcastReceiver { public void run() { pump.refreshDataFromPump("KeepAlive. Basal outdated."); } - }); + }, "pump-refresh"); t.start(); } } - - log.debug("KeepAlive received"); - wl.release(); } public void setAlarm(Context context) { diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index c3041e9f7d..2dcc1663df 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -757,5 +757,14 @@ Waiting for estimated bolus end. Remaining %d sec. Processing event Starting bolus delivery + Pump unreachable + Missed BG readings + raise_urgent_alarms_as_android_notification + Use system notifications for alerts + enable_pump_unreachable_alert + enable_missed_bg_readings + Local alerts + Alert if no BGs received in 30 min + Alert if pump unreachable for 30 min diff --git a/app/src/main/res/xml/pref_others.xml b/app/src/main/res/xml/pref_others.xml index e0b5f02c5b..2053859b5e 100644 --- a/app/src/main/res/xml/pref_others.xml +++ b/app/src/main/res/xml/pref_others.xml @@ -72,4 +72,20 @@ android:key="short_tabtitles" android:title="@string/short_tabtitles"/> + + + + +