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/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/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/openAPSSMB/OpenAPSSMBPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMB/OpenAPSSMBPlugin.java index 30cc40fa42..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; @@ -268,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/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/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/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/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/res/values/strings.xml b/app/src/main/res/values/strings.xml index 8d1b16a7ad..cb8329872e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -294,12 +294,11 @@ To deliver bolus %1$.2fU reply with code %2$s To send calibration %1$.2f reply with code %2$s Bolus failed - Bolus %.2fU delivered successfully - Going to deliver %.2fU - Bolus %.2fU delivered successfully - Delivering %.2fU + Bolus %1$.2fU delivered successfully + Going to deliver %1$.2fU + Bolus %1$.2fU delivered successfully + Delivering %1$.2fU Allow remote commands via SMS - Remote bolus not allowed Finger Sensor Manual @@ -367,16 +366,25 @@ Loop is enabled %1$.2f limited to %2$.2f Value %s is out of hard limits - Remote basal setting is not allowed Remote command is not allowed - To start basal %1$.2fU/h reply with code %2$s + Remote bolus not available. Try again later. + To start basal %1$.2fU/h for %2$d min reply with code %3$s + To switch profile to %1$s %2$d%% reply with code %3$s + To start extended bolus %1$.2fU for %2$d min reply with code %3$s + To start basal %1$d%% for %2$d min reply with code %3$s To suspend loop for %1$d minutes reply with code %2$s Temp basal %1$.2fU/h for %2$d min started successfully + Extended bolus %1$.2fU for %2$d min started successfully + Temp basal %1$d%% for %2$d min started successfully Temp basal start failed - To stop temp basal reply with code %s + Extended bolus start failed + To stop temp basal reply with code %1$s + To stop extended bolus reply with code %1$s Temp basal canceled + Extended bolus canceled Canceling temp basal failed - Uknown command or wrong reply + Canceling extended bolus failed + Unknown command or wrong reply QuickWizard QuickWizard settings @@ -509,7 +517,6 @@ Send calibration %.1f to xDrip? xDrip+ not installed Calibration sent to xDrip - Remote calibration not allowed Calibration sent. Receiving must be enabled in xDrip. xDrip is not receiving calibrations Pump suspended @@ -1315,6 +1322,10 @@ Dayligh Saving time change in less than 3 hours - Closed loop diabled internal storage constraint Free at least %1$d MB from internal storage! Loop disabled! + Wrong format + Wrong code. Command cancelled. + Not configured + Profile switch created %1$d day %1$d days diff --git a/app/src/test/java/info/AAPSMocker.java b/app/src/test/java/info/AAPSMocker.java index f1ec982f9b..7d4884bb96 100644 --- a/app/src/test/java/info/AAPSMocker.java +++ b/app/src/test/java/info/AAPSMocker.java @@ -2,6 +2,7 @@ package info; import android.content.Context; import android.content.Intent; +import android.content.pm.PackageManager; import android.content.res.Resources; import com.squareup.otto.Bus; @@ -9,6 +10,7 @@ import com.squareup.otto.Bus; import org.json.JSONException; import org.json.JSONObject; import org.junit.Assert; +import org.mockito.stubbing.Answer; import org.powermock.api.mockito.PowerMockito; import java.util.Locale; @@ -17,6 +19,7 @@ import info.nightscout.androidaps.Constants; import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.R; import info.nightscout.androidaps.data.ConstraintChecker; +import info.nightscout.androidaps.data.IobTotal; import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.data.ProfileStore; import info.nightscout.androidaps.db.DatabaseHelper; @@ -24,11 +27,14 @@ import info.nightscout.androidaps.logging.L; 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.iob.iobCobCalculator.CobInfo; +import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin; +import info.nightscout.androidaps.plugins.pump.danaR.DanaRPlugin; +import info.nightscout.androidaps.plugins.pump.danaRKorean.DanaRKoreanPlugin; import info.nightscout.androidaps.plugins.pump.danaRv2.DanaRv2Plugin; import info.nightscout.androidaps.plugins.treatments.TreatmentService; import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin; -import info.nightscout.androidaps.plugins.pump.danaR.DanaRPlugin; -import info.nightscout.androidaps.plugins.pump.danaRKorean.DanaRKoreanPlugin; +import info.nightscout.androidaps.queue.Callback; import info.nightscout.androidaps.queue.CommandQueue; import info.nightscout.androidaps.utils.SP; @@ -36,6 +42,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -51,6 +58,8 @@ public class AAPSMocker { public static Intent intentSent = null; + public static CommandQueue queue; + public static void mockStrings() { Locale.setDefault(new Locale("en", "US")); @@ -104,6 +113,43 @@ public class AAPSMocker { when(MainApp.gs(R.string.profile_per_unit)).thenReturn("/U"); when(MainApp.gs(R.string.profile_carbs_per_unit)).thenReturn("g/U"); when(MainApp.gs(R.string.profile_ins_units_per_hout)).thenReturn("U/h"); + when(MainApp.gs(R.string.sms_wrongcode)).thenReturn("Wrong code. Command cancelled."); + when(MainApp.gs(R.string.sms_iob)).thenReturn("IOB:"); + when(MainApp.gs(R.string.sms_lastbg)).thenReturn("Last BG:"); + when(MainApp.gs(R.string.sms_minago)).thenReturn("%1$dmin ago"); + when(MainApp.gs(R.string.smscommunicator_remotecommandnotallowed)).thenReturn("Remote command is not allowed"); + when(MainApp.gs(R.string.loopsuspendedfor)).thenReturn("Suspended (%1$d m)"); + when(MainApp.gs(R.string.smscommunicator_loopisdisabled)).thenReturn("Loop is disabled"); + when(MainApp.gs(R.string.smscommunicator_loopisenabled)).thenReturn("Loop is enabled"); + when(MainApp.gs(R.string.wrongformat)).thenReturn("Wrong format"); + when(MainApp.gs(R.string.smscommunicator_loophasbeendisabled)).thenReturn("Loop has been disabled"); + when(MainApp.gs(R.string.smscommunicator_loophasbeenenabled)).thenReturn("Loop has been enabled"); + when(MainApp.gs(R.string.smscommunicator_tempbasalcanceled)).thenReturn("Temp basal canceled"); + when(MainApp.gs(R.string.smscommunicator_loopresumed)).thenReturn("Loop resumed"); + when(MainApp.gs(R.string.smscommunicator_wrongduration)).thenReturn("Wrong duration"); + when(MainApp.gs(R.string.smscommunicator_suspendreplywithcode)).thenReturn("To suspend loop for %1$d minutes reply with code %2$s"); + when(MainApp.gs(R.string.smscommunicator_loopsuspended)).thenReturn("Loop suspended"); + when(MainApp.gs(R.string.smscommunicator_unknowncommand)).thenReturn("Unknown command or wrong reply"); + when(MainApp.gs(R.string.notconfigured)).thenReturn("Not configured"); + when(MainApp.gs(R.string.smscommunicator_profilereplywithcode)).thenReturn("To switch profile to %1$s %2$d%% reply with code %3$s"); + when(MainApp.gs(R.string.profileswitchcreated)).thenReturn("Profile switch created"); + when(MainApp.gs(R.string.smscommunicator_basalstopreplywithcode)).thenReturn("To stop temp basal reply with code %1$s"); + when(MainApp.gs(R.string.smscommunicator_basalpctreplywithcode)).thenReturn("To start basal %1$d%% for %2$d min reply with code %3$s"); + when(MainApp.gs(R.string.smscommunicator_tempbasalset_percent)).thenReturn("Temp basal %1$d%% for %2$d min started successfully"); + when(MainApp.gs(R.string.smscommunicator_basalreplywithcode)).thenReturn("To start basal %1$.2fU/h for %2$d min reply with code %3$s"); + when(MainApp.gs(R.string.smscommunicator_tempbasalset)).thenReturn("Temp basal %1$.2fU/h for %2$d min started successfully"); + when(MainApp.gs(R.string.smscommunicator_extendedstopreplywithcode)).thenReturn("To stop extended bolus reply with code %1$s"); + when(MainApp.gs(R.string.smscommunicator_extendedcanceled)).thenReturn("Extended bolus canceled"); + when(MainApp.gs(R.string.smscommunicator_extendedreplywithcode)).thenReturn("To start extended bolus %1$.2fU for %2$d min reply with code %3$s"); + when(MainApp.gs(R.string.smscommunicator_extendedset)).thenReturn("Extended bolus %1$.2fU for %2$d min started successfully"); + when(MainApp.gs(R.string.smscommunicator_bolusreplywithcode)).thenReturn("To deliver bolus %1$.2fU reply with code %2$s"); + when(MainApp.gs(R.string.smscommunicator_bolusdelivered)).thenReturn("Bolus %1$.2fU delivered successfully"); + when(MainApp.gs(R.string.smscommunicator_remotebolusnotallowed)).thenReturn("Remote bolus not available. Try again later."); + when(MainApp.gs(R.string.smscommunicator_calibrationreplywithcode)).thenReturn("To send calibration %1$.2f reply with code %2$s"); + when(MainApp.gs(R.string.smscommunicator_calibrationsent)).thenReturn("Calibration sent. Receiving must be enabled in xDrip."); + when(MainApp.gs(R.string.pumpsuspended)).thenReturn("Pump suspended"); + when(MainApp.gs(R.string.cob)).thenReturn("COB"); + when(MainApp.gs(R.string.value_unavailable_short)).thenReturn("n/a"); } public static MainApp mockMainApp() { @@ -143,7 +189,7 @@ public class AAPSMocker { when(L.isEnabled(any())).thenReturn(true); } - public static void mockNSUpload(){ + public static void mockNSUpload() { PowerMockito.mockStatic(NSUpload.class); } @@ -152,6 +198,8 @@ public class AAPSMocker { Resources mResources = mock(Resources.class); when(MainApp.instance().getApplicationContext()).thenReturn(mockedContext); when(mockedContext.getResources()).thenReturn(mResources); + PackageManager packageManager = mock(PackageManager.class); + when(mockedContext.getPackageManager()).thenReturn(packageManager); } public static DatabaseHelper mockDatabaseHelper() { @@ -161,7 +209,7 @@ public class AAPSMocker { } public static void mockCommandQueue() { - CommandQueue queue = mock(CommandQueue.class); + queue = mock(CommandQueue.class); when(ConfigBuilderPlugin.getPlugin().getCommandQueue()).thenReturn(queue); } @@ -169,12 +217,21 @@ public class AAPSMocker { PowerMockito.mockStatic(TreatmentsPlugin.class); TreatmentsPlugin treatmentsPlugin = PowerMockito.mock(TreatmentsPlugin.class); when(TreatmentsPlugin.getPlugin()).thenReturn(treatmentsPlugin); + when(treatmentsPlugin.getLastCalculationTreatments()).thenReturn(new IobTotal(0)); + when(treatmentsPlugin.getLastCalculationTempBasals()).thenReturn(new IobTotal(0)); + + TreatmentService treatmentService = PowerMockito.mock(TreatmentService.class); + when(treatmentsPlugin.getService()).thenReturn(treatmentService); return treatmentsPlugin; } - public static void mockTreatmentService() throws Exception { + public static void mockTreatmentService() { TreatmentService treatmentService = PowerMockito.mock(TreatmentService.class); - PowerMockito.whenNew(TreatmentService.class).withNoArguments().thenReturn(treatmentService); + try { + PowerMockito.whenNew(TreatmentService.class).withNoArguments().thenReturn(treatmentService); + } catch (Exception e) { + } + } public static DanaRPlugin mockDanaRPlugin() { @@ -221,6 +278,14 @@ public class AAPSMocker { PowerMockito.when(ProfileFunctions.getInstance()).thenReturn(profileFunctions); profile = getValidProfile(); PowerMockito.when(ProfileFunctions.getInstance().getProfile()).thenReturn(profile); + PowerMockito.when(ProfileFunctions.getInstance().getProfileUnits()).thenReturn(Constants.MGDL); + PowerMockito.when(ProfileFunctions.getInstance().getProfileName()).thenReturn(TESTPROFILENAME); + } + + public static void mockIobCobCalculatorPlugin() { + PowerMockito.mockStatic(IobCobCalculatorPlugin.class); + IobCobCalculatorPlugin iobCobCalculatorPlugin = PowerMockito.mock(IobCobCalculatorPlugin.class); + PowerMockito.when(IobCobCalculatorPlugin.getPlugin()).thenReturn(iobCobCalculatorPlugin); } private static MockedBus bus = new MockedBus(); diff --git a/app/src/test/java/info/nightscout/androidaps/interfaces/ConstraintTest.java b/app/src/test/java/info/nightscout/androidaps/interfaces/ConstraintTest.java index 4b2d209661..3dbe770bfc 100644 --- a/app/src/test/java/info/nightscout/androidaps/interfaces/ConstraintTest.java +++ b/app/src/test/java/info/nightscout/androidaps/interfaces/ConstraintTest.java @@ -2,6 +2,7 @@ package info.nightscout.androidaps.interfaces; import junit.framework.Assert; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.powermock.core.classloader.annotations.PrepareForTest; @@ -9,6 +10,7 @@ import org.powermock.modules.junit4.PowerMockRunner; import info.AAPSMocker; import info.nightscout.androidaps.MainApp; +import info.nightscout.androidaps.logging.L; import info.nightscout.androidaps.utils.SP; /** @@ -16,15 +18,11 @@ import info.nightscout.androidaps.utils.SP; */ @RunWith(PowerMockRunner.class) -@PrepareForTest({MainApp.class, SP.class}) +@PrepareForTest({MainApp.class, SP.class, L.class}) public class ConstraintTest { @Test public void doTests() { - AAPSMocker.mockMainApp(); - AAPSMocker.mockApplicationContext(); - AAPSMocker.mockSP(); - Constraint b = new Constraint<>(true); Assert.assertEquals(Boolean.TRUE, b.value()); Assert.assertEquals("", b.getReasons()); @@ -56,5 +54,18 @@ public class ConstraintTest { Assert.assertEquals("ConstraintTest: Set 5d\nConstraintTest: Set 6d\nConstraintTest: Set 4d", d.getReasons()); Assert.assertEquals("ConstraintTest: Set 4d", d.getMostLimitedReasons()); Assert.assertEquals(10d, d.originalValue()); + d.setIfDifferent(7d, "Set 7d", this); + Assert.assertEquals(7d, d.value()); + Assert.assertEquals("ConstraintTest: Set 5d\nConstraintTest: Set 6d\nConstraintTest: Set 4d\nConstraintTest: Set 7d", d.getReasons()); + Assert.assertEquals("ConstraintTest: Set 4d\nConstraintTest: Set 7d", d.getMostLimitedReasons()); + Assert.assertEquals(10d, d.originalValue()); + } + + @Before + public void prepareMock() { + AAPSMocker.mockMainApp(); + AAPSMocker.mockApplicationContext(); + AAPSMocker.mockSP(); + AAPSMocker.mockL(); } } diff --git a/app/src/test/java/info/nightscout/androidaps/interfaces/ConstraintsCheckerTest.java b/app/src/test/java/info/nightscout/androidaps/interfaces/ConstraintsCheckerTest.java index 113cff31f8..ee03ef73d7 100644 --- a/app/src/test/java/info/nightscout/androidaps/interfaces/ConstraintsCheckerTest.java +++ b/app/src/test/java/info/nightscout/androidaps/interfaces/ConstraintsCheckerTest.java @@ -54,6 +54,7 @@ public class ConstraintsCheckerTest { DanaRPlugin danaRPlugin; DanaRSPlugin danaRSPlugin; LocalInsightPlugin insightPlugin; + OpenAPSSMBPlugin openAPSSMBPlugin; boolean notificationSent = false; @@ -119,6 +120,14 @@ public class ConstraintsCheckerTest { Assert.assertEquals(Boolean.FALSE, c.value()); } + @Test + public void isSuperBolusEnabledTest() throws Exception { + OpenAPSSMBPlugin.getPlugin().setPluginEnabled(PluginType.APS, true); + + Constraint c = constraintChecker.isSuperBolusEnabled(); + Assert.assertEquals(Boolean.FALSE, c.value()); // SMB should limit + } + @Test public void isSMBModeEnabledTest() throws Exception { objectivesPlugin.objectives.get(7).setStartedOn(null); @@ -288,6 +297,7 @@ public class ConstraintsCheckerTest { danaRPlugin = DanaRPlugin.getPlugin(); danaRSPlugin = DanaRSPlugin.getPlugin(); insightPlugin = LocalInsightPlugin.getPlugin(); + openAPSSMBPlugin = OpenAPSSMBPlugin.getPlugin(); ArrayList constraintsPluginsList = new ArrayList<>(); constraintsPluginsList.add(safetyPlugin); constraintsPluginsList.add(objectivesPlugin); @@ -295,6 +305,7 @@ public class ConstraintsCheckerTest { constraintsPluginsList.add(danaRPlugin); constraintsPluginsList.add(danaRSPlugin); constraintsPluginsList.add(insightPlugin); + constraintsPluginsList.add(openAPSSMBPlugin); when(mainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class)).thenReturn(constraintsPluginsList); } diff --git a/app/src/test/java/info/nightscout/androidaps/plugins/general/smsCommunicator/AuthRequestTest.java b/app/src/test/java/info/nightscout/androidaps/plugins/general/smsCommunicator/AuthRequestTest.java new file mode 100644 index 0000000000..dd41f9873a --- /dev/null +++ b/app/src/test/java/info/nightscout/androidaps/plugins/general/smsCommunicator/AuthRequestTest.java @@ -0,0 +1,94 @@ +package info.nightscout.androidaps.plugins.general.smsCommunicator; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.stubbing.Answer; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; + +import java.util.Date; + +import info.AAPSMocker; +import info.nightscout.androidaps.Constants; +import info.nightscout.androidaps.MainApp; +import info.nightscout.androidaps.logging.L; +import info.nightscout.androidaps.utils.DateUtil; +import info.nightscout.androidaps.utils.SP; +import info.nightscout.androidaps.utils.T; + +import static org.mockito.ArgumentMatchers.any; +import static org.powermock.api.mockito.PowerMockito.doAnswer; +import static org.powermock.api.mockito.PowerMockito.mock; +import static org.powermock.api.mockito.PowerMockito.mockStatic; +import static org.powermock.api.mockito.PowerMockito.when; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({SmsCommunicatorPlugin.class, L.class, SP.class, MainApp.class, DateUtil.class}) + +public class AuthRequestTest { + SmsCommunicatorPlugin smsCommunicatorPlugin; + Sms sentSms; + boolean actionCalled = false; + + @Test + public void doTests() { + Sms requester = new Sms("aNumber", "aText"); + SmsAction action = new SmsAction() { + @Override + public void run() { + actionCalled = true; + } + }; + + // Check if SMS requesting code is sent + AuthRequest authRequest = new AuthRequest(smsCommunicatorPlugin, requester, "Request text", "ABC", action); + + Assert.assertEquals(sentSms.phoneNumber, "aNumber"); + Assert.assertEquals(sentSms.text, "Request text"); + + // wrong reply + actionCalled = false; + authRequest.action("EFG"); + Assert.assertEquals(sentSms.phoneNumber, "aNumber"); + Assert.assertEquals(sentSms.text, "Wrong code. Command cancelled."); + Assert.assertFalse(actionCalled); + + // correct reply + authRequest = new AuthRequest(smsCommunicatorPlugin, requester, "Request text", "ABC", action); + actionCalled = false; + authRequest.action("ABC"); + Assert.assertTrue(actionCalled); + // second time action should not be called + actionCalled = false; + authRequest.action("ABC"); + Assert.assertFalse(actionCalled); + + // test timed out message + long now = 10000; + when(DateUtil.now()).thenReturn(now); + authRequest = new AuthRequest(smsCommunicatorPlugin, requester, "Request text", "ABC", action); + actionCalled = false; + when(DateUtil.now()).thenReturn(now + T.mins(Constants.SMS_CONFIRM_TIMEOUT).msecs() + 1); + authRequest.action("ABC"); + Assert.assertFalse(actionCalled); + } + + @Before + public void prepareTests() { + smsCommunicatorPlugin = mock(SmsCommunicatorPlugin.class); + doAnswer((Answer) invocation -> { + sentSms = invocation.getArgument(0); + return null; + }).when(smsCommunicatorPlugin).sendSMS(any(Sms.class)); + + AAPSMocker.mockMainApp(); + AAPSMocker.mockApplicationContext(); + AAPSMocker.mockSP(); + AAPSMocker.mockL(); + AAPSMocker.mockStrings(); + + mockStatic(DateUtil.class); + } +} diff --git a/app/src/test/java/info/nightscout/androidaps/plugins/general/smsCommunicator/SmsActionTest.java b/app/src/test/java/info/nightscout/androidaps/plugins/general/smsCommunicator/SmsActionTest.java new file mode 100644 index 0000000000..f4d61e56eb --- /dev/null +++ b/app/src/test/java/info/nightscout/androidaps/plugins/general/smsCommunicator/SmsActionTest.java @@ -0,0 +1,90 @@ +package info.nightscout.androidaps.plugins.general.smsCommunicator; + +import android.telephony.SmsMessage; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; + +import info.AAPSMocker; +import info.nightscout.androidaps.MainApp; +import info.nightscout.androidaps.R; + +import static org.powermock.api.mockito.PowerMockito.mock; +import static org.powermock.api.mockito.PowerMockito.when; + +@RunWith(PowerMockRunner.class) + +public class SmsActionTest { + String result = ""; + + @Test + public void doTests() { + + SmsAction smsAction = new SmsAction() { + @Override + public void run() { + result = "A"; + } + }; + smsAction.run(); + Assert.assertEquals(result, "A"); + + smsAction = new SmsAction(1d) { + @Override + public void run() { + result = "B"; + } + }; + smsAction.run(); + Assert.assertEquals(result, "B"); + Assert.assertEquals(smsAction.aDouble, 1d, 0.000001d); + + smsAction = new SmsAction(1d, 2) { + @Override + public void run() { + result = "C"; + } + }; + smsAction.run(); + Assert.assertEquals(result, "C"); + Assert.assertEquals(smsAction.aDouble, 1d, 0.000001d); + Assert.assertEquals(smsAction.secondInteger.intValue(), 2); + + smsAction = new SmsAction("aString", 3) { + @Override + public void run() { + result = "D"; + } + }; + smsAction.run(); + Assert.assertEquals(result, "D"); + Assert.assertEquals(smsAction.aString, "aString"); + Assert.assertEquals(smsAction.secondInteger.intValue(), 3); + + smsAction = new SmsAction(4) { + @Override + public void run() { + result = "E"; + } + }; + smsAction.run(); + Assert.assertEquals(result, "E"); + Assert.assertEquals(smsAction.anInteger.intValue(), 4); + + smsAction = new SmsAction(5, 6) { + @Override + public void run() { + result = "F"; + } + }; + smsAction.run(); + Assert.assertEquals(result, "F"); + Assert.assertEquals(smsAction.anInteger.intValue(), 5); + Assert.assertEquals(smsAction.secondInteger.intValue(), 6); + } + +} diff --git a/app/src/test/java/info/nightscout/androidaps/plugins/general/smsCommunicator/SmsCommunicatorPluginTest.java b/app/src/test/java/info/nightscout/androidaps/plugins/general/smsCommunicator/SmsCommunicatorPluginTest.java new file mode 100644 index 0000000000..abc29216b0 --- /dev/null +++ b/app/src/test/java/info/nightscout/androidaps/plugins/general/smsCommunicator/SmsCommunicatorPluginTest.java @@ -0,0 +1,804 @@ +package info.nightscout.androidaps.plugins.general.smsCommunicator; + +import android.telephony.SmsManager; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.mockito.stubbing.Answer; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; + +import java.util.ArrayList; +import java.util.List; + +import info.AAPSMocker; +import info.nightscout.androidaps.Constants; +import info.nightscout.androidaps.MainApp; +import info.nightscout.androidaps.R; +import info.nightscout.androidaps.data.DetailedBolusInfo; +import info.nightscout.androidaps.data.PumpEnactResult; +import info.nightscout.androidaps.db.BgReading; +import info.nightscout.androidaps.interfaces.Constraint; +import info.nightscout.androidaps.interfaces.PluginType; +import info.nightscout.androidaps.interfaces.ProfileInterface; +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.configBuilder.ProfileFunctions; +import info.nightscout.androidaps.plugins.general.nsclient.NSUpload; +import info.nightscout.androidaps.plugins.iob.iobCobCalculator.CobInfo; +import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin; +import info.nightscout.androidaps.plugins.profile.simple.SimpleProfilePlugin; +import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin; +import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin; +import info.nightscout.androidaps.queue.Callback; +import info.nightscout.androidaps.queue.CommandQueue; +import info.nightscout.androidaps.utils.DateUtil; +import info.nightscout.androidaps.utils.SP; +import info.nightscout.androidaps.utils.XdripCalibrations; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyDouble; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; +import static org.powermock.api.mockito.PowerMockito.doAnswer; +import static org.powermock.api.mockito.PowerMockito.mock; +import static org.powermock.api.mockito.PowerMockito.mockStatic; +import static org.powermock.api.mockito.PowerMockito.when; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({ + L.class, SP.class, MainApp.class, DateUtil.class, ProfileFunctions.class, + TreatmentsPlugin.class, SmsManager.class, IobCobCalculatorPlugin.class, + CommandQueue.class, ConfigBuilderPlugin.class, NSUpload.class, ProfileInterface.class, + SimpleProfilePlugin.class, XdripCalibrations.class, VirtualPumpPlugin.class +}) + +public class SmsCommunicatorPluginTest { + + private SmsCommunicatorPlugin smsCommunicatorPlugin; + private LoopPlugin loopPlugin; + + private boolean hasBeenRun = false; + + @Test + public void processSettingsTest() { + // called from constructor + Assert.assertEquals("1234", smsCommunicatorPlugin.allowedNumbers.get(0)); + Assert.assertEquals("5678", smsCommunicatorPlugin.allowedNumbers.get(1)); + Assert.assertEquals(2, smsCommunicatorPlugin.allowedNumbers.size()); + } + + @Test + public void isCommandTest() { + Assert.assertTrue(smsCommunicatorPlugin.isCommand("BOLUS", "")); + smsCommunicatorPlugin.messageToConfirm = null; + Assert.assertFalse(smsCommunicatorPlugin.isCommand("BLB", "")); + smsCommunicatorPlugin.messageToConfirm = new AuthRequest(smsCommunicatorPlugin, new Sms("1234", "ddd"), "RequestText", "ccode", new SmsAction() { + @Override + public void run() { + } + }); + Assert.assertTrue(smsCommunicatorPlugin.isCommand("BLB", "1234")); + Assert.assertFalse(smsCommunicatorPlugin.isCommand("BLB", "2345")); + smsCommunicatorPlugin.messageToConfirm = null; + } + + @Test + public void isAllowedNumberTest() { + Assert.assertTrue(smsCommunicatorPlugin.isAllowedNumber("5678")); + Assert.assertFalse(smsCommunicatorPlugin.isAllowedNumber("56")); + } + + @Test + public void processSmsTest() { + Sms sms; + + // SMS from not allowed number should be ignored + smsCommunicatorPlugin.messages = new ArrayList<>(); + sms = new Sms("12", "aText"); + smsCommunicatorPlugin.processSms(sms); + Assert.assertTrue(sms.ignored); + Assert.assertEquals("aText", smsCommunicatorPlugin.messages.get(0).text); + + //UNKNOWN + smsCommunicatorPlugin.messages = new ArrayList<>(); + sms = new Sms("1234", "UNKNOWN"); + smsCommunicatorPlugin.processSms(sms); + Assert.assertEquals("UNKNOWN", smsCommunicatorPlugin.messages.get(0).text); + + //BG + smsCommunicatorPlugin.messages = new ArrayList<>(); + sms = new Sms("1234", "BG"); + smsCommunicatorPlugin.processSms(sms); + Assert.assertEquals("BG", smsCommunicatorPlugin.messages.get(0).text); + Assert.assertTrue(smsCommunicatorPlugin.messages.get(1).text.contains("IOB:")); + Assert.assertTrue(smsCommunicatorPlugin.messages.get(1).text.contains("Last BG: 100")); + Assert.assertTrue(smsCommunicatorPlugin.messages.get(1).text.contains("COB: 10(2)g")); + + // LOOP : test remote control disabled + when(SP.getBoolean(R.string.key_smscommunicator_remotecommandsallowed, false)).thenReturn(false); + smsCommunicatorPlugin.messages = new ArrayList<>(); + sms = new Sms("1234", "LOOP STATUS"); + smsCommunicatorPlugin.processSms(sms); + Assert.assertFalse(sms.ignored); + Assert.assertEquals("LOOP STATUS", smsCommunicatorPlugin.messages.get(0).text); + Assert.assertTrue(smsCommunicatorPlugin.messages.get(1).text.contains("Remote command is not allowed")); + when(SP.getBoolean(R.string.key_smscommunicator_remotecommandsallowed, false)).thenReturn(true); + + //LOOP STATUS : disabled + when(loopPlugin.isEnabled(PluginType.LOOP)).thenReturn(false); + smsCommunicatorPlugin.messages = new ArrayList<>(); + sms = new Sms("1234", "LOOP STATUS"); + smsCommunicatorPlugin.processSms(sms); + Assert.assertEquals("LOOP STATUS", smsCommunicatorPlugin.messages.get(0).text); + Assert.assertEquals("Loop is disabled", smsCommunicatorPlugin.messages.get(1).text); + + //LOOP STATUS : suspended + when(loopPlugin.minutesToEndOfSuspend()).thenReturn(10); + when(loopPlugin.isEnabled(PluginType.LOOP)).thenReturn(true); + when(loopPlugin.isSuspended()).thenReturn(true); + smsCommunicatorPlugin.messages = new ArrayList<>(); + sms = new Sms("1234", "LOOP STATUS"); + smsCommunicatorPlugin.processSms(sms); + Assert.assertEquals("LOOP STATUS", smsCommunicatorPlugin.messages.get(0).text); + Assert.assertEquals("Suspended (10 m)", smsCommunicatorPlugin.messages.get(1).text); + + //LOOP STATUS : enabled + when(loopPlugin.isEnabled(PluginType.LOOP)).thenReturn(true); + when(loopPlugin.isSuspended()).thenReturn(false); + smsCommunicatorPlugin.messages = new ArrayList<>(); + sms = new Sms("1234", "LOOP STATUS"); + smsCommunicatorPlugin.processSms(sms); + Assert.assertFalse(sms.ignored); + Assert.assertEquals("LOOP STATUS", smsCommunicatorPlugin.messages.get(0).text); + Assert.assertEquals("Loop is enabled", smsCommunicatorPlugin.messages.get(1).text); + + //LOOP : wrong format + when(loopPlugin.isEnabled(PluginType.LOOP)).thenReturn(true); + smsCommunicatorPlugin.messages = new ArrayList<>(); + sms = new Sms("1234", "LOOP"); + smsCommunicatorPlugin.processSms(sms); + Assert.assertFalse(sms.ignored); + Assert.assertEquals("LOOP", smsCommunicatorPlugin.messages.get(0).text); + Assert.assertEquals("Wrong format", smsCommunicatorPlugin.messages.get(1).text); + + //LOOP DISABLE : already disabled + when(loopPlugin.isEnabled(PluginType.LOOP)).thenReturn(false); + smsCommunicatorPlugin.messages = new ArrayList<>(); + sms = new Sms("1234", "LOOP DISABLE"); + smsCommunicatorPlugin.processSms(sms); + Assert.assertFalse(sms.ignored); + Assert.assertEquals("LOOP DISABLE", smsCommunicatorPlugin.messages.get(0).text); + Assert.assertEquals("Loop is disabled", smsCommunicatorPlugin.messages.get(1).text); + + //LOOP DISABLE : from enabled + hasBeenRun = false; + when(loopPlugin.isEnabled(PluginType.LOOP)).thenReturn(true); + doAnswer((Answer) invocation -> { + hasBeenRun = true; + return null; + }).when(loopPlugin).setPluginEnabled(PluginType.LOOP, false); + smsCommunicatorPlugin.messages = new ArrayList<>(); + sms = new Sms("1234", "LOOP DISABLE"); + smsCommunicatorPlugin.processSms(sms); + Assert.assertFalse(sms.ignored); + Assert.assertEquals("LOOP DISABLE", smsCommunicatorPlugin.messages.get(0).text); + Assert.assertEquals("Loop has been disabled Temp basal canceled", smsCommunicatorPlugin.messages.get(1).text); + Assert.assertTrue(hasBeenRun); + + //LOOP ENABLE : already enabled + when(loopPlugin.isEnabled(PluginType.LOOP)).thenReturn(true); + smsCommunicatorPlugin.messages = new ArrayList<>(); + sms = new Sms("1234", "LOOP ENABLE"); + smsCommunicatorPlugin.processSms(sms); + Assert.assertFalse(sms.ignored); + Assert.assertEquals("LOOP ENABLE", smsCommunicatorPlugin.messages.get(0).text); + Assert.assertEquals("Loop is enabled", smsCommunicatorPlugin.messages.get(1).text); + + //LOOP ENABLE : from disabled + hasBeenRun = false; + when(loopPlugin.isEnabled(PluginType.LOOP)).thenReturn(false); + doAnswer((Answer) invocation -> { + hasBeenRun = true; + return null; + }).when(loopPlugin).setPluginEnabled(PluginType.LOOP, true); + smsCommunicatorPlugin.messages = new ArrayList<>(); + sms = new Sms("1234", "LOOP ENABLE"); + smsCommunicatorPlugin.processSms(sms); + Assert.assertFalse(sms.ignored); + Assert.assertEquals("LOOP ENABLE", smsCommunicatorPlugin.messages.get(0).text); + Assert.assertEquals("Loop has been enabled", smsCommunicatorPlugin.messages.get(1).text); + Assert.assertTrue(hasBeenRun); + + //LOOP RESUME : already enabled + smsCommunicatorPlugin.messages = new ArrayList<>(); + sms = new Sms("1234", "LOOP RESUME"); + smsCommunicatorPlugin.processSms(sms); + Assert.assertFalse(sms.ignored); + Assert.assertEquals("LOOP RESUME", smsCommunicatorPlugin.messages.get(0).text); + Assert.assertEquals("Loop resumed", smsCommunicatorPlugin.messages.get(1).text); + + //LOOP SUSPEND 1 2: wrong format + smsCommunicatorPlugin.messages = new ArrayList<>(); + sms = new Sms("1234", "LOOP SUSPEND 1 2"); + smsCommunicatorPlugin.processSms(sms); + Assert.assertFalse(sms.ignored); + Assert.assertEquals("LOOP SUSPEND 1 2", smsCommunicatorPlugin.messages.get(0).text); + Assert.assertEquals("Wrong format", smsCommunicatorPlugin.messages.get(1).text); + + //LOOP SUSPEND 0 : wrong duration + smsCommunicatorPlugin.messages = new ArrayList<>(); + sms = new Sms("1234", "LOOP SUSPEND 0"); + smsCommunicatorPlugin.processSms(sms); + Assert.assertFalse(sms.ignored); + Assert.assertEquals("LOOP SUSPEND 0", smsCommunicatorPlugin.messages.get(0).text); + Assert.assertEquals("Wrong duration", smsCommunicatorPlugin.messages.get(1).text); + + //LOOP SUSPEND 100 : suspend for 100 min + correct answer + smsCommunicatorPlugin.messages = new ArrayList<>(); + sms = new Sms("1234", "LOOP SUSPEND 100"); + smsCommunicatorPlugin.processSms(sms); + Assert.assertFalse(sms.ignored); + Assert.assertEquals("LOOP SUSPEND 100", smsCommunicatorPlugin.messages.get(0).text); + Assert.assertTrue(smsCommunicatorPlugin.messages.get(1).text.contains("To suspend loop for 100 minutes reply with code ")); + String passCode = smsCommunicatorPlugin.messageToConfirm.confirmCode; + smsCommunicatorPlugin.processSms(new Sms("1234", passCode)); + Assert.assertEquals(passCode, smsCommunicatorPlugin.messages.get(2).text); + Assert.assertEquals("Loop suspended Temp basal canceled", smsCommunicatorPlugin.messages.get(3).text); + + //LOOP SUSPEND 200 : limit to 180 min + wrong answer + smsCommunicatorPlugin.messages = new ArrayList<>(); + sms = new Sms("1234", "LOOP SUSPEND 200"); + smsCommunicatorPlugin.processSms(sms); + Assert.assertFalse(sms.ignored); + Assert.assertEquals("LOOP SUSPEND 200", smsCommunicatorPlugin.messages.get(0).text); + Assert.assertTrue(smsCommunicatorPlugin.messages.get(1).text.contains("To suspend loop for 180 minutes reply with code ")); + passCode = smsCommunicatorPlugin.messageToConfirm.confirmCode; + // ignore from other number + smsCommunicatorPlugin.processSms(new Sms("5678", passCode)); + smsCommunicatorPlugin.processSms(new Sms("1234", "XXXX")); + Assert.assertEquals("XXXX", smsCommunicatorPlugin.messages.get(3).text); + Assert.assertEquals("Wrong code. Command cancelled.", smsCommunicatorPlugin.messages.get(4).text); + //then correct code should not work + smsCommunicatorPlugin.processSms(new Sms("1234", passCode)); + Assert.assertEquals(passCode, smsCommunicatorPlugin.messages.get(5).text); + Assert.assertEquals(6, smsCommunicatorPlugin.messages.size()); // processed as common message + + //LOOP BLABLA + smsCommunicatorPlugin.messages = new ArrayList<>(); + sms = new Sms("1234", "LOOP BLABLA"); + smsCommunicatorPlugin.processSms(sms); + Assert.assertFalse(sms.ignored); + Assert.assertEquals("LOOP BLABLA", smsCommunicatorPlugin.messages.get(0).text); + Assert.assertEquals("Wrong format", smsCommunicatorPlugin.messages.get(1).text); + + //TREATMENTS REFRESH + when(loopPlugin.isEnabled(PluginType.LOOP)).thenReturn(true); + when(loopPlugin.isSuspended()).thenReturn(false); + smsCommunicatorPlugin.messages = new ArrayList<>(); + sms = new Sms("1234", "TREATMENTS REFRESH"); + smsCommunicatorPlugin.processSms(sms); + Assert.assertFalse(sms.ignored); + Assert.assertEquals("TREATMENTS REFRESH", smsCommunicatorPlugin.messages.get(0).text); + Assert.assertTrue(smsCommunicatorPlugin.messages.get(1).text.contains("TREATMENTS REFRESH")); + + //TREATMENTS BLA BLA + when(loopPlugin.isEnabled(PluginType.LOOP)).thenReturn(true); + when(loopPlugin.isSuspended()).thenReturn(false); + smsCommunicatorPlugin.messages = new ArrayList<>(); + sms = new Sms("1234", "TREATMENTS BLA BLA"); + smsCommunicatorPlugin.processSms(sms); + Assert.assertFalse(sms.ignored); + Assert.assertEquals("TREATMENTS BLA BLA", smsCommunicatorPlugin.messages.get(0).text); + Assert.assertEquals("Wrong format", smsCommunicatorPlugin.messages.get(1).text); + + //TREATMENTS BLABLA + when(loopPlugin.isEnabled(PluginType.LOOP)).thenReturn(true); + when(loopPlugin.isSuspended()).thenReturn(false); + smsCommunicatorPlugin.messages = new ArrayList<>(); + sms = new Sms("1234", "TREATMENTS BLABLA"); + smsCommunicatorPlugin.processSms(sms); + Assert.assertFalse(sms.ignored); + Assert.assertEquals("TREATMENTS BLABLA", smsCommunicatorPlugin.messages.get(0).text); + Assert.assertEquals("Wrong format", smsCommunicatorPlugin.messages.get(1).text); + + //NSCLIENT RESTART + when(loopPlugin.isEnabled(PluginType.LOOP)).thenReturn(true); + when(loopPlugin.isSuspended()).thenReturn(false); + smsCommunicatorPlugin.messages = new ArrayList<>(); + sms = new Sms("1234", "NSCLIENT RESTART"); + smsCommunicatorPlugin.processSms(sms); + Assert.assertFalse(sms.ignored); + Assert.assertEquals("NSCLIENT RESTART", smsCommunicatorPlugin.messages.get(0).text); + Assert.assertTrue(smsCommunicatorPlugin.messages.get(1).text.contains("NSCLIENT RESTART")); + + //NSCLIENT BLA BLA + when(loopPlugin.isEnabled(PluginType.LOOP)).thenReturn(true); + when(loopPlugin.isSuspended()).thenReturn(false); + smsCommunicatorPlugin.messages = new ArrayList<>(); + sms = new Sms("1234", "NSCLIENT BLA BLA"); + smsCommunicatorPlugin.processSms(sms); + Assert.assertFalse(sms.ignored); + Assert.assertEquals("NSCLIENT BLA BLA", smsCommunicatorPlugin.messages.get(0).text); + Assert.assertEquals("Wrong format", smsCommunicatorPlugin.messages.get(1).text); + + //NSCLIENT BLABLA + when(loopPlugin.isEnabled(PluginType.LOOP)).thenReturn(true); + when(loopPlugin.isSuspended()).thenReturn(false); + smsCommunicatorPlugin.messages = new ArrayList<>(); + sms = new Sms("1234", "NSCLIENT BLABLA"); + smsCommunicatorPlugin.processSms(sms); + Assert.assertFalse(sms.ignored); + Assert.assertEquals("NSCLIENT BLABLA", smsCommunicatorPlugin.messages.get(0).text); + Assert.assertEquals("Wrong format", smsCommunicatorPlugin.messages.get(1).text); + + //PUMP + smsCommunicatorPlugin.messages = new ArrayList<>(); + sms = new Sms("1234", "PUMP"); + smsCommunicatorPlugin.processSms(sms); + Assert.assertEquals("PUMP", smsCommunicatorPlugin.messages.get(0).text); + Assert.assertEquals("Virtual Pump", smsCommunicatorPlugin.messages.get(1).text); + + } + + @Test + public void processProfileTest() { + Sms sms; + + //PROFILE + smsCommunicatorPlugin.messages = new ArrayList<>(); + sms = new Sms("1234", "PROFILE"); + smsCommunicatorPlugin.processSms(sms); + Assert.assertEquals("PROFILE", smsCommunicatorPlugin.messages.get(0).text); + Assert.assertEquals("Remote command is not allowed", smsCommunicatorPlugin.messages.get(1).text); + + when(SP.getBoolean(R.string.key_smscommunicator_remotecommandsallowed, false)).thenReturn(true); + + //PROFILE + smsCommunicatorPlugin.messages = new ArrayList<>(); + sms = new Sms("1234", "PROFILE"); + smsCommunicatorPlugin.processSms(sms); + Assert.assertEquals("PROFILE", smsCommunicatorPlugin.messages.get(0).text); + Assert.assertEquals("Wrong format", smsCommunicatorPlugin.messages.get(1).text); + + //PROFILE LIST (no profile interface) + smsCommunicatorPlugin.messages = new ArrayList<>(); + sms = new Sms("1234", "PROFILE LIST"); + smsCommunicatorPlugin.processSms(sms); + Assert.assertEquals("PROFILE LIST", smsCommunicatorPlugin.messages.get(0).text); + Assert.assertEquals("Not configured", smsCommunicatorPlugin.messages.get(1).text); + + ProfileInterface profileInterface = mock(SimpleProfilePlugin.class); + when(ConfigBuilderPlugin.getPlugin().getActiveProfileInterface()).thenReturn(profileInterface); + + //PROFILE LIST (no profile defined) + smsCommunicatorPlugin.messages = new ArrayList<>(); + sms = new Sms("1234", "PROFILE LIST"); + smsCommunicatorPlugin.processSms(sms); + Assert.assertEquals("PROFILE LIST", smsCommunicatorPlugin.messages.get(0).text); + Assert.assertEquals("Not configured", smsCommunicatorPlugin.messages.get(1).text); + + when(profileInterface.getProfile()).thenReturn(AAPSMocker.getValidProfileStore()); + + //PROFILE STATUS + smsCommunicatorPlugin.messages = new ArrayList<>(); + sms = new Sms("1234", "PROFILE STATUS"); + smsCommunicatorPlugin.processSms(sms); + Assert.assertEquals("PROFILE STATUS", smsCommunicatorPlugin.messages.get(0).text); + Assert.assertEquals(AAPSMocker.TESTPROFILENAME, smsCommunicatorPlugin.messages.get(1).text); + + //PROFILE LIST + smsCommunicatorPlugin.messages = new ArrayList<>(); + sms = new Sms("1234", "PROFILE LIST"); + smsCommunicatorPlugin.processSms(sms); + Assert.assertEquals("PROFILE LIST", smsCommunicatorPlugin.messages.get(0).text); + Assert.assertEquals("1. " + AAPSMocker.TESTPROFILENAME, smsCommunicatorPlugin.messages.get(1).text); + + //PROFILE 2 (non existing) + smsCommunicatorPlugin.messages = new ArrayList<>(); + sms = new Sms("1234", "PROFILE 2"); + smsCommunicatorPlugin.processSms(sms); + Assert.assertEquals("PROFILE 2", smsCommunicatorPlugin.messages.get(0).text); + Assert.assertEquals("Wrong format", smsCommunicatorPlugin.messages.get(1).text); + + //PROFILE 1 0(wrong percentage) + smsCommunicatorPlugin.messages = new ArrayList<>(); + sms = new Sms("1234", "PROFILE 1 0"); + smsCommunicatorPlugin.processSms(sms); + Assert.assertEquals("PROFILE 1 0", smsCommunicatorPlugin.messages.get(0).text); + Assert.assertEquals("Wrong format", smsCommunicatorPlugin.messages.get(1).text); + + //PROFILE 0(wrong index) + smsCommunicatorPlugin.messages = new ArrayList<>(); + sms = new Sms("1234", "PROFILE 0"); + smsCommunicatorPlugin.processSms(sms); + Assert.assertEquals("PROFILE 0", smsCommunicatorPlugin.messages.get(0).text); + Assert.assertEquals("Wrong format", smsCommunicatorPlugin.messages.get(1).text); + + //PROFILE 1(OK) + smsCommunicatorPlugin.messages = new ArrayList<>(); + sms = new Sms("1234", "PROFILE 1"); + smsCommunicatorPlugin.processSms(sms); + Assert.assertEquals("PROFILE 1", smsCommunicatorPlugin.messages.get(0).text); + Assert.assertTrue(smsCommunicatorPlugin.messages.get(1).text.contains("To switch profile to someProfile 100% reply with code")); + + //PROFILE 1 90(OK) + smsCommunicatorPlugin.messages = new ArrayList<>(); + sms = new Sms("1234", "PROFILE 1 90"); + smsCommunicatorPlugin.processSms(sms); + Assert.assertEquals("PROFILE 1 90", smsCommunicatorPlugin.messages.get(0).text); + Assert.assertTrue(smsCommunicatorPlugin.messages.get(1).text.contains("To switch profile to someProfile 90% reply with code")); + String passCode = smsCommunicatorPlugin.messageToConfirm.confirmCode; + smsCommunicatorPlugin.processSms(new Sms("1234", passCode)); + Assert.assertEquals(passCode, smsCommunicatorPlugin.messages.get(2).text); + Assert.assertEquals("Profile switch created", smsCommunicatorPlugin.messages.get(3).text); + } + + @Test + public void processBasalTest() { + Sms sms; + + //BASAL + smsCommunicatorPlugin.messages = new ArrayList<>(); + sms = new Sms("1234", "BASAL"); + smsCommunicatorPlugin.processSms(sms); + Assert.assertEquals("BASAL", smsCommunicatorPlugin.messages.get(0).text); + Assert.assertEquals("Remote command is not allowed", smsCommunicatorPlugin.messages.get(1).text); + + when(SP.getBoolean(R.string.key_smscommunicator_remotecommandsallowed, false)).thenReturn(true); + + //BASAL + smsCommunicatorPlugin.messages = new ArrayList<>(); + sms = new Sms("1234", "BASAL"); + smsCommunicatorPlugin.processSms(sms); + Assert.assertEquals("BASAL", smsCommunicatorPlugin.messages.get(0).text); + Assert.assertEquals("Wrong format", smsCommunicatorPlugin.messages.get(1).text); + + //BASAL CANCEL + smsCommunicatorPlugin.messages = new ArrayList<>(); + sms = new Sms("1234", "BASAL CANCEL"); + smsCommunicatorPlugin.processSms(sms); + Assert.assertEquals("BASAL CANCEL", smsCommunicatorPlugin.messages.get(0).text); + Assert.assertTrue(smsCommunicatorPlugin.messages.get(1).text.contains("To stop temp basal reply with code")); + String passCode = smsCommunicatorPlugin.messageToConfirm.confirmCode; + smsCommunicatorPlugin.processSms(new Sms("1234", passCode)); + Assert.assertEquals(passCode, smsCommunicatorPlugin.messages.get(2).text); + Assert.assertEquals("Temp basal canceled\nVirtual Pump", smsCommunicatorPlugin.messages.get(3).text); + + //BASAL a% + smsCommunicatorPlugin.messages = new ArrayList<>(); + sms = new Sms("1234", "BASAL a%"); + smsCommunicatorPlugin.processSms(sms); + Assert.assertEquals("BASAL a%", smsCommunicatorPlugin.messages.get(0).text); + Assert.assertEquals("Wrong format", smsCommunicatorPlugin.messages.get(1).text); + + //BASAL 10% 0 + smsCommunicatorPlugin.messages = new ArrayList<>(); + sms = new Sms("1234", "BASAL 10% 0"); + smsCommunicatorPlugin.processSms(sms); + Assert.assertEquals("BASAL 10% 0", smsCommunicatorPlugin.messages.get(0).text); + Assert.assertEquals("Wrong format", smsCommunicatorPlugin.messages.get(1).text); + + when(MainApp.getConstraintChecker().applyBasalPercentConstraints(any(), any())).thenReturn(new Constraint<>(20)); + + //BASAL 20% 20 + smsCommunicatorPlugin.messages = new ArrayList<>(); + sms = new Sms("1234", "BASAL 20% 20"); + smsCommunicatorPlugin.processSms(sms); + Assert.assertEquals("BASAL 20% 20", smsCommunicatorPlugin.messages.get(0).text); + Assert.assertTrue(smsCommunicatorPlugin.messages.get(1).text.contains("To start basal 20% for 20 min reply with code")); + passCode = smsCommunicatorPlugin.messageToConfirm.confirmCode; + smsCommunicatorPlugin.processSms(new Sms("1234", passCode)); + Assert.assertEquals(passCode, smsCommunicatorPlugin.messages.get(2).text); + Assert.assertEquals("Temp basal 20% for 20 min started successfully\nVirtual Pump", smsCommunicatorPlugin.messages.get(3).text); + + //BASAL a + smsCommunicatorPlugin.messages = new ArrayList<>(); + sms = new Sms("1234", "BASAL a"); + smsCommunicatorPlugin.processSms(sms); + Assert.assertEquals("BASAL a", smsCommunicatorPlugin.messages.get(0).text); + Assert.assertEquals("Wrong format", smsCommunicatorPlugin.messages.get(1).text); + + //BASAL 1 0 + smsCommunicatorPlugin.messages = new ArrayList<>(); + sms = new Sms("1234", "BASAL 1 0"); + smsCommunicatorPlugin.processSms(sms); + Assert.assertEquals("BASAL 1 0", smsCommunicatorPlugin.messages.get(0).text); + Assert.assertEquals("Wrong format", smsCommunicatorPlugin.messages.get(1).text); + + when(MainApp.getConstraintChecker().applyBasalConstraints(any(), any())).thenReturn(new Constraint<>(1d)); + + //BASAL 1 20 + smsCommunicatorPlugin.messages = new ArrayList<>(); + sms = new Sms("1234", "BASAL 1 20"); + smsCommunicatorPlugin.processSms(sms); + Assert.assertEquals("BASAL 1 20", smsCommunicatorPlugin.messages.get(0).text); + Assert.assertTrue(smsCommunicatorPlugin.messages.get(1).text.contains("To start basal 1.00U/h for 20 min reply with code")); + passCode = smsCommunicatorPlugin.messageToConfirm.confirmCode; + smsCommunicatorPlugin.processSms(new Sms("1234", passCode)); + Assert.assertEquals(passCode, smsCommunicatorPlugin.messages.get(2).text); + Assert.assertEquals("Temp basal 1.00U/h for 20 min started successfully\nVirtual Pump", smsCommunicatorPlugin.messages.get(3).text); + + } + + @Test + public void processExtendedTest() { + Sms sms; + + //EXTENDED + smsCommunicatorPlugin.messages = new ArrayList<>(); + sms = new Sms("1234", "EXTENDED"); + smsCommunicatorPlugin.processSms(sms); + Assert.assertEquals("EXTENDED", smsCommunicatorPlugin.messages.get(0).text); + Assert.assertEquals("Remote command is not allowed", smsCommunicatorPlugin.messages.get(1).text); + + when(SP.getBoolean(R.string.key_smscommunicator_remotecommandsallowed, false)).thenReturn(true); + + //EXTENDED + smsCommunicatorPlugin.messages = new ArrayList<>(); + sms = new Sms("1234", "EXTENDED"); + smsCommunicatorPlugin.processSms(sms); + Assert.assertEquals("EXTENDED", smsCommunicatorPlugin.messages.get(0).text); + Assert.assertEquals("Wrong format", smsCommunicatorPlugin.messages.get(1).text); + + //EXTENDED CANCEL + smsCommunicatorPlugin.messages = new ArrayList<>(); + sms = new Sms("1234", "EXTENDED CANCEL"); + smsCommunicatorPlugin.processSms(sms); + Assert.assertEquals("EXTENDED CANCEL", smsCommunicatorPlugin.messages.get(0).text); + Assert.assertTrue(smsCommunicatorPlugin.messages.get(1).text.contains("To stop extended bolus reply with code")); + String passCode = smsCommunicatorPlugin.messageToConfirm.confirmCode; + smsCommunicatorPlugin.processSms(new Sms("1234", passCode)); + Assert.assertEquals(passCode, smsCommunicatorPlugin.messages.get(2).text); + Assert.assertEquals("Extended bolus canceled\nVirtual Pump", smsCommunicatorPlugin.messages.get(3).text); + + //EXTENDED a% + smsCommunicatorPlugin.messages = new ArrayList<>(); + sms = new Sms("1234", "EXTENDED a%"); + smsCommunicatorPlugin.processSms(sms); + Assert.assertEquals("EXTENDED a%", smsCommunicatorPlugin.messages.get(0).text); + Assert.assertEquals("Wrong format", smsCommunicatorPlugin.messages.get(1).text); + + when(MainApp.getConstraintChecker().applyExtendedBolusConstraints(any())).thenReturn(new Constraint<>(1d)); + + //EXTENDED 1 0 + smsCommunicatorPlugin.messages = new ArrayList<>(); + sms = new Sms("1234", "EXTENDED 1 0"); + smsCommunicatorPlugin.processSms(sms); + Assert.assertEquals("EXTENDED 1 0", smsCommunicatorPlugin.messages.get(0).text); + Assert.assertEquals("Wrong format", smsCommunicatorPlugin.messages.get(1).text); + + //EXTENDED 1 20 + smsCommunicatorPlugin.messages = new ArrayList<>(); + sms = new Sms("1234", "EXTENDED 1 20"); + smsCommunicatorPlugin.processSms(sms); + Assert.assertEquals("EXTENDED 1 20", smsCommunicatorPlugin.messages.get(0).text); + Assert.assertTrue(smsCommunicatorPlugin.messages.get(1).text.contains("To start extended bolus 1.00U for 20 min reply with code")); + passCode = smsCommunicatorPlugin.messageToConfirm.confirmCode; + smsCommunicatorPlugin.processSms(new Sms("1234", passCode)); + Assert.assertEquals(passCode, smsCommunicatorPlugin.messages.get(2).text); + Assert.assertEquals("Extended bolus 1.00U for 20 min started successfully\nVirtual Pump", smsCommunicatorPlugin.messages.get(3).text); + } + + @Test + public void processBolusTest() { + Sms sms; + + //BOLUS + smsCommunicatorPlugin.messages = new ArrayList<>(); + sms = new Sms("1234", "BOLUS"); + smsCommunicatorPlugin.processSms(sms); + Assert.assertEquals("BOLUS", smsCommunicatorPlugin.messages.get(0).text); + Assert.assertEquals("Remote command is not allowed", smsCommunicatorPlugin.messages.get(1).text); + + when(SP.getBoolean(R.string.key_smscommunicator_remotecommandsallowed, false)).thenReturn(true); + + //BOLUS + smsCommunicatorPlugin.messages = new ArrayList<>(); + sms = new Sms("1234", "BOLUS"); + smsCommunicatorPlugin.processSms(sms); + Assert.assertEquals("BOLUS", smsCommunicatorPlugin.messages.get(0).text); + Assert.assertEquals("Wrong format", smsCommunicatorPlugin.messages.get(1).text); + + when(MainApp.getConstraintChecker().applyBolusConstraints(any())).thenReturn(new Constraint<>(1d)); + + when(DateUtil.now()).thenReturn(1000L); + //BOLUS 1 + smsCommunicatorPlugin.messages = new ArrayList<>(); + sms = new Sms("1234", "BOLUS 1"); + smsCommunicatorPlugin.processSms(sms); + Assert.assertEquals("BOLUS 1", smsCommunicatorPlugin.messages.get(0).text); + Assert.assertEquals("Remote bolus not available. Try again later.", smsCommunicatorPlugin.messages.get(1).text); + + when(MainApp.getConstraintChecker().applyBolusConstraints(any())).thenReturn(new Constraint<>(0d)); + + when(DateUtil.now()).thenReturn(Constants.remoteBolusMinDistance + 1002L); + + //BOLUS 0 + smsCommunicatorPlugin.messages = new ArrayList<>(); + sms = new Sms("1234", "BOLUS 0"); + smsCommunicatorPlugin.processSms(sms); + Assert.assertEquals("BOLUS 0", smsCommunicatorPlugin.messages.get(0).text); + Assert.assertEquals("Wrong format", smsCommunicatorPlugin.messages.get(1).text); + + //BOLUS a + smsCommunicatorPlugin.messages = new ArrayList<>(); + sms = new Sms("1234", "BOLUS a"); + smsCommunicatorPlugin.processSms(sms); + Assert.assertEquals("BOLUS a", smsCommunicatorPlugin.messages.get(0).text); + Assert.assertEquals("Wrong format", smsCommunicatorPlugin.messages.get(1).text); + + when(MainApp.getConstraintChecker().applyExtendedBolusConstraints(any())).thenReturn(new Constraint<>(1d)); + + when(MainApp.getConstraintChecker().applyBolusConstraints(any())).thenReturn(new Constraint<>(1d)); + + //BOLUS 1 + smsCommunicatorPlugin.messages = new ArrayList<>(); + sms = new Sms("1234", "BOLUS 1"); + smsCommunicatorPlugin.processSms(sms); + Assert.assertEquals("BOLUS 1", smsCommunicatorPlugin.messages.get(0).text); + Assert.assertTrue(smsCommunicatorPlugin.messages.get(1).text.contains("To deliver bolus 1.00U reply with code")); + String passCode = smsCommunicatorPlugin.messageToConfirm.confirmCode; + smsCommunicatorPlugin.processSms(new Sms("1234", passCode)); + Assert.assertEquals(passCode, smsCommunicatorPlugin.messages.get(2).text); + Assert.assertEquals("Bolus 1.00U delivered successfully\nVirtual Pump", smsCommunicatorPlugin.messages.get(3).text); + + //BOLUS 1 (Suspended pump) + smsCommunicatorPlugin.lastRemoteBolusTime = 0; + PumpInterface pump = mock(VirtualPumpPlugin.class); + when(ConfigBuilderPlugin.getPlugin().getActivePump()).thenReturn(pump); + when(pump.isSuspended()).thenReturn(true); + smsCommunicatorPlugin.messages = new ArrayList<>(); + sms = new Sms("1234", "BOLUS 1"); + smsCommunicatorPlugin.processSms(sms); + Assert.assertEquals("BOLUS 1", smsCommunicatorPlugin.messages.get(0).text); + Assert.assertEquals("Pump suspended", smsCommunicatorPlugin.messages.get(1).text); + when(pump.isSuspended()).thenReturn(false); + } + + @Test + public void processCalTest() { + Sms sms; + + //CAL + smsCommunicatorPlugin.messages = new ArrayList<>(); + sms = new Sms("1234", "CAL"); + smsCommunicatorPlugin.processSms(sms); + Assert.assertEquals("CAL", smsCommunicatorPlugin.messages.get(0).text); + Assert.assertEquals("Remote command is not allowed", smsCommunicatorPlugin.messages.get(1).text); + + when(SP.getBoolean(R.string.key_smscommunicator_remotecommandsallowed, false)).thenReturn(true); + + //CAL + smsCommunicatorPlugin.messages = new ArrayList<>(); + sms = new Sms("1234", "CAL"); + smsCommunicatorPlugin.processSms(sms); + Assert.assertEquals("CAL", smsCommunicatorPlugin.messages.get(0).text); + Assert.assertEquals("Wrong format", smsCommunicatorPlugin.messages.get(1).text); + + //CAL 0 + smsCommunicatorPlugin.messages = new ArrayList<>(); + sms = new Sms("1234", "CAL 0"); + smsCommunicatorPlugin.processSms(sms); + Assert.assertEquals("CAL 0", smsCommunicatorPlugin.messages.get(0).text); + Assert.assertEquals("Wrong format", smsCommunicatorPlugin.messages.get(1).text); + + when(XdripCalibrations.sendIntent(any())).thenReturn(true); + //CAL 1 + smsCommunicatorPlugin.messages = new ArrayList<>(); + sms = new Sms("1234", "CAL 1"); + smsCommunicatorPlugin.processSms(sms); + Assert.assertEquals("CAL 1", smsCommunicatorPlugin.messages.get(0).text); + Assert.assertTrue(smsCommunicatorPlugin.messages.get(1).text.contains("To send calibration 1.00 reply with code")); + String passCode = smsCommunicatorPlugin.messageToConfirm.confirmCode; + smsCommunicatorPlugin.processSms(new Sms("1234", passCode)); + Assert.assertEquals(passCode, smsCommunicatorPlugin.messages.get(2).text); + Assert.assertEquals("Calibration sent. Receiving must be enabled in xDrip.", smsCommunicatorPlugin.messages.get(3).text); + } + + @Test + public void sendNotificationToAllNumbers() { + smsCommunicatorPlugin.messages = new ArrayList<>(); + smsCommunicatorPlugin.sendNotificationToAllNumbers("abc"); + Assert.assertEquals("abc", smsCommunicatorPlugin.messages.get(0).text); + Assert.assertEquals("abc", smsCommunicatorPlugin.messages.get(1).text); + } + + @Before + public void prepareTests() { + AAPSMocker.mockMainApp(); + AAPSMocker.mockApplicationContext(); + AAPSMocker.mockSP(); + AAPSMocker.mockL(); + AAPSMocker.mockStrings(); + AAPSMocker.mockBus(); + AAPSMocker.mockProfileFunctions(); + AAPSMocker.mockTreatmentPlugin(); + AAPSMocker.mockTreatmentService(); + AAPSMocker.mockIobCobCalculatorPlugin(); + AAPSMocker.mockConfigBuilder(); + AAPSMocker.mockCommandQueue(); + AAPSMocker.mockNSUpload(); + AAPSMocker.mockConstraintsChecker(); + + BgReading reading = new BgReading(); + reading.value = 100; + List bgList = new ArrayList<>(); + bgList.add(reading); + PowerMockito.when(IobCobCalculatorPlugin.getPlugin().getBgReadings()).thenReturn(bgList); + PowerMockito.when(IobCobCalculatorPlugin.getPlugin().getCobInfo(false, "SMS COB")).thenReturn(new CobInfo(10d, 2d)); + + mockStatic(XdripCalibrations.class); + mockStatic(DateUtil.class); + mockStatic(SmsManager.class); + SmsManager smsManager = mock(SmsManager.class); + when(SmsManager.getDefault()).thenReturn(smsManager); + + when(SP.getString(R.string.key_smscommunicator_allowednumbers, "")).thenReturn("1234;5678"); + smsCommunicatorPlugin = SmsCommunicatorPlugin.getPlugin(); + smsCommunicatorPlugin.setPluginEnabled(PluginType.GENERAL, true); + + loopPlugin = mock(LoopPlugin.class); + when(MainApp.getSpecificPlugin(LoopPlugin.class)).thenReturn(loopPlugin); + + Mockito.doAnswer(invocation -> { + Callback callback = invocation.getArgument(1); + callback.result = new PumpEnactResult().success(true); + callback.run(); + return null; + }).when(AAPSMocker.queue).cancelTempBasal(anyBoolean(), any(Callback.class)); + + Mockito.doAnswer(invocation -> { + Callback callback = invocation.getArgument(0); + callback.result = new PumpEnactResult().success(true); + callback.run(); + return null; + }).when(AAPSMocker.queue).cancelExtended(any(Callback.class)); + + Mockito.doAnswer(invocation -> { + Callback callback = invocation.getArgument(1); + callback.result = new PumpEnactResult().success(true); + callback.run(); + return null; + }).when(AAPSMocker.queue).readStatus(anyString(), any(Callback.class)); + + Mockito.doAnswer(invocation -> { + Callback callback = invocation.getArgument(1); + callback.result = new PumpEnactResult().success(true).bolusDelivered(1); + callback.run(); + return null; + }).when(AAPSMocker.queue).bolus(any(DetailedBolusInfo.class), any(Callback.class)); + + Mockito.doAnswer(invocation -> { + Callback callback = invocation.getArgument(4); + callback.result = new PumpEnactResult().success(true).isPercent(true).percent(invocation.getArgument(0)).duration(invocation.getArgument(1)); + callback.run(); + return null; + }).when(AAPSMocker.queue).tempBasalPercent(anyInt(), anyInt(), anyBoolean(), any(), any(Callback.class)); + + Mockito.doAnswer(invocation -> { + Callback callback = invocation.getArgument(4); + callback.result = new PumpEnactResult().success(true).isPercent(false).absolute(invocation.getArgument(0)).duration(invocation.getArgument(1)); + callback.run(); + return null; + }).when(AAPSMocker.queue).tempBasalAbsolute(anyDouble(), anyInt(), anyBoolean(), any(), any(Callback.class)); + + Mockito.doAnswer(invocation -> { + Callback callback = invocation.getArgument(2); + callback.result = new PumpEnactResult().success(true).isPercent(false).absolute(invocation.getArgument(0)).duration(invocation.getArgument(1)); + callback.run(); + return null; + }).when(AAPSMocker.queue).extendedBolus(anyDouble(), anyInt(), any(Callback.class)); + + VirtualPumpPlugin virtualPumpPlugin = VirtualPumpPlugin.getPlugin(); + when(ConfigBuilderPlugin.getPlugin().getActivePump()).thenReturn(virtualPumpPlugin); + } + +} diff --git a/app/src/test/java/info/nightscout/androidaps/plugins/general/smsCommunicator/SmsTest.java b/app/src/test/java/info/nightscout/androidaps/plugins/general/smsCommunicator/SmsTest.java new file mode 100644 index 0000000000..5f7af11a67 --- /dev/null +++ b/app/src/test/java/info/nightscout/androidaps/plugins/general/smsCommunicator/SmsTest.java @@ -0,0 +1,53 @@ +package info.nightscout.androidaps.plugins.general.smsCommunicator; + +import android.telephony.SmsMessage; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; + +import info.AAPSMocker; +import info.nightscout.androidaps.MainApp; +import info.nightscout.androidaps.R; + +import static org.powermock.api.mockito.PowerMockito.mock; +import static org.powermock.api.mockito.PowerMockito.when; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({SmsMessage.class, MainApp.class}) + +public class SmsTest { + + @Test + public void doTests() { + SmsMessage smsMessage = mock(SmsMessage.class); + when(smsMessage.getOriginatingAddress()).thenReturn("aNumber"); + when(smsMessage.getMessageBody()).thenReturn("aBody"); + + Sms sms = new Sms(smsMessage); + Assert.assertEquals(sms.phoneNumber, "aNumber"); + Assert.assertEquals(sms.text, "aBody"); + Assert.assertTrue(sms.received); + + sms = new Sms("aNumber", "aBody"); + Assert.assertEquals(sms.phoneNumber, "aNumber"); + Assert.assertEquals(sms.text, "aBody"); + Assert.assertTrue(sms.sent); + + sms = new Sms("aNumber", R.string.insulin_unit_shortname); + Assert.assertEquals(sms.phoneNumber, "aNumber"); + Assert.assertEquals(sms.text, MainApp.gs(R.string.insulin_unit_shortname)); + Assert.assertTrue(sms.sent); + + Assert.assertEquals(sms.toString(), "SMS from aNumber: U"); + } + + @Before + public void prepareTests() { + AAPSMocker.mockMainApp(); + AAPSMocker.mockStrings(); + } +} diff --git a/app/src/test/java/info/nightscout/androidaps/plugins/IobCobCalculatorPlugin/IobCobCalculatorPluginTest.java b/app/src/test/java/info/nightscout/androidaps/plugins/iob/iobCobCalculatorPlugin/IobCobCalculatorPluginTest.java similarity index 99% rename from app/src/test/java/info/nightscout/androidaps/plugins/IobCobCalculatorPlugin/IobCobCalculatorPluginTest.java rename to app/src/test/java/info/nightscout/androidaps/plugins/iob/iobCobCalculatorPlugin/IobCobCalculatorPluginTest.java index 8cb7f2e4ad..4cd57f93ad 100644 --- a/app/src/test/java/info/nightscout/androidaps/plugins/IobCobCalculatorPlugin/IobCobCalculatorPluginTest.java +++ b/app/src/test/java/info/nightscout/androidaps/plugins/iob/iobCobCalculatorPlugin/IobCobCalculatorPluginTest.java @@ -1,4 +1,4 @@ -package info.nightscout.androidaps.plugins.IobCobCalculatorPlugin; +package info.nightscout.androidaps.plugins.iob.iobCobCalculatorPlugin; import android.content.Context;