diff --git a/app/build.gradle b/app/build.gradle index 52ca877595..7920ea6240 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -63,11 +63,12 @@ android { targetSdkVersion 25 multiDexEnabled true versionCode 1500 - version "2.1.2" + version "2.2" buildConfigField "String", "VERSION", '"' + version + '"' buildConfigField "String", "BUILDVERSION", '"' + generateGitBuild() + '-' + generateDate() + '"' buildConfigField "String", "HEAD", '"' + generateGitBuild() + '"' testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + // if you change minSdkVersion to less than 11, you need to change executeTask for wear ndk { moduleName "BleCommandUtil" @@ -77,7 +78,7 @@ android { // TODO remove once wear dependency com.google.android.gms:play-services-wearable:7.3.0 // has been upgraded (requiring significant code changes), which currently fails release // build with a deprecation warning - abortOnError false + // abortOnError false // (disabled entirely to avoid reports on the error, which would still be displayed // and it's easy to overlook that it's ignored) checkReleaseBuilds false @@ -194,7 +195,7 @@ dependencies { implementation "org.slf4j:slf4j-api:1.7.12" implementation "com.jjoe64:graphview:4.0.1" implementation "com.joanzapata.iconify:android-iconify-fontawesome:2.1.1" - implementation "com.google.android.gms:play-services-wearable:7.5.0" + implementation 'com.google.android.gms:play-services-wearable:10.2.1' implementation(name: "android-edittext-validator-v1.3.4-mod", ext: "aar") implementation(name: "sightparser-release", ext: "aar") implementation 'com.madgag.spongycastle:core:1.58.0.0' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 2ec11e5a33..dc9201d86c 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -169,7 +169,63 @@ android:name=".plugins.general.wear.wearintegration.WatchUpdaterService" android:exported="true"> - + + + + + + + + + + + + + + + + + + - \ No newline at end of file + diff --git a/app/src/main/java/info/nightscout/androidaps/Constants.java b/app/src/main/java/info/nightscout/androidaps/Constants.java index 183975b984..2ecabfe965 100644 --- a/app/src/main/java/info/nightscout/androidaps/Constants.java +++ b/app/src/main/java/info/nightscout/androidaps/Constants.java @@ -68,4 +68,7 @@ public class Constants { //SMS Communicator public static final long SMS_CONFIRM_TIMEOUT = T.mins(5).msecs(); + //Storage [MB] + public static final long MINIMUM_FREE_SPACE = 200; + } diff --git a/app/src/main/java/info/nightscout/androidaps/MainApp.java b/app/src/main/java/info/nightscout/androidaps/MainApp.java index 96b55286db..eca527543c 100644 --- a/app/src/main/java/info/nightscout/androidaps/MainApp.java +++ b/app/src/main/java/info/nightscout/androidaps/MainApp.java @@ -37,6 +37,7 @@ import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.constraints.dstHelper.DstHelperPlugin; import info.nightscout.androidaps.plugins.constraints.objectives.ObjectivesPlugin; import info.nightscout.androidaps.plugins.constraints.safety.SafetyPlugin; +import info.nightscout.androidaps.plugins.constraints.storage.StorageConstraintPlugin; import info.nightscout.androidaps.plugins.general.actions.ActionsFragment; import info.nightscout.androidaps.plugins.general.careportal.CareportalPlugin; import info.nightscout.androidaps.plugins.general.food.FoodPlugin; @@ -175,6 +176,7 @@ public class MainApp extends Application { if (Config.OTHERPROFILES) pluginsList.add(LocalProfilePlugin.getPlugin()); pluginsList.add(TreatmentsPlugin.getPlugin()); if (Config.SAFETY) pluginsList.add(SafetyPlugin.getPlugin()); + if (Config.SAFETY) pluginsList.add(StorageConstraintPlugin.getPlugin()); if (Config.APS) pluginsList.add(ObjectivesPlugin.getPlugin()); pluginsList.add(SourceXdripPlugin.getPlugin()); pluginsList.add(SourceNSClientPlugin.getPlugin()); @@ -198,6 +200,7 @@ public class MainApp extends Application { pluginsList.add(DstHelperPlugin.getPlugin()); + ConfigBuilderPlugin.getPlugin().initialize(); } diff --git a/app/src/main/java/info/nightscout/androidaps/data/ConstraintChecker.java b/app/src/main/java/info/nightscout/androidaps/data/ConstraintChecker.java index ceb85c6967..68664033d0 100644 --- a/app/src/main/java/info/nightscout/androidaps/data/ConstraintChecker.java +++ b/app/src/main/java/info/nightscout/androidaps/data/ConstraintChecker.java @@ -50,6 +50,10 @@ public class ConstraintChecker implements ConstraintsInterface { return isAdvancedFilteringEnabled(new Constraint<>(true)); } + public Constraint isSuperBolusEnabled() { + return isSuperBolusEnabled(new Constraint<>(true)); + } + public Constraint getMaxBasalAllowed(Profile profile) { return applyBasalConstraints(new Constraint<>(Constants.REALLYHIGHBASALRATE), profile); } @@ -157,6 +161,17 @@ public class ConstraintChecker implements ConstraintsInterface { return value; } + @Override + public Constraint isSuperBolusEnabled(Constraint value) { + ArrayList constraintsPlugins = mainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class); + for (PluginBase p : constraintsPlugins) { + ConstraintsInterface constraint = (ConstraintsInterface) p; + if (!p.isEnabled(PluginType.CONSTRAINTS)) continue; + constraint.isSuperBolusEnabled(value); + } + return value; + } + @Override public Constraint applyBasalConstraints(Constraint absoluteRate, Profile profile) { ArrayList constraintsPlugins = mainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class); diff --git a/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelper.java b/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelper.java index f3d1e84a2b..6600632869 100644 --- a/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelper.java +++ b/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelper.java @@ -464,7 +464,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper { } catch (SQLException e) { log.error("Unhandled exception", e); } - return new ArrayList(); + return new ArrayList<>(); } public List getBgreadingsDataFromTime(long start, long end, boolean ascending) { @@ -481,7 +481,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper { } catch (SQLException e) { log.error("Unhandled exception", e); } - return new ArrayList(); + return new ArrayList<>(); } public List getAllBgreadingsDataFromTime(long mills, boolean ascending) { diff --git a/app/src/main/java/info/nightscout/androidaps/interfaces/ConstraintsInterface.java b/app/src/main/java/info/nightscout/androidaps/interfaces/ConstraintsInterface.java index 5ac8cc83f7..f1c79dd5cb 100644 --- a/app/src/main/java/info/nightscout/androidaps/interfaces/ConstraintsInterface.java +++ b/app/src/main/java/info/nightscout/androidaps/interfaces/ConstraintsInterface.java @@ -35,6 +35,10 @@ public interface ConstraintsInterface { return value; } + default Constraint isSuperBolusEnabled(Constraint value) { + return value; + } + default Constraint applyBasalConstraints(Constraint absoluteRate, Profile profile) { return absoluteRate; } diff --git a/app/src/main/java/info/nightscout/androidaps/interfaces/PluginBase.java b/app/src/main/java/info/nightscout/androidaps/interfaces/PluginBase.java index b92b8a8f87..01be296539 100644 --- a/app/src/main/java/info/nightscout/androidaps/interfaces/PluginBase.java +++ b/app/src/main/java/info/nightscout/androidaps/interfaces/PluginBase.java @@ -93,6 +93,8 @@ public abstract class PluginBase { return state == State.ENABLED && specialEnableCondition(); if (type == PluginType.CONSTRAINTS && pluginDescription.mainType == PluginType.PUMP && isEnabled(PluginType.PUMP)) return true; + if (type == PluginType.CONSTRAINTS && pluginDescription.mainType == PluginType.APS && isEnabled(PluginType.APS)) + return true; if (type == PluginType.PROFILE && pluginDescription.mainType == PluginType.PUMP) return isProfileInterfaceEnabled; return false; diff --git a/app/src/main/java/info/nightscout/androidaps/interfaces/PumpInterface.java b/app/src/main/java/info/nightscout/androidaps/interfaces/PumpInterface.java index 976ac5c607..3690312cf8 100644 --- a/app/src/main/java/info/nightscout/androidaps/interfaces/PumpInterface.java +++ b/app/src/main/java/info/nightscout/androidaps/interfaces/PumpInterface.java @@ -2,9 +2,13 @@ package info.nightscout.androidaps.interfaces; import org.json.JSONObject; +import java.util.List; + import info.nightscout.androidaps.data.DetailedBolusInfo; import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.data.PumpEnactResult; +import info.nightscout.androidaps.plugins.general.actions.defs.CustomAction; +import info.nightscout.androidaps.plugins.general.actions.defs.CustomActionType; /** * Created by mike on 04.06.2016. @@ -61,4 +65,10 @@ public interface PumpInterface { PumpEnactResult loadTDDs(); + public boolean canHandleDST(); + + List getCustomActions(); + + void executeCustomAction(CustomActionType customActionType); + } diff --git a/app/src/main/java/info/nightscout/androidaps/logging/L.java b/app/src/main/java/info/nightscout/androidaps/logging/L.java index 2c9201bd79..583969c739 100644 --- a/app/src/main/java/info/nightscout/androidaps/logging/L.java +++ b/app/src/main/java/info/nightscout/androidaps/logging/L.java @@ -95,6 +95,7 @@ public class L { public static final String PROFILE = "PROFILE"; public static final String CONFIGBUILDER = "CONFIGBUILDER"; public static final String UI = "UI"; + public static final String SMS = "SMS"; private static void initialize() { logElements = new ArrayList<>(); @@ -117,6 +118,7 @@ public class L { logElements.add(new LogElement(PUMPBTCOMM, false)); logElements.add(new LogElement(PUMPCOMM, true)); logElements.add(new LogElement(PUMPQUEUE, true)); + logElements.add(new LogElement(SMS, true)); logElements.add(new LogElement(UI, true)); } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/LoopPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/LoopPlugin.java index 7ee7cf0348..91bbccc515 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/LoopPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/LoopPlugin.java @@ -34,6 +34,7 @@ import info.nightscout.androidaps.db.DatabaseHelper; import info.nightscout.androidaps.db.Source; import info.nightscout.androidaps.db.TemporaryBasal; import info.nightscout.androidaps.events.EventNewBG; +import info.nightscout.androidaps.events.EventTempTargetChange; import info.nightscout.androidaps.interfaces.APSInterface; import info.nightscout.androidaps.interfaces.Constraint; import info.nightscout.androidaps.interfaces.PluginBase; @@ -175,6 +176,14 @@ public class LoopPlugin extends PluginBase { return loopSuspendedTill; } + @Subscribe + public void onStatusEvent(final EventTempTargetChange ev) { + new Thread(() -> invoke("EventTempTargetChange", true)).start(); + FabricPrivacy.getInstance().logCustom(new CustomEvent("TT_Loop_Run")); + } + + + public void suspendTo(long endTime) { loopSuspendedTill = endTime; isSuperBolus = false; diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMB/OpenAPSSMBPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMB/OpenAPSSMBPlugin.java index f1232e39c3..73914662d7 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMB/OpenAPSSMBPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMB/OpenAPSSMBPlugin.java @@ -13,6 +13,7 @@ import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.db.TempTarget; import info.nightscout.androidaps.interfaces.APSInterface; import info.nightscout.androidaps.interfaces.Constraint; +import info.nightscout.androidaps.interfaces.ConstraintsInterface; import info.nightscout.androidaps.interfaces.PluginBase; import info.nightscout.androidaps.interfaces.PluginDescription; import info.nightscout.androidaps.interfaces.PluginType; @@ -38,7 +39,7 @@ import info.nightscout.androidaps.utils.ToastUtils; /** * Created by mike on 05.08.2016. */ -public class OpenAPSSMBPlugin extends PluginBase implements APSInterface { +public class OpenAPSSMBPlugin extends PluginBase implements APSInterface, ConstraintsInterface { private static Logger log = LoggerFactory.getLogger(L.APS); private static OpenAPSSMBPlugin openAPSSMBPlugin; @@ -147,7 +148,9 @@ public class OpenAPSSMBPlugin extends PluginBase implements APSInterface { if (L.isEnabled(L.APS)) Profiler.log(log, "getMealData()", startPart); - double maxIob = MainApp.getConstraintChecker().getMaxIOBAllowed().value(); + Constraint maxIOBAllowedConstraint = MainApp.getConstraintChecker().getMaxIOBAllowed(); + inputConstraints.copyReasons(maxIOBAllowedConstraint); + double maxIob = maxIOBAllowedConstraint.value(); minBg = verifyHardLimits(minBg, "minBg", HardLimits.VERY_HARD_LIMIT_MIN_BG[0], HardLimits.VERY_HARD_LIMIT_MIN_BG[1]); maxBg = verifyHardLimits(maxBg, "maxBg", HardLimits.VERY_HARD_LIMIT_MAX_BG[0], HardLimits.VERY_HARD_LIMIT_MAX_BG[1]); @@ -266,4 +269,9 @@ public class OpenAPSSMBPlugin extends PluginBase implements APSInterface { return newvalue; } + public Constraint isSuperBolusEnabled(Constraint value) { + value.set(false); + return value; + } + } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/configBuilder/ConfigBuilderFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/configBuilder/ConfigBuilderFragment.java index c456a626e7..b374c78413 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/configBuilder/ConfigBuilderFragment.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/configBuilder/ConfigBuilderFragment.java @@ -42,6 +42,7 @@ import info.nightscout.androidaps.interfaces.SensitivityInterface; import info.nightscout.androidaps.plugins.common.SubscriberFragment; import info.nightscout.androidaps.plugins.insulin.InsulinOrefRapidActingPlugin; import info.nightscout.androidaps.plugins.profile.ns.NSProfilePlugin; + import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin; import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref0Plugin; import info.nightscout.androidaps.utils.FabricPrivacy; diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/configBuilder/ProfileFunctions.java b/app/src/main/java/info/nightscout/androidaps/plugins/configBuilder/ProfileFunctions.java index c87432a9ab..6b9b353979 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/configBuilder/ProfileFunctions.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/configBuilder/ProfileFunctions.java @@ -16,6 +16,7 @@ import info.nightscout.androidaps.R; import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.data.ProfileStore; import info.nightscout.androidaps.db.ProfileSwitch; +import info.nightscout.androidaps.db.Source; import info.nightscout.androidaps.events.EventNewBasalProfile; import info.nightscout.androidaps.events.EventProfileSwitchChange; import info.nightscout.androidaps.interfaces.ProfileInterface; @@ -139,4 +140,44 @@ public class ProfileFunctions { return null; } + public static ProfileSwitch prepareProfileSwitch(final ProfileStore profileStore, final String profileName, final int duration, final int percentage, final int timeshift, long date) { + ProfileSwitch profileSwitch = new ProfileSwitch(); + profileSwitch.date = date; + profileSwitch.source = Source.USER; + profileSwitch.profileName = profileName; + profileSwitch.profileJson = profileStore.getSpecificProfile(profileName).getData().toString(); + profileSwitch.profilePlugin = ConfigBuilderPlugin.getPlugin().getActiveProfileInterface().getClass().getName(); + profileSwitch.durationInMinutes = duration; + profileSwitch.isCPP = percentage != 100 || timeshift != 0; + profileSwitch.timeshift = timeshift; + profileSwitch.percentage = percentage; + return profileSwitch; + } + + public static void doProfileSwitch(final ProfileStore profileStore, final String profileName, final int duration, final int percentage, final int timeshift) { + ProfileSwitch profileSwitch = prepareProfileSwitch(profileStore, profileName, duration, percentage, timeshift, System.currentTimeMillis()); + TreatmentsPlugin.getPlugin().addToHistoryProfileSwitch(profileSwitch); + FabricPrivacy.getInstance().logCustom(new CustomEvent("ProfileSwitch")); + } + + public static void doProfileSwitch(final int duration, final int percentage, final int timeshift) { + ProfileSwitch profileSwitch = TreatmentsPlugin.getPlugin().getProfileSwitchFromHistory(System.currentTimeMillis()); + if (profileSwitch != null) { + profileSwitch = new ProfileSwitch(); + profileSwitch.date = System.currentTimeMillis(); + profileSwitch.source = Source.USER; + profileSwitch.profileName = getInstance().getProfileName(System.currentTimeMillis(), false); + profileSwitch.profileJson = getInstance().getProfile().getData().toString(); + profileSwitch.profilePlugin = ConfigBuilderPlugin.getPlugin().getActiveProfileInterface().getClass().getName(); + profileSwitch.durationInMinutes = duration; + profileSwitch.isCPP = percentage != 100 || timeshift != 0; + profileSwitch.timeshift = timeshift; + profileSwitch.percentage = percentage; + TreatmentsPlugin.getPlugin().addToHistoryProfileSwitch(profileSwitch); + FabricPrivacy.getInstance().logCustom(new CustomEvent("ProfileSwitch")); + } else { + log.error("No profile switch existing"); + } + } + } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/dstHelper/DstHelperPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/dstHelper/DstHelperPlugin.java index 2862cc3d7a..ec3ef44881 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/dstHelper/DstHelperPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/dstHelper/DstHelperPlugin.java @@ -12,18 +12,17 @@ import info.nightscout.androidaps.interfaces.ConstraintsInterface; import info.nightscout.androidaps.interfaces.PluginBase; import info.nightscout.androidaps.interfaces.PluginDescription; import info.nightscout.androidaps.interfaces.PluginType; +import info.nightscout.androidaps.interfaces.PumpInterface; import info.nightscout.androidaps.logging.L; import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin; +import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification; import info.nightscout.androidaps.plugins.general.overview.notifications.Notification; -import info.nightscout.androidaps.utils.T; -/** - * Created by Rumen on 31.10.2018. - */ public class DstHelperPlugin extends PluginBase implements ConstraintsInterface { + public static final int DISABLE_TIMEFRAME_HOURS = -3; + public static final int WARN_PRIOR_TIMEFRAME_HOURS = 24; private static Logger log = LoggerFactory.getLogger(L.CONSTRAINTS); - private int minutesToChange = 0; static DstHelperPlugin plugin = null; @@ -43,83 +42,53 @@ public class DstHelperPlugin extends PluginBase implements ConstraintsInterface ); } - public int dstTest(Calendar c) throws Exception { -// c = Calendar.getInstance(TimeZone.getDefault()); -// c = Calendar.getInstance(TimeZone.getTimeZone("Australia/Lord_Howe")); -// c.setTimeInMillis(DateUtil.fromISODateString("2018-10-07T01:00:00Z").getTime()); - long zoneOffset = c.get(Calendar.ZONE_OFFSET); - long d1 = c.getTimeInMillis() - zoneOffset; - c.setTimeInMillis(d1); - int offset1 = c.get(Calendar.DST_OFFSET); - - c.add(Calendar.DATE, 1); - long d2 = c.getTimeInMillis(); - - int diffInHours = (int) ((d1 - d2) / -T.hours(1).msecs()); - long offsetDetectedTime = 0; - // comparing millis because change can be < 1 hour -// log.debug("Starting from: "+startTimeString + " to "+endTimeString); -// log.debug("start "+offset1+" end "+c.get(Calendar.DST_OFFSET)); - if (offset1 != c.get(Calendar.DST_OFFSET)) { - //we have a time change in next 24 hours, but when exactly -// log.debug("Daylight saving time detected between " + startTimeString + " and " + endTimeString); -// log.debug("Diff in hours is: "+diffInHours); - c.setTimeInMillis(d1 - zoneOffset); - offset1 = c.get(Calendar.DST_OFFSET); - for (int i = 0; i <= diffInHours * 4; i++) { - - if (offset1 != c.get(Calendar.DST_OFFSET)) { - log.debug("Detected offset in " + ((i / 4) - zoneOffset / T.hours(1).msecs()) + " hours value is " + (offset1 - c.get(Calendar.DST_OFFSET)) / T.mins(1).msecs() + " minutes"); - offsetDetectedTime = c.getTimeInMillis() - d1; - break; - } - c.add(Calendar.MINUTE, 15); - - } - } - int minutesLeft = (int) ((offsetDetectedTime / T.mins(1).msecs())); - /*log.debug("zoneoffset(minutes):"+zoneOffset/T.mins(1).msecs()); - log.debug("Start offset: "+offset1/T.mins(1).msecs()); - log.debug("End offset :" + c.get(Calendar.DST_OFFSET)/T.mins(1).msecs()); - log.debug("Now is:"+startTimeString); - log.debug("Detected in(min): "+(offsetDetectedTime/T.mins(1).msecs())); - log.debug("Returning value of: " + minutesLeft); */ - minutesToChange = minutesLeft; - return minutesLeft; - + public static boolean wasDST(Calendar now) { + Calendar ago = (Calendar) now.clone(); + ago.add(Calendar.HOUR, DISABLE_TIMEFRAME_HOURS); + return now.get(Calendar.DST_OFFSET) != ago.get(Calendar.DST_OFFSET); } - //Return false if time to DST change is less than 91 and positive + public static boolean willBeDST(Calendar now) { + Calendar ago = (Calendar) now.clone(); + ago.add(Calendar.HOUR, WARN_PRIOR_TIMEFRAME_HOURS); + return now.get(Calendar.DST_OFFSET) != ago.get(Calendar.DST_OFFSET); + } + + //Return false if time to DST change happened in the last 3 hours. @Override public Constraint isLoopInvocationAllowed(Constraint value) { - try { - this.dstTest(Calendar.getInstance()); - } catch (Exception e) { - e.printStackTrace(); - } - if (this.minutesToChange <= 90 && minutesToChange > 0 && value.value()) { - try { - LoopPlugin loopPlugin = LoopPlugin.getPlugin(); - if (loopPlugin.suspendedTo() == 0L) { -// loopPlugin.suspendTo(System.currentTimeMillis() + minutesToChange * T.mins(1).msecs()); - warnUser(Notification.DST_LOOP_DISABLED, MainApp.gs(R.string.dst_loop_disabled_warning)); - } else - log.debug("Loop already suspended"); - } catch (Exception e) { - e.printStackTrace(); - } - value.set(false, "DST in 90 minutes or less", this); - } else if (minutesToChange <= 24 * T.hours(1).mins() && minutesToChange > 0) { + PumpInterface pump = ConfigBuilderPlugin.getPlugin().getActivePump(); + if (pump == null || pump.canHandleDST()) { + log.debug("Pump can handle DST"); + return value; + } + + Calendar cal = Calendar.getInstance(); + + if (willBeDST(cal)) { warnUser(Notification.DST_IN_24H, MainApp.gs(R.string.dst_in_24h_warning)); } + + if (!value.value()) { + log.debug("Already not allowed - don't check further"); + return value; + } + + if (wasDST(cal)) { + LoopPlugin loopPlugin = LoopPlugin.getPlugin(); + if (!loopPlugin.isSuspended()) { + warnUser(Notification.DST_LOOP_DISABLED, MainApp.gs(R.string.dst_loop_disabled_warning)); + } else { + log.debug("Loop already suspended"); + } + value.set(false, "DST in last 3 hours.", this); + } return value; } - // display warning - void warnUser(int id, String warningText) { + private void warnUser(int id, String warningText) { Notification notification = new Notification(id, warningText, Notification.LOW); MainApp.bus().post(new EventNewNotification(notification)); } - } \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/ObjectivesFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/ObjectivesFragment.java index 9f1ac748d5..b943571089 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/ObjectivesFragment.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/ObjectivesFragment.java @@ -120,6 +120,7 @@ public class ObjectivesFragment extends SubscriberFragment { public void onBindViewHolder(@NonNull ViewHolder holder, int position) { Objective objective = ObjectivesPlugin.getPlugin().getObjectives().get(position); holder.title.setText(MainApp.gs(R.string.nth_objective, position + 1)); + holder.revert.setVisibility(View.INVISIBLE); if (objective.getObjective() != 0) { holder.objective.setVisibility(View.VISIBLE); holder.objective.setText(MainApp.gs(objective.getObjective())); @@ -145,6 +146,9 @@ public class ObjectivesFragment extends SubscriberFragment { holder.verify.setVisibility(View.VISIBLE); holder.verify.setEnabled(objective.isCompleted() || enableFake.isChecked()); holder.start.setVisibility(View.GONE); + if(objective.isRevertable()) { + holder.revert.setVisibility(View.VISIBLE); + } holder.progress.setVisibility(View.VISIBLE); holder.progress.removeAllViews(); for (Objective.Task task : objective.getTasks()) { @@ -169,8 +173,20 @@ public class ObjectivesFragment extends SubscriberFragment { scrollToCurrentObjective(); startUpdateTimer(); }); + holder.revert.setOnClickListener((view) -> { + objective.setAccomplishedOn(null); + objective.setStartedOn(null); + if (position > 0) { + Objective prevObj = ObjectivesPlugin.getPlugin().getObjectives().get(position - 1); + prevObj.setAccomplishedOn(null); + } + notifyDataSetChanged(); + scrollToCurrentObjective(); + }); } + + @Override public int getItemCount() { return ObjectivesPlugin.getPlugin().getObjectives().size(); @@ -185,6 +201,7 @@ public class ObjectivesFragment extends SubscriberFragment { public LinearLayout progress; public Button verify; public Button start; + public Button revert; public ViewHolder(View itemView) { super(itemView); @@ -195,6 +212,7 @@ public class ObjectivesFragment extends SubscriberFragment { progress = itemView.findViewById(R.id.objective_progress); verify = itemView.findViewById(R.id.objective_verify); start = itemView.findViewById(R.id.objective_start); + revert = itemView.findViewById(R.id.objective_back); } } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective.java b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective.java index a1935c2ec6..83abe15688 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective.java @@ -42,6 +42,10 @@ public abstract class Objective { return true; } + public boolean isRevertable() { + return false; + } + public boolean isAccomplished() { return accomplishedOn != null; } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective4.java b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective4.java index 5708565ebe..1bbb4ef7c2 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective4.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective4.java @@ -25,4 +25,9 @@ public class Objective4 extends Objective { } }); } + + @Override + public boolean isRevertable() { + return true; + } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/storage/StorageConstraintPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/storage/StorageConstraintPlugin.java new file mode 100644 index 0000000000..197fd5c17a --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/storage/StorageConstraintPlugin.java @@ -0,0 +1,76 @@ +package info.nightscout.androidaps.plugins.constraints.storage; + +import android.os.Environment; +import android.os.StatFs; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; + +import info.nightscout.androidaps.Constants; +import info.nightscout.androidaps.MainApp; +import info.nightscout.androidaps.R; +import info.nightscout.androidaps.interfaces.Constraint; +import info.nightscout.androidaps.interfaces.ConstraintsInterface; +import info.nightscout.androidaps.interfaces.PluginBase; +import info.nightscout.androidaps.interfaces.PluginDescription; +import info.nightscout.androidaps.interfaces.PluginType; +import info.nightscout.androidaps.logging.L; +import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification; +import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification; +import info.nightscout.androidaps.plugins.general.overview.notifications.Notification; + +/** + * Created by Rumen on 06.03.2019. + */ +public class StorageConstraintPlugin extends PluginBase implements ConstraintsInterface { + private static Logger log = LoggerFactory.getLogger(L.CONSTRAINTS); + static StorageConstraintPlugin plugin = null; + + public static StorageConstraintPlugin getPlugin() { + if (plugin == null) + plugin = new StorageConstraintPlugin(); + return plugin; + } + + public StorageConstraintPlugin() { + super(new PluginDescription() + .mainType(PluginType.CONSTRAINTS) + .neverVisible(true) + .alwaysEnabled(true) + .showInList(false) + .pluginName(R.string.storage) + ); + } + + /** + * Constraints interface + **/ + + @Override + public Constraint isClosedLoopAllowed(Constraint value) { + long diskfree = getAvailableInternalMemorySize(); + if (L.isEnabled(L.CONSTRAINTS)) + log.debug("Internal storage free (Mb):" + diskfree); + if (diskfree < Constants.MINIMUM_FREE_SPACE) { + value.set(false, MainApp.gs(R.string.diskfull, Constants.MINIMUM_FREE_SPACE), this); + Notification notification = new Notification(Notification.DISKFULL, MainApp.gs(R.string.diskfull, Constants.MINIMUM_FREE_SPACE), Notification.NORMAL); + MainApp.bus().post(new EventNewNotification(notification)); + } else { + MainApp.bus().post(new EventDismissNotification(Notification.DISKFULL)); + } + + return value; + } + + public static long getAvailableInternalMemorySize() { + File path = Environment.getDataDirectory(); + StatFs stat = new StatFs(path.getPath()); + long blockSize = stat.getBlockSizeLong(); + long blocksAvailable = stat.getAvailableBlocksLong(); + int size = 1048576; // blocksize of 1 Mb + return ((blocksAvailable * blockSize) / size); + } + +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/actions/ActionsFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/actions/ActionsFragment.java index a0b6e2c1e6..02ff6e6b5c 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/actions/ActionsFragment.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/actions/ActionsFragment.java @@ -3,16 +3,23 @@ package info.nightscout.androidaps.plugins.general.actions; import android.app.Activity; import android.content.Intent; +import android.graphics.drawable.Drawable; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.LinearLayout; import com.crashlytics.android.answers.CustomEvent; import com.squareup.otto.Subscribe; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + import info.nightscout.androidaps.Config; import info.nightscout.androidaps.activities.HistoryBrowseActivity; import info.nightscout.androidaps.MainApp; @@ -25,19 +32,22 @@ import info.nightscout.androidaps.events.EventInitializationChanged; import info.nightscout.androidaps.events.EventRefreshOverview; import info.nightscout.androidaps.events.EventTempBasalChange; import info.nightscout.androidaps.interfaces.PumpInterface; +import info.nightscout.androidaps.plugins.common.SubscriberFragment; +import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin; +import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions; +import info.nightscout.androidaps.plugins.general.actions.ActionsPlugin; +import info.nightscout.androidaps.plugins.general.actions.defs.CustomAction; import info.nightscout.androidaps.plugins.general.actions.dialogs.FillDialog; import info.nightscout.androidaps.plugins.general.actions.dialogs.NewExtendedBolusDialog; import info.nightscout.androidaps.plugins.general.actions.dialogs.NewTempBasalDialog; import info.nightscout.androidaps.plugins.general.careportal.CareportalFragment; import info.nightscout.androidaps.plugins.general.careportal.Dialogs.NewNSTreatmentDialog; import info.nightscout.androidaps.plugins.general.careportal.OptionsToShow; -import info.nightscout.androidaps.plugins.common.SubscriberFragment; -import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin; -import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions; import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin; import info.nightscout.androidaps.utils.FabricPrivacy; import info.nightscout.androidaps.utils.SingleClickButton; + /** * A simple {@link Fragment} subclass. */ @@ -49,6 +59,7 @@ public class ActionsFragment extends SubscriberFragment implements View.OnClickL return actionsPlugin; } + View actionsFragmentView; SingleClickButton profileSwitch; SingleClickButton tempTarget; SingleClickButton extendedBolus; @@ -59,6 +70,9 @@ public class ActionsFragment extends SubscriberFragment implements View.OnClickL SingleClickButton tddStats; SingleClickButton history; + private Map pumpCustomActions = new HashMap<>(); + private List pumpCustomButtons = new ArrayList<>(); + public ActionsFragment() { super(); } @@ -90,6 +104,8 @@ public class ActionsFragment extends SubscriberFragment implements View.OnClickL history.setOnClickListener(this); tddStats.setOnClickListener(this); + actionsFragmentView = view; + updateGUI(); return view; } catch (Exception e) { @@ -192,13 +208,87 @@ public class ActionsFragment extends SubscriberFragment implements View.OnClickL else tempTarget.setVisibility(View.VISIBLE); - if (!ConfigBuilderPlugin.getPlugin().getActivePump().getPumpDescription().supportsTDDs) tddStats.setVisibility(View.GONE); - else tddStats.setVisibility(View.VISIBLE); + if (!pump.getPumpDescription().supportsTDDs) + tddStats.setVisibility(View.GONE); + else + tddStats.setVisibility(View.VISIBLE); + + checkPumpCustomActions(); + } }); } + View.OnClickListener pumpCustomActionsListener = v -> { + + SingleClickButton btn = (SingleClickButton)v; + + CustomAction customAction = this.pumpCustomActions.get(btn.getText().toString()); + + ConfigBuilderPlugin.getPlugin().getActivePump().executeCustomAction(customAction.getCustomActionType()); + + }; + + + private void checkPumpCustomActions() { + + PumpInterface activePump = ConfigBuilderPlugin.getPlugin().getActivePump(); + + removePumpCustomActions(); + + if (activePump == null) { + return; + } + + List customActions = activePump.getCustomActions(); + + if (customActions != null && customActions.size()>0) { + + LinearLayout ll = actionsFragmentView.findViewById(R.id.action_buttons_layout); + + for (CustomAction customAction : customActions) { + + SingleClickButton btn = new SingleClickButton(getContext(), null, android.R.attr.buttonStyle); + btn.setText(MainApp.gs(customAction.getName())); + + LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams( + LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT, 0.5f); + layoutParams.setMargins(20, 8, 20, 8); // 10,3,10,3 + + btn.setLayoutParams(layoutParams); + btn.setOnClickListener(pumpCustomActionsListener); + + Drawable top = getResources().getDrawable(customAction.getIconResourceId()); + btn.setCompoundDrawablesWithIntrinsicBounds(null, top, null, null); + + ll.addView(btn); + + this.pumpCustomActions.put(MainApp.gs(customAction.getName()), customAction); + this.pumpCustomButtons.add(btn); + + } + } + + } + + + private void removePumpCustomActions() { + + if (pumpCustomActions.size()==0) + return; + + LinearLayout ll = actionsFragmentView.findViewById(R.id.action_buttons_layout); + + for (SingleClickButton customButton : pumpCustomButtons) { + ll.removeView(customButton); + } + + pumpCustomButtons.clear(); + pumpCustomActions.clear(); + } + + @Override public void onClick(View view) { FragmentManager manager = getFragmentManager(); diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/actions/defs/CustomAction.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/actions/defs/CustomAction.java new file mode 100644 index 0000000000..e5e119baad --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/actions/defs/CustomAction.java @@ -0,0 +1,47 @@ +package info.nightscout.androidaps.plugins.general.actions.defs; + +import info.nightscout.androidaps.R; + +/** + * Created by andy on 9/20/18. + */ + +public class CustomAction { + + private int name; + private String iconName; + private CustomActionType customActionType; + private int iconResourceId; + + + public CustomAction(int nameResourceId, CustomActionType actionType) { + this.name = nameResourceId; + this.customActionType = actionType; + this.iconResourceId = R.drawable.icon_actions_profileswitch; + } + + public CustomAction(int nameResourceId, CustomActionType actionType, int iconResourceId) { + this.name = nameResourceId; + this.customActionType = actionType; + this.iconResourceId = iconResourceId; + } + + + public int getName() { + + return name; + } + + + + + public CustomActionType getCustomActionType() { + + return customActionType; + } + + + public int getIconResourceId() { + return iconResourceId; + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/actions/defs/CustomActionType.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/actions/defs/CustomActionType.java new file mode 100644 index 0000000000..74ecf3c0e3 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/actions/defs/CustomActionType.java @@ -0,0 +1,11 @@ +package info.nightscout.androidaps.plugins.general.actions.defs; + +/** + * Created by andy on 9/20/18. + */ + +public interface CustomActionType { + + String getKey(); + +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/careportal/CareportalFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/careportal/CareportalFragment.java index 058c31b0b5..991fc962ee 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/careportal/CareportalFragment.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/careportal/CareportalFragment.java @@ -229,8 +229,8 @@ public class CareportalFragment extends SubscriberFragment implements View.OnCli double sageWarn = nsSettings.getExtendedWarnValue("sage", "warn", 164); handleAge(sage, CareportalEvent.SENSORCHANGE, sageWarn, sageUrgent); - double pbageUrgent = nsSettings.getExtendedWarnValue("pgage", "urgent", 360); - double pbageWarn = nsSettings.getExtendedWarnValue("pgage", "warn", 240); + double pbageUrgent = nsSettings.getExtendedWarnValue("bage", "urgent", 360); + double pbageWarn = nsSettings.getExtendedWarnValue("bage", "warn", 240); handleAge(pbage, CareportalEvent.PUMPBATTERYCHANGE, pbageWarn, pbageUrgent); } ); diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/careportal/Dialogs/NewNSTreatmentDialog.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/careportal/Dialogs/NewNSTreatmentDialog.java index 1e38a0131a..e4eccd18d9 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/careportal/Dialogs/NewNSTreatmentDialog.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/careportal/Dialogs/NewNSTreatmentDialog.java @@ -722,7 +722,7 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick public void createNSTreatment(JSONObject data) { if (options.executeProfileSwitch) { if (data.has("profile")) { - doProfileSwitch(profileStore, JsonHelper.safeGetString(data, "profile"), JsonHelper.safeGetInt(data, "duration"), JsonHelper.safeGetInt(data, "percentage"), JsonHelper.safeGetInt(data, "timeshift")); + ProfileFunctions.doProfileSwitch(profileStore, JsonHelper.safeGetString(data, "profile"), JsonHelper.safeGetInt(data, "duration"), JsonHelper.safeGetInt(data, "percentage"), JsonHelper.safeGetInt(data, "timeshift")); } } else if (options.executeTempTarget) { final int duration = JsonHelper.safeGetInt(data, "duration"); @@ -746,7 +746,7 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick } } else { if (JsonHelper.safeGetString(data, "eventType").equals(CareportalEvent.PROFILESWITCH)) { - ProfileSwitch profileSwitch = prepareProfileSwitch( + ProfileSwitch profileSwitch = ProfileFunctions.prepareProfileSwitch( profileStore, JsonHelper.safeGetString(data, "profile"), JsonHelper.safeGetInt(data, "duration"), @@ -762,46 +762,6 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick } } - public static ProfileSwitch prepareProfileSwitch(final ProfileStore profileStore, final String profileName, final int duration, final int percentage, final int timeshift, long date) { - ProfileSwitch profileSwitch = new ProfileSwitch(); - profileSwitch.date = date; - profileSwitch.source = Source.USER; - profileSwitch.profileName = profileName; - profileSwitch.profileJson = profileStore.getSpecificProfile(profileName).getData().toString(); - profileSwitch.profilePlugin = ConfigBuilderPlugin.getPlugin().getActiveProfileInterface().getClass().getName(); - profileSwitch.durationInMinutes = duration; - profileSwitch.isCPP = percentage != 100 || timeshift != 0; - profileSwitch.timeshift = timeshift; - profileSwitch.percentage = percentage; - return profileSwitch; - } - - public static void doProfileSwitch(final ProfileStore profileStore, final String profileName, final int duration, final int percentage, final int timeshift) { - ProfileSwitch profileSwitch = prepareProfileSwitch(profileStore, profileName, duration, percentage, timeshift, System.currentTimeMillis()); - TreatmentsPlugin.getPlugin().addToHistoryProfileSwitch(profileSwitch); - FabricPrivacy.getInstance().logCustom(new CustomEvent("ProfileSwitch")); - } - - public static void doProfileSwitch(final int duration, final int percentage, final int timeshift) { - ProfileSwitch profileSwitch = TreatmentsPlugin.getPlugin().getProfileSwitchFromHistory(System.currentTimeMillis()); - if (profileSwitch != null) { - profileSwitch = new ProfileSwitch(); - profileSwitch.date = System.currentTimeMillis(); - profileSwitch.source = Source.USER; - profileSwitch.profileName = ProfileFunctions.getInstance().getProfileName(System.currentTimeMillis(), false); - profileSwitch.profileJson = ProfileFunctions.getInstance().getProfile().getData().toString(); - profileSwitch.profilePlugin = ConfigBuilderPlugin.getPlugin().getActiveProfileInterface().getClass().getName(); - profileSwitch.durationInMinutes = duration; - profileSwitch.isCPP = percentage != 100 || timeshift != 0; - profileSwitch.timeshift = timeshift; - profileSwitch.percentage = percentage; - TreatmentsPlugin.getPlugin().addToHistoryProfileSwitch(profileSwitch); - FabricPrivacy.getInstance().logCustom(new CustomEvent("ProfileSwitch")); - } else { - log.error("No profile switch existing"); - } - } - @Override public void onSaveInstanceState(Bundle savedInstanceState) { savedInstanceState.putString("notesEdit", notesEdit.getText().toString()); diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NsClientReceiverDelegate.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NsClientReceiverDelegate.java index 07d76d90fe..8eeee8c43c 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NsClientReceiverDelegate.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NsClientReceiverDelegate.java @@ -48,9 +48,7 @@ class NsClientReceiverDelegate { bus.post(event); context.registerReceiver(chargingStateReceiver, - new IntentFilter(Intent.ACTION_POWER_CONNECTED)); - context.registerReceiver(chargingStateReceiver, - new IntentFilter(Intent.ACTION_POWER_DISCONNECTED)); + new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); EventChargingState eventChargingState = chargingStateReceiver.grabChargingState(context); if (eventChargingState != null) @@ -97,7 +95,7 @@ class NsClientReceiverDelegate { } void processStateChange() { - boolean newAllowedState = allowedChargingState && allowedNetworkState; + boolean newAllowedState = allowedChargingState && allowedNetworkState; if (newAllowedState != allowed) { allowed = newAllowedState; bus.post(new EventPreferenceChange(R.string.key_nsclientinternal_paused)); @@ -109,7 +107,9 @@ class NsClientReceiverDelegate { boolean newAllowedState = true; - if (!ev.isCharging && chargingOnly) newAllowedState = false; + if (!ev.isCharging && chargingOnly) { + newAllowedState = false; + } return newAllowedState; } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/Dialogs/WizardDialog.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/Dialogs/WizardDialog.java index d357bf9f06..33b3019668 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/Dialogs/WizardDialog.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/Dialogs/WizardDialog.java @@ -51,17 +51,16 @@ import info.nightscout.androidaps.db.DatabaseHelper; import info.nightscout.androidaps.db.Source; import info.nightscout.androidaps.db.TempTarget; import info.nightscout.androidaps.events.EventFeatureRunning; -import info.nightscout.androidaps.events.EventNewBG; import info.nightscout.androidaps.events.EventRefreshOverview; import info.nightscout.androidaps.interfaces.Constraint; import info.nightscout.androidaps.interfaces.PluginType; import info.nightscout.androidaps.interfaces.PumpInterface; +import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin; import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions; import info.nightscout.androidaps.plugins.iob.iobCobCalculator.CobInfo; import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin; import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventAutosensCalculationFinished; -import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin; import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin; import info.nightscout.androidaps.queue.Callback; import info.nightscout.androidaps.utils.BolusWizard; @@ -165,18 +164,6 @@ public class WizardDialog extends DialogFragment implements OnClickListener, Com } - @Subscribe - public void onStatusEvent(final EventNewBG e) { - Activity activity = getActivity(); - if (activity != null) - activity.runOnUiThread(new Runnable() { - @Override - public void run() { - calculateInsulin(); - } - }); - } - @Subscribe public void onStatusEvent(final EventAutosensCalculationFinished e) { Activity activity = getActivity(); diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/notifications/Notification.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/notifications/Notification.java index 5477963240..3b6bcf615d 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/notifications/Notification.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/notifications/Notification.java @@ -73,6 +73,7 @@ public class Notification { public static final int INSIGHT_TIMEOUT_DURING_HANDSHAKE = 48; public static final int DST_LOOP_DISABLED = 49; public static final int DST_IN_24H = 50; + public static final int DISKFULL = 51; public int id; diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/persistentNotification/PersistentNotificationPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/persistentNotification/PersistentNotificationPlugin.java index 04d5e9ffbe..0287c21260 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/persistentNotification/PersistentNotificationPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/persistentNotification/PersistentNotificationPlugin.java @@ -27,7 +27,6 @@ import info.nightscout.androidaps.db.DatabaseHelper; import info.nightscout.androidaps.db.TemporaryBasal; import info.nightscout.androidaps.events.EventExtendedBolusChange; import info.nightscout.androidaps.events.EventInitializationChanged; -import info.nightscout.androidaps.events.EventNewBG; import info.nightscout.androidaps.events.EventNewBasalProfile; import info.nightscout.androidaps.events.EventPreferenceChange; import info.nightscout.androidaps.events.EventRefreshOverview; @@ -39,6 +38,7 @@ import info.nightscout.androidaps.interfaces.PluginType; import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions; import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin; +import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventAutosensCalculationFinished; import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin; import info.nightscout.androidaps.utils.DecimalFormatter; @@ -283,7 +283,7 @@ public class PersistentNotificationPlugin extends PluginBase { } @Subscribe - public void onStatusEvent(final EventNewBG ev) { + public void onStatusEvent(final EventAutosensCalculationFinished ev) { triggerNotificationUpdate(); } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/AuthRequest.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/AuthRequest.java new file mode 100644 index 0000000000..4b05072eb1 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/AuthRequest.java @@ -0,0 +1,59 @@ +package info.nightscout.androidaps.plugins.general.smsCommunicator; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import info.nightscout.androidaps.Constants; +import info.nightscout.androidaps.R; +import info.nightscout.androidaps.logging.L; +import info.nightscout.androidaps.utils.DateUtil; + +class AuthRequest { + private static Logger log = LoggerFactory.getLogger(L.SMS); + + Sms requester; + String confirmCode; + private Runnable action; + + private long date; + + private boolean processed; + private SmsCommunicatorPlugin plugin; + + AuthRequest(SmsCommunicatorPlugin plugin, Sms requester, String requestText, String confirmCode, SmsAction action) { + this.requester = requester; + this.confirmCode = confirmCode; + this.action = action; + this.plugin = plugin; + + this.date = DateUtil.now(); + + plugin.sendSMS(new Sms(requester.phoneNumber, requestText)); + } + + void action(String codeReceived) { + if (processed) { + if (L.isEnabled(L.SMS)) + log.debug("Already processed"); + return; + } + if (!confirmCode.equals(codeReceived)) { + processed = true; + if (L.isEnabled(L.SMS)) + log.debug("Wrong code"); + plugin.sendSMS(new Sms(requester.phoneNumber, R.string.sms_wrongcode)); + return; + } + if (DateUtil.now() - date < Constants.SMS_CONFIRM_TIMEOUT) { + processed = true; + if (L.isEnabled(L.SMS)) + log.debug("Processing confirmed SMS: " + requester.text); + if (action != null) + action.run(); + return; + } + if (L.isEnabled(L.SMS)) + log.debug("Timed out SMS: " + requester.text); + } + +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/Sms.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/Sms.java new file mode 100644 index 0000000000..2eedfa0a51 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/Sms.java @@ -0,0 +1,42 @@ +package info.nightscout.androidaps.plugins.general.smsCommunicator; + +import android.telephony.SmsMessage; + +import info.nightscout.androidaps.MainApp; +import info.nightscout.androidaps.utils.DateUtil; + +class Sms { + String phoneNumber; + String text; + long date; + boolean received = false; + boolean sent = false; + boolean processed = false; + boolean ignored = false; + + Sms(SmsMessage message) { + phoneNumber = message.getOriginatingAddress(); + text = message.getMessageBody(); + date = message.getTimestampMillis(); + received = true; + } + + Sms(String phoneNumber, String text) { + this.phoneNumber = phoneNumber; + this.text = text; + this.date = DateUtil.now(); + sent = true; + } + + Sms(String phoneNumber, int textId) { + this.phoneNumber = phoneNumber; + this.text = MainApp.gs(textId); + this.date = DateUtil.now(); + sent = true; + } + + public String toString() { + return "SMS from " + phoneNumber + ": " + text; + } +} + diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/SmsAction.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/SmsAction.java new file mode 100644 index 0000000000..6b5d5b8747 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/SmsAction.java @@ -0,0 +1,33 @@ +package info.nightscout.androidaps.plugins.general.smsCommunicator; + +abstract class SmsAction implements Runnable { + Double aDouble; + Integer anInteger; + Integer secondInteger; + String aString; + + SmsAction() {} + + SmsAction(Double aDouble) { + this.aDouble = aDouble; + } + + SmsAction(Double aDouble, Integer secondInteger) { + this.aDouble = aDouble; + this.secondInteger = secondInteger; + } + + SmsAction(String aString, Integer secondInteger) { + this.aString = aString; + this.secondInteger = secondInteger; + } + + SmsAction(Integer anInteger) { + this.anInteger = anInteger; + } + + SmsAction(Integer anInteger, Integer secondInteger) { + this.anInteger = anInteger; + this.secondInteger = secondInteger; + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/SmsCommunicatorFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/SmsCommunicatorFragment.java index 8e46159bd9..d1c4adf5fe 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/SmsCommunicatorFragment.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/SmsCommunicatorFragment.java @@ -3,7 +3,6 @@ package info.nightscout.androidaps.plugins.general.smsCommunicator; import android.app.Activity; import android.os.Bundle; -import android.support.v4.app.Fragment; import android.text.Html; import android.view.LayoutInflater; import android.view.View; @@ -12,9 +11,6 @@ import android.widget.TextView; import com.squareup.otto.Subscribe; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import java.util.Collections; import java.util.Comparator; @@ -22,14 +18,8 @@ import info.nightscout.androidaps.R; import info.nightscout.androidaps.plugins.common.SubscriberFragment; import info.nightscout.androidaps.plugins.general.smsCommunicator.events.EventSmsCommunicatorUpdateGui; import info.nightscout.androidaps.utils.DateUtil; -import info.nightscout.androidaps.utils.FabricPrivacy; -/** - * A simple {@link Fragment} subclass. - */ public class SmsCommunicatorFragment extends SubscriberFragment { - private static Logger log = LoggerFactory.getLogger(SmsCommunicatorFragment.class); - TextView logView; public SmsCommunicatorFragment() { @@ -39,18 +29,11 @@ public class SmsCommunicatorFragment extends SubscriberFragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - try { - View view = inflater.inflate(R.layout.smscommunicator_fragment, container, false); + View view = inflater.inflate(R.layout.smscommunicator_fragment, container, false); - logView = (TextView) view.findViewById(R.id.smscommunicator_log); + logView = (TextView) view.findViewById(R.id.smscommunicator_log); - updateGUI(); - return view; - } catch (Exception e) { - FabricPrivacy.logException(e); - } - - return null; + return view; } @Subscribe @@ -58,35 +41,33 @@ public class SmsCommunicatorFragment extends SubscriberFragment { updateGUI(); } - @Override protected void updateGUI() { Activity activity = getActivity(); if (activity != null) - activity.runOnUiThread(new Runnable() { - @Override - public void run() { - class CustomComparator implements Comparator { - public int compare(SmsCommunicatorPlugin.Sms object1, SmsCommunicatorPlugin.Sms object2) { - return (int) (object1.date - object2.date); - } + activity.runOnUiThread(() -> { + class CustomComparator implements Comparator { + public int compare(Sms object1, Sms object2) { + return (int) (object1.date - object2.date); } - Collections.sort(SmsCommunicatorPlugin.getPlugin().messages, new CustomComparator()); - int messagesToShow = 40; - - int start = Math.max(0, SmsCommunicatorPlugin.getPlugin().messages.size() - messagesToShow); - - String logText = ""; - for (int x = start; x < SmsCommunicatorPlugin.getPlugin().messages.size(); x++) { - SmsCommunicatorPlugin.Sms sms = SmsCommunicatorPlugin.getPlugin().messages.get(x); - if (sms.received) { - logText += DateUtil.timeString(sms.date) + " <<< " + (sms.processed ? "● " : "○ ") + sms.phoneNumber + " " + sms.text + "
"; - } else if (sms.sent) { - logText += DateUtil.timeString(sms.date) + " >>> " + (sms.processed ? "● " : "○ ") + sms.phoneNumber + " " + sms.text + "
"; - } - } - logView.setText(Html.fromHtml(logText)); } + Collections.sort(SmsCommunicatorPlugin.getPlugin().messages, new CustomComparator()); + int messagesToShow = 40; + + int start = Math.max(0, SmsCommunicatorPlugin.getPlugin().messages.size() - messagesToShow); + + String logText = ""; + for (int x = start; x < SmsCommunicatorPlugin.getPlugin().messages.size(); x++) { + Sms sms = SmsCommunicatorPlugin.getPlugin().messages.get(x); + if (sms.ignored) { + logText += DateUtil.timeString(sms.date) + " <<< " + "░ " + sms.phoneNumber + " " + sms.text + "
"; + } else if (sms.received) { + logText += DateUtil.timeString(sms.date) + " <<< " + (sms.processed ? "● " : "○ ") + sms.phoneNumber + " " + sms.text + "
"; + } else if (sms.sent) { + logText += DateUtil.timeString(sms.date) + " >>> " + (sms.processed ? "● " : "○ ") + sms.phoneNumber + " " + sms.text + "
"; + } + } + logView.setText(Html.fromHtml(logText)); }); } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/SmsCommunicatorPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/SmsCommunicatorPlugin.java index 95ceccab3d..e4ec65df11 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/SmsCommunicatorPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/SmsCommunicatorPlugin.java @@ -3,30 +3,27 @@ package info.nightscout.androidaps.plugins.general.smsCommunicator; import android.content.Intent; import android.content.pm.ResolveInfo; import android.os.Bundle; -import android.os.SystemClock; import android.telephony.SmsManager; import android.telephony.SmsMessage; -import com.crashlytics.android.answers.CustomEvent; import com.squareup.otto.Subscribe; +import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.text.Normalizer; import java.util.ArrayList; -import java.util.Date; import java.util.List; import info.nightscout.androidaps.Constants; import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.R; -import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions; -import info.nightscout.androidaps.services.Intents; import info.nightscout.androidaps.data.DetailedBolusInfo; import info.nightscout.androidaps.data.GlucoseStatus; import info.nightscout.androidaps.data.IobTotal; import info.nightscout.androidaps.data.Profile; +import info.nightscout.androidaps.data.ProfileStore; import info.nightscout.androidaps.db.BgReading; import info.nightscout.androidaps.db.DatabaseHelper; import info.nightscout.androidaps.db.Source; @@ -36,27 +33,32 @@ import info.nightscout.androidaps.interfaces.Constraint; import info.nightscout.androidaps.interfaces.PluginBase; import info.nightscout.androidaps.interfaces.PluginDescription; import info.nightscout.androidaps.interfaces.PluginType; +import info.nightscout.androidaps.interfaces.ProfileInterface; import info.nightscout.androidaps.interfaces.PumpInterface; -import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin; +import info.nightscout.androidaps.logging.L; import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin; +import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin; +import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions; +import info.nightscout.androidaps.plugins.general.nsclient.NSUpload; import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification; import info.nightscout.androidaps.plugins.general.overview.notifications.Notification; import info.nightscout.androidaps.plugins.general.smsCommunicator.events.EventSmsCommunicatorUpdateGui; +import info.nightscout.androidaps.plugins.iob.iobCobCalculator.CobInfo; +import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin; import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin; import info.nightscout.androidaps.queue.Callback; +import info.nightscout.androidaps.services.Intents; +import info.nightscout.androidaps.utils.DateUtil; import info.nightscout.androidaps.utils.DecimalFormatter; -import info.nightscout.androidaps.utils.FabricPrivacy; -import info.nightscout.androidaps.plugins.general.nsclient.NSUpload; import info.nightscout.androidaps.utils.SP; import info.nightscout.androidaps.utils.SafeParse; -import info.nightscout.androidaps.utils.T; import info.nightscout.androidaps.utils.XdripCalibrations; /** * Created by mike on 05.08.2016. */ public class SmsCommunicatorPlugin extends PluginBase { - private static Logger log = LoggerFactory.getLogger(SmsCommunicatorPlugin.class); + private static Logger log = LoggerFactory.getLogger(L.SMS); private static SmsCommunicatorPlugin smsCommunicatorPlugin; @@ -68,59 +70,15 @@ public class SmsCommunicatorPlugin extends PluginBase { return smsCommunicatorPlugin; } - private List allowedNumbers = new ArrayList<>(); + List allowedNumbers = new ArrayList<>(); - class Sms { - String phoneNumber; - String text; - long date; - boolean received = false; - boolean sent = false; - boolean processed = false; + AuthRequest messageToConfirm = null; - String confirmCode; - double bolusRequested = 0d; - double tempBasal = 0d; - double calibrationRequested = 0d; - int duration = 0; - - Sms(SmsMessage message) { - phoneNumber = message.getOriginatingAddress(); - text = message.getMessageBody(); - date = message.getTimestampMillis(); - received = true; - } - - Sms(String phoneNumber, String text, long date) { - this.phoneNumber = phoneNumber; - this.text = text; - this.date = date; - sent = true; - } - - Sms(String phoneNumber, String text, long date, String confirmCode) { - this.phoneNumber = phoneNumber; - this.text = text; - this.date = date; - this.confirmCode = confirmCode; - sent = true; - } - - public String toString() { - return "SMS from " + phoneNumber + ": " + text; - } - } - - private Sms cancelTempBasalWaitingForConfirmation = null; - private Sms tempBasalWaitingForConfirmation = null; - private Sms bolusWaitingForConfirmation = null; - private Sms calibrationWaitingForConfirmation = null; - private Sms suspendWaitingForConfirmation = null; - private Date lastRemoteBolusTime = new Date(0); + long lastRemoteBolusTime = 0; ArrayList messages = new ArrayList<>(); - private SmsCommunicatorPlugin() { + SmsCommunicatorPlugin() { super(new PluginDescription() .mainType(PluginType.GENERAL) .fragmentClass(SmsCommunicatorFragment.class.getName()) @@ -159,7 +117,26 @@ public class SmsCommunicatorPlugin extends PluginBase { } } - private boolean isAllowedNumber(String number) { + boolean isCommand(String command, String number) { + switch(command.toUpperCase()) { + case "BG": + case "LOOP": + case "TREATMENTS": + case "NSCLIENT": + case "PUMP": + case "BASAL": + case "BOLUS": + case "EXTENDED": + case "CAL": + case "PROFILE": + return true; + } + if (messageToConfirm != null && messageToConfirm.requester.phoneNumber.equals(number)) + return true; + return false; + } + + boolean isAllowedNumber(String number) { for (String num : allowedNumbers) { if (num.equals(number)) return true; } @@ -180,367 +157,103 @@ public class SmsCommunicatorPlugin extends PluginBase { } } - private void processSms(final Sms receivedSms) { + void processSms(final Sms receivedSms) { if (!isEnabled(PluginType.GENERAL)) { log.debug("Ignoring SMS. Plugin disabled."); return; } if (!isAllowedNumber(receivedSms.phoneNumber)) { log.debug("Ignoring SMS from: " + receivedSms.phoneNumber + ". Sender not allowed"); + receivedSms.ignored = true; + messages.add(receivedSms); + MainApp.bus().post(new EventSmsCommunicatorUpdateGui()); return; } - String reply = ""; - messages.add(receivedSms); log.debug(receivedSms.toString()); - String[] splited = receivedSms.text.split("\\s+"); - Double amount; - Double tempBasal; - int duration = 0; - String passCode; + String[] splitted = receivedSms.text.split("\\s+"); boolean remoteCommandsAllowed = SP.getBoolean(R.string.key_smscommunicator_remotecommandsallowed, false); - if (splited.length > 0) { - switch (splited[0].toUpperCase()) { + if (splitted.length > 0 && isCommand(splitted[0].toUpperCase(), receivedSms.phoneNumber)) { + switch (splitted[0].toUpperCase()) { case "BG": - BgReading actualBG = DatabaseHelper.actualBg(); - BgReading lastBG = DatabaseHelper.lastBg(); - - String units = ProfileFunctions.getInstance().getProfileUnits(); - - if (actualBG != null) { - reply = MainApp.gs(R.string.sms_actualbg) + " " + actualBG.valueToUnitsToString(units) + ", "; - } else if (lastBG != null) { - Long agoMsec = System.currentTimeMillis() - lastBG.date; - int agoMin = (int) (agoMsec / 60d / 1000d); - reply = MainApp.gs(R.string.sms_lastbg) + " " + lastBG.valueToUnitsToString(units) + " " + String.format(MainApp.gs(R.string.sms_minago), agoMin) + ", "; - } - GlucoseStatus glucoseStatus = GlucoseStatus.getGlucoseStatusData(); - if (glucoseStatus != null) - reply += MainApp.gs(R.string.sms_delta) + " " + Profile.toUnitsString(glucoseStatus.delta, glucoseStatus.delta * Constants.MGDL_TO_MMOLL, units) + " " + units + ", "; - - TreatmentsPlugin.getPlugin().updateTotalIOBTreatments(); - IobTotal bolusIob = TreatmentsPlugin.getPlugin().getLastCalculationTreatments().round(); - TreatmentsPlugin.getPlugin().updateTotalIOBTempBasals(); - IobTotal basalIob = TreatmentsPlugin.getPlugin().getLastCalculationTempBasals().round(); - - reply += MainApp.gs(R.string.sms_iob) + " " + DecimalFormatter.to2Decimal(bolusIob.iob + basalIob.basaliob) + "U (" - + MainApp.gs(R.string.sms_bolus) + " " + DecimalFormatter.to2Decimal(bolusIob.iob) + "U " - + MainApp.gs(R.string.sms_basal) + " " + DecimalFormatter.to2Decimal(basalIob.basaliob) + "U)"; - - sendSMS(new Sms(receivedSms.phoneNumber, reply, System.currentTimeMillis())); - receivedSms.processed = true; - FabricPrivacy.getInstance().logCustom(new CustomEvent("SMS_Bg")); + processBG(splitted, receivedSms); break; case "LOOP": - if (splited.length > 1) - switch (splited[1].toUpperCase()) { - case "DISABLE": - case "STOP": - LoopPlugin loopPlugin = MainApp.getSpecificPlugin(LoopPlugin.class); - if (loopPlugin != null && loopPlugin.isEnabled(PluginType.LOOP)) { - loopPlugin.setPluginEnabled(PluginType.LOOP, false); - ConfigBuilderPlugin.getPlugin().getCommandQueue().cancelTempBasal(true, new Callback() { - @Override - public void run() { - MainApp.bus().post(new EventRefreshOverview("SMS_LOOP_STOP")); - String reply = MainApp.gs(R.string.smscommunicator_loophasbeendisabled) + " " + - MainApp.gs(result.success ? R.string.smscommunicator_tempbasalcanceled : R.string.smscommunicator_tempbasalcancelfailed); - sendSMS(new Sms(receivedSms.phoneNumber, reply, System.currentTimeMillis())); - } - }); - } - receivedSms.processed = true; - FabricPrivacy.getInstance().logCustom(new CustomEvent("SMS_Loop_Stop")); - break; - case "ENABLE": - case "START": - loopPlugin = MainApp.getSpecificPlugin(LoopPlugin.class); - if (loopPlugin != null && !loopPlugin.isEnabled(PluginType.LOOP)) { - loopPlugin.setPluginEnabled(PluginType.LOOP, true); - reply = MainApp.gs(R.string.smscommunicator_loophasbeenenabled); - sendSMS(new Sms(receivedSms.phoneNumber, reply, System.currentTimeMillis())); - MainApp.bus().post(new EventRefreshOverview("SMS_LOOP_START")); - } - receivedSms.processed = true; - FabricPrivacy.getInstance().logCustom(new CustomEvent("SMS_Loop_Start")); - break; - case "STATUS": - loopPlugin = MainApp.getSpecificPlugin(LoopPlugin.class); - if (loopPlugin != null) { - if (loopPlugin.isEnabled(PluginType.LOOP)) { - if (loopPlugin.isSuspended()) - reply = String.format(MainApp.gs(R.string.loopsuspendedfor), loopPlugin.minutesToEndOfSuspend()); - else - reply = MainApp.gs(R.string.smscommunicator_loopisenabled); - } else { - reply = MainApp.gs(R.string.smscommunicator_loopisdisabled); - } - sendSMS(new Sms(receivedSms.phoneNumber, reply, System.currentTimeMillis())); - } - receivedSms.processed = true; - FabricPrivacy.getInstance().logCustom(new CustomEvent("SMS_Loop_Status")); - break; - case "RESUME": - LoopPlugin.getPlugin().suspendTo(0); - MainApp.bus().post(new EventRefreshOverview("SMS_LOOP_RESUME")); - NSUpload.uploadOpenAPSOffline(0); - reply = MainApp.gs(R.string.smscommunicator_loopresumed); - sendSMSToAllNumbers(new Sms(receivedSms.phoneNumber, reply, System.currentTimeMillis())); - FabricPrivacy.getInstance().logCustom(new CustomEvent("SMS_Loop_Resume")); - break; - case "SUSPEND": - if (splited.length >= 3) - duration = SafeParse.stringToInt(splited[2]); - duration = Math.max(0, duration); - duration = Math.min(180, duration); - if (duration == 0) { - reply = MainApp.gs(R.string.smscommunicator_wrongduration); - sendSMS(new Sms(receivedSms.phoneNumber, reply, System.currentTimeMillis())); - } else if (remoteCommandsAllowed) { - passCode = generatePasscode(); - reply = String.format(MainApp.gs(R.string.smscommunicator_suspendreplywithcode), duration, passCode); - receivedSms.processed = true; - resetWaitingMessages(); - sendSMS(suspendWaitingForConfirmation = new Sms(receivedSms.phoneNumber, reply, System.currentTimeMillis(), passCode)); - suspendWaitingForConfirmation.duration = duration; - FabricPrivacy.getInstance().logCustom(new CustomEvent("SMS_Loop_Suspend")); - } else { - reply = MainApp.gs(R.string.smscommunicator_remotecommandnotallowed); - sendSMS(new Sms(receivedSms.phoneNumber, reply, System.currentTimeMillis())); - } - break; - } + if (!remoteCommandsAllowed) + sendSMS(new Sms(receivedSms.phoneNumber, R.string.smscommunicator_remotecommandnotallowed)); + else if (splitted.length == 2 || splitted.length == 3) + processLOOP(splitted, receivedSms); + else + sendSMS(new Sms(receivedSms.phoneNumber, R.string.wrongformat)); break; case "TREATMENTS": - if (splited.length > 1) - switch (splited[1].toUpperCase()) { - case "REFRESH": - Intent restartNSClient = new Intent(Intents.ACTION_RESTART); - TreatmentsPlugin.getPlugin().getService().resetTreatments(); - MainApp.instance().getApplicationContext().sendBroadcast(restartNSClient); - List q = MainApp.instance().getApplicationContext().getPackageManager().queryBroadcastReceivers(restartNSClient, 0); - reply = "TERATMENTS REFRESH " + q.size() + " receivers"; - sendSMS(new Sms(receivedSms.phoneNumber, reply, System.currentTimeMillis())); - receivedSms.processed = true; - FabricPrivacy.getInstance().logCustom(new CustomEvent("SMS_Treatments_Refresh")); - break; - } + if (splitted.length == 2) + processTREATMENTS(splitted, receivedSms); + else + sendSMS(new Sms(receivedSms.phoneNumber, R.string.wrongformat)); break; case "NSCLIENT": - if (splited.length > 1) - switch (splited[1].toUpperCase()) { - case "RESTART": - Intent restartNSClient = new Intent(Intents.ACTION_RESTART); - MainApp.instance().getApplicationContext().sendBroadcast(restartNSClient); - List q = MainApp.instance().getApplicationContext().getPackageManager().queryBroadcastReceivers(restartNSClient, 0); - reply = "NSCLIENT RESTART " + q.size() + " receivers"; - sendSMS(new Sms(receivedSms.phoneNumber, reply, System.currentTimeMillis())); - receivedSms.processed = true; - FabricPrivacy.getInstance().logCustom(new CustomEvent("SMS_Nsclient_Restart")); - break; - } + if (splitted.length == 2) + processNSCLIENT(splitted, receivedSms); + else + sendSMS(new Sms(receivedSms.phoneNumber, R.string.wrongformat)); break; case "PUMP": - case "DANAR": - ConfigBuilderPlugin.getPlugin().getCommandQueue().readStatus("SMS", new Callback() { - @Override - public void run() { - PumpInterface pump = ConfigBuilderPlugin.getPlugin().getActivePump(); - if (result.success) { - if (pump != null) { - String reply = pump.shortStatus(true); - sendSMSToAllNumbers(new Sms(receivedSms.phoneNumber, reply, System.currentTimeMillis())); - } - } else { - String reply = MainApp.gs(R.string.readstatusfailed); - sendSMS(new Sms(receivedSms.phoneNumber, reply, System.currentTimeMillis())); - } - } - }); - receivedSms.processed = true; - FabricPrivacy.getInstance().logCustom(new CustomEvent("SMS_Pump")); + processPUMP(splitted, receivedSms); + break; + case "PROFILE": + if (!remoteCommandsAllowed) + sendSMS(new Sms(receivedSms.phoneNumber, R.string.smscommunicator_remotecommandnotallowed)); + else if (splitted.length == 2 || splitted.length == 3) + processPROFILE(splitted, receivedSms); + else + sendSMS(new Sms(receivedSms.phoneNumber, R.string.wrongformat)); break; case "BASAL": - if (splited.length > 1) { - if (splited[1].toUpperCase().equals("CANCEL") || splited[1].toUpperCase().equals("STOP")) { - if (remoteCommandsAllowed) { - passCode = generatePasscode(); - reply = String.format(MainApp.gs(R.string.smscommunicator_basalstopreplywithcode), passCode); - receivedSms.processed = true; - resetWaitingMessages(); - sendSMS(cancelTempBasalWaitingForConfirmation = new Sms(receivedSms.phoneNumber, reply, System.currentTimeMillis(), passCode)); - FabricPrivacy.getInstance().logCustom(new CustomEvent("SMS_Basal")); - } else { - reply = MainApp.gs(R.string.smscommunicator_remotebasalnotallowed); - sendSMS(new Sms(receivedSms.phoneNumber, reply, System.currentTimeMillis())); - } - } else { - tempBasal = SafeParse.stringToDouble(splited[1]); - Profile profile = ProfileFunctions.getInstance().getProfile(); - if (profile == null) { - reply = MainApp.gs(R.string.noprofile); - sendSMS(new Sms(receivedSms.phoneNumber, reply, System.currentTimeMillis())); - } else { - tempBasal = MainApp.getConstraintChecker().applyBasalConstraints(new Constraint<>(tempBasal), profile).value(); - if (remoteCommandsAllowed) { - passCode = generatePasscode(); - reply = String.format(MainApp.gs(R.string.smscommunicator_basalreplywithcode), tempBasal, passCode); - receivedSms.processed = true; - resetWaitingMessages(); - sendSMS(tempBasalWaitingForConfirmation = new Sms(receivedSms.phoneNumber, reply, System.currentTimeMillis(), passCode)); - tempBasalWaitingForConfirmation.tempBasal = tempBasal; - FabricPrivacy.getInstance().logCustom(new CustomEvent("SMS_Basal")); - } else { - reply = MainApp.gs(R.string.smscommunicator_remotebasalnotallowed); - sendSMS(new Sms(receivedSms.phoneNumber, reply, System.currentTimeMillis())); - } - } - } - } + if (!remoteCommandsAllowed) + sendSMS(new Sms(receivedSms.phoneNumber, R.string.smscommunicator_remotecommandnotallowed)); + else if (splitted.length == 2 || splitted.length == 3) + processBASAL(splitted, receivedSms); + else + sendSMS(new Sms(receivedSms.phoneNumber, R.string.wrongformat)); + break; + case "EXTENDED": + if (!remoteCommandsAllowed) + sendSMS(new Sms(receivedSms.phoneNumber, R.string.smscommunicator_remotecommandnotallowed)); + else if (splitted.length == 2 || splitted.length == 3) + processEXTENDED(splitted, receivedSms); + else + sendSMS(new Sms(receivedSms.phoneNumber, R.string.wrongformat)); break; case "BOLUS": - if (System.currentTimeMillis() - lastRemoteBolusTime.getTime() < Constants.remoteBolusMinDistance) { - reply = MainApp.gs(R.string.smscommunicator_remotebolusnotallowed); - sendSMS(new Sms(receivedSms.phoneNumber, reply, System.currentTimeMillis())); - } else if (ConfigBuilderPlugin.getPlugin().getActivePump().isSuspended()) { - reply = MainApp.gs(R.string.pumpsuspended); - sendSMS(new Sms(receivedSms.phoneNumber, reply, System.currentTimeMillis())); - } else if (splited.length > 1) { - amount = SafeParse.stringToDouble(splited[1]); - amount = MainApp.getConstraintChecker().applyBolusConstraints(new Constraint<>(amount)).value(); - if (amount > 0d && remoteCommandsAllowed) { - passCode = generatePasscode(); - reply = String.format(MainApp.gs(R.string.smscommunicator_bolusreplywithcode), amount, passCode); - receivedSms.processed = true; - resetWaitingMessages(); - sendSMS(bolusWaitingForConfirmation = new Sms(receivedSms.phoneNumber, reply, System.currentTimeMillis(), passCode)); - bolusWaitingForConfirmation.bolusRequested = amount; - FabricPrivacy.getInstance().logCustom(new CustomEvent("SMS_Bolus")); - } else { - reply = MainApp.gs(R.string.smscommunicator_remotebolusnotallowed); - sendSMS(new Sms(receivedSms.phoneNumber, reply, System.currentTimeMillis())); - } - } + if (!remoteCommandsAllowed) + sendSMS(new Sms(receivedSms.phoneNumber, R.string.smscommunicator_remotecommandnotallowed)); + else if (splitted.length == 2 && DateUtil.now() - lastRemoteBolusTime < Constants.remoteBolusMinDistance) + sendSMS(new Sms(receivedSms.phoneNumber, R.string.smscommunicator_remotebolusnotallowed)); + else if (splitted.length == 2 && ConfigBuilderPlugin.getPlugin().getActivePump().isSuspended()) + sendSMS(new Sms(receivedSms.phoneNumber, R.string.pumpsuspended)); + else if (splitted.length == 2) + processBOLUS(splitted, receivedSms); + else + sendSMS(new Sms(receivedSms.phoneNumber, R.string.wrongformat)); break; case "CAL": - if (splited.length > 1) { - amount = SafeParse.stringToDouble(splited[1]); - if (amount > 0d && remoteCommandsAllowed) { - passCode = generatePasscode(); - reply = String.format(MainApp.gs(R.string.smscommunicator_calibrationreplywithcode), amount, passCode); - receivedSms.processed = true; - resetWaitingMessages(); - sendSMS(calibrationWaitingForConfirmation = new Sms(receivedSms.phoneNumber, reply, System.currentTimeMillis(), passCode)); - calibrationWaitingForConfirmation.calibrationRequested = amount; - FabricPrivacy.getInstance().logCustom(new CustomEvent("SMS_Cal")); - } else { - reply = MainApp.gs(R.string.smscommunicator_remotecalibrationnotallowed); - sendSMS(new Sms(receivedSms.phoneNumber, reply, System.currentTimeMillis())); - } - } + if (!remoteCommandsAllowed) + sendSMS(new Sms(receivedSms.phoneNumber, R.string.smscommunicator_remotecommandnotallowed)); + else if (splitted.length == 2) + processCAL(splitted, receivedSms); + else + sendSMS(new Sms(receivedSms.phoneNumber, R.string.wrongformat)); break; default: // expect passCode here - if (bolusWaitingForConfirmation != null && !bolusWaitingForConfirmation.processed && - bolusWaitingForConfirmation.confirmCode.equals(splited[0]) && System.currentTimeMillis() - bolusWaitingForConfirmation.date < Constants.SMS_CONFIRM_TIMEOUT) { - bolusWaitingForConfirmation.processed = true; - DetailedBolusInfo detailedBolusInfo = new DetailedBolusInfo(); - detailedBolusInfo.insulin = bolusWaitingForConfirmation.bolusRequested; - detailedBolusInfo.source = Source.USER; - ConfigBuilderPlugin.getPlugin().getCommandQueue().bolus(detailedBolusInfo, new Callback() { - @Override - public void run() { - PumpInterface pump = ConfigBuilderPlugin.getPlugin().getActivePump(); - if (result.success) { - SystemClock.sleep(T.secs(15).msecs()); // wait some time to get history - String reply = String.format(MainApp.gs(R.string.smscommunicator_bolusdelivered), result.bolusDelivered); - if (pump != null) - reply += "\n" + pump.shortStatus(true); - lastRemoteBolusTime = new Date(); - sendSMSToAllNumbers(new Sms(receivedSms.phoneNumber, reply, System.currentTimeMillis())); - } else { - SystemClock.sleep(T.secs(60).msecs()); // wait some time to get history - String reply = MainApp.gs(R.string.smscommunicator_bolusfailed); - if (pump != null) - reply += "\n" + pump.shortStatus(true); - sendSMS(new Sms(receivedSms.phoneNumber, reply, System.currentTimeMillis())); - } - } - }); - } else if (tempBasalWaitingForConfirmation != null && !tempBasalWaitingForConfirmation.processed && - tempBasalWaitingForConfirmation.confirmCode.equals(splited[0]) && System.currentTimeMillis() - tempBasalWaitingForConfirmation.date < Constants.SMS_CONFIRM_TIMEOUT) { - tempBasalWaitingForConfirmation.processed = true; - Profile profile = ProfileFunctions.getInstance().getProfile(); - if (profile != null) - ConfigBuilderPlugin.getPlugin().getCommandQueue().tempBasalAbsolute(tempBasalWaitingForConfirmation.tempBasal, 30, true, profile, new Callback() { - @Override - public void run() { - if (result.success) { - String reply = String.format(MainApp.gs(R.string.smscommunicator_tempbasalset), result.absolute, result.duration); - reply += "\n" + ConfigBuilderPlugin.getPlugin().getActivePump().shortStatus(true); - sendSMSToAllNumbers(new Sms(receivedSms.phoneNumber, reply, System.currentTimeMillis())); - } else { - String reply = MainApp.gs(R.string.smscommunicator_tempbasalfailed); - reply += "\n" + ConfigBuilderPlugin.getPlugin().getActivePump().shortStatus(true); - sendSMS(new Sms(receivedSms.phoneNumber, reply, System.currentTimeMillis())); - } - } - }); - } else if (cancelTempBasalWaitingForConfirmation != null && !cancelTempBasalWaitingForConfirmation.processed && - cancelTempBasalWaitingForConfirmation.confirmCode.equals(splited[0]) && System.currentTimeMillis() - cancelTempBasalWaitingForConfirmation.date < Constants.SMS_CONFIRM_TIMEOUT) { - cancelTempBasalWaitingForConfirmation.processed = true; - ConfigBuilderPlugin.getPlugin().getCommandQueue().cancelTempBasal(true, new Callback() { - @Override - public void run() { - if (result.success) { - String reply = MainApp.gs(R.string.smscommunicator_tempbasalcanceled); - reply += "\n" + ConfigBuilderPlugin.getPlugin().getActivePump().shortStatus(true); - sendSMSToAllNumbers(new Sms(receivedSms.phoneNumber, reply, System.currentTimeMillis())); - } else { - String reply = MainApp.gs(R.string.smscommunicator_tempbasalcancelfailed); - reply += "\n" + ConfigBuilderPlugin.getPlugin().getActivePump().shortStatus(true); - sendSMS(new Sms(receivedSms.phoneNumber, reply, System.currentTimeMillis())); - } - } - }); - } else if (calibrationWaitingForConfirmation != null && !calibrationWaitingForConfirmation.processed && - calibrationWaitingForConfirmation.confirmCode.equals(splited[0]) && System.currentTimeMillis() - calibrationWaitingForConfirmation.date < Constants.SMS_CONFIRM_TIMEOUT) { - calibrationWaitingForConfirmation.processed = true; - boolean result = XdripCalibrations.sendIntent(calibrationWaitingForConfirmation.calibrationRequested); - if (result) { - reply = MainApp.gs(R.string.smscommunicator_calibrationsent); - sendSMSToAllNumbers(new Sms(receivedSms.phoneNumber, reply, System.currentTimeMillis())); - } else { - reply = MainApp.gs(R.string.smscommunicator_calibrationfailed); - sendSMS(new Sms(receivedSms.phoneNumber, reply, System.currentTimeMillis())); - } - } else if (suspendWaitingForConfirmation != null && !suspendWaitingForConfirmation.processed && - suspendWaitingForConfirmation.confirmCode.equals(splited[0]) && System.currentTimeMillis() - suspendWaitingForConfirmation.date < Constants.SMS_CONFIRM_TIMEOUT) { - suspendWaitingForConfirmation.processed = true; - final int dur = suspendWaitingForConfirmation.duration; - ConfigBuilderPlugin.getPlugin().getCommandQueue().cancelTempBasal(true, new Callback() { - @Override - public void run() { - if (result.success) { - LoopPlugin.getPlugin().suspendTo(System.currentTimeMillis() + dur * 60L * 1000); - NSUpload.uploadOpenAPSOffline(dur * 60); - MainApp.bus().post(new EventRefreshOverview("SMS_LOOP_SUSPENDED")); - String reply = MainApp.gs(R.string.smscommunicator_loopsuspended) + " " + - MainApp.gs(result.success ? R.string.smscommunicator_tempbasalcanceled : R.string.smscommunicator_tempbasalcancelfailed); - sendSMSToAllNumbers(new Sms(receivedSms.phoneNumber, reply, System.currentTimeMillis())); - } else { - String reply = MainApp.gs(R.string.smscommunicator_tempbasalcancelfailed); - reply += "\n" + ConfigBuilderPlugin.getPlugin().getActivePump().shortStatus(true); - sendSMS(new Sms(receivedSms.phoneNumber, reply, System.currentTimeMillis())); - } - } - }); - } else { - sendSMS(new Sms(receivedSms.phoneNumber, MainApp.gs(R.string.smscommunicator_unknowncommand), System.currentTimeMillis())); - } - resetWaitingMessages(); + if (messageToConfirm != null && messageToConfirm.requester.phoneNumber.equals(receivedSms.phoneNumber)) { + messageToConfirm.action(splitted[0]); + messageToConfirm = null; + } else + sendSMS(new Sms(receivedSms.phoneNumber, R.string.smscommunicator_unknowncommand)); break; } } @@ -548,9 +261,491 @@ public class SmsCommunicatorPlugin extends PluginBase { MainApp.bus().post(new EventSmsCommunicatorUpdateGui()); } + @SuppressWarnings("unused") + private void processBG(String[] splitted, Sms receivedSms) { + BgReading actualBG = DatabaseHelper.actualBg(); + BgReading lastBG = DatabaseHelper.lastBg(); + + String reply = ""; + + String units = ProfileFunctions.getInstance().getProfileUnits(); + + if (actualBG != null) { + reply = MainApp.gs(R.string.sms_actualbg) + " " + actualBG.valueToUnitsToString(units) + ", "; + } else if (lastBG != null) { + Long agoMsec = System.currentTimeMillis() - lastBG.date; + int agoMin = (int) (agoMsec / 60d / 1000d); + reply = MainApp.gs(R.string.sms_lastbg) + " " + lastBG.valueToUnitsToString(units) + " " + String.format(MainApp.gs(R.string.sms_minago), agoMin) + ", "; + } + GlucoseStatus glucoseStatus = GlucoseStatus.getGlucoseStatusData(); + if (glucoseStatus != null) + reply += MainApp.gs(R.string.sms_delta) + " " + Profile.toUnitsString(glucoseStatus.delta, glucoseStatus.delta * Constants.MGDL_TO_MMOLL, units) + " " + units + ", "; + + TreatmentsPlugin.getPlugin().updateTotalIOBTreatments(); + IobTotal bolusIob = TreatmentsPlugin.getPlugin().getLastCalculationTreatments().round(); + TreatmentsPlugin.getPlugin().updateTotalIOBTempBasals(); + IobTotal basalIob = TreatmentsPlugin.getPlugin().getLastCalculationTempBasals().round(); + + String cobText = MainApp.gs(R.string.value_unavailable_short); + CobInfo cobInfo = IobCobCalculatorPlugin.getPlugin().getCobInfo(false, "SMS COB"); + + reply += MainApp.gs(R.string.sms_iob) + " " + DecimalFormatter.to2Decimal(bolusIob.iob + basalIob.basaliob) + "U (" + + MainApp.gs(R.string.sms_bolus) + " " + DecimalFormatter.to2Decimal(bolusIob.iob) + "U " + + MainApp.gs(R.string.sms_basal) + " " + DecimalFormatter.to2Decimal(basalIob.basaliob) + "U), " + + MainApp.gs(R.string.cob) + ": " + cobInfo.generateCOBString(); + + sendSMS(new Sms(receivedSms.phoneNumber, reply)); + receivedSms.processed = true; + } + + private void processLOOP(String[] splitted, Sms receivedSms) { + String reply; + switch (splitted[1].toUpperCase()) { + case "DISABLE": + case "STOP": + LoopPlugin loopPlugin = MainApp.getSpecificPlugin(LoopPlugin.class); + if (loopPlugin != null && loopPlugin.isEnabled(PluginType.LOOP)) { + loopPlugin.setPluginEnabled(PluginType.LOOP, false); + ConfigBuilderPlugin.getPlugin().getCommandQueue().cancelTempBasal(true, new Callback() { + @Override + public void run() { + MainApp.bus().post(new EventRefreshOverview("SMS_LOOP_STOP")); + String reply = MainApp.gs(R.string.smscommunicator_loophasbeendisabled) + " " + + MainApp.gs(result.success ? R.string.smscommunicator_tempbasalcanceled : R.string.smscommunicator_tempbasalcancelfailed); + sendSMS(new Sms(receivedSms.phoneNumber, reply)); + } + }); + } else { + sendSMS(new Sms(receivedSms.phoneNumber, R.string.smscommunicator_loopisdisabled)); + } + receivedSms.processed = true; + break; + case "ENABLE": + case "START": + loopPlugin = MainApp.getSpecificPlugin(LoopPlugin.class); + if (loopPlugin != null && !loopPlugin.isEnabled(PluginType.LOOP)) { + loopPlugin.setPluginEnabled(PluginType.LOOP, true); + sendSMS(new Sms(receivedSms.phoneNumber, R.string.smscommunicator_loophasbeenenabled)); + MainApp.bus().post(new EventRefreshOverview("SMS_LOOP_START")); + } else { + sendSMS(new Sms(receivedSms.phoneNumber, R.string.smscommunicator_loopisenabled)); + } + receivedSms.processed = true; + break; + case "STATUS": + loopPlugin = MainApp.getSpecificPlugin(LoopPlugin.class); + if (loopPlugin != null) { + if (loopPlugin.isEnabled(PluginType.LOOP)) { + if (loopPlugin.isSuspended()) + reply = String.format(MainApp.gs(R.string.loopsuspendedfor), loopPlugin.minutesToEndOfSuspend()); + else + reply = MainApp.gs(R.string.smscommunicator_loopisenabled); + } else { + reply = MainApp.gs(R.string.smscommunicator_loopisdisabled); + } + sendSMS(new Sms(receivedSms.phoneNumber, reply)); + } + receivedSms.processed = true; + break; + case "RESUME": + LoopPlugin.getPlugin().suspendTo(0); + MainApp.bus().post(new EventRefreshOverview("SMS_LOOP_RESUME")); + NSUpload.uploadOpenAPSOffline(0); + sendSMSToAllNumbers(new Sms(receivedSms.phoneNumber, R.string.smscommunicator_loopresumed)); + break; + case "SUSPEND": + int duration = 0; + if (splitted.length == 3) + duration = SafeParse.stringToInt(splitted[2]); + duration = Math.max(0, duration); + duration = Math.min(180, duration); + if (duration == 0) { + receivedSms.processed = true; + sendSMS(new Sms(receivedSms.phoneNumber, R.string.smscommunicator_wrongduration)); + return; + } else { + String passCode = generatePasscode(); + reply = String.format(MainApp.gs(R.string.smscommunicator_suspendreplywithcode), duration, passCode); + receivedSms.processed = true; + messageToConfirm = new AuthRequest(this, receivedSms, reply, passCode, new SmsAction(duration) { + @Override + public void run() { + ConfigBuilderPlugin.getPlugin().getCommandQueue().cancelTempBasal(true, new Callback() { + @Override + public void run() { + if (result.success) { + LoopPlugin.getPlugin().suspendTo(System.currentTimeMillis() + anInteger * 60L * 1000); + NSUpload.uploadOpenAPSOffline(anInteger * 60); + MainApp.bus().post(new EventRefreshOverview("SMS_LOOP_SUSPENDED")); + String reply = MainApp.gs(R.string.smscommunicator_loopsuspended) + " " + + MainApp.gs(result.success ? R.string.smscommunicator_tempbasalcanceled : R.string.smscommunicator_tempbasalcancelfailed); + sendSMSToAllNumbers(new Sms(receivedSms.phoneNumber, reply)); + } else { + String reply = MainApp.gs(R.string.smscommunicator_tempbasalcancelfailed); + reply += "\n" + ConfigBuilderPlugin.getPlugin().getActivePump().shortStatus(true); + sendSMS(new Sms(receivedSms.phoneNumber, reply)); + } + } + }); + + } + }); + } + break; + default: + sendSMS(new Sms(receivedSms.phoneNumber, R.string.wrongformat)); + break; + } + } + + private void processTREATMENTS(String[] splitted, Sms receivedSms) { + if (splitted[1].toUpperCase().equals("REFRESH")) { + Intent restartNSClient = new Intent(Intents.ACTION_RESTART); + TreatmentsPlugin.getPlugin().getService().resetTreatments(); + MainApp.instance().getApplicationContext().sendBroadcast(restartNSClient); + List q = MainApp.instance().getApplicationContext().getPackageManager().queryBroadcastReceivers(restartNSClient, 0); + String reply = "TREATMENTS REFRESH " + q.size() + " receivers"; + sendSMS(new Sms(receivedSms.phoneNumber, reply)); + receivedSms.processed = true; + } else + sendSMS(new Sms(receivedSms.phoneNumber, R.string.wrongformat)); + } + + private void processNSCLIENT(String[] splitted, Sms receivedSms) { + if (splitted[1].toUpperCase().equals("RESTART")) { + Intent restartNSClient = new Intent(Intents.ACTION_RESTART); + MainApp.instance().getApplicationContext().sendBroadcast(restartNSClient); + List q = MainApp.instance().getApplicationContext().getPackageManager().queryBroadcastReceivers(restartNSClient, 0); + String reply = "NSCLIENT RESTART " + q.size() + " receivers"; + sendSMS(new Sms(receivedSms.phoneNumber, reply)); + receivedSms.processed = true; + } else + sendSMS(new Sms(receivedSms.phoneNumber, R.string.wrongformat)); + } + + @SuppressWarnings("unused") + private void processPUMP(String[] splitted, Sms receivedSms) { + ConfigBuilderPlugin.getPlugin().getCommandQueue().readStatus("SMS", new Callback() { + @Override + public void run() { + PumpInterface pump = ConfigBuilderPlugin.getPlugin().getActivePump(); + if (result.success) { + if (pump != null) { + String reply = pump.shortStatus(true); + sendSMS(new Sms(receivedSms.phoneNumber, reply)); + } + } else { + String reply = MainApp.gs(R.string.readstatusfailed); + sendSMS(new Sms(receivedSms.phoneNumber, reply)); + } + } + }); + receivedSms.processed = true; + } + + private void processPROFILE(String[] splitted, Sms receivedSms) { + // load profiles + ProfileInterface anInterface = ConfigBuilderPlugin.getPlugin().getActiveProfileInterface(); + if (anInterface == null) { + sendSMS(new Sms(receivedSms.phoneNumber, R.string.notconfigured)); + receivedSms.processed = true; + return; + } + ProfileStore store = anInterface.getProfile(); + if (store == null) { + sendSMS(new Sms(receivedSms.phoneNumber, R.string.notconfigured)); + receivedSms.processed = true; + return; + } + final ArrayList list = store.getProfileList(); + + if (splitted[1].toUpperCase().equals("STATUS")) { + sendSMS(new Sms(receivedSms.phoneNumber, ProfileFunctions.getInstance().getProfileName())); + } else if (splitted[1].toUpperCase().equals("LIST")) { + if (list.isEmpty()) + sendSMS(new Sms(receivedSms.phoneNumber, R.string.invalidprofile)); + else { + String reply = ""; + for (int i = 0; i < list.size(); i++) { + if (i > 0) + reply += "\n"; + reply += (i + 1) + ". "; + reply += list.get(i); + } + sendSMS(new Sms(receivedSms.phoneNumber, reply)); + } + } else { + + int pindex = SafeParse.stringToInt(splitted[1]); + int percentage = 100; + if (splitted.length > 2) + percentage = SafeParse.stringToInt(splitted[2]); + + if (pindex > list.size()) + sendSMS(new Sms(receivedSms.phoneNumber, R.string.wrongformat)); + else if (percentage == 0) + sendSMS(new Sms(receivedSms.phoneNumber, R.string.wrongformat)); + else if (pindex == 0) + sendSMS(new Sms(receivedSms.phoneNumber, R.string.wrongformat)); + else { + final Profile profile = store.getSpecificProfile((String) list.get(pindex - 1)); + if (profile == null) + sendSMS(new Sms(receivedSms.phoneNumber, R.string.noprofile)); + else { + String passCode = generatePasscode(); + String reply = String.format(MainApp.gs(R.string.smscommunicator_profilereplywithcode), list.get(pindex - 1), percentage, passCode); + receivedSms.processed = true; + int finalPercentage = percentage; + messageToConfirm = new AuthRequest(this, receivedSms, reply, passCode, new SmsAction((String) list.get(pindex - 1), finalPercentage) { + @Override + public void run() { + ProfileFunctions.doProfileSwitch(store, (String) list.get(pindex - 1), 0, finalPercentage, 0); + sendSMS(new Sms(receivedSms.phoneNumber, R.string.profileswitchcreated)); + } + }); + } + } + } + receivedSms.processed = true; + } + + private void processBASAL(String[] splitted, Sms receivedSms) { + if (splitted[1].toUpperCase().equals("CANCEL") || splitted[1].toUpperCase().equals("STOP")) { + String passCode = generatePasscode(); + String reply = String.format(MainApp.gs(R.string.smscommunicator_basalstopreplywithcode), passCode); + receivedSms.processed = true; + messageToConfirm = new AuthRequest(this, receivedSms, reply, passCode, new SmsAction() { + @Override + public void run() { + ConfigBuilderPlugin.getPlugin().getCommandQueue().cancelTempBasal(true, new Callback() { + @Override + public void run() { + if (result.success) { + String reply = MainApp.gs(R.string.smscommunicator_tempbasalcanceled); + reply += "\n" + ConfigBuilderPlugin.getPlugin().getActivePump().shortStatus(true); + sendSMSToAllNumbers(new Sms(receivedSms.phoneNumber, reply)); + } else { + String reply = MainApp.gs(R.string.smscommunicator_tempbasalcancelfailed); + reply += "\n" + ConfigBuilderPlugin.getPlugin().getActivePump().shortStatus(true); + sendSMS(new Sms(receivedSms.phoneNumber, reply)); + } + } + }); + } + }); + } else if (splitted[1].endsWith("%")) { + int tempBasalPct = SafeParse.stringToInt(StringUtils.removeEnd(splitted[1], "%")); + int duration = 30; + if (splitted.length > 2) + duration = SafeParse.stringToInt(splitted[2]); + final Profile profile = ProfileFunctions.getInstance().getProfile(); + + if (profile == null) + sendSMS(new Sms(receivedSms.phoneNumber, R.string.noprofile)); + else if (tempBasalPct == 0 && !splitted[1].equals("0%")) + sendSMS(new Sms(receivedSms.phoneNumber, R.string.wrongformat)); + else if (duration == 0) + sendSMS(new Sms(receivedSms.phoneNumber, R.string.wrongformat)); + else { + tempBasalPct = MainApp.getConstraintChecker().applyBasalPercentConstraints(new Constraint<>(tempBasalPct), profile).value(); + String passCode = generatePasscode(); + String reply = String.format(MainApp.gs(R.string.smscommunicator_basalpctreplywithcode), tempBasalPct, duration, passCode); + receivedSms.processed = true; + messageToConfirm = new AuthRequest(this, receivedSms, reply, passCode, new SmsAction(tempBasalPct, duration) { + @Override + public void run() { + ConfigBuilderPlugin.getPlugin().getCommandQueue().tempBasalPercent(anInteger, secondInteger, true, profile, new Callback() { + @Override + public void run() { + if (result.success) { + String reply; + if (result.isPercent) + reply = String.format(MainApp.gs(R.string.smscommunicator_tempbasalset_percent), result.percent, result.duration); + else + reply = String.format(MainApp.gs(R.string.smscommunicator_tempbasalset), result.absolute, result.duration); + reply += "\n" + ConfigBuilderPlugin.getPlugin().getActivePump().shortStatus(true); + sendSMSToAllNumbers(new Sms(receivedSms.phoneNumber, reply)); + } else { + String reply = MainApp.gs(R.string.smscommunicator_tempbasalfailed); + reply += "\n" + ConfigBuilderPlugin.getPlugin().getActivePump().shortStatus(true); + sendSMS(new Sms(receivedSms.phoneNumber, reply)); + } + } + }); + } + }); + } + } else { + Double tempBasal = SafeParse.stringToDouble(splitted[1]); + int duration = 30; + if (splitted.length > 2) + duration = SafeParse.stringToInt(splitted[2]); + final Profile profile = ProfileFunctions.getInstance().getProfile(); + if (profile == null) + sendSMS(new Sms(receivedSms.phoneNumber, R.string.noprofile)); + else if (tempBasal == 0 && !splitted[1].equals("0")) + sendSMS(new Sms(receivedSms.phoneNumber, R.string.wrongformat)); + else if (duration == 0) + sendSMS(new Sms(receivedSms.phoneNumber, R.string.wrongformat)); + else { + tempBasal = MainApp.getConstraintChecker().applyBasalConstraints(new Constraint<>(tempBasal), profile).value(); + String passCode = generatePasscode(); + String reply = String.format(MainApp.gs(R.string.smscommunicator_basalreplywithcode), tempBasal, duration, passCode); + receivedSms.processed = true; + messageToConfirm = new AuthRequest(this, receivedSms, reply, passCode, new SmsAction(tempBasal, duration) { + @Override + public void run() { + ConfigBuilderPlugin.getPlugin().getCommandQueue().tempBasalAbsolute(aDouble, secondInteger, true, profile, new Callback() { + @Override + public void run() { + if (result.success) { + String reply; + if (result.isPercent) + reply = String.format(MainApp.gs(R.string.smscommunicator_tempbasalset_percent), result.percent, result.duration); + else + reply = String.format(MainApp.gs(R.string.smscommunicator_tempbasalset), result.absolute, result.duration); + reply += "\n" + ConfigBuilderPlugin.getPlugin().getActivePump().shortStatus(true); + sendSMSToAllNumbers(new Sms(receivedSms.phoneNumber, reply)); + } else { + String reply = MainApp.gs(R.string.smscommunicator_tempbasalfailed); + reply += "\n" + ConfigBuilderPlugin.getPlugin().getActivePump().shortStatus(true); + sendSMS(new Sms(receivedSms.phoneNumber, reply)); + } + } + }); + } + }); + } + } + } + + private void processEXTENDED(String[] splitted, Sms receivedSms) { + if (splitted[1].toUpperCase().equals("CANCEL") || splitted[1].toUpperCase().equals("STOP")) { + String passCode = generatePasscode(); + String reply = String.format(MainApp.gs(R.string.smscommunicator_extendedstopreplywithcode), passCode); + receivedSms.processed = true; + messageToConfirm = new AuthRequest(this, receivedSms, reply, passCode, new SmsAction() { + @Override + public void run() { + ConfigBuilderPlugin.getPlugin().getCommandQueue().cancelExtended(new Callback() { + @Override + public void run() { + if (result.success) { + String reply = MainApp.gs(R.string.smscommunicator_extendedcanceled); + reply += "\n" + ConfigBuilderPlugin.getPlugin().getActivePump().shortStatus(true); + sendSMSToAllNumbers(new Sms(receivedSms.phoneNumber, reply)); + } else { + String reply = MainApp.gs(R.string.smscommunicator_extendedcancelfailed); + reply += "\n" + ConfigBuilderPlugin.getPlugin().getActivePump().shortStatus(true); + sendSMS(new Sms(receivedSms.phoneNumber, reply)); + } + } + }); + } + }); + } else if (splitted.length != 3) { + sendSMS(new Sms(receivedSms.phoneNumber, R.string.wrongformat)); + } else { + Double extended = SafeParse.stringToDouble(splitted[1]); + int duration = SafeParse.stringToInt(splitted[2]); + extended = MainApp.getConstraintChecker().applyExtendedBolusConstraints(new Constraint<>(extended)).value(); + if (extended == 0 || duration == 0) + sendSMS(new Sms(receivedSms.phoneNumber, R.string.wrongformat)); + else { + String passCode = generatePasscode(); + String reply = String.format(MainApp.gs(R.string.smscommunicator_extendedreplywithcode), extended, duration, passCode); + receivedSms.processed = true; + messageToConfirm = new AuthRequest(this, receivedSms, reply, passCode, new SmsAction(extended, duration) { + @Override + public void run() { + ConfigBuilderPlugin.getPlugin().getCommandQueue().extendedBolus(aDouble, secondInteger, new Callback() { + @Override + public void run() { + if (result.success) { + String reply = String.format(MainApp.gs(R.string.smscommunicator_extendedset), aDouble, duration); + reply += "\n" + ConfigBuilderPlugin.getPlugin().getActivePump().shortStatus(true); + sendSMSToAllNumbers(new Sms(receivedSms.phoneNumber, reply)); + } else { + String reply = MainApp.gs(R.string.smscommunicator_extendedfailed); + reply += "\n" + ConfigBuilderPlugin.getPlugin().getActivePump().shortStatus(true); + sendSMS(new Sms(receivedSms.phoneNumber, reply)); + } + } + }); + } + }); + } + } + } + + + private void processBOLUS(String[] splitted, Sms receivedSms) { + Double bolus = SafeParse.stringToDouble(splitted[1]); + bolus = MainApp.getConstraintChecker().applyBolusConstraints(new Constraint<>(bolus)).value(); + if (bolus > 0d) { + String passCode = generatePasscode(); + String reply = String.format(MainApp.gs(R.string.smscommunicator_bolusreplywithcode), bolus, passCode); + receivedSms.processed = true; + messageToConfirm = new AuthRequest(this, receivedSms, reply, passCode, new SmsAction(bolus) { + @Override + public void run() { + DetailedBolusInfo detailedBolusInfo = new DetailedBolusInfo(); + detailedBolusInfo.insulin = aDouble; + detailedBolusInfo.source = Source.USER; + ConfigBuilderPlugin.getPlugin().getCommandQueue().bolus(detailedBolusInfo, new Callback() { + @Override + public void run() { + final boolean resultSuccess = result.success; + final double resultBolusDelivered = result.bolusDelivered; + ConfigBuilderPlugin.getPlugin().getCommandQueue().readStatus("SMS", new Callback() { + @Override + public void run() { + PumpInterface pump = ConfigBuilderPlugin.getPlugin().getActivePump(); + if (resultSuccess) { + String reply = String.format(MainApp.gs(R.string.smscommunicator_bolusdelivered), resultBolusDelivered); + if (pump != null) + reply += "\n" + pump.shortStatus(true); + lastRemoteBolusTime = DateUtil.now(); + sendSMSToAllNumbers(new Sms(receivedSms.phoneNumber, reply)); + } else { + String reply = MainApp.gs(R.string.smscommunicator_bolusfailed); + if (pump != null) + reply += "\n" + pump.shortStatus(true); + sendSMS(new Sms(receivedSms.phoneNumber, reply)); + } + } + }); + } + }); + } + }); + } else + sendSMS(new Sms(receivedSms.phoneNumber, R.string.wrongformat)); + } + + private void processCAL(String[] splitted, Sms receivedSms) { + Double cal = SafeParse.stringToDouble(splitted[1]); + if (cal > 0d) { + String passCode = generatePasscode(); + String reply = String.format(MainApp.gs(R.string.smscommunicator_calibrationreplywithcode), cal, passCode); + receivedSms.processed = true; + messageToConfirm = new AuthRequest(this, receivedSms, reply, passCode, new SmsAction() { + @Override + public void run() { + boolean result = XdripCalibrations.sendIntent(aDouble); + if (result) + sendSMSToAllNumbers(new Sms(receivedSms.phoneNumber, R.string.smscommunicator_calibrationsent)); + else + sendSMS(new Sms(receivedSms.phoneNumber, R.string.smscommunicator_calibrationfailed)); + } + }); + } else + sendSMS(new Sms(receivedSms.phoneNumber, R.string.wrongformat)); + } + public void sendNotificationToAllNumbers(String text) { for (int i = 0; i < allowedNumbers.size(); i++) { - Sms sms = new Sms(allowedNumbers.get(i), text, System.currentTimeMillis()); + Sms sms = new Sms(allowedNumbers.get(i), text); sendSMS(sms); } } @@ -562,12 +757,13 @@ public class SmsCommunicatorPlugin extends PluginBase { } } - private void sendSMS(Sms sms) { + void sendSMS(Sms sms) { SmsManager smsManager = SmsManager.getDefault(); sms.text = stripAccents(sms.text); if (sms.text.length() > 140) sms.text = sms.text.substring(0, 139); try { - log.debug("Sending SMS to " + sms.phoneNumber + ": " + sms.text); + if (L.isEnabled(L.SMS)) + log.debug("Sending SMS to " + sms.phoneNumber + ": " + sms.text); smsManager.sendTextMessage(sms.phoneNumber, null, sms.text, null, null); messages.add(sms); } catch (IllegalArgumentException e) { @@ -577,6 +773,7 @@ public class SmsCommunicatorPlugin extends PluginBase { Notification notification = new Notification(Notification.MISSING_SMS_PERMISSION, MainApp.gs(R.string.smscommunicator_missingsmspermission), Notification.NORMAL); MainApp.bus().post(new EventNewNotification(notification)); } + MainApp.bus().post(new EventSmsCommunicatorUpdateGui()); } private String generatePasscode() { @@ -586,17 +783,10 @@ public class SmsCommunicatorPlugin extends PluginBase { passCode += Character.toString((char) (startChar2 + Math.random() * ('z' - 'a' + 1))); int startChar3 = Math.random() > 0.5 ? 'a' : 'A'; passCode += Character.toString((char) (startChar3 + Math.random() * ('z' - 'a' + 1))); + passCode.replace('l', 'k').replace('I', 'J'); return passCode; } - private void resetWaitingMessages() { - tempBasalWaitingForConfirmation = null; - cancelTempBasalWaitingForConfirmation = null; - bolusWaitingForConfirmation = null; - calibrationWaitingForConfirmation = null; - suspendWaitingForConfirmation = null; - } - private static String stripAccents(String s) { s = Normalizer.normalize(s, Normalizer.Form.NFD); s = s.replaceAll("[\\p{InCombiningDiacriticalMarks}]", ""); diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/ActionStringHandler.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/ActionStringHandler.java index aef742b49b..b92410d67f 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/ActionStringHandler.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/ActionStringHandler.java @@ -693,7 +693,7 @@ public class ActionStringHandler { //send profile to pumpe new NewNSTreatmentDialog(); //init - NewNSTreatmentDialog.doProfileSwitch(0, percentage, timeshift); + ProfileFunctions.doProfileSwitch(0, percentage, timeshift); } private static void generateTempTarget(int duration, double low, double high) { diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/WearPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/WearPlugin.java index ca24c4ed9e..2d7f13f221 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/WearPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/WearPlugin.java @@ -2,6 +2,7 @@ package info.nightscout.androidaps.plugins.general.wear; import android.content.Context; import android.content.Intent; +import android.util.Log; import com.squareup.otto.Subscribe; @@ -9,7 +10,6 @@ import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.R; import info.nightscout.androidaps.events.EventBolusRequested; import info.nightscout.androidaps.events.EventExtendedBolusChange; -import info.nightscout.androidaps.events.EventNewBG; import info.nightscout.androidaps.events.EventNewBasalProfile; import info.nightscout.androidaps.events.EventPreferenceChange; import info.nightscout.androidaps.events.EventRefreshOverview; @@ -23,6 +23,7 @@ import info.nightscout.androidaps.plugins.aps.openAPSMA.events.EventOpenAPSUpdat import info.nightscout.androidaps.plugins.general.overview.events.EventDismissBolusprogressIfRunning; import info.nightscout.androidaps.plugins.general.overview.events.EventOverviewBolusProgress; import info.nightscout.androidaps.plugins.general.wear.wearintegration.WatchUpdaterService; +import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventAutosensCalculationFinished; import info.nightscout.androidaps.utils.SP; /** @@ -35,6 +36,8 @@ public class WearPlugin extends PluginBase { private final Context ctx; private static WearPlugin wearPlugin; + private static String TAG = "WearPlugin"; + public static WearPlugin getPlugin() { return wearPlugin; @@ -76,7 +79,10 @@ public class WearPlugin extends PluginBase { } private void sendDataToWatch(boolean status, boolean basals, boolean bgValue) { - if (isEnabled(getType())) { //only start service when this plugin is enabled + + //Log.d(TAG, "WR: WearPlugin:sendDataToWatch (status=" + status + ",basals=" + basals + ",bgValue=" + bgValue + ")"); + + if (isEnabled(getType())) { // only start service when this plugin is enabled if (bgValue) { ctx.startService(new Intent(ctx, WatchUpdaterService.class)); @@ -93,15 +99,20 @@ public class WearPlugin extends PluginBase { } void resendDataToWatch() { + //Log.d(TAG, "WR: WearPlugin:resendDataToWatch"); ctx.startService(new Intent(ctx, WatchUpdaterService.class).setAction(WatchUpdaterService.ACTION_RESEND)); } void openSettings() { + //Log.d(TAG, "WR: WearPlugin:openSettings"); ctx.startService(new Intent(ctx, WatchUpdaterService.class).setAction(WatchUpdaterService.ACTION_OPEN_SETTINGS)); } void requestNotificationCancel(String actionstring) { - Intent intent = new Intent(ctx, WatchUpdaterService.class).setAction(WatchUpdaterService.ACTION_CANCEL_NOTIFICATION); + //Log.d(TAG, "WR: WearPlugin:requestNotificationCancel"); + + Intent intent = new Intent(ctx, WatchUpdaterService.class) + .setAction(WatchUpdaterService.ACTION_CANCEL_NOTIFICATION); intent.putExtra("actionstring", actionstring); ctx.startService(intent); } @@ -136,7 +147,7 @@ public class WearPlugin extends PluginBase { } @Subscribe - public void onStatusEvent(final EventNewBG ev) { + public void onStatusEvent(final EventAutosensCalculationFinished ev) { sendDataToWatch(true, true, true); } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/wearintegration/SendToDataLayerThread.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/wearintegration/SendToDataLayerThread.java index d935bafec6..aa6498563d 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/wearintegration/SendToDataLayerThread.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/wearintegration/SendToDataLayerThread.java @@ -13,40 +13,127 @@ import com.google.android.gms.wearable.PutDataRequest; import com.google.android.gms.wearable.Wearable; import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.ReentrantLock; /** * Created by emmablack on 12/26/14. */ class SendToDataLayerThread extends AsyncTask { private GoogleApiClient googleApiClient; - private static final String TAG = "SendDataThread"; - String path; + private static final String TAG = "SendToDataLayerThread"; + private String path; + private String logPrefix = ""; // "WR: "; + private static int concurrency = 0; + private static int state = 0; + private static final ReentrantLock lock = new ReentrantLock(); + private static long lastlock = 0; + private static final boolean testlockup = false; // always false in production + SendToDataLayerThread(String path, GoogleApiClient pGoogleApiClient) { + // Log.d(TAG, logPrefix + "SendToDataLayerThread: " + path); this.path = path; googleApiClient = pGoogleApiClient; } + + @Override + protected void onPreExecute() { + concurrency++; + if ((concurrency > 12) || ((concurrency > 3 && (lastlock != 0) && (tsl() - lastlock) > 300000))) { + // error if 9 concurrent threads or lock held for >5 minutes with concurrency of 4 + final String err = "Wear Integration deadlock detected!! " + ((lastlock != 0) ? "locked" : "") + " state:" + + state + " @" + hourMinuteString(tsl()); + // Home.toaststaticnext(err); + Log.e(TAG, logPrefix + err); + } + if (concurrency < 0) + Log.d(TAG, logPrefix + "Wear Integration impossible concurrency!!"); + + Log.d(TAG, logPrefix + "SendDataToLayerThread pre-execute concurrency: " + concurrency); + } + + @Override protected Void doInBackground(DataMap... params) { - try { - final NodeApi.GetConnectedNodesResult nodes = Wearable.NodeApi.getConnectedNodes(googleApiClient).await(15, TimeUnit.SECONDS); - for (Node node : nodes.getNodes()) { - for (DataMap dataMap : params) { - PutDataMapRequest putDMR = PutDataMapRequest.create(path); - putDMR.getDataMap().putAll(dataMap); - PutDataRequest request = putDMR.asPutDataRequest(); - DataApi.DataItemResult result = Wearable.DataApi.putDataItem(googleApiClient, request).await(15, TimeUnit.SECONDS); - if (result.getStatus().isSuccess()) { - Log.d(TAG, "DataMap: " + dataMap + " sent to: " + node.getDisplayName()); - } else { - Log.d(TAG, "ERROR: failed to send DataMap"); - } - } + if (testlockup) { + try { + Log.e(TAG, logPrefix + "WARNING RUNNING TEST LOCK UP CODE - NEVER FOR PRODUCTION"); + Thread.sleep(1000000); // DEEEBBUUGGGG + } catch (Exception e) { } - } catch (Exception e) { - Log.e(TAG, "Got exception sending data to wear: " + e.toString()); } + sendToWear(params); + concurrency--; + Log.d(TAG, logPrefix + "SendDataToLayerThread post-execute concurrency: " + concurrency); return null; } + + + // Debug function to expose where it might be locking up + private synchronized void sendToWear(final DataMap... params) { + if (!lock.tryLock()) { + Log.d(TAG, logPrefix + "Concurrent access - waiting for thread unlock"); + lock.lock(); // enforce single threading + Log.d(TAG, logPrefix + "Thread unlocked - proceeding"); + } + lastlock = tsl(); + try { + if (state != 0) { + Log.e(TAG, logPrefix + "WEAR STATE ERROR: state=" + state); + } + state = 1; + final NodeApi.GetConnectedNodesResult nodes = Wearable.NodeApi.getConnectedNodes(googleApiClient).await(15, + TimeUnit.SECONDS); + + Log.d(TAG, logPrefix + "Nodes: " + nodes); + + state = 2; + for (Node node : nodes.getNodes()) { + state = 3; + for (DataMap dataMap : params) { + state = 4; + PutDataMapRequest putDMR = PutDataMapRequest.create(path); + state = 5; + putDMR.getDataMap().putAll(dataMap); + putDMR.setUrgent(); + state = 6; + PutDataRequest request = putDMR.asPutDataRequest(); + state = 7; + DataApi.DataItemResult result = Wearable.DataApi.putDataItem(googleApiClient, request).await(15, + TimeUnit.SECONDS); + state = 8; + if (result.getStatus().isSuccess()) { + Log.d(TAG, logPrefix + "DataMap: " + dataMap + " sent to: " + node.getDisplayName()); + } else { + Log.e(TAG, logPrefix + "ERROR: failed to send DataMap"); + result = Wearable.DataApi.putDataItem(googleApiClient, request).await(30, TimeUnit.SECONDS); + if (result.getStatus().isSuccess()) { + Log.d(TAG, logPrefix + "DataMap retry: " + dataMap + " sent to: " + node.getDisplayName()); + } else { + Log.e(TAG, logPrefix + "ERROR on retry: failed to send DataMap: " + + result.getStatus().toString()); + } + } + state = 9; + } + } + state = 0; + } catch (Exception e) { + Log.e(TAG, logPrefix + "Got exception in sendToWear: " + e.toString()); + } finally { + lastlock = 0; + lock.unlock(); + } + } + + + private static long tsl() { + return System.currentTimeMillis(); + } + + + private static String hourMinuteString(long timestamp) { + return android.text.format.DateFormat.format("kk:mm", timestamp).toString(); + } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/wearintegration/WatchUpdaterService.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/wearintegration/WatchUpdaterService.java index 12dc116895..52dbeed75c 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/wearintegration/WatchUpdaterService.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/wearintegration/WatchUpdaterService.java @@ -1,9 +1,17 @@ package info.nightscout.androidaps.plugins.general.wear.wearintegration; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.SharedPreferences; +import android.os.AsyncTask; import android.os.BatteryManager; import android.os.Bundle; import android.os.Handler; @@ -14,8 +22,11 @@ import android.util.Log; import com.google.android.gms.common.ConnectionResult; import com.google.android.gms.common.api.GoogleApiClient; +import com.google.android.gms.wearable.CapabilityApi; +import com.google.android.gms.wearable.CapabilityInfo; import com.google.android.gms.wearable.DataMap; import com.google.android.gms.wearable.MessageEvent; +import com.google.android.gms.wearable.Node; import com.google.android.gms.wearable.PutDataMapRequest; import com.google.android.gms.wearable.PutDataRequest; import com.google.android.gms.wearable.Wearable; @@ -42,21 +53,24 @@ import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorP import info.nightscout.androidaps.plugins.treatments.Treatment; import info.nightscout.androidaps.interfaces.PluginType; import info.nightscout.androidaps.interfaces.TreatmentsInterface; -import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin; +import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin; +import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions; import info.nightscout.androidaps.plugins.general.nsclient.data.NSDeviceStatus; import info.nightscout.androidaps.plugins.general.overview.OverviewPlugin; import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin; import info.nightscout.androidaps.plugins.general.wear.ActionStringHandler; import info.nightscout.androidaps.plugins.general.wear.WearPlugin; +import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin; +import info.nightscout.androidaps.plugins.treatments.Treatment; +import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin; import info.nightscout.androidaps.utils.DecimalFormatter; import info.nightscout.androidaps.utils.SP; import info.nightscout.androidaps.utils.SafeParse; import info.nightscout.androidaps.utils.ToastUtils; -public class WatchUpdaterService extends WearableListenerService implements - GoogleApiClient.ConnectionCallbacks, - GoogleApiClient.OnConnectionFailedListener { +public class WatchUpdaterService extends WearableListenerService implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener { + public static final String ACTION_RESEND = WatchUpdaterService.class.getName().concat(".Resend"); public static final String ACTION_OPEN_SETTINGS = WatchUpdaterService.class.getName().concat(".OpenSettings"); public static final String ACTION_SEND_STATUS = WatchUpdaterService.class.getName().concat(".SendStatus"); @@ -91,6 +105,17 @@ public class WatchUpdaterService extends WearableListenerService implements private Handler handler; + // Phone + private static final String CAPABILITY_PHONE_APP = "phone_app_sync_bgs"; + private static final String MESSAGE_PATH_PHONE = "/phone_message_path"; + // Wear + private static final String CAPABILITY_WEAR_APP = "wear_app_sync_bgs"; + private static final String MESSAGE_PATH_WEAR = "/wear_message_path"; + private String mWearNodeId = null; + private String localnode = null; + private String logPrefix = ""; // "WR: " + + @Override public void onCreate() { mPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); @@ -112,24 +137,24 @@ public class WatchUpdaterService extends WearableListenerService implements public void setSettings() { wear_integration = WearPlugin.getPlugin().isEnabled(PluginType.GENERAL); + // Log.d(TAG, "WR: wear_integration=" + wear_integration); if (wear_integration) { googleApiConnect(); } } - public void googleApiConnect() { + + private void googleApiConnect() { if (googleApiClient != null && (googleApiClient.isConnected() || googleApiClient.isConnecting())) { googleApiClient.disconnect(); } - googleApiClient = new GoogleApiClient.Builder(this) - .addConnectionCallbacks(this) - .addOnConnectionFailedListener(this) - .addApi(Wearable.API) - .build(); + googleApiClient = new GoogleApiClient.Builder(this).addConnectionCallbacks(this) + .addOnConnectionFailedListener(this).addApi(Wearable.API).build(); Wearable.MessageApi.addListener(googleApiClient, this); if (googleApiClient.isConnected()) { - Log.d("WatchUpdater", "API client is connected"); + log.debug(logPrefix + "API client is connected"); } else { + // Log.d("WatchUpdater", logPrefix + "API client is not connected and is trying to connect"); googleApiClient.connect(); } } @@ -138,6 +163,8 @@ public class WatchUpdaterService extends WearableListenerService implements public int onStartCommand(Intent intent, int flags, int startId) { String action = intent != null ? intent.getAction() : null; + // Log.d(TAG, logPrefix + "onStartCommand: " + action); + if (wear_integration) { handler.post(() -> { if (googleApiClient.isConnected()) { @@ -177,13 +204,63 @@ public class WatchUpdaterService extends WearableListenerService implements } + private void updateWearSyncBgsCapability(CapabilityInfo capabilityInfo) { + Log.d("WatchUpdaterService", logPrefix + "CabilityInfo: " + capabilityInfo); + Set connectedNodes = capabilityInfo.getNodes(); + mWearNodeId = pickBestNodeId(connectedNodes); + } + + + private String pickBestNodeId(Set nodes) { + String bestNodeId = null; + // Find a nearby node or pick one arbitrarily + for (Node node : nodes) { + if (node.isNearby()) { + return node.getId(); + } + bestNodeId = node.getId(); + } + return bestNodeId; + } + + @Override public void onConnected(Bundle connectionHint) { + CapabilityApi.CapabilityListener capabilityListener = capabilityInfo -> { + updateWearSyncBgsCapability(capabilityInfo); + // Log.d(TAG, logPrefix + "onConnected onCapabilityChanged mWearNodeID:" + mWearNodeId); + // new CheckWearableConnected().execute(); + }; + + Wearable.CapabilityApi.addCapabilityListener(googleApiClient, capabilityListener, CAPABILITY_WEAR_APP); sendData(); } + + @Override + public void onPeerConnected(com.google.android.gms.wearable.Node peer) {// KS + super.onPeerConnected(peer); + String id = peer.getId(); + String name = peer.getDisplayName(); + // Log.d(TAG, logPrefix + "onPeerConnected peer name & ID: " + name + "|" + id); + } + + + @Override + public void onPeerDisconnected(com.google.android.gms.wearable.Node peer) {// KS + super.onPeerDisconnected(peer); + String id = peer.getId(); + String name = peer.getDisplayName(); + // Log.d(TAG, logPrefix + "onPeerDisconnected peer name & ID: " + name + "|" + id); + SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); + } + + @Override public void onMessageReceived(MessageEvent event) { + + // Log.d(TAG, logPrefix + "onMessageRecieved: " + event); + if (wear_integration) { if (event != null && event.getPath().equals(WEARABLE_RESEND_PATH)) { resendData(); @@ -214,6 +291,7 @@ public class WatchUpdaterService extends WearableListenerService implements private void sendData() { BgReading lastBG = DatabaseHelper.lastBg(); + // Log.d(TAG, logPrefix + "LastBg=" + lastBG); if (lastBG != null) { GlucoseStatus glucoseStatus = GlucoseStatus.getGlucoseStatusData(); @@ -228,18 +306,19 @@ public class WatchUpdaterService extends WearableListenerService implements return; } - new SendToDataLayerThread(WEARABLE_DATA_PATH, googleApiClient).execute(dataMap); + executeTask(new SendToDataLayerThread(WEARABLE_DATA_PATH, googleApiClient), dataMap); } } } + private DataMap dataMapSingleBG(BgReading lastBG, GlucoseStatus glucoseStatus) { String units = ProfileFunctions.getInstance().getProfileUnits(); Double lowLine = SafeParse.stringToDouble(mPrefs.getString("low_mark", "0")); Double highLine = SafeParse.stringToDouble(mPrefs.getString("high_mark", "0")); - //convert to mg/dl + // convert to mg/dl if (!units.equals(Constants.MGDL)) { lowLine *= Constants.MMOLL_TO_MGDL; highLine *= Constants.MMOLL_TO_MGDL; @@ -287,7 +366,6 @@ public class WatchUpdaterService extends WearableListenerService implements deltastring += "+"; } else { deltastring += "-"; - } boolean detailed = SP.getBoolean("wear_detailed_delta", false); @@ -352,7 +430,7 @@ public class WatchUpdaterService extends WearableListenerService implements } } entries.putDataMapArrayList("entries", dataMaps); - new SendToDataLayerThread(WEARABLE_DATA_PATH, googleApiClient).execute(entries); + executeTask(new SendToDataLayerThread(WEARABLE_DATA_PATH, googleApiClient), entries); } sendPreferences(); sendBasals(); @@ -501,7 +579,7 @@ public class WatchUpdaterService extends WearableListenerService implements dm.putDataMapArrayList("boluses", boluses); dm.putDataMapArrayList("predictions", predictions); - new SendToDataLayerThread(BASAL_DATA_PATH, googleApiClient).execute(dm); + executeTask(new SendToDataLayerThread(BASAL_DATA_PATH, googleApiClient), dm); } private DataMap tempDatamap(long startTime, double startBasal, long to, double toBasal, double amount) { @@ -548,6 +626,7 @@ public class WatchUpdaterService extends WearableListenerService implements dataMapRequest.getDataMap().putLong("timestamp", System.currentTimeMillis()); dataMapRequest.getDataMap().putString("openSettings", "openSettings"); PutDataRequest putDataRequest = dataMapRequest.asPutDataRequest(); + debugData("sendNotification", putDataRequest); Wearable.DataApi.putDataItem(googleApiClient, putDataRequest); } else { Log.e("OpenSettings", "No connection to wearable available!"); @@ -563,6 +642,7 @@ public class WatchUpdaterService extends WearableListenerService implements dataMapRequest.getDataMap().putString("progressstatus", status); dataMapRequest.getDataMap().putInt("progresspercent", progresspercent); PutDataRequest putDataRequest = dataMapRequest.asPutDataRequest(); + debugData("sendBolusProgress", putDataRequest); Wearable.DataApi.putDataItem(googleApiClient, putDataRequest); } else { Log.e("BolusProgress", "No connection to wearable available!"); @@ -582,6 +662,7 @@ public class WatchUpdaterService extends WearableListenerService implements log.debug("Requesting confirmation from wear: " + actionstring); PutDataRequest putDataRequest = dataMapRequest.asPutDataRequest(); + debugData("sendActionConfirmationRequest", putDataRequest); Wearable.DataApi.putDataItem(googleApiClient, putDataRequest); } else { Log.e("confirmationRequest", "No connection to wearable available!"); @@ -601,6 +682,7 @@ public class WatchUpdaterService extends WearableListenerService implements log.debug("Requesting confirmation from wear: " + actionstring); PutDataRequest putDataRequest = dataMapRequest.asPutDataRequest(); + debugData("sendChangeConfirmationRequest", putDataRequest); Wearable.DataApi.putDataItem(googleApiClient, putDataRequest); } else { Log.e("changeConfirmRequest", "No connection to wearable available!"); @@ -618,9 +700,10 @@ public class WatchUpdaterService extends WearableListenerService implements log.debug("Canceling notification on wear: " + actionstring); PutDataRequest putDataRequest = dataMapRequest.asPutDataRequest(); + debugData("sendCancelNotificationRequest", putDataRequest); Wearable.DataApi.putDataItem(googleApiClient, putDataRequest); } else { - Log.e("cancelNotificationRequest", "No connection to wearable available!"); + Log.e("cancelNotificationReq", "No connection to wearable available!"); } } @@ -683,6 +766,7 @@ public class WatchUpdaterService extends WearableListenerService implements dataMapRequest.getDataMap().putBoolean("showBgi", mPrefs.getBoolean("wear_showbgi", false)); dataMapRequest.getDataMap().putInt("batteryLevel", (phoneBattery >= 30) ? 1 : 0); PutDataRequest putDataRequest = dataMapRequest.asPutDataRequest(); + debugData("sendStatus", putDataRequest); Wearable.DataApi.putDataItem(googleApiClient, putDataRequest); } else { Log.e("SendStatus", "No connection to wearable available!"); @@ -699,12 +783,29 @@ public class WatchUpdaterService extends WearableListenerService implements dataMapRequest.getDataMap().putLong("timestamp", System.currentTimeMillis()); dataMapRequest.getDataMap().putBoolean("wearcontrol", wearcontrol); PutDataRequest putDataRequest = dataMapRequest.asPutDataRequest(); + debugData("sendPreferences", putDataRequest); Wearable.DataApi.putDataItem(googleApiClient, putDataRequest); } else { Log.e("SendStatus", "No connection to wearable available!"); } } + + private void debugData(String source, Object data) { + // Log.d(TAG, "WR: " + source + " " + data); + } + + + private void executeTask(AsyncTask task, DataMap... parameters) { + task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Object[])parameters); + // if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { + // task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + // } else { + // task.execute(); + // } + } + + @NonNull private String generateStatusString(Profile profile, String currentBasal, String iobSum, String iobDetail, String bgiString) { diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/xdripStatusline/StatuslinePlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/xdripStatusline/StatuslinePlugin.java index d0794bf4d5..fe89cc8304 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/xdripStatusline/StatuslinePlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/xdripStatusline/StatuslinePlugin.java @@ -17,7 +17,6 @@ import info.nightscout.androidaps.db.TemporaryBasal; import info.nightscout.androidaps.events.EventAppInitialized; import info.nightscout.androidaps.events.EventConfigBuilderChange; import info.nightscout.androidaps.events.EventExtendedBolusChange; -import info.nightscout.androidaps.events.EventNewBG; import info.nightscout.androidaps.events.EventPreferenceChange; import info.nightscout.androidaps.events.EventRefreshOverview; import info.nightscout.androidaps.events.EventTempBasalChange; @@ -26,10 +25,11 @@ import info.nightscout.androidaps.interfaces.PluginBase; import info.nightscout.androidaps.interfaces.PluginDescription; import info.nightscout.androidaps.interfaces.PluginType; import info.nightscout.androidaps.interfaces.TreatmentsInterface; +import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin; import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions; import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin; -import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin; +import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventAutosensCalculationFinished; import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin; import info.nightscout.androidaps.utils.DecimalFormatter; @@ -115,7 +115,7 @@ public class StatuslinePlugin extends PluginBase { if (ConfigBuilderPlugin.getPlugin().getActivePump() == null) return ""; - + LoopPlugin loopPlugin = LoopPlugin.getPlugin(); if (!loopPlugin.isEnabled(PluginType.LOOP)) { @@ -138,7 +138,7 @@ public class StatuslinePlugin extends PluginBase { IobTotal bolusIob = treatmentsInterface.getLastCalculationTreatments().round(); treatmentsInterface.updateTotalIOBTempBasals(); IobTotal basalIob = treatmentsInterface.getLastCalculationTempBasals().round(); - status += DecimalFormatter.to2Decimal(bolusIob.iob + basalIob.basaliob)+"U"; + status += DecimalFormatter.to2Decimal(bolusIob.iob + basalIob.basaliob) + "U"; if (mPrefs.getBoolean("xdripstatus_detailediob", true)) { @@ -182,7 +182,7 @@ public class StatuslinePlugin extends PluginBase { } @Subscribe - public void onStatusEvent(final EventNewBG ev) { + public void onStatusEvent(final EventAutosensCalculationFinished ev) { sendStatus(); } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobCalculatorPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobCalculatorPlugin.java index d08485dd1a..aac0985fba 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobCalculatorPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobCalculatorPlugin.java @@ -65,8 +65,6 @@ public class IobCobCalculatorPlugin extends PluginBase { private volatile List bgReadings = null; // newest at index 0 private volatile List bucketed_data = null; - private double dia = Constants.defaultDIA; - final Object dataLock = new Object(); boolean stopCalculationTrigger = false; @@ -118,11 +116,22 @@ public class IobCobCalculatorPlugin extends PluginBase { return rounded; } - void loadBgData(long now) { - long start = (long) (now - 60 * 60 * 1000L * (24 + dia)); - bgReadings = MainApp.getDbHelper().getBgreadingsDataFromTime(start, now, false); - if (L.isEnabled(L.AUTOSENS)) - log.debug("BG data loaded. Size: " + bgReadings.size() + " Start date: " + DateUtil.dateAndTimeString(start) + " End date: " + DateUtil.dateAndTimeString(now)); + void loadBgData(long to) { + Profile profile = ProfileFunctions.getInstance().getProfile(to); + double dia = Constants.defaultDIA; + if (profile != null) dia = profile.getDia(); + long start = to - T.hours((long) (24 + dia)).msecs(); + if (DateUtil.isCloseToNow(to)) { + // if close to now expect there can be some readings with time in close future (caused by wrong time setting) + // so read all records + bgReadings = MainApp.getDbHelper().getBgreadingsDataFromTime(start, false); + if (L.isEnabled(L.AUTOSENS)) + log.debug("BG data loaded. Size: " + bgReadings.size() + " Start date: " + DateUtil.dateAndTimeString(start)); + } else { + bgReadings = MainApp.getDbHelper().getBgreadingsDataFromTime(start, to, false); + if (L.isEnabled(L.AUTOSENS)) + log.debug("BG data loaded. Size: " + bgReadings.size() + " Start date: " + DateUtil.dateAndTimeString(start) + " End date: " + DateUtil.dateAndTimeString(to)); + } } public boolean isAbout5minData() { @@ -608,10 +617,6 @@ public class IobCobCalculatorPlugin extends PluginBase { } if (ConfigBuilderPlugin.getPlugin() == null) return; // app still initializing - Profile profile = ProfileFunctions.getInstance().getProfile(); - if (profile == null) - return; // app still initializing - dia = profile.getDia(); if (ev == null) { // on init no need of reset return; } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobOref1Thread.java b/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobOref1Thread.java index fa590c9c0e..6dcb35ef9b 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobOref1Thread.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobOref1Thread.java @@ -41,6 +41,7 @@ import info.nightscout.androidaps.utils.FabricPrivacy; import info.nightscout.androidaps.utils.MidnightTime; import info.nightscout.androidaps.utils.Profiler; import info.nightscout.androidaps.utils.SP; +import info.nightscout.androidaps.utils.T; import static info.nightscout.androidaps.utils.DateUtil.now; import static java.util.Calendar.MINUTE; @@ -61,7 +62,7 @@ public class IobCobOref1Thread extends Thread { private PowerManager.WakeLock mWakeLock; - public IobCobOref1Thread(IobCobCalculatorPlugin plugin, String from, long end, boolean bgDataReload, boolean limitDataToOldestAvailable, Event cause) { + IobCobOref1Thread(IobCobCalculatorPlugin plugin, String from, long end, boolean bgDataReload, boolean limitDataToOldestAvailable, Event cause) { super(); this.iobCobCalculatorPlugin = plugin; @@ -72,13 +73,15 @@ public class IobCobOref1Thread extends Thread { this.end = end; PowerManager powerManager = (PowerManager) MainApp.instance().getApplicationContext().getSystemService(Context.POWER_SERVICE); - mWakeLock = powerManager.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, "iobCobThread"); + if (powerManager != null) + mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, MainApp.gs(R.string.app_name) + ":iobCobThread"); } @Override public final void run() { long start = DateUtil.now(); - mWakeLock.acquire(); + if (mWakeLock != null) + mWakeLock.acquire(T.mins(10).msecs()); try { if (L.isEnabled(L.AUTOSENS)) log.debug("AUTOSENSDATA thread started: " + from); @@ -173,7 +176,7 @@ public class IobCobOref1Thread extends Thread { double bgi = -iob.activity * sens * 5; double deviation = delta - bgi; - double avgDeviation = Math.round((avgDelta - bgi) * 1000) / 1000; + double avgDeviation = Math.round((avgDelta - bgi) * 1000) / 1000d; double slopeFromMaxDeviation = 0; double slopeFromMinDeviation = 999; @@ -395,7 +398,8 @@ public class IobCobOref1Thread extends Thread { MainApp.bus().post(new EventAutosensCalculationFinished(cause)); }).start(); } finally { - mWakeLock.release(); + if (mWakeLock != null) + mWakeLock.release(); MainApp.bus().post(new EventIobCalculationProgress("")); if (L.isEnabled(L.AUTOSENS)) { log.debug("AUTOSENSDATA thread ended: " + from); diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobThread.java b/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobThread.java index 89bc0a6606..2970f07aca 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobThread.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobThread.java @@ -41,6 +41,7 @@ import info.nightscout.androidaps.utils.FabricPrivacy; import info.nightscout.androidaps.utils.MidnightTime; import info.nightscout.androidaps.utils.Profiler; import info.nightscout.androidaps.utils.SP; +import info.nightscout.androidaps.utils.T; import static info.nightscout.androidaps.utils.DateUtil.now; @@ -60,7 +61,7 @@ public class IobCobThread extends Thread { private PowerManager.WakeLock mWakeLock; - public IobCobThread(IobCobCalculatorPlugin plugin, String from, long end, boolean bgDataReload, boolean limitDataToOldestAvailable, Event cause) { + IobCobThread(IobCobCalculatorPlugin plugin, String from, long end, boolean bgDataReload, boolean limitDataToOldestAvailable, Event cause) { super(); this.iobCobCalculatorPlugin = plugin; @@ -71,13 +72,15 @@ public class IobCobThread extends Thread { this.end = end; PowerManager powerManager = (PowerManager) MainApp.instance().getApplicationContext().getSystemService(Context.POWER_SERVICE); - mWakeLock = powerManager.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, "iobCobThread"); + if (powerManager != null) + mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, MainApp.gs(R.string.app_name) + ":iobCobThread"); } @Override public final void run() { long start = DateUtil.now(); - mWakeLock.acquire(); + if (mWakeLock != null) + mWakeLock.acquire(T.mins(10).msecs()); try { if (L.isEnabled(L.AUTOSENS)) log.debug("AUTOSENSDATA thread started: " + from); @@ -172,7 +175,7 @@ public class IobCobThread extends Thread { double bgi = -iob.activity * sens * 5; double deviation = delta - bgi; - double avgDeviation = Math.round((avgDelta - bgi) * 1000) / 1000; + double avgDeviation = Math.round((avgDelta - bgi) * 1000) / 1000d; double slopeFromMaxDeviation = 0; double slopeFromMinDeviation = 999; @@ -321,7 +324,8 @@ public class IobCobThread extends Thread { MainApp.bus().post(new EventAutosensCalculationFinished(cause)); }).start(); } finally { - mWakeLock.release(); + if (mWakeLock != null) + mWakeLock.release(); MainApp.bus().post(new EventIobCalculationProgress("")); if (L.isEnabled(L.AUTOSENS)) { log.debug("AUTOSENSDATA thread ended: " + from); diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/profile/ns/NSProfileFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/profile/ns/NSProfileFragment.java index 913f6a1d12..66b895839d 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/profile/ns/NSProfileFragment.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/profile/ns/NSProfileFragment.java @@ -22,7 +22,6 @@ import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.R; import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.data.ProfileStore; -import info.nightscout.androidaps.plugins.general.careportal.Dialogs.NewNSTreatmentDialog; import info.nightscout.androidaps.plugins.common.SubscriberFragment; import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions; import info.nightscout.androidaps.plugins.profile.ns.events.EventNSProfileUpdateGUI; @@ -157,7 +156,7 @@ public class NSProfileFragment extends SubscriberFragment { Profile profile = store.getSpecificProfile(name); if (profile != null) { OKDialog.showConfirmation(getActivity(), MainApp.gs(R.string.activate_profile) + ": " + name + " ?", () -> - NewNSTreatmentDialog.doProfileSwitch(store, name, 0, 100, 0) + ProfileFunctions.doProfileSwitch(store, name, 0, 100, 0) ); } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/combo/ComboPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/pump/combo/ComboPlugin.java index c666d18699..557ba42168 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/combo/ComboPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/combo/ComboPlugin.java @@ -42,6 +42,8 @@ import info.nightscout.androidaps.logging.L; import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderFragment; import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions; +import info.nightscout.androidaps.plugins.general.actions.defs.CustomAction; +import info.nightscout.androidaps.plugins.general.actions.defs.CustomActionType; import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification; import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification; import info.nightscout.androidaps.plugins.general.overview.events.EventOverviewBolusProgress; @@ -64,7 +66,6 @@ import info.nightscout.androidaps.plugins.treatments.Treatment; import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin; import info.nightscout.androidaps.utils.DateUtil; import info.nightscout.androidaps.utils.SP; - /** * Created by mike on 05.08.2016. */ @@ -1379,4 +1380,20 @@ public class ComboPlugin extends PluginBase implements PumpInterface, Constraint maxIob.setIfSmaller(0d, String.format(MainApp.gs(R.string.limitingmaxiob), 0d, MainApp.gs(R.string.unsafeusage)), this); return maxIob; } + + @Override + public List getCustomActions() { + return null; + } + + @Override + public void executeCustomAction(CustomActionType customActionType) { + + } + + @Override + public boolean canHandleDST() { + return false; + } + } \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/danaR/AbstractDanaRPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/pump/danaR/AbstractDanaRPlugin.java index dcc98bc9c0..749307e1a7 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/danaR/AbstractDanaRPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/danaR/AbstractDanaRPlugin.java @@ -8,6 +8,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.Date; +import java.util.List; import info.nightscout.androidaps.BuildConfig; import info.nightscout.androidaps.MainApp; @@ -27,6 +28,8 @@ import info.nightscout.androidaps.interfaces.ProfileInterface; import info.nightscout.androidaps.interfaces.PumpDescription; import info.nightscout.androidaps.interfaces.PumpInterface; import info.nightscout.androidaps.logging.L; +import info.nightscout.androidaps.plugins.general.actions.defs.CustomAction; +import info.nightscout.androidaps.plugins.general.actions.defs.CustomActionType; import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification; import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification; import info.nightscout.androidaps.plugins.general.overview.notifications.Notification; @@ -473,4 +476,24 @@ public abstract class AbstractDanaRPlugin extends PluginBase implements PumpInte } // TODO: daily total constraint + + @Override + public List getCustomActions() { + return null; + } + + + @Override + public void executeCustomAction(CustomActionType customActionType) { + + } + + @Override + public boolean canHandleDST() { + return false; + } + + + + } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/danaRS/DanaRSPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/pump/danaRS/DanaRSPlugin.java index 681e13eb8c..ddbb8547ae 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/danaRS/DanaRSPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/danaRS/DanaRSPlugin.java @@ -16,6 +16,8 @@ import org.json.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.List; + import info.nightscout.androidaps.BuildConfig; import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.R; @@ -39,6 +41,8 @@ import info.nightscout.androidaps.logging.L; import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderFragment; import info.nightscout.androidaps.plugins.configBuilder.DetailedBolusInfoStorage; import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions; +import info.nightscout.androidaps.plugins.general.actions.defs.CustomAction; +import info.nightscout.androidaps.plugins.general.actions.defs.CustomActionType; import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification; import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification; import info.nightscout.androidaps.plugins.general.overview.notifications.Notification; @@ -813,4 +817,19 @@ public class DanaRSPlugin extends PluginBase implements PumpInterface, DanaRInte return loadHistory(RecordTypes.RECORD_TYPE_DAILY); } + @Override + public List getCustomActions() { + return null; + } + + @Override + public void executeCustomAction(CustomActionType customActionType) { + + } + + @Override + public boolean canHandleDST() { + return false; + } + } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/danaRv2/DanaRv2Plugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/pump/danaRv2/DanaRv2Plugin.java index 438142f5f1..9e3ca499d0 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/danaRv2/DanaRv2Plugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/danaRv2/DanaRv2Plugin.java @@ -19,9 +19,11 @@ import info.nightscout.androidaps.db.TemporaryBasal; import info.nightscout.androidaps.events.EventAppExit; import info.nightscout.androidaps.interfaces.Constraint; import info.nightscout.androidaps.logging.L; + import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderFragment; import info.nightscout.androidaps.plugins.configBuilder.DetailedBolusInfoStorage; import info.nightscout.androidaps.plugins.pump.common.defs.PumpType; + import info.nightscout.androidaps.plugins.pump.danaR.AbstractDanaRPlugin; import info.nightscout.androidaps.plugins.pump.danaR.DanaRPump; import info.nightscout.androidaps.plugins.pump.danaR.comm.MsgBolusStartWithSpeed; diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/insight/LocalInsightFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/pump/insight/LocalInsightFragment.java index 4aefd391c1..26f5180f47 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/insight/LocalInsightFragment.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/insight/LocalInsightFragment.java @@ -298,4 +298,4 @@ public class LocalInsightFragment extends SubscriberFragment implements View.OnC statusItems.add(getStatusItem(label, MainApp.gs(R.string.eb_formatter, activeBolus.getRemainingAmount(), activeBolus.getInitialAmount(), activeBolus.getRemainingDuration()))); } } -} +} \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/insight/LocalInsightPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/pump/insight/LocalInsightPlugin.java index 1ef940aeb9..ccc38c1b9b 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/insight/LocalInsightPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/insight/LocalInsightPlugin.java @@ -8,6 +8,10 @@ import android.os.Handler; import android.os.IBinder; import android.os.Looper; +import info.nightscout.androidaps.plugins.general.actions.defs.CustomAction; +import info.nightscout.androidaps.plugins.general.actions.defs.CustomActionType; +import info.nightscout.androidaps.plugins.pump.insight.app_layer.parameter_blocks.*; +import info.nightscout.androidaps.plugins.pump.insight.descriptors.*; import org.json.JSONException; import org.json.JSONObject; import org.slf4j.Logger; @@ -69,12 +73,6 @@ import info.nightscout.androidaps.plugins.pump.insight.app_layer.history.history import info.nightscout.androidaps.plugins.pump.insight.app_layer.history.history_events.StartOfTBREvent; import info.nightscout.androidaps.plugins.pump.insight.app_layer.history.history_events.TotalDailyDoseEvent; import info.nightscout.androidaps.plugins.pump.insight.app_layer.history.history_events.TubeFilledEvent; -import info.nightscout.androidaps.plugins.pump.insight.app_layer.parameter_blocks.BRProfile1Block; -import info.nightscout.androidaps.plugins.pump.insight.app_layer.parameter_blocks.BRProfileBlock; -import info.nightscout.androidaps.plugins.pump.insight.app_layer.parameter_blocks.FactoryMinBolusAmountBlock; -import info.nightscout.androidaps.plugins.pump.insight.app_layer.parameter_blocks.MaxBasalAmountBlock; -import info.nightscout.androidaps.plugins.pump.insight.app_layer.parameter_blocks.MaxBolusAmountBlock; -import info.nightscout.androidaps.plugins.pump.insight.app_layer.parameter_blocks.TBROverNotificationBlock; import info.nightscout.androidaps.plugins.pump.insight.app_layer.remote_control.CancelBolusMessage; import info.nightscout.androidaps.plugins.pump.insight.app_layer.remote_control.CancelTBRMessage; import info.nightscout.androidaps.plugins.pump.insight.app_layer.remote_control.ChangeTBRMessage; @@ -98,18 +96,6 @@ import info.nightscout.androidaps.plugins.pump.insight.connection_service.Insigh import info.nightscout.androidaps.plugins.pump.insight.database.InsightBolusID; import info.nightscout.androidaps.plugins.pump.insight.database.InsightHistoryOffset; import info.nightscout.androidaps.plugins.pump.insight.database.InsightPumpID; -import info.nightscout.androidaps.plugins.pump.insight.descriptors.ActiveBasalRate; -import info.nightscout.androidaps.plugins.pump.insight.descriptors.ActiveBolus; -import info.nightscout.androidaps.plugins.pump.insight.descriptors.ActiveTBR; -import info.nightscout.androidaps.plugins.pump.insight.descriptors.AlertType; -import info.nightscout.androidaps.plugins.pump.insight.descriptors.BasalProfileBlock; -import info.nightscout.androidaps.plugins.pump.insight.descriptors.BatteryStatus; -import info.nightscout.androidaps.plugins.pump.insight.descriptors.BolusType; -import info.nightscout.androidaps.plugins.pump.insight.descriptors.CartridgeStatus; -import info.nightscout.androidaps.plugins.pump.insight.descriptors.InsightState; -import info.nightscout.androidaps.plugins.pump.insight.descriptors.OperatingMode; -import info.nightscout.androidaps.plugins.pump.insight.descriptors.PumpTime; -import info.nightscout.androidaps.plugins.pump.insight.descriptors.TotalDailyDose; import info.nightscout.androidaps.plugins.pump.insight.exceptions.InsightException; import info.nightscout.androidaps.plugins.pump.insight.exceptions.app_layer_errors.AppLayerErrorException; import info.nightscout.androidaps.plugins.pump.insight.exceptions.app_layer_errors.NoActiveTBRToCanceLException; @@ -152,6 +138,7 @@ public class LocalInsightPlugin extends PluginBase implements PumpInterface, Con private final Object $bolusLock = new Object[0]; private int bolusID; private boolean bolusCancelled; + private BasalProfile activeBasalProfile; private List profileBlocks; private boolean limitsFetched; private double maximumBolusAmount; @@ -345,6 +332,7 @@ public class LocalInsightPlugin extends PluginBase implements PumpInterface, Con } private void fetchBasalProfile() throws Exception { + activeBasalProfile = ParameterBlockUtil.readParameterBlock(connectionService, Service.CONFIGURATION, ActiveBRProfileBlock.class).getActiveBasalProfile(); profileBlocks = ParameterBlockUtil.readParameterBlock(connectionService, Service.CONFIGURATION, BRProfile1Block.class).getProfileBlocks(); } @@ -438,6 +426,10 @@ public class LocalInsightPlugin extends PluginBase implements PumpInterface, Con profileBlocks.add(profileBlock); } try { + ActiveBRProfileBlock activeBRProfileBlock = new ActiveBRProfileBlock(); + activeBRProfileBlock.setActiveBasalProfile(BasalProfile.PROFILE_1); + ParameterBlockUtil.writeConfigurationBlock(connectionService, activeBRProfileBlock); + activeBasalProfile = BasalProfile.PROFILE_1; BRProfileBlock profileBlock = new BRProfile1Block(); profileBlock.setProfileBlocks(profileBlocks); ParameterBlockUtil.writeConfigurationBlock(connectionService, profileBlock); @@ -475,6 +467,7 @@ public class LocalInsightPlugin extends PluginBase implements PumpInterface, Con public boolean isThisProfileSet(Profile profile) { if (!isInitialized() || profileBlocks == null) return true; if (profile.getBasalValues().length != profileBlocks.size()) return false; + if (activeBasalProfile != BasalProfile.PROFILE_1) return false; for (int i = 0; i < profileBlocks.size(); i++) { BasalProfileBlock profileBlock = profileBlocks.get(i); Profile.BasalValue basalValue = profile.getBasalValues()[i]; @@ -1068,6 +1061,16 @@ public class LocalInsightPlugin extends PluginBase implements PumpInterface, Con return new PumpEnactResult().success(true); } + @Override + public List getCustomActions() { + return null; + } + + @Override + public void executeCustomAction(CustomActionType customActionType) { + + } + private void readHistory() { try { PumpTime pumpTime = connectionService.requestMessage(new GetDateTimeMessage()).await().getPumpTime(); @@ -1566,4 +1569,9 @@ public class LocalInsightPlugin extends PluginBase implements PumpInterface, Con Notification notification = new Notification(Notification.INSIGHT_TIMEOUT_DURING_HANDSHAKE, MainApp.gs(R.string.timeout_during_handshake), Notification.URGENT); new Handler(Looper.getMainLooper()).post(() -> MainApp.bus().post(new EventNewNotification(notification))); } -} + + @Override + public boolean canHandleDST() { + return true; + } +} \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/mdi/MDIPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/pump/mdi/MDIPlugin.java index b717cda71f..89d1184581 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/mdi/MDIPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/mdi/MDIPlugin.java @@ -5,6 +5,8 @@ import org.json.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.List; + import info.nightscout.androidaps.BuildConfig; import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.R; @@ -17,9 +19,12 @@ import info.nightscout.androidaps.interfaces.PluginType; import info.nightscout.androidaps.interfaces.PumpDescription; import info.nightscout.androidaps.interfaces.PumpInterface; import info.nightscout.androidaps.logging.L; +import info.nightscout.androidaps.plugins.general.actions.defs.CustomAction; +import info.nightscout.androidaps.plugins.general.actions.defs.CustomActionType; import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin; import info.nightscout.androidaps.utils.DateUtil; + /** * Created by mike on 05.08.2016. */ @@ -137,14 +142,10 @@ public class MDIPlugin extends PluginBase implements PumpInterface { } @Override - public double getReservoirLevel() { - return -1; - } + public double getReservoirLevel() { return -1; } @Override - public int getBatteryLevel() { - return -1; - } + public int getBatteryLevel() { return -1; } @Override public PumpEnactResult deliverTreatment(DetailedBolusInfo detailedBolusInfo) { @@ -249,4 +250,19 @@ public class MDIPlugin extends PluginBase implements PumpInterface { return deviceID(); } + @Override + public List getCustomActions() { + return null; + } + + @Override + public void executeCustomAction(CustomActionType customActionType) { + + } + + @Override + public boolean canHandleDST() { + return true; + } + } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/virtual/VirtualPumpFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/pump/virtual/VirtualPumpFragment.java index b03847182c..0b764f5382 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/virtual/VirtualPumpFragment.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/virtual/VirtualPumpFragment.java @@ -20,11 +20,14 @@ import info.nightscout.androidaps.R; import info.nightscout.androidaps.db.ExtendedBolus; import info.nightscout.androidaps.db.TemporaryBasal; import info.nightscout.androidaps.plugins.common.SubscriberFragment; +import info.nightscout.androidaps.plugins.general.actions.defs.CustomAction; +import info.nightscout.androidaps.plugins.general.actions.defs.CustomActionType; import info.nightscout.androidaps.plugins.pump.common.defs.PumpType; import info.nightscout.androidaps.plugins.pump.virtual.events.EventVirtualPumpUpdateGui; import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin; import info.nightscout.androidaps.utils.FabricPrivacy; + public class VirtualPumpFragment extends SubscriberFragment { private static Logger log = LoggerFactory.getLogger(VirtualPumpFragment.class); @@ -119,4 +122,6 @@ public class VirtualPumpFragment extends SubscriberFragment { } }); } + + } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/virtual/VirtualPumpPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/pump/virtual/VirtualPumpPlugin.java index 6ede588389..461f71c31d 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/virtual/VirtualPumpPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/virtual/VirtualPumpPlugin.java @@ -9,6 +9,8 @@ import org.json.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.List; + import info.nightscout.androidaps.BuildConfig; import info.nightscout.androidaps.Config; import info.nightscout.androidaps.MainApp; @@ -27,6 +29,8 @@ import info.nightscout.androidaps.interfaces.PumpDescription; import info.nightscout.androidaps.interfaces.PumpInterface; import info.nightscout.androidaps.logging.L; import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions; +import info.nightscout.androidaps.plugins.general.actions.defs.CustomAction; +import info.nightscout.androidaps.plugins.general.actions.defs.CustomActionType; import info.nightscout.androidaps.plugins.general.nsclient.NSUpload; import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification; import info.nightscout.androidaps.plugins.general.overview.events.EventOverviewBolusProgress; @@ -37,6 +41,7 @@ import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin; import info.nightscout.androidaps.utils.DateUtil; import info.nightscout.androidaps.utils.SP; + /** * Created by mike on 05.08.2016. */ @@ -140,6 +145,16 @@ public class VirtualPumpPlugin extends PluginBase implements PumpInterface { return new PumpEnactResult(); } + @Override + public List getCustomActions() { + return null; + } + + @Override + public void executeCustomAction(CustomActionType customActionType) { + + } + @Override public boolean isInitialized() { return true; @@ -440,6 +455,11 @@ public class VirtualPumpPlugin extends PluginBase implements PumpInterface { return pumpType; } + @Override + public boolean canHandleDST() { + return true; + } + public void refreshConfiguration() { String pumptype = SP.getString(R.string.key_virtualpump_type, "Generic AAPS"); diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/source/BGSourceFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/source/BGSourceFragment.java index 09e85b2417..211cbb0bb0 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/source/BGSourceFragment.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/source/BGSourceFragment.java @@ -21,10 +21,10 @@ import info.nightscout.androidaps.Constants; import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.R; import info.nightscout.androidaps.db.BgReading; -import info.nightscout.androidaps.events.EventNewBG; import info.nightscout.androidaps.plugins.common.SubscriberFragment; import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.general.nsclient.NSUpload; +import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventAutosensCalculationFinished; import info.nightscout.androidaps.utils.DateUtil; import info.nightscout.androidaps.utils.FabricPrivacy; import info.nightscout.androidaps.utils.T; @@ -67,7 +67,7 @@ public class BGSourceFragment extends SubscriberFragment { } @Subscribe - public void onStatusEvent(final EventNewBG unused) { + public void onStatusEvent(final EventAutosensCalculationFinished unused) { updateGUI(); } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsBolusFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsBolusFragment.java index 083b63c924..64e93f3f95 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsBolusFragment.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsBolusFragment.java @@ -28,12 +28,12 @@ import info.nightscout.androidaps.R; import info.nightscout.androidaps.data.Iob; import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.db.Source; -import info.nightscout.androidaps.events.EventNewBG; import info.nightscout.androidaps.events.EventTreatmentChange; import info.nightscout.androidaps.plugins.common.SubscriberFragment; import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions; import info.nightscout.androidaps.plugins.general.nsclient.NSUpload; import info.nightscout.androidaps.plugins.general.nsclient.UploadQueue; +import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventAutosensCalculationFinished; import info.nightscout.androidaps.plugins.treatments.Treatment; import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin; import info.nightscout.androidaps.plugins.treatments.dialogs.WizardInfoDialog; @@ -266,7 +266,7 @@ public class TreatmentsBolusFragment extends SubscriberFragment implements View. } @Subscribe - public void onStatusEvent(final EventNewBG ev) { + public void onStatusEvent(final EventAutosensCalculationFinished ev) { updateGUI(); } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsExtendedBolusesFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsExtendedBolusesFragment.java index dbbf59311c..93f2a64006 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsExtendedBolusesFragment.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsExtendedBolusesFragment.java @@ -25,14 +25,14 @@ import info.nightscout.androidaps.data.IobTotal; import info.nightscout.androidaps.db.ExtendedBolus; import info.nightscout.androidaps.db.Source; import info.nightscout.androidaps.events.EventExtendedBolusChange; -import info.nightscout.androidaps.events.EventNewBG; import info.nightscout.androidaps.plugins.common.SubscriberFragment; +import info.nightscout.androidaps.plugins.general.nsclient.NSUpload; import info.nightscout.androidaps.plugins.general.nsclient.UploadQueue; +import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventAutosensCalculationFinished; import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin; import info.nightscout.androidaps.utils.DateUtil; import info.nightscout.androidaps.utils.DecimalFormatter; import info.nightscout.androidaps.utils.FabricPrivacy; -import info.nightscout.androidaps.plugins.general.nsclient.NSUpload; public class TreatmentsExtendedBolusesFragment extends SubscriberFragment { @@ -186,7 +186,7 @@ public class TreatmentsExtendedBolusesFragment extends SubscriberFragment { } @Subscribe - public void onStatusEvent(final EventNewBG ev) { + public void onStatusEvent(final EventAutosensCalculationFinished ev) { updateGUI(); } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsTemporaryBasalsFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsTemporaryBasalsFragment.java index dbb6ff99d7..b928263ed5 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsTemporaryBasalsFragment.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsTemporaryBasalsFragment.java @@ -25,16 +25,16 @@ import info.nightscout.androidaps.data.IobTotal; import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.db.Source; import info.nightscout.androidaps.db.TemporaryBasal; -import info.nightscout.androidaps.events.EventNewBG; import info.nightscout.androidaps.events.EventTempBasalChange; import info.nightscout.androidaps.plugins.common.SubscriberFragment; import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions; +import info.nightscout.androidaps.plugins.general.nsclient.NSUpload; import info.nightscout.androidaps.plugins.general.nsclient.UploadQueue; +import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventAutosensCalculationFinished; import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin; import info.nightscout.androidaps.utils.DateUtil; import info.nightscout.androidaps.utils.DecimalFormatter; import info.nightscout.androidaps.utils.FabricPrivacy; -import info.nightscout.androidaps.plugins.general.nsclient.NSUpload; public class TreatmentsTemporaryBasalsFragment extends SubscriberFragment { @@ -212,7 +212,7 @@ public class TreatmentsTemporaryBasalsFragment extends SubscriberFragment { } @Subscribe - public void onStatusEvent(final EventNewBG ignored) { + public void onStatusEvent(final EventAutosensCalculationFinished ignored) { updateGUI(); } diff --git a/app/src/main/java/info/nightscout/androidaps/utils/DateUtil.java b/app/src/main/java/info/nightscout/androidaps/utils/DateUtil.java index 943de83cef..7cc4424244 100644 --- a/app/src/main/java/info/nightscout/androidaps/utils/DateUtil.java +++ b/app/src/main/java/info/nightscout/androidaps/utils/DateUtil.java @@ -182,4 +182,9 @@ public class DateUtil { public static long roundDateToSec(long date) { return date - date % 1000; } + + public static boolean isCloseToNow(long date) { + long diff = Math.abs(date - now()); + return diff < T.mins(2).msecs(); + } } diff --git a/app/src/main/java/info/nightscout/androidaps/utils/MidnightTime.java b/app/src/main/java/info/nightscout/androidaps/utils/MidnightTime.java index d3d75feda3..668ca02e96 100644 --- a/app/src/main/java/info/nightscout/androidaps/utils/MidnightTime.java +++ b/app/src/main/java/info/nightscout/androidaps/utils/MidnightTime.java @@ -5,7 +5,7 @@ import android.util.LongSparseArray; import java.util.Calendar; public class MidnightTime { - private static LongSparseArray times = new LongSparseArray(); + private static final LongSparseArray times = new LongSparseArray<>(); private static long hits = 0; private static long misses = 0; @@ -20,20 +20,23 @@ public class MidnightTime { } public static long calc(long time) { - Long m = (Long) times.get(time); - if (m != null) { - ++hits; - return m; + Long m; + synchronized (times) { + m = times.get(time); + if (m != null) { + ++hits; + return m; + } + Calendar c = Calendar.getInstance(); + c.setTimeInMillis(time); + c.set(Calendar.HOUR_OF_DAY, 0); + c.set(Calendar.MINUTE, 0); + c.set(Calendar.SECOND, 0); + c.set(Calendar.MILLISECOND, 0); + m = c.getTimeInMillis(); + times.append(time, m); + ++misses; } - Calendar c = Calendar.getInstance(); - c.setTimeInMillis(time); - c.set(Calendar.HOUR_OF_DAY, 0); - c.set(Calendar.MINUTE, 0); - c.set(Calendar.SECOND, 0); - c.set(Calendar.MILLISECOND, 0); - m = c.getTimeInMillis(); - times.append(time, m); - ++misses; return m; } diff --git a/app/src/main/res/layout/actions_fragment.xml b/app/src/main/res/layout/actions_fragment.xml index d74c4b4cc2..3e809b3b02 100644 --- a/app/src/main/res/layout/actions_fragment.xml +++ b/app/src/main/res/layout/actions_fragment.xml @@ -9,6 +9,7 @@ android:layout_height="wrap_content"> diff --git a/app/src/main/res/layout/objectives_item.xml b/app/src/main/res/layout/objectives_item.xml index b6029e5842..283195db23 100644 --- a/app/src/main/res/layout/objectives_item.xml +++ b/app/src/main/res/layout/objectives_item.xml @@ -65,6 +65,13 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/objectives_button_start" /> + +