diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000000..d15d2440fd --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,48 @@ +This document speciffy hints and good practices for source code contributions. + +AndroidAPS is community effort and all contributions are welcome! If you wish help us improving AndroidAPS - please read and try to adhere to +this guidelines, to make the development and process of change aproval as smooth as possible :) + +General rules +============= + +* There are plenty of ways you can help, some of them are listed on wiki: + https://androidaps.readthedocs.io/en/latest/EN/Getting-Started/How-can-I-help.html +* If you wish to help with documentation or translating: + https://androidaps.readthedocs.io/en/latest/EN/translations.html + +Development guidelines +====================== + +Coding convetions +----------------- +1. Use Android Studio with default indents (4 chars, use spaces) +2. Use autoformat feature CTRL-ALT-L in every changed file before commit + +Commiting Changes / Pull Requests +--------------------------------- + +1. Make fork of repository on github +2. Create separate branch for each feature, branch from most recent dev +3. Commit all changes to your fork +4. When ready, rebase on top of dev and make pull request to main repo + +Naming Conventions for Pull Requests / Branches +----------------------------------------------- + +TODO + +Translations +------------ + +* If possible, always use Android translation mechanism (with strings.xml and @strings/id) instead of hardcoded texts +* Provide only English strings - all other languages will be crowd translated via Crowdn https://translations.androidaps.org/ + +Hints +----- + +* Start small, it is easier to review smaller changes that affect fewer parts of code +* Take a look into Issues list (https://github.com/MilosKozak/AndroidAPS/issues) - maybe there is somthing you can fix or implement +* For new features, make sure there is Issue to track progress and have on-topic discussion +* Reach out to community, discuss idea on Gitter (https://gitter.im/MilosKozak/AndroidAPS) +* Speak with other developers to minimise merge conflicts. Find out who worked, working or plan to work on speciffic issue or part of app diff --git a/app/src/main/java/info/nightscout/androidaps/MainApp.java b/app/src/main/java/info/nightscout/androidaps/MainApp.java index a0cb5a44c4..8abc5464f7 100644 --- a/app/src/main/java/info/nightscout/androidaps/MainApp.java +++ b/app/src/main/java/info/nightscout/androidaps/MainApp.java @@ -130,7 +130,14 @@ public class MainApp extends Application { sConstraintsChecker = new ConstraintChecker(); sDatabaseHelper = OpenHelperManager.getHelper(sInstance, DatabaseHelper.class); - Thread.setDefaultUncaughtExceptionHandler((thread, ex) -> log.error("Uncaught exception crashing app", ex)); + Thread.setDefaultUncaughtExceptionHandler((thread, ex) -> { + if (ex instanceof InternalError) { + // usually the app trying to spawn a thread while being killed + return; + } + + log.error("Uncaught exception crashing app", ex); + }); try { if (FabricPrivacy.fabricEnabled()) { @@ -207,7 +214,7 @@ public class MainApp extends Application { pluginsList.add(SourcePoctechPlugin.getPlugin()); pluginsList.add(SourceTomatoPlugin.getPlugin()); pluginsList.add(SourceEversensePlugin.getPlugin()); - if (!Config.NSCLIENT) pluginsList.add(SmsCommunicatorPlugin.getPlugin()); + if (!Config.NSCLIENT) pluginsList.add(SmsCommunicatorPlugin.INSTANCE); pluginsList.add(FoodPlugin.getPlugin()); pluginsList.add(WearPlugin.initPlugin(this)); diff --git a/app/src/main/java/info/nightscout/androidaps/activities/PreferencesActivity.java b/app/src/main/java/info/nightscout/androidaps/activities/PreferencesActivity.java index 367429dbbf..0e93a47151 100644 --- a/app/src/main/java/info/nightscout/androidaps/activities/PreferencesActivity.java +++ b/app/src/main/java/info/nightscout/androidaps/activities/PreferencesActivity.java @@ -9,27 +9,28 @@ import android.preference.PreferenceActivity; import android.preference.PreferenceFragment; import android.preference.PreferenceGroup; import android.preference.PreferenceManager; -import android.preference.PreferenceScreen; -import android.text.TextUtils; import info.nightscout.androidaps.Config; import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.R; -import info.nightscout.androidaps.plugins.bus.RxBus; import info.nightscout.androidaps.events.EventPreferenceChange; import info.nightscout.androidaps.events.EventRebuildTabs; import info.nightscout.androidaps.interfaces.PluginBase; import info.nightscout.androidaps.interfaces.PluginType; -import info.nightscout.androidaps.plugins.general.careportal.CareportalPlugin; -import info.nightscout.androidaps.plugins.constraints.safety.SafetyPlugin; -import info.nightscout.androidaps.plugins.general.tidepool.TidepoolPlugin; -import info.nightscout.androidaps.plugins.general.tidepool.comm.TidepoolUploader; -import info.nightscout.androidaps.plugins.insulin.InsulinOrefFreePeakPlugin; import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin; -import info.nightscout.androidaps.plugins.general.nsclient.NSClientPlugin; import info.nightscout.androidaps.plugins.aps.openAPSAMA.OpenAPSAMAPlugin; import info.nightscout.androidaps.plugins.aps.openAPSMA.OpenAPSMAPlugin; import info.nightscout.androidaps.plugins.aps.openAPSSMB.OpenAPSSMBPlugin; +import info.nightscout.androidaps.plugins.bus.RxBus; +import info.nightscout.androidaps.plugins.constraints.safety.SafetyPlugin; +import info.nightscout.androidaps.plugins.general.automation.AutomationPlugin; +import info.nightscout.androidaps.plugins.general.careportal.CareportalPlugin; +import info.nightscout.androidaps.plugins.general.nsclient.NSClientPlugin; +import info.nightscout.androidaps.plugins.general.smsCommunicator.SmsCommunicatorPlugin; +import info.nightscout.androidaps.plugins.general.tidepool.TidepoolPlugin; +import info.nightscout.androidaps.plugins.general.wear.WearPlugin; +import info.nightscout.androidaps.plugins.general.xdripStatusline.StatuslinePlugin; +import info.nightscout.androidaps.plugins.insulin.InsulinOrefFreePeakPlugin; import info.nightscout.androidaps.plugins.pump.combo.ComboPlugin; import info.nightscout.androidaps.plugins.pump.danaR.DanaRPlugin; import info.nightscout.androidaps.plugins.pump.danaRKorean.DanaRKoreanPlugin; @@ -42,14 +43,9 @@ import info.nightscout.androidaps.plugins.sensitivity.SensitivityAAPSPlugin; import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref0Plugin; import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref1Plugin; import info.nightscout.androidaps.plugins.sensitivity.SensitivityWeightedAveragePlugin; -import info.nightscout.androidaps.plugins.general.smsCommunicator.SmsCommunicatorPlugin; -import info.nightscout.androidaps.plugins.general.wear.WearPlugin; -import info.nightscout.androidaps.plugins.general.xdripStatusline.StatuslinePlugin; import info.nightscout.androidaps.plugins.source.SourceDexcomPlugin; -import info.nightscout.androidaps.utils.LocaleHelper; import info.nightscout.androidaps.utils.OKDialog; import info.nightscout.androidaps.utils.SP; -import info.nightscout.androidaps.plugins.general.automation.AutomationPlugin; public class PreferencesActivity extends PreferenceActivity implements SharedPreferences.OnSharedPreferenceChangeListener { MyPreferenceFragment myPreferenceFragment; @@ -80,7 +76,7 @@ public class PreferencesActivity extends PreferenceActivity implements SharedPre if (key.equals(MainApp.gs(R.string.key_openapsama_useautosens)) && SP.getBoolean(R.string.key_openapsama_useautosens, false)) { OKDialog.show(this, MainApp.gs(R.string.configbuilder_sensitivity), MainApp.gs(R.string.sensitivity_warning), null); } - updatePrefSummary(myPreferenceFragment.getPreference(key)); + updatePrefSummary(myPreferenceFragment.findPreference(key)); } private static void updatePrefSummary(Preference pref) { @@ -92,13 +88,13 @@ public class PreferencesActivity extends PreferenceActivity implements SharedPre EditTextPreference editTextPref = (EditTextPreference) pref; if (pref.getKey().contains("password") || pref.getKey().contains("secret")) { pref.setSummary("******"); - } else if (pref.getKey().equals(MainApp.gs(R.string.key_danars_name))) { - pref.setSummary(SP.getString(R.string.key_danars_name, "")); } else if (editTextPref.getText() != null) { ((EditTextPreference) pref).setDialogMessage(editTextPref.getDialogMessage()); pref.setSummary(editTextPref.getText()); - } else if (pref.getKey().contains("smscommunicator_allowednumbers") && (editTextPref.getText() == null || TextUtils.isEmpty(editTextPref.getText().trim()))) { - pref.setSummary(MainApp.gs(R.string.smscommunicator_allowednumbers_summary)); + } else { + for (PluginBase plugin : MainApp.getPluginsList()) { + plugin.updatePreferenceSummary(pref); + } } } } @@ -188,7 +184,7 @@ public class PreferencesActivity extends PreferenceActivity implements SharedPre addPreferencesFromResourceIfEnabled(NSClientPlugin.getPlugin(), PluginType.GENERAL); addPreferencesFromResourceIfEnabled(TidepoolPlugin.INSTANCE, PluginType.GENERAL); - addPreferencesFromResourceIfEnabled(SmsCommunicatorPlugin.getPlugin(), PluginType.GENERAL); + addPreferencesFromResourceIfEnabled(SmsCommunicatorPlugin.INSTANCE, PluginType.GENERAL); addPreferencesFromResourceIfEnabled(AutomationPlugin.INSTANCE, PluginType.GENERAL); addPreferencesFromResource(R.xml.pref_others); @@ -198,26 +194,11 @@ public class PreferencesActivity extends PreferenceActivity implements SharedPre addPreferencesFromResourceIfEnabled(StatuslinePlugin.getPlugin(), PluginType.GENERAL); } - if (Config.NSCLIENT) { - PreferenceScreen scrnAdvancedSettings = (PreferenceScreen) findPreference(getString(R.string.key_advancedsettings)); - if (scrnAdvancedSettings != null) { - scrnAdvancedSettings.removePreference(getPreference(getString(R.string.key_statuslights_res_warning))); - scrnAdvancedSettings.removePreference(getPreference(getString(R.string.key_statuslights_res_critical))); - scrnAdvancedSettings.removePreference(getPreference(getString(R.string.key_statuslights_bat_warning))); - scrnAdvancedSettings.removePreference(getPreference(getString(R.string.key_statuslights_bat_critical))); - scrnAdvancedSettings.removePreference(getPreference(getString(R.string.key_show_statuslights))); - scrnAdvancedSettings.removePreference(getPreference(getString(R.string.key_show_statuslights_extended))); - } - } - initSummary(getPreferenceScreen()); - final Preference tidepoolTestLogin = findPreference(MainApp.gs(R.string.key_tidepool_test_login)); - if (tidepoolTestLogin != null) - tidepoolTestLogin.setOnPreferenceClickListener(preference -> { - TidepoolUploader.INSTANCE.testLogin(getActivity()); - return false; - }); + for (PluginBase plugin : MainApp.getPluginsList()) { + plugin.preprocessPreferences(this); + } } @Override @@ -225,9 +206,5 @@ public class PreferencesActivity extends PreferenceActivity implements SharedPre super.onSaveInstanceState(outState); outState.putInt("id", id); } - - public Preference getPreference(String key) { - return findPreference(key); - } } } diff --git a/app/src/main/java/info/nightscout/androidaps/db/CareportalEvent.java b/app/src/main/java/info/nightscout/androidaps/db/CareportalEvent.java index 40fadff684..1c33e8f1be 100644 --- a/app/src/main/java/info/nightscout/androidaps/db/CareportalEvent.java +++ b/app/src/main/java/info/nightscout/androidaps/db/CareportalEvent.java @@ -100,8 +100,8 @@ public class CareportalEvent implements DataPointWithLabelInterface, Interval { String hours = " " + MainApp.gs(R.string.hours) + " "; if (useShortText) { - days = "d"; - hours = "h"; + days = MainApp.gs(R.string.shortday); + hours = MainApp.gs(R.string.shorthour); } return diff.get(TimeUnit.DAYS) + days + diff.get(TimeUnit.HOURS) + hours; 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 f7c8e9ada4..8de88e1e0e 100644 --- a/app/src/main/java/info/nightscout/androidaps/interfaces/PluginBase.java +++ b/app/src/main/java/info/nightscout/androidaps/interfaces/PluginBase.java @@ -1,10 +1,13 @@ package info.nightscout.androidaps.interfaces; import android.os.SystemClock; +import android.preference.Preference; +import android.preference.PreferenceFragment; import androidx.appcompat.app.AlertDialog; import androidx.fragment.app.FragmentActivity; +import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -215,4 +218,10 @@ public abstract class PluginBase { protected void onStateChange(PluginType type, State oldState, State newState) { } + + public void preprocessPreferences(@NotNull final PreferenceFragment preferenceFragment) { + } + + public void updatePreferenceSummary(@NotNull final Preference pref) { + } } \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/APSResult.java b/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/APSResult.java index b3b0c091d5..7e568af2d9 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/APSResult.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/APSResult.java @@ -247,7 +247,7 @@ public class APSResult { } } } catch (JSONException e) { - e.printStackTrace(); + log.error("Unhandled exception", e); } return array; } @@ -280,7 +280,7 @@ public class APSResult { } } } catch (JSONException e) { - e.printStackTrace(); + log.error("Unhandled exception", e); } return latest; diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSAMA/OpenAPSAMAPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSAMA/OpenAPSAMAPlugin.java index ef31ad599e..65db6e440c 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSAMA/OpenAPSAMAPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSAMA/OpenAPSAMAPlugin.java @@ -164,7 +164,7 @@ public class OpenAPSAMAPlugin extends PluginBase implements APSInterface { return; if (!HardLimits.checkOnlyHardLimits(Profile.toMgdl(profile.getIsf(), units), "sens", HardLimits.MINISF, HardLimits.MAXISF)) return; - if (!HardLimits.checkOnlyHardLimits(profile.getMaxDailyBasal(), "max_daily_basal", 0.05, HardLimits.maxBasal())) + if (!HardLimits.checkOnlyHardLimits(profile.getMaxDailyBasal(), "max_daily_basal", 0.02, HardLimits.maxBasal())) return; if (!HardLimits.checkOnlyHardLimits(pump.getBaseBasalRate(), "current_basal", 0.01, HardLimits.maxBasal())) return; diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSMA/OpenAPSMAPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSMA/OpenAPSMAPlugin.java index 899c0151d8..8cac8b87cc 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSMA/OpenAPSMAPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSMA/OpenAPSMAPlugin.java @@ -162,7 +162,7 @@ public class OpenAPSMAPlugin extends PluginBase implements APSInterface { return; if (!checkOnlyHardLimits(Profile.toMgdl(profile.getIsf(), units), "sens", HardLimits.MINISF, HardLimits.MAXISF)) return; - if (!checkOnlyHardLimits(profile.getMaxDailyBasal(), "max_daily_basal", 0.05, HardLimits.maxBasal())) + if (!checkOnlyHardLimits(profile.getMaxDailyBasal(), "max_daily_basal", 0.02, HardLimits.maxBasal())) return; if (!checkOnlyHardLimits(pump.getBaseBasalRate(), "current_basal", 0.01, HardLimits.maxBasal())) return; 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 d410eba291..c27a3f2059 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 @@ -170,7 +170,7 @@ public class OpenAPSSMBPlugin extends PluginBase implements APSInterface, Constr return; if (!checkOnlyHardLimits(Profile.toMgdl(profile.getIsf(), units), "sens", HardLimits.MINISF, HardLimits.MAXISF)) return; - if (!checkOnlyHardLimits(profile.getMaxDailyBasal(), "max_daily_basal", 0.05, HardLimits.maxBasal())) + if (!checkOnlyHardLimits(profile.getMaxDailyBasal(), "max_daily_basal", 0.02, HardLimits.maxBasal())) return; if (!checkOnlyHardLimits(pump.getBaseBasalRate(), "current_basal", 0.01, HardLimits.maxBasal())) return; 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 025d8dac1e..91c20b095a 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 @@ -27,6 +27,7 @@ import info.nightscout.androidaps.plugins.bus.RxBus; import info.nightscout.androidaps.plugins.general.overview.dialogs.ErrorHelperActivity; import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin; import info.nightscout.androidaps.queue.Callback; +import info.nightscout.androidaps.utils.DateUtil; import info.nightscout.androidaps.utils.FabricPrivacy; import info.nightscout.androidaps.utils.SP; import io.reactivex.disposables.CompositeDisposable; @@ -75,35 +76,42 @@ public class ProfileFunctions { } public String getProfileName() { - return getProfileName(System.currentTimeMillis()); + return getProfileName(System.currentTimeMillis(), true, false); } public String getProfileName(boolean customized) { - return getProfileName(System.currentTimeMillis(), customized); + return getProfileName(System.currentTimeMillis(), customized, false); } - public String getProfileName(long time) { - return getProfileName(time, true); + public String getProfileNameWithDuration() { + return getProfileName(System.currentTimeMillis(), true, true); } - public String getProfileName(long time, boolean customized) { + public String getProfileName(long time, boolean customized, boolean showRemainingTime) { + String profileName = MainApp.gs(R.string.noprofileselected); + TreatmentsInterface activeTreatments = TreatmentsPlugin.getPlugin(); ProfileInterface activeProfile = ConfigBuilderPlugin.getPlugin().getActiveProfileInterface(); ProfileSwitch profileSwitch = activeTreatments.getProfileSwitchFromHistory(time); if (profileSwitch != null) { if (profileSwitch.profileJson != null) { - return customized ? profileSwitch.getCustomizedName() : profileSwitch.profileName; + profileName = customized ? profileSwitch.getCustomizedName() : profileSwitch.profileName; } else { ProfileStore profileStore = activeProfile.getProfile(); if (profileStore != null) { Profile profile = profileStore.getSpecificProfile(profileSwitch.profileName); if (profile != null) - return profileSwitch.profileName; + profileName = profileSwitch.profileName; } } + + if (showRemainingTime && profileSwitch.durationInMinutes != 0) { + profileName += DateUtil.untilString(profileSwitch.originalEnd()); + } + return profileName; } - return MainApp.gs(R.string.noprofileselected); + return profileName; } public boolean isProfileValid(String from) { @@ -176,7 +184,7 @@ public class ProfileFunctions { profileSwitch = new ProfileSwitch(); profileSwitch.date = System.currentTimeMillis(); profileSwitch.source = Source.USER; - profileSwitch.profileName = getInstance().getProfileName(System.currentTimeMillis(), false); + profileSwitch.profileName = getInstance().getProfileName(System.currentTimeMillis(), false, false); profileSwitch.profileJson = getInstance().getProfile().getData().toString(); profileSwitch.profilePlugin = ConfigBuilderPlugin.getPlugin().getActiveProfileInterface().getClass().getName(); profileSwitch.durationInMinutes = duration; diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/dstHelper/DstHelperPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/dstHelper/DstHelperPlugin.java index e026d6589d..828fa1b86f 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/dstHelper/DstHelperPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/dstHelper/DstHelperPlugin.java @@ -22,7 +22,7 @@ import info.nightscout.androidaps.plugins.general.overview.notifications.Notific public class DstHelperPlugin extends PluginBase implements ConstraintsInterface { public static final int DISABLE_TIMEFRAME_HOURS = -3; - public static final int WARN_PRIOR_TIMEFRAME_HOURS = 24; + public static final int WARN_PRIOR_TIMEFRAME_HOURS = 12; private static Logger log = LoggerFactory.getLogger(L.CONSTRAINTS); static DstHelperPlugin plugin = null; diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/ObjectivesFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/ObjectivesFragment.kt index aafd877672..34aadf84c6 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/ObjectivesFragment.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/ObjectivesFragment.kt @@ -4,6 +4,7 @@ import android.graphics.Color import android.os.Bundle import android.os.Handler import android.os.Looper +import android.os.SystemClock import android.view.Gravity import android.view.LayoutInflater import android.view.View @@ -12,6 +13,7 @@ import android.widget.Button import android.widget.EditText import android.widget.LinearLayout import android.widget.TextView +import androidx.appcompat.app.AppCompatActivity import androidx.fragment.app.Fragment import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearSmoothScroller @@ -21,6 +23,8 @@ import info.nightscout.androidaps.R import info.nightscout.androidaps.logging.L import info.nightscout.androidaps.plugins.bus.RxBus import info.nightscout.androidaps.plugins.constraints.objectives.activities.ObjectivesExamDialog +import info.nightscout.androidaps.plugins.constraints.objectives.dialogs.NtpProgressDialog +import info.nightscout.androidaps.plugins.constraints.objectives.events.EventNtpStatus import info.nightscout.androidaps.plugins.constraints.objectives.events.EventObjectivesUpdateGui import info.nightscout.androidaps.plugins.constraints.objectives.objectives.Objective.ExamTask import info.nightscout.androidaps.receivers.NetworkChangeReceiver @@ -101,18 +105,20 @@ class ObjectivesFragment : Fragment() { } private fun scrollToCurrentObjective() { - for (i in 0 until ObjectivesPlugin.objectives.size) { - val objective = ObjectivesPlugin.objectives[i] - if (!objective.isStarted || !objective.isAccomplished) { - context?.let { - val smoothScroller = object : LinearSmoothScroller(it) { - override fun getVerticalSnapPreference(): Int = SNAP_TO_START - override fun calculateTimeForScrolling(dx: Int): Int = super.calculateTimeForScrolling(dx) * 4 + activity?.runOnUiThread { + for (i in 0 until ObjectivesPlugin.objectives.size) { + val objective = ObjectivesPlugin.objectives[i] + if (!objective.isStarted || !objective.isAccomplished) { + context?.let { + val smoothScroller = object : LinearSmoothScroller(it) { + override fun getVerticalSnapPreference(): Int = SNAP_TO_START + override fun calculateTimeForScrolling(dx: Int): Int = super.calculateTimeForScrolling(dx) * 4 + } + smoothScroller.targetPosition = i + objectives_recyclerview.layoutManager?.startSmoothScroll(smoothScroller) } - smoothScroller.targetPosition = i - objectives_recyclerview.layoutManager?.startSmoothScroll(smoothScroller) + break } - break } } } @@ -126,7 +132,6 @@ class ObjectivesFragment : Fragment() { override fun onBindViewHolder(holder: ViewHolder, position: Int) { val objective = ObjectivesPlugin.objectives[position] holder.title.text = MainApp.gs(R.string.nth_objective, position + 1) - holder.revert.visibility = View.GONE if (objective.objective != 0) { holder.objective.visibility = View.VISIBLE holder.objective.text = MainApp.gs(objective.objective) @@ -142,6 +147,8 @@ class ObjectivesFragment : Fragment() { holder.verify.visibility = View.GONE holder.progress.visibility = View.GONE holder.accomplished.visibility = View.GONE + holder.unFinish.visibility = View.GONE + holder.unStart.visibility = View.GONE if (position == 0 || ObjectivesPlugin.objectives[position - 1].isAccomplished) holder.start.visibility = View.VISIBLE else @@ -152,15 +159,16 @@ class ObjectivesFragment : Fragment() { holder.progress.visibility = View.GONE holder.start.visibility = View.GONE holder.accomplished.visibility = View.VISIBLE + holder.unFinish.visibility = View.VISIBLE + holder.unStart.visibility = View.GONE } else if (objective.isStarted) { holder.gate.setTextColor(-0x1) holder.verify.visibility = View.VISIBLE holder.verify.isEnabled = objective.isCompleted || objectives_fake.isChecked holder.start.visibility = View.GONE holder.accomplished.visibility = View.GONE - if (objective.isRevertable) { - holder.revert.visibility = View.VISIBLE - } + holder.unFinish.visibility = View.GONE + holder.unStart.visibility = View.VISIBLE holder.progress.visibility = View.VISIBLE holder.progress.removeAllViews() for (task in objective.tasks) { @@ -203,76 +211,87 @@ class ObjectivesFragment : Fragment() { holder.accomplished.text = MainApp.gs(R.string.accomplished, DateUtil.dateAndTimeString(objective.accomplishedOn)) holder.accomplished.setTextColor(-0x3e3e3f) holder.verify.setOnClickListener { - holder.verify.visibility = View.INVISIBLE - NetworkChangeReceiver.fetch() + NetworkChangeReceiver.grabNetworkStatus(context) if (objectives_fake.isChecked) { objective.accomplishedOn = DateUtil.now() scrollToCurrentObjective() startUpdateTimer() RxBus.send(EventObjectivesUpdateGui()) - } else - SntpClient.ntpTime(object : SntpClient.Callback() { - override fun run() { - activity?.runOnUiThread { - holder.verify.visibility = View.VISIBLE + } else { + // move out of UI thread + Thread { + NtpProgressDialog().show((context as AppCompatActivity).supportFragmentManager, "NtpCheck") + RxBus.send(EventNtpStatus(MainApp.gs(R.string.timedetection), 0)) + SntpClient.ntpTime(object : SntpClient.Callback() { + override fun run() { log.debug("NTP time: $time System time: ${DateUtil.now()}") + SystemClock.sleep(300) if (!networkConnected) { - ToastUtils.showToastInUiThread(context, R.string.notconnected) + RxBus.send(EventNtpStatus(MainApp.gs(R.string.notconnected), 99)) } else if (success) { if (objective.isCompleted(time)) { objective.accomplishedOn = time - scrollToCurrentObjective() - startUpdateTimer() + RxBus.send(EventNtpStatus(MainApp.gs(R.string.success), 100)) + SystemClock.sleep(1000) RxBus.send(EventObjectivesUpdateGui()) + SystemClock.sleep(100) + scrollToCurrentObjective() } else { - ToastUtils.showToastInUiThread(context, R.string.requirementnotmet) + RxBus.send(EventNtpStatus(MainApp.gs(R.string.requirementnotmet), 99)) } } else { - ToastUtils.showToastInUiThread(context, R.string.failedretrievetime) + RxBus.send(EventNtpStatus(MainApp.gs(R.string.failedretrievetime), 99)) } } - } - }, NetworkChangeReceiver.isConnected()) + }, NetworkChangeReceiver.isConnected()) + }.start() + } } holder.start.setOnClickListener { - holder.start.visibility = View.INVISIBLE - NetworkChangeReceiver.fetch() + NetworkChangeReceiver.grabNetworkStatus(context) if (objectives_fake.isChecked) { objective.startedOn = DateUtil.now() scrollToCurrentObjective() startUpdateTimer() RxBus.send(EventObjectivesUpdateGui()) } else - SntpClient.ntpTime(object : SntpClient.Callback() { - override fun run() { - activity?.runOnUiThread { - holder.start.visibility = View.VISIBLE + // move out of UI thread + Thread { + NtpProgressDialog().show((context as AppCompatActivity).supportFragmentManager, "NtpCheck") + RxBus.send(EventNtpStatus(MainApp.gs(R.string.timedetection), 0)) + SntpClient.ntpTime(object : SntpClient.Callback() { + override fun run() { log.debug("NTP time: $time System time: ${DateUtil.now()}") + SystemClock.sleep(300) if (!networkConnected) { - ToastUtils.showToastInUiThread(context, R.string.notconnected) + RxBus.send(EventNtpStatus(MainApp.gs(R.string.notconnected), 99)) } else if (success) { objective.startedOn = time - scrollToCurrentObjective() - startUpdateTimer() + RxBus.send(EventNtpStatus(MainApp.gs(R.string.success), 100)) + SystemClock.sleep(1000) RxBus.send(EventObjectivesUpdateGui()) + SystemClock.sleep(100) + scrollToCurrentObjective() } else { - ToastUtils.showToastInUiThread(context, R.string.failedretrievetime) + RxBus.send(EventNtpStatus(MainApp.gs(R.string.failedretrievetime), 99)) } } - } - }, NetworkChangeReceiver.isConnected()) + }, NetworkChangeReceiver.isConnected()) + }.start() } - holder.revert.setOnClickListener { - objective.accomplishedOn = 0 - objective.startedOn = 0 - if (position > 0) { - val prevObj = ObjectivesPlugin.objectives[position - 1] - prevObj.accomplishedOn = 0 + holder.unStart.setOnClickListener { + OKDialog.showConfirmation(activity, MainApp.gs(R.string.doyouwantresetstart)) { + objective.startedOn = 0 + scrollToCurrentObjective() + RxBus.send(EventObjectivesUpdateGui()) } + } + holder.unFinish.setOnClickListener { + objective.accomplishedOn = 0 scrollToCurrentObjective() RxBus.send(EventObjectivesUpdateGui()) } - if (objective.hasSpecialInput && !objective.isAccomplished && objective.isStarted) { + if (objective.hasSpecialInput && !objective.isAccomplished && objective.isStarted && objective.specialActionEnabled()) { // generate random request code if none exists val request = SP.getString(R.string.key_objectives_request_code, String.format("%1$05d", (Math.random() * 99999).toInt())) SP.putString(R.string.key_objectives_request_code, request) @@ -307,7 +326,8 @@ class ObjectivesFragment : Fragment() { val progress: LinearLayout = itemView.findViewById(R.id.objective_progress) val verify: Button = itemView.findViewById(R.id.objective_verify) val start: Button = itemView.findViewById(R.id.objective_start) - val revert: Button = itemView.findViewById(R.id.objective_back) + val unFinish: Button = itemView.findViewById(R.id.objective_unfinish) + val unStart: Button = itemView.findViewById(R.id.objective_unstart) val inputHint: TextView = itemView.findViewById(R.id.objective_inputhint) val input: EditText = itemView.findViewById(R.id.objective_input) val enterButton: Button = itemView.findViewById(R.id.objective_enterbutton) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/ObjectivesPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/ObjectivesPlugin.kt index ca3e1d3126..f8b0ca26ec 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/ObjectivesPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/ObjectivesPlugin.kt @@ -104,8 +104,8 @@ object ObjectivesPlugin : PluginBase(PluginDescription() fun completeObjectives(activity: Activity, request: String) { val requestCode = SP.getString(R.string.key_objectives_request_code, "") var url = SP.getString(R.string.key_nsclientinternal_url, "").toLowerCase() - if (!url.endsWith("\"")) url = "$url/" - val hashNS = Hashing.sha1().hashString(url + BuildConfig.APPLICATION_ID + "/" + requestCode, Charsets.UTF_8).toString() + if (!url.endsWith("/")) url = "$url/" + @Suppress("DEPRECATION") val hashNS = Hashing.sha1().hashString(url + BuildConfig.APPLICATION_ID + "/" + requestCode, Charsets.UTF_8).toString() if (request.equals(hashNS.substring(0, 10), ignoreCase = true)) { SP.putLong("Objectives_" + "openloop" + "_started", DateUtil.now()) SP.putLong("Objectives_" + "openloop" + "_accomplished", DateUtil.now()) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/dialogs/NtpProgressDialog.kt b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/dialogs/NtpProgressDialog.kt new file mode 100644 index 0000000000..cef9bc232a --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/dialogs/NtpProgressDialog.kt @@ -0,0 +1,84 @@ +package info.nightscout.androidaps.plugins.constraints.objectives.dialogs + +import android.os.Bundle +import android.os.SystemClock +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.DialogFragment +import info.nightscout.androidaps.MainApp +import info.nightscout.androidaps.R +import info.nightscout.androidaps.logging.L +import info.nightscout.androidaps.plugins.bus.RxBus.toObservable +import info.nightscout.androidaps.plugins.constraints.objectives.events.EventNtpStatus +import info.nightscout.androidaps.utils.FabricPrivacy +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.disposables.CompositeDisposable +import kotlinx.android.synthetic.main.overview_bolusprogress_dialog.* +import org.slf4j.LoggerFactory + +class NtpProgressDialog : DialogFragment() { + private val log = LoggerFactory.getLogger(L.UI) + private val disposable = CompositeDisposable() + + private val DEFAULT_STATE = MainApp.gs(R.string.timedetection) + private var state: String = DEFAULT_STATE + private var percent = 0 + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle?): View? { + dialog?.setTitle(String.format(MainApp.gs(R.string.objectives))) + isCancelable = false + + state = savedInstanceState?.getString("state", DEFAULT_STATE) ?: DEFAULT_STATE + percent = savedInstanceState?.getInt("percent", 0) ?: 0 + + return inflater.inflate(R.layout.overview_bolusprogress_dialog, container, false) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + overview_bolusprogress_stop.setOnClickListener { dismiss() } + overview_bolusprogress_status.setText(state) + overview_bolusprogress_progressbar.setMax(100) + overview_bolusprogress_progressbar.setProgress(percent) + overview_bolusprogress_stop.text = MainApp.gs(R.string.close) + } + + override fun onResume() { + super.onResume() + if (L.isEnabled(L.UI)) log.debug("onResume") + if (percent == 100) { + dismiss() + return + } else + dialog?.window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) + + disposable.add(toObservable(EventNtpStatus::class.java) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe({ event: EventNtpStatus -> + if (L.isEnabled(L.UI)) log.debug("Status: " + event.status + " Percent: " + event.percent) + overview_bolusprogress_status?.text = event.status + overview_bolusprogress_progressbar?.progress = event.percent + if (event.percent == 100) { + SystemClock.sleep(100) + dismiss() + } + state = event.status + percent = event.percent + }) { FabricPrivacy.logException(it) } + ) + } + + override fun onPause() { + if (L.isEnabled(L.UI)) log.debug("onPause") + super.onPause() + disposable.clear() + } + + override fun onSaveInstanceState(outState: Bundle) { + outState.putString("state", state) + outState.putInt("percent", percent) + super.onSaveInstanceState(outState) + } +} \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/events/EventNtpStatus.kt b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/events/EventNtpStatus.kt new file mode 100644 index 0000000000..fc4e5cb8e9 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/events/EventNtpStatus.kt @@ -0,0 +1,5 @@ +package info.nightscout.androidaps.plugins.constraints.objectives.events + +import info.nightscout.androidaps.events.Event + +class EventNtpStatus(val status: String, val percent: Int) : Event() \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective.java b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective.java index c882a921f5..7082c7e7bc 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective.java @@ -61,10 +61,6 @@ public abstract class Objective { return true; } - public boolean isRevertable() { - return false; - } - public boolean isAccomplished() { return accomplishedOn != 0 && accomplishedOn < DateUtil.now(); } @@ -107,6 +103,8 @@ public abstract class Objective { return tasks; } + public boolean specialActionEnabled() { return true; } + public void specialAction(Activity activity, String input) {} public abstract class Task { diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective3.java b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective3.java index c9ac7d8935..f8eb45bb2a 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective3.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective3.java @@ -7,6 +7,7 @@ import java.util.List; import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.R; import info.nightscout.androidaps.plugins.constraints.objectives.ObjectivesPlugin; +import info.nightscout.androidaps.plugins.general.nsclient.NSClientPlugin; import info.nightscout.androidaps.utils.SP; import info.nightscout.androidaps.utils.T; @@ -38,6 +39,11 @@ public class Objective3 extends Objective { }); } + @Override + public boolean specialActionEnabled() { + return NSClientPlugin.getPlugin().nsClientService.isConnected && NSClientPlugin.getPlugin().nsClientService.hasWriteAuth; + } + @Override public void specialAction(Activity activity, String input) { ObjectivesPlugin.INSTANCE.completeObjectives(activity, input); diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective5.java b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective5.java index 2407594069..bd3e69c751 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective5.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective5.java @@ -25,9 +25,4 @@ public class Objective5 extends Objective { } }); } - - @Override - public boolean isRevertable() { - return true; - } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationEvent.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationEvent.java index 6eb3be382b..4f7bb62c74 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationEvent.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationEvent.java @@ -10,8 +10,11 @@ import java.util.List; import info.nightscout.androidaps.plugins.general.automation.actions.Action; import info.nightscout.androidaps.plugins.general.automation.triggers.Trigger; import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerConnector; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class AutomationEvent { + private static final Logger log = LoggerFactory.getLogger(AutomationEvent.class); private Trigger trigger = new TriggerConnector(); private List actions = new ArrayList<>(); @@ -74,7 +77,7 @@ public class AutomationEvent { } o.put("actions", array); } catch (JSONException e) { - e.printStackTrace(); + log.error("Unhandled exception", e); } return o.toString(); } @@ -91,7 +94,7 @@ public class AutomationEvent { actions.add(Action.instantiate(new JSONObject(array.getString(i)))); } } catch (JSONException e) { - e.printStackTrace(); + log.error("Unhandled exception", e); } return this; } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/Action.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/Action.java index 796f023f1d..ee4564fd6f 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/Action.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/Action.java @@ -11,6 +11,8 @@ import javax.annotation.Nullable; import info.nightscout.androidaps.plugins.general.automation.triggers.Trigger; import info.nightscout.androidaps.queue.Callback; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /* Action ideas: @@ -44,6 +46,7 @@ import info.nightscout.androidaps.queue.Callback; public abstract class Action { + private static final Logger log = LoggerFactory.getLogger(Action.class); public Trigger precondition = null; @@ -65,7 +68,7 @@ public abstract class Action { try { o.put("type", this.getClass().getName()); } catch (JSONException e) { - e.printStackTrace(); + log.error("Unhandled exception", e); } return o.toString(); } @@ -84,7 +87,7 @@ public abstract class Action { Class clazz = Class.forName(type); return ((Action) clazz.newInstance()).fromJSON(data != null ? data.toString() : ""); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | JSONException e) { - e.printStackTrace(); + log.error("Unhandled exception", e); } return null; } @@ -98,7 +101,7 @@ public abstract class Action { fromJSON(data.toString()); } } catch (JSONException e) { - e.printStackTrace(); + log.error("Unhandled exception", e); } } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionLoopSuspend.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionLoopSuspend.java index bd221d8f81..39adbcac27 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionLoopSuspend.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionLoopSuspend.java @@ -18,8 +18,12 @@ import info.nightscout.androidaps.plugins.general.automation.elements.LabelWithE import info.nightscout.androidaps.plugins.general.automation.elements.LayoutBuilder; import info.nightscout.androidaps.queue.Callback; import info.nightscout.androidaps.utils.JsonHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class ActionLoopSuspend extends Action { + private static final Logger log = LoggerFactory.getLogger(ActionLoopSuspend.class); + public InputDuration minutes = new InputDuration(0, InputDuration.TimeUnit.MINUTES); @Override @@ -59,7 +63,7 @@ public class ActionLoopSuspend extends Action { o.put("type", this.getClass().getName()); o.put("data", data); } catch (JSONException e) { - e.printStackTrace(); + log.error("Unhandled exception", e); } return o.toString(); } @@ -70,7 +74,7 @@ public class ActionLoopSuspend extends Action { JSONObject o = new JSONObject(data); minutes.setMinutes(JsonHelper.safeGetInt(o, "minutes")); } catch (JSONException e) { - e.printStackTrace(); + log.error("Unhandled exception", e); } return this; } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionNotification.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionNotification.java index 1f7ad543c2..7bd501b460 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionNotification.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionNotification.java @@ -20,8 +20,12 @@ import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotifi import info.nightscout.androidaps.plugins.general.overview.notifications.Notification; import info.nightscout.androidaps.queue.Callback; import info.nightscout.androidaps.utils.JsonHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class ActionNotification extends Action { + private static final Logger log = LoggerFactory.getLogger(ActionNotification.class); + public InputString text = new InputString(); @Override @@ -59,7 +63,7 @@ public class ActionNotification extends Action { o.put("type", this.getClass().getName()); o.put("data", data); } catch (JSONException e) { - e.printStackTrace(); + log.error("Unhandled exception", e); } return o.toString(); } @@ -70,7 +74,7 @@ public class ActionNotification extends Action { JSONObject o = new JSONObject(data); text.setValue(JsonHelper.safeGetString(o, "text")); } catch (JSONException e) { - e.printStackTrace(); + log.error("Unhandled exception", e); } return this; } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionProfileSwitch.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionProfileSwitch.java index 50fbb786db..8a4762bd08 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionProfileSwitch.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionProfileSwitch.java @@ -92,7 +92,7 @@ public class ActionProfileSwitch extends Action { data.put("profileToSwitchTo", inputProfileName.getValue()); o.put("data", data); } catch (JSONException e) { - e.printStackTrace(); + log.error("Unhandled exception", e); } return o.toString(); } @@ -105,7 +105,7 @@ public class ActionProfileSwitch extends Action { profileName = JsonHelper.safeGetString(d, "profileToSwitchTo"); inputProfileName.setValue(profileName); } catch (JSONException e) { - e.printStackTrace(); + log.error("Unhandled exception", e); } return this; } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionProfileSwitchPercent.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionProfileSwitchPercent.java index 20b6abb081..23b54640a5 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionProfileSwitchPercent.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionProfileSwitchPercent.java @@ -19,8 +19,12 @@ import info.nightscout.androidaps.plugins.general.automation.elements.LayoutBuil import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerProfilePercent; import info.nightscout.androidaps.queue.Callback; import info.nightscout.androidaps.utils.JsonHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class ActionProfileSwitchPercent extends Action { + private static final Logger log = LoggerFactory.getLogger(ActionProfileSwitchPercent.class); + InputPercent pct = new InputPercent(); InputDuration duration = new InputDuration(0, InputDuration.TimeUnit.MINUTES); @@ -71,7 +75,7 @@ public class ActionProfileSwitchPercent extends Action { data.put("durationInMinutes", duration.getMinutes()); o.put("data", data); } catch (JSONException e) { - e.printStackTrace(); + log.error("Unhandled exception", e); } return o.toString(); } @@ -83,7 +87,7 @@ public class ActionProfileSwitchPercent extends Action { pct.setValue(JsonHelper.safeGetInt(d, "percentage")); duration.setMinutes(JsonHelper.safeGetInt(d, "durationInMinutes")); } catch (JSONException e) { - e.printStackTrace(); + log.error("Unhandled exception", e); } return this; } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionSendSMS.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionSendSMS.java index f8afafca75..fa9140e5f9 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionSendSMS.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionSendSMS.java @@ -21,6 +21,7 @@ import info.nightscout.androidaps.queue.Callback; import info.nightscout.androidaps.utils.JsonHelper; public class ActionSendSMS extends Action { + private static final Logger log = LoggerFactory.getLogger(ActionSendSMS.class); public InputString text = new InputString(); @@ -36,7 +37,7 @@ public class ActionSendSMS extends Action { @Override public void doAction(Callback callback) { - boolean result = SmsCommunicatorPlugin.getPlugin().sendNotificationToAllNumbers(text.getValue()); + boolean result = SmsCommunicatorPlugin.INSTANCE.sendNotificationToAllNumbers(text.getValue()); if (callback != null) callback.result(new PumpEnactResult().success(result).comment(result ? R.string.ok : R.string.danar_error)).run(); @@ -56,7 +57,7 @@ public class ActionSendSMS extends Action { o.put("type", this.getClass().getName()); o.put("data", data); } catch (JSONException e) { - e.printStackTrace(); + log.error("Unhandled exception", e); } return o.toString(); } @@ -67,7 +68,7 @@ public class ActionSendSMS extends Action { JSONObject o = new JSONObject(data); text.setValue(JsonHelper.safeGetString(o, "text")); } catch (JSONException e) { - e.printStackTrace(); + log.error("Unhandled exception", e); } return this; } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionStartTempTarget.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionStartTempTarget.java index 659bb508eb..b0ef645069 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionStartTempTarget.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionStartTempTarget.java @@ -24,8 +24,12 @@ import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin; import info.nightscout.androidaps.queue.Callback; import info.nightscout.androidaps.utils.DateUtil; import info.nightscout.androidaps.utils.JsonHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class ActionStartTempTarget extends Action { + private static final Logger log = LoggerFactory.getLogger(ActionStartTempTarget.class); + String reason = ""; InputTempTarget value = new InputTempTarget(); InputDuration duration = new InputDuration(0, InputDuration.TimeUnit.MINUTES); @@ -93,7 +97,7 @@ public class ActionStartTempTarget extends Action { data.put("durationInMinutes", duration.getMinutes()); o.put("data", data); } catch (JSONException e) { - e.printStackTrace(); + log.error("Unhandled exception", e); } return o.toString(); } @@ -107,7 +111,7 @@ public class ActionStartTempTarget extends Action { value.setValue(JsonHelper.safeGetDouble(d, "value")); duration.setMinutes(JsonHelper.safeGetInt(d, "durationInMinutes")); } catch (JSONException e) { - e.printStackTrace(); + log.error("Unhandled exception", e); } return this; } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionStopTempTarget.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionStopTempTarget.java index de251c499e..abf354bc9c 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionStopTempTarget.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionStopTempTarget.java @@ -14,8 +14,12 @@ import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin; import info.nightscout.androidaps.queue.Callback; import info.nightscout.androidaps.utils.DateUtil; import info.nightscout.androidaps.utils.JsonHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class ActionStopTempTarget extends Action { + private static final Logger log = LoggerFactory.getLogger(ActionStopTempTarget.class); + String reason = ""; private TempTarget tempTarget; @@ -54,7 +58,7 @@ public class ActionStopTempTarget extends Action { data.put("reason", reason); o.put("data", data); } catch (JSONException e) { - e.printStackTrace(); + log.error("Unhandled exception", e); } return o.toString(); } @@ -65,7 +69,7 @@ public class ActionStopTempTarget extends Action { JSONObject d = new JSONObject(data); reason = JsonHelper.safeGetString(d, "reason"); } catch (JSONException e) { - e.printStackTrace(); + log.error("Unhandled exception", e); } return this; } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/Trigger.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/Trigger.java index f6ba6b6f67..69ac67bf07 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/Trigger.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/Trigger.java @@ -13,10 +13,13 @@ import com.google.common.base.Optional; import org.json.JSONException; import org.json.JSONObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import javax.annotation.Nullable; public abstract class Trigger { + private static final Logger log = LoggerFactory.getLogger(Trigger.class); TriggerConnector connector = null; long lastRun; @@ -56,7 +59,7 @@ public abstract class Trigger { try { return instantiate(new JSONObject(json)); } catch (JSONException e) { - e.printStackTrace(); + log.error("Unhandled exception", e); } return null; } @@ -69,7 +72,7 @@ public abstract class Trigger { Class clazz = Class.forName(type); return ((Trigger) clazz.newInstance()).fromJSON(data.toString()); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | JSONException e) { - e.printStackTrace(); + log.error("Unhandled exception", e); } return null; } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerAutosensValue.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerAutosensValue.java index da850b187d..ce0a8f63bb 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerAutosensValue.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerAutosensValue.java @@ -89,7 +89,7 @@ public class TriggerAutosensValue extends Trigger { data.put("comparator", comparator.getValue().toString()); o.put("data", data); } catch (JSONException e) { - e.printStackTrace(); + log.error("Unhandled exception", e); } return o.toString(); } @@ -102,7 +102,7 @@ public class TriggerAutosensValue extends Trigger { lastRun = JsonHelper.safeGetLong(d, "lastRun"); comparator.setValue(Comparator.Compare.valueOf(JsonHelper.safeGetString(d, "comparator"))); } catch (Exception e) { - e.printStackTrace(); + log.error("Unhandled exception", e); } return this; } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerBg.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerBg.java index 1636377bf2..3733859b96 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerBg.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerBg.java @@ -104,7 +104,7 @@ public class TriggerBg extends Trigger { data.put("units", bg.getUnits()); o.put("data", data); } catch (JSONException e) { - e.printStackTrace(); + log.error("Unhandled exception", e); } return o.toString(); } @@ -118,7 +118,7 @@ public class TriggerBg extends Trigger { lastRun = JsonHelper.safeGetLong(d, "lastRun"); comparator.setValue(Comparator.Compare.valueOf(JsonHelper.safeGetString(d, "comparator"))); } catch (Exception e) { - e.printStackTrace(); + log.error("Unhandled exception", e); } return this; } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerBolusAgo.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerBolusAgo.java index 0ad9f75ab2..0a038112e2 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerBolusAgo.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerBolusAgo.java @@ -86,7 +86,7 @@ public class TriggerBolusAgo extends Trigger { data.put("comparator", comparator.getValue().toString()); o.put("data", data); } catch (JSONException e) { - e.printStackTrace(); + log.error("Unhandled exception", e); } return o.toString(); } @@ -99,7 +99,7 @@ public class TriggerBolusAgo extends Trigger { lastRun = JsonHelper.safeGetLong(d, "lastRun"); comparator.setValue(Comparator.Compare.valueOf(JsonHelper.safeGetString(d, "comparator"))); } catch (Exception e) { - e.printStackTrace(); + log.error("Unhandled exception", e); } return this; } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerCOB.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerCOB.java index 4ddeb4299a..bf17dc72d1 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerCOB.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerCOB.java @@ -87,7 +87,7 @@ public class TriggerCOB extends Trigger { data.put("comparator", comparator.getValue().toString()); o.put("data", data); } catch (JSONException e) { - e.printStackTrace(); + log.error("Unhandled exception", e); } return o.toString(); } @@ -100,7 +100,7 @@ public class TriggerCOB extends Trigger { lastRun = JsonHelper.safeGetLong(d, "lastRun"); comparator.setValue(Comparator.Compare.valueOf(JsonHelper.safeGetString(d, "comparator"))); } catch (Exception e) { - e.printStackTrace(); + log.error("Unhandled exception", e); } return this; } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerConnector.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerConnector.java index ae4bd35ad5..549925528a 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerConnector.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerConnector.java @@ -162,7 +162,7 @@ public class TriggerConnector extends Trigger { data.put("triggerList", array); o.put("data", data); } catch (JSONException e) { - e.printStackTrace(); + log.error("Unhandled exception", e); } return o.toString(); } @@ -179,7 +179,7 @@ public class TriggerConnector extends Trigger { add(newItem); } } catch (JSONException e) { - e.printStackTrace(); + log.error("Unhandled exception", e); } return this; } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerDelta.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerDelta.java index a3939a60b7..eee649307b 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerDelta.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerDelta.java @@ -129,7 +129,7 @@ public class TriggerDelta extends Trigger { data.put("comparator", comparator.getValue().toString()); o.put("data", data); } catch (JSONException e) { - e.printStackTrace(); + log.error("Unhandled exception", e); } return o.toString(); } @@ -144,7 +144,7 @@ public class TriggerDelta extends Trigger { lastRun = JsonHelper.safeGetLong(d, "lastRun"); comparator.setValue(Comparator.Compare.valueOf(JsonHelper.safeGetString(d, "comparator"))); } catch (Exception e) { - e.printStackTrace(); + log.error("Unhandled exception", e); } return this; } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerIob.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerIob.java index c4003af861..a3935d7cec 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerIob.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerIob.java @@ -82,7 +82,7 @@ public class TriggerIob extends Trigger { data.put("comparator", comparator.getValue().toString()); o.put("data", data); } catch (JSONException e) { - e.printStackTrace(); + log.error("Unhandled exception", e); } return o.toString(); } @@ -95,7 +95,7 @@ public class TriggerIob extends Trigger { lastRun = JsonHelper.safeGetLong(d, "lastRun"); comparator.setValue(Comparator.Compare.valueOf(JsonHelper.safeGetString(d, "comparator"))); } catch (Exception e) { - e.printStackTrace(); + log.error("Unhandled exception", e); } return this; } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerLocation.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerLocation.java index 4772d29112..19965cfc9a 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerLocation.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerLocation.java @@ -93,7 +93,7 @@ public class TriggerLocation extends Trigger { data.put("lastRun", lastRun); o.put("data", data); } catch (JSONException e) { - e.printStackTrace(); + log.error("Unhandled exception", e); } return o.toString(); } @@ -108,7 +108,7 @@ public class TriggerLocation extends Trigger { name.setValue(JsonHelper.safeGetString(d, "name")); lastRun = JsonHelper.safeGetLong(d, "lastRun"); } catch (Exception e) { - e.printStackTrace(); + log.error("Unhandled exception", e); } return this; } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerProfilePercent.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerProfilePercent.java index d86bc35cb8..e4c0ae4346 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerProfilePercent.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerProfilePercent.java @@ -88,7 +88,7 @@ public class TriggerProfilePercent extends Trigger { data.put("comparator", comparator.getValue().toString()); o.put("data", data); } catch (JSONException e) { - e.printStackTrace(); + log.error("Unhandled exception", e); } return o.toString(); } @@ -101,7 +101,7 @@ public class TriggerProfilePercent extends Trigger { lastRun = JsonHelper.safeGetLong(d, "lastRun"); comparator.setValue(Comparator.Compare.valueOf(JsonHelper.safeGetString(d, "comparator"))); } catch (Exception e) { - e.printStackTrace(); + log.error("Unhandled exception", e); } return this; } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerPumpLastConnection.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerPumpLastConnection.java index 8cec3bdf44..ff8bb335f9 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerPumpLastConnection.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerPumpLastConnection.java @@ -82,7 +82,7 @@ public class TriggerPumpLastConnection extends Trigger { data.put("comparator", comparator.getValue().toString()); o.put("data", data); } catch (JSONException e) { - e.printStackTrace(); + log.error("Unhandled exception", e); } return o.toString(); } @@ -95,7 +95,7 @@ public class TriggerPumpLastConnection extends Trigger { lastRun = JsonHelper.safeGetLong(d, "lastRun"); comparator.setValue(Comparator.Compare.valueOf(JsonHelper.safeGetString(d, "comparator"))); } catch (Exception e) { - e.printStackTrace(); + log.error("Unhandled exception", e); } return this; } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerRecurringTime.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerRecurringTime.java index a145253b36..89c8d17085 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerRecurringTime.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerRecurringTime.java @@ -163,7 +163,7 @@ public class TriggerRecurringTime extends Trigger { object.put("type", TriggerRecurringTime.class.getName()); object.put("data", data); } catch (JSONException e) { - e.printStackTrace(); + log.error("Unhandled exception", e); } return object.toString(); } @@ -181,7 +181,7 @@ public class TriggerRecurringTime extends Trigger { minute = JsonHelper.safeGetInt(o, "minute"); validTo = JsonHelper.safeGetLong(o, "validTo"); } catch (JSONException e) { - e.printStackTrace(); + log.error("Unhandled exception", e); } return this; } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerTempTarget.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerTempTarget.java index 378652ed2a..f45efdf4a4 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerTempTarget.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerTempTarget.java @@ -74,7 +74,7 @@ public class TriggerTempTarget extends Trigger { data.put("comparator", comparator.getValue().toString()); o.put("data", data); } catch (JSONException e) { - e.printStackTrace(); + log.error("Unhandled exception", e); } return o.toString(); } @@ -86,7 +86,7 @@ public class TriggerTempTarget extends Trigger { lastRun = JsonHelper.safeGetLong(d, "lastRun"); comparator.setValue(ComparatorExists.Compare.valueOf(JsonHelper.safeGetString(d, "comparator"))); } catch (Exception e) { - e.printStackTrace(); + log.error("Unhandled exception", e); } return this; } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerTime.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerTime.java index 261783b99c..08f9a65aa7 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerTime.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerTime.java @@ -65,7 +65,7 @@ public class TriggerTime extends Trigger { object.put("type", TriggerTime.class.getName()); object.put("data", data); } catch (JSONException e) { - e.printStackTrace(); + log.error("Unhandled exception", e); } return object.toString(); } @@ -78,7 +78,7 @@ public class TriggerTime extends Trigger { lastRun = JsonHelper.safeGetLong(o, "lastRun"); runAt = JsonHelper.safeGetLong(o, "runAt"); } catch (JSONException e) { - e.printStackTrace(); + log.error("Unhandled exception", e); } return this; } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerTimeRange.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerTimeRange.java index 8755c3559c..1d03871620 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerTimeRange.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerTimeRange.java @@ -93,7 +93,7 @@ public class TriggerTimeRange extends Trigger { object.put("type", TriggerTimeRange.class.getName()); object.put("data", data); } catch (JSONException e) { - e.printStackTrace(); + log.error("Unhandled exception", e); } log.debug(object.toString()); return object.toString(); @@ -108,7 +108,7 @@ public class TriggerTimeRange extends Trigger { start = JsonHelper.safeGetInt(o, "start"); end = JsonHelper.safeGetInt(o, "end"); } catch (JSONException e) { - e.printStackTrace(); + log.error("Unhandled exception", e); } return this; } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerWifiSsid.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerWifiSsid.java index ba10e81583..dd2c34bcb8 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerWifiSsid.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerWifiSsid.java @@ -85,7 +85,7 @@ public class TriggerWifiSsid extends Trigger { data.put("comparator", comparator.getValue().toString()); o.put("data", data); } catch (JSONException e) { - e.printStackTrace(); + log.error("Unhandled exception", e); } return o.toString(); } @@ -98,7 +98,7 @@ public class TriggerWifiSsid extends Trigger { lastRun = JsonHelper.safeGetLong(d, "lastRun"); comparator.setValue(Comparator.Compare.valueOf(JsonHelper.safeGetString(d, "comparator"))); } catch (Exception e) { - e.printStackTrace(); + log.error("Unhandled exception", e); } return this; } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientPlugin.java index ae5d090211..037f91b3f0 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientPlugin.java @@ -7,9 +7,12 @@ import android.content.ServiceConnection; import android.os.Handler; import android.os.HandlerThread; import android.os.IBinder; +import android.preference.PreferenceFragment; +import android.preference.PreferenceScreen; import android.text.Html; import android.text.Spanned; +import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -89,7 +92,7 @@ public class NSClientPlugin extends PluginBase { } nsClientReceiverDelegate = - new NsClientReceiverDelegate(MainApp.instance().getApplicationContext()); + new NsClientReceiverDelegate(); } public boolean isAllowed() { @@ -104,7 +107,7 @@ public class NSClientPlugin extends PluginBase { context.bindService(intent, mConnection, Context.BIND_AUTO_CREATE); super.onStart(); - nsClientReceiverDelegate.registerReceivers(); + nsClientReceiverDelegate.grabReceiversState(); disposable.add(RxBus.INSTANCE .toObservable(EventNSClientStatus.class) .observeOn(Schedulers.io()) @@ -129,7 +132,6 @@ public class NSClientPlugin extends PluginBase { .subscribe(event -> { if (nsClientService != null) { MainApp.instance().getApplicationContext().unbindService(mConnection); - nsClientReceiverDelegate.unregisterReceivers(); } }, FabricPrivacy::logException) ); @@ -152,11 +154,27 @@ public class NSClientPlugin extends PluginBase { @Override protected void onStop() { MainApp.instance().getApplicationContext().unbindService(mConnection); - nsClientReceiverDelegate.unregisterReceivers(); disposable.clear(); super.onStop(); } + @Override + public void preprocessPreferences(@NotNull PreferenceFragment preferenceFragment) { + super.preprocessPreferences(preferenceFragment); + + if (Config.NSCLIENT) { + PreferenceScreen scrnAdvancedSettings = (PreferenceScreen) preferenceFragment.findPreference(MainApp.gs(R.string.key_advancedsettings)); + if (scrnAdvancedSettings != null) { + scrnAdvancedSettings.removePreference(preferenceFragment.findPreference(MainApp.gs(R.string.key_statuslights_res_warning))); + scrnAdvancedSettings.removePreference(preferenceFragment.findPreference(MainApp.gs(R.string.key_statuslights_res_critical))); + scrnAdvancedSettings.removePreference(preferenceFragment.findPreference(MainApp.gs(R.string.key_statuslights_bat_warning))); + scrnAdvancedSettings.removePreference(preferenceFragment.findPreference(MainApp.gs(R.string.key_statuslights_bat_critical))); + scrnAdvancedSettings.removePreference(preferenceFragment.findPreference(MainApp.gs(R.string.key_show_statuslights))); + scrnAdvancedSettings.removePreference(preferenceFragment.findPreference(MainApp.gs(R.string.key_show_statuslights_extended))); + } + } + } + private ServiceConnection mConnection = new ServiceConnection() { public void onServiceDisconnected(ComponentName name) { diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSUpload.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSUpload.java index 881593b32a..f5582b71a2 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSUpload.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSUpload.java @@ -594,7 +594,7 @@ public class NSUpload { } catch (JSONException e) { - e.printStackTrace(); + log.error("Unhandled exception", e); } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NsClientReceiverDelegate.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NsClientReceiverDelegate.java index c68750d828..fd05b133f5 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NsClientReceiverDelegate.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NsClientReceiverDelegate.java @@ -18,44 +18,19 @@ import info.nightscout.androidaps.utils.SP; class NsClientReceiverDelegate { - private final Context context; - - private NetworkChangeReceiver networkChangeReceiver = new NetworkChangeReceiver(); - private ChargingStateReceiver chargingStateReceiver = new ChargingStateReceiver(); - private boolean allowedChargingState = true; private boolean allowedNetworkState = true; boolean allowed = true; - NsClientReceiverDelegate(Context context) { - this.context = context; - } - - void registerReceivers() { + void grabReceiversState() { Context context = MainApp.instance().getApplicationContext(); - // register NetworkChangeReceiver --> https://developer.android.com/training/monitoring-device-state/connectivity-monitoring.html - // Nougat is not providing Connectivity-Action anymore ;-( - context.registerReceiver(networkChangeReceiver, - new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)); - context.registerReceiver(networkChangeReceiver, - new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION)); - EventNetworkChange event = networkChangeReceiver.grabNetworkStatus(context); - if (event != null) - RxBus.INSTANCE.send(event); + EventNetworkChange event = NetworkChangeReceiver.grabNetworkStatus(context); + if (event != null) RxBus.INSTANCE.send(event); - context.registerReceiver(chargingStateReceiver, - new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); + EventChargingState eventChargingState = ChargingStateReceiver.grabChargingState(context); + if (eventChargingState != null) RxBus.INSTANCE.send(eventChargingState); - EventChargingState eventChargingState = chargingStateReceiver.grabChargingState(context); - if (eventChargingState != null) - RxBus.INSTANCE.send(eventChargingState); - - } - - void unregisterReceivers() { - context.unregisterReceiver(networkChangeReceiver); - context.unregisterReceiver(chargingStateReceiver); } void onStatusEvent(EventPreferenceChange ev) { @@ -63,11 +38,11 @@ class NsClientReceiverDelegate { ev.isChanged(R.string.key_ns_wifi_ssids) || ev.isChanged(R.string.key_ns_allowroaming) ) { - EventNetworkChange event = networkChangeReceiver.grabNetworkStatus(MainApp.instance().getApplicationContext()); + EventNetworkChange event = NetworkChangeReceiver.grabNetworkStatus(MainApp.instance().getApplicationContext()); if (event != null) RxBus.INSTANCE.send(event); } else if (ev.isChanged(R.string.key_ns_chargingonly)) { - EventChargingState event = chargingStateReceiver.grabChargingState(MainApp.instance().getApplicationContext()); + EventChargingState event = ChargingStateReceiver.grabChargingState(MainApp.instance().getApplicationContext()); if (event != null) RxBus.INSTANCE.send(event); } @@ -91,7 +66,7 @@ class NsClientReceiverDelegate { } } - void processStateChange() { + private void processStateChange() { boolean newAllowedState = allowedChargingState && allowedNetworkState; if (newAllowedState != allowed) { allowed = newAllowedState; @@ -101,7 +76,6 @@ class NsClientReceiverDelegate { boolean calculateStatus(final EventChargingState ev) { boolean chargingOnly = SP.getBoolean(R.string.key_ns_chargingonly, false); - boolean newAllowedState = true; if (!ev.isCharging() && chargingOnly) { @@ -129,8 +103,6 @@ class NsClientReceiverDelegate { } } - return newAllowedState; } - } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewFragment.java index 5c2a7cac84..046290500d 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewFragment.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewFragment.java @@ -1223,7 +1223,7 @@ public class OverviewFragment extends Fragment implements View.OnClickListener, extendedBolusView.setVisibility(View.VISIBLE); } - activeProfileView.setText(ProfileFunctions.getInstance().getProfileName()); + activeProfileView.setText(ProfileFunctions.getInstance().getProfileNameWithDuration()); if (profile.getPercentage() != 100 || profile.getTimeshift() != 0) { activeProfileView.setBackgroundColor(MainApp.gc(R.color.ribbonWarning)); activeProfileView.setTextColor(MainApp.gc(R.color.ribbonTextWarning)); 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 deleted file mode 100644 index 4b05072eb1..0000000000 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/AuthRequest.java +++ /dev/null @@ -1,59 +0,0 @@ -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/AuthRequest.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/AuthRequest.kt new file mode 100644 index 0000000000..48e816928f --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/AuthRequest.kt @@ -0,0 +1,38 @@ +package info.nightscout.androidaps.plugins.general.smsCommunicator + +import info.nightscout.androidaps.Constants +import info.nightscout.androidaps.R +import info.nightscout.androidaps.logging.L +import info.nightscout.androidaps.utils.DateUtil +import org.slf4j.LoggerFactory + +class AuthRequest internal constructor(val plugin: SmsCommunicatorPlugin, var requester: Sms, requestText: String, var confirmCode: String, val action: SmsAction) { + private val log = LoggerFactory.getLogger(L.SMS) + + private val date = DateUtil.now() + private var processed = false + + init { + plugin.sendSMS(Sms(requester.phoneNumber, requestText)) + } + + fun action(codeReceived: String) { + if (processed) { + if (L.isEnabled(L.SMS)) log.debug("Already processed") + return + } + if (confirmCode != codeReceived) { + processed = true + if (L.isEnabled(L.SMS)) log.debug("Wrong code") + plugin.sendSMS(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) + action.run() + return + } + if (L.isEnabled(L.SMS)) log.debug("Timed out SMS: " + requester.text) + } +} \ No newline at end of file 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 deleted file mode 100644 index 2eedfa0a51..0000000000 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/Sms.java +++ /dev/null @@ -1,42 +0,0 @@ -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/Sms.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/Sms.kt new file mode 100644 index 0000000000..868620be2e --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/Sms.kt @@ -0,0 +1,40 @@ +package info.nightscout.androidaps.plugins.general.smsCommunicator + +import android.telephony.SmsMessage +import info.nightscout.androidaps.MainApp +import info.nightscout.androidaps.utils.DateUtil + +class Sms { + var phoneNumber: String + var text: String + var date: Long + var received = false + var sent = false + var processed = false + var ignored = false + + internal constructor(message: SmsMessage) { + phoneNumber = message.originatingAddress ?: "" + text = message.messageBody + date = message.timestampMillis + received = true + } + + internal constructor(phoneNumber: String, text: String) { + this.phoneNumber = phoneNumber + this.text = text + date = DateUtil.now() + sent = true + } + + internal constructor(phoneNumber: String, textId: Int) { + this.phoneNumber = phoneNumber + text = MainApp.gs(textId) + date = DateUtil.now() + sent = true + } + + override fun toString(): String { + return "SMS from $phoneNumber: $text" + } +} \ No newline at end of file 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 deleted file mode 100644 index 6b5d5b8747..0000000000 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/SmsAction.java +++ /dev/null @@ -1,33 +0,0 @@ -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/SmsAction.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/SmsAction.kt new file mode 100644 index 0000000000..98c892d918 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/SmsAction.kt @@ -0,0 +1,68 @@ +package info.nightscout.androidaps.plugins.general.smsCommunicator + +abstract class SmsAction : Runnable { + var aDouble: Double? = null + var anInteger: Int? = null + var secondInteger: Int? = null + var secondLong: Long? = null + var aString: String? = null + + internal constructor() + internal constructor(aDouble: Double) { + this.aDouble = aDouble + } + + internal constructor(aDouble: Double, secondInteger: Int) { + this.aDouble = aDouble + this.secondInteger = secondInteger + } + + internal constructor(aString: String, secondInteger: Int) { + this.aString = aString + this.secondInteger = secondInteger + } + + internal constructor(anInteger: Int) { + this.anInteger = anInteger + } + + internal constructor(anInteger: Int, secondInteger: Int) { + this.anInteger = anInteger + this.secondInteger = secondInteger + } + + internal constructor(anInteger: Int, secondLong: Long) { + this.anInteger = anInteger + this.secondLong = secondLong + } + + fun aDouble(): Double { + return aDouble?.let { + aDouble + } ?: throw IllegalStateException() + } + + fun anInteger(): Int { + return anInteger?.let { + anInteger + } ?: throw IllegalStateException() + } + + fun secondInteger(): Int { + return secondInteger?.let { + secondInteger + } ?: throw IllegalStateException() + } + + fun secondLong(): Long { + return secondLong?.let { + secondLong + } ?: throw IllegalStateException() + } + + fun aString(): String { + return aString?.let { + aString + } ?: throw IllegalStateException() + } +} \ No newline at end of file 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 deleted file mode 100644 index 31f335a7cf..0000000000 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/SmsCommunicatorFragment.java +++ /dev/null @@ -1,83 +0,0 @@ -package info.nightscout.androidaps.plugins.general.smsCommunicator; - - -import android.os.Bundle; -import android.text.Html; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.TextView; - -import androidx.fragment.app.Fragment; - -import java.util.Collections; -import java.util.Comparator; - -import info.nightscout.androidaps.R; -import info.nightscout.androidaps.plugins.bus.RxBus; -import info.nightscout.androidaps.plugins.general.smsCommunicator.events.EventSmsCommunicatorUpdateGui; -import info.nightscout.androidaps.utils.DateUtil; -import info.nightscout.androidaps.utils.FabricPrivacy; -import io.reactivex.android.schedulers.AndroidSchedulers; -import io.reactivex.disposables.CompositeDisposable; - -public class SmsCommunicatorFragment extends Fragment { - private CompositeDisposable disposable = new CompositeDisposable(); - TextView logView; - - public SmsCommunicatorFragment() { - super(); - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.smscommunicator_fragment, container, false); - - logView = (TextView) view.findViewById(R.id.smscommunicator_log); - - return view; - } - - @Override - public synchronized void onResume() { - super.onResume(); - disposable.add(RxBus.INSTANCE - .toObservable(EventSmsCommunicatorUpdateGui.class) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(event -> updateGui(), FabricPrivacy::logException) - ); - updateGui(); - } - - @Override - public synchronized void onPause() { - super.onPause(); - disposable.clear(); - } - - protected void updateGui() { - 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++) { - 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/SmsCommunicatorFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/SmsCommunicatorFragment.kt new file mode 100644 index 0000000000..90ec078931 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/SmsCommunicatorFragment.kt @@ -0,0 +1,70 @@ +package info.nightscout.androidaps.plugins.general.smsCommunicator + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import info.nightscout.androidaps.R +import info.nightscout.androidaps.plugins.bus.RxBus.toObservable +import info.nightscout.androidaps.plugins.general.smsCommunicator.events.EventSmsCommunicatorUpdateGui +import info.nightscout.androidaps.utils.DateUtil +import info.nightscout.androidaps.utils.FabricPrivacy +import info.nightscout.androidaps.utils.HtmlHelper +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.disposables.CompositeDisposable +import kotlinx.android.synthetic.main.smscommunicator_fragment.* +import java.util.* +import kotlin.math.max + +class SmsCommunicatorFragment : Fragment() { + private val disposable = CompositeDisposable() + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle?): View? { + return inflater.inflate(R.layout.smscommunicator_fragment, container, false) + } + + @Synchronized + override fun onResume() { + super.onResume() + disposable.add(toObservable(EventSmsCommunicatorUpdateGui::class.java) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe({ updateGui() }) { FabricPrivacy.logException(it) } + ) + updateGui() + } + + @Synchronized + override fun onPause() { + super.onPause() + disposable.clear() + } + + fun updateGui() { + class CustomComparator : Comparator { + override fun compare(object1: Sms, object2: Sms): Int { + return (object1.date - object2.date).toInt() + } + } + Collections.sort(SmsCommunicatorPlugin.messages, CustomComparator()) + val messagesToShow = 40 + val start = max(0, SmsCommunicatorPlugin.messages.size - messagesToShow) + var logText = "" + for (x in start until SmsCommunicatorPlugin.messages.size) { + val sms = SmsCommunicatorPlugin.messages[x] + when { + sms.ignored -> { + logText += DateUtil.timeString(sms.date) + " <<< " + "░ " + sms.phoneNumber + " " + sms.text + "
" + } + sms.received -> { + logText += DateUtil.timeString(sms.date) + " <<< " + (if (sms.processed) "● " else "○ ") + sms.phoneNumber + " " + sms.text + "
" + } + sms.sent -> { + logText += DateUtil.timeString(sms.date) + " >>> " + (if (sms.processed) "● " else "○ ") + sms.phoneNumber + " " + sms.text + "
" + } + } + } + smscommunicator_log?.text = HtmlHelper.fromHtml(logText) + } +} \ No newline at end of file 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 deleted file mode 100644 index 264d7c3e52..0000000000 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/SmsCommunicatorPlugin.java +++ /dev/null @@ -1,812 +0,0 @@ -package info.nightscout.androidaps.plugins.general.smsCommunicator; - -import android.content.Intent; -import android.os.Bundle; -import android.telephony.SmsManager; -import android.telephony.SmsMessage; - -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.List; - -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.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; -import info.nightscout.androidaps.events.EventPreferenceChange; -import info.nightscout.androidaps.events.EventRefreshOverview; -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.logging.L; -import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin; -import info.nightscout.androidaps.plugins.bus.RxBus; -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.nsclient.events.EventNSClientRestart; -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.GlucoseStatus; -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.utils.DateUtil; -import info.nightscout.androidaps.utils.DecimalFormatter; -import info.nightscout.androidaps.utils.FabricPrivacy; -import info.nightscout.androidaps.utils.SP; -import info.nightscout.androidaps.utils.SafeParse; -import info.nightscout.androidaps.utils.XdripCalibrations; -import io.reactivex.disposables.CompositeDisposable; -import io.reactivex.schedulers.Schedulers; - -/** - * Created by mike on 05.08.2016. - */ -public class SmsCommunicatorPlugin extends PluginBase { - private static Logger log = LoggerFactory.getLogger(L.SMS); - private CompositeDisposable disposable = new CompositeDisposable(); - - private static SmsCommunicatorPlugin smsCommunicatorPlugin; - - public static SmsCommunicatorPlugin getPlugin() { - - if (smsCommunicatorPlugin == null) { - smsCommunicatorPlugin = new SmsCommunicatorPlugin(); - } - return smsCommunicatorPlugin; - } - - List allowedNumbers = new ArrayList<>(); - - AuthRequest messageToConfirm = null; - - long lastRemoteBolusTime = 0; - - ArrayList messages = new ArrayList<>(); - - SmsCommunicatorPlugin() { - super(new PluginDescription() - .mainType(PluginType.GENERAL) - .fragmentClass(SmsCommunicatorFragment.class.getName()) - .pluginName(R.string.smscommunicator) - .shortName(R.string.smscommunicator_shortname) - .preferencesId(R.xml.pref_smscommunicator) - .description(R.string.description_sms_communicator) - ); - processSettings(null); - } - - @Override - protected void onStart() { - super.onStart(); - disposable.add(RxBus.INSTANCE - .toObservable(EventPreferenceChange.class) - .observeOn(Schedulers.io()) - .subscribe(event -> { - processSettings(event); - }, FabricPrivacy::logException) - ); - } - - @Override - protected void onStop() { - disposable.clear(); - super.onStop(); - } - - private void processSettings(final EventPreferenceChange ev) { - if (ev == null || ev.isChanged(R.string.key_smscommunicator_allowednumbers)) { - String settings = SP.getString(R.string.key_smscommunicator_allowednumbers, ""); - - allowedNumbers.clear(); - String[] substrings = settings.split(";"); - for (String number : substrings) { - String cleaned = number.replaceAll("\\s+", ""); - allowedNumbers.add(cleaned); - log.debug("Found allowed number: " + cleaned); - } - } - } - - 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; - } - return false; - } - - public void handleNewData(Intent intent) { - Bundle bundle = intent.getExtras(); - if (bundle == null) return; - - Object[] pdus = (Object[]) bundle.get("pdus"); - if (pdus != null) { - // For every SMS message received - for (Object pdu : pdus) { - SmsMessage message = SmsMessage.createFromPdu((byte[]) pdu); - processSms(new Sms(message)); - } - } - } - - 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); - RxBus.INSTANCE.send(new EventSmsCommunicatorUpdateGui()); - return; - } - - messages.add(receivedSms); - log.debug(receivedSms.toString()); - - String[] splitted = receivedSms.text.split("\\s+"); - boolean remoteCommandsAllowed = SP.getBoolean(R.string.key_smscommunicator_remotecommandsallowed, false); - - if (splitted.length > 0 && isCommand(splitted[0].toUpperCase(), receivedSms.phoneNumber)) { - switch (splitted[0].toUpperCase()) { - case "BG": - processBG(splitted, receivedSms); - break; - case "LOOP": - 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 (splitted.length == 2) - processTREATMENTS(splitted, receivedSms); - else - sendSMS(new Sms(receivedSms.phoneNumber, R.string.wrongformat)); - break; - case "NSCLIENT": - if (splitted.length == 2) - processNSCLIENT(splitted, receivedSms); - else - sendSMS(new Sms(receivedSms.phoneNumber, R.string.wrongformat)); - break; - case "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 (!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 (!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 (!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 (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; - } - } - - RxBus.INSTANCE.send(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 = LoopPlugin.getPlugin(); - if (loopPlugin.isEnabled(PluginType.LOOP)) { - loopPlugin.setPluginEnabled(PluginType.LOOP, false); - ConfigBuilderPlugin.getPlugin().getCommandQueue().cancelTempBasal(true, new Callback() { - @Override - public void run() { - RxBus.INSTANCE.send(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 = LoopPlugin.getPlugin(); - if (!loopPlugin.isEnabled(PluginType.LOOP)) { - loopPlugin.setPluginEnabled(PluginType.LOOP, true); - sendSMS(new Sms(receivedSms.phoneNumber, R.string.smscommunicator_loophasbeenenabled)); - RxBus.INSTANCE.send(new EventRefreshOverview("SMS_LOOP_START")); - } else { - sendSMS(new Sms(receivedSms.phoneNumber, R.string.smscommunicator_loopisenabled)); - } - receivedSms.processed = true; - break; - case "STATUS": - loopPlugin = LoopPlugin.getPlugin(); - 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); - RxBus.INSTANCE.send(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); - RxBus.INSTANCE.send(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")) { - TreatmentsPlugin.getPlugin().getService().resetTreatments(); - RxBus.INSTANCE.send(new EventNSClientRestart()); - sendSMS(new Sms(receivedSms.phoneNumber, "TREATMENTS REFRESH SENT")); - 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")) { - RxBus.INSTANCE.send(new EventNSClientRestart()); - sendSMS(new Sms(receivedSms.phoneNumber, "NSCLIENT RESTART SENT")); - 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(cal) { - @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 boolean sendNotificationToAllNumbers(String text) { - boolean result = true; - for (int i = 0; i < allowedNumbers.size(); i++) { - Sms sms = new Sms(allowedNumbers.get(i), text); - result = result && sendSMS(sms); - } - return result; - } - - private void sendSMSToAllNumbers(Sms sms) { - for (String number : allowedNumbers) { - sms.phoneNumber = number; - sendSMS(sms); - } - } - - boolean sendSMS(Sms sms) { - SmsManager smsManager = SmsManager.getDefault(); - sms.text = stripAccents(sms.text); - - try { - if (L.isEnabled(L.SMS)) - log.debug("Sending SMS to " + sms.phoneNumber + ": " + sms.text); - if (sms.text.getBytes().length <= 140) - smsManager.sendTextMessage(sms.phoneNumber, null, sms.text, null, null); - else { - ArrayList parts = smsManager.divideMessage(sms.text); - smsManager.sendMultipartTextMessage(sms.phoneNumber, null, parts, - null, null); - } - - messages.add(sms); - } catch (IllegalArgumentException e) { - if (e.getMessage().equals("Invalid message body")) { - Notification notification = new Notification(Notification.INVALID_MESSAGE_BODY, MainApp.gs(R.string.smscommunicator_messagebody), Notification.NORMAL); - RxBus.INSTANCE.send(new EventNewNotification(notification)); - return false; - } else { - Notification notification = new Notification(Notification.INVALID_PHONE_NUMBER, MainApp.gs(R.string.smscommunicator_invalidphonennumber), Notification.NORMAL); - RxBus.INSTANCE.send(new EventNewNotification(notification)); - return false; - } - } catch (java.lang.SecurityException e) { - Notification notification = new Notification(Notification.MISSING_SMS_PERMISSION, MainApp.gs(R.string.smscommunicator_missingsmspermission), Notification.NORMAL); - RxBus.INSTANCE.send(new EventNewNotification(notification)); - return false; - } - RxBus.INSTANCE.send(new EventSmsCommunicatorUpdateGui()); - return true; - } - - private String generatePasscode() { - int startChar1 = 'A'; // on iphone 1st char is uppercase :) - String passCode = Character.toString((char) (startChar1 + Math.random() * ('z' - 'a' + 1))); - int startChar2 = Math.random() > 0.5 ? 'a' : 'A'; - 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 = passCode.replace('l', 'k').replace('I', 'J'); - return passCode; - } - - private static String stripAccents(String s) { - s = Normalizer.normalize(s, Normalizer.Form.NFD); - s = s.replaceAll("[\\p{InCombiningDiacriticalMarks}]", ""); - return s; - } -} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/SmsCommunicatorPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/SmsCommunicatorPlugin.kt new file mode 100644 index 0000000000..e40ed8b1df --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/SmsCommunicatorPlugin.kt @@ -0,0 +1,922 @@ +package info.nightscout.androidaps.plugins.general.smsCommunicator + +import android.content.Intent +import android.preference.EditTextPreference +import android.preference.Preference +import android.preference.Preference.OnPreferenceChangeListener +import android.preference.PreferenceFragment +import android.telephony.SmsManager +import android.telephony.SmsMessage +import android.text.TextUtils +import com.andreabaccega.widget.ValidatingEditTextPreference +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.Profile +import info.nightscout.androidaps.db.DatabaseHelper +import info.nightscout.androidaps.db.Source +import info.nightscout.androidaps.db.TempTarget +import info.nightscout.androidaps.events.EventPreferenceChange +import info.nightscout.androidaps.events.EventRefreshOverview +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.logging.L +import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin +import info.nightscout.androidaps.plugins.bus.RxBus.send +import info.nightscout.androidaps.plugins.bus.RxBus.toObservable +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.nsclient.events.EventNSClientRestart +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.GlucoseStatus +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.utils.* +import io.reactivex.disposables.CompositeDisposable +import io.reactivex.schedulers.Schedulers +import org.apache.commons.lang3.StringUtils +import org.slf4j.LoggerFactory +import java.text.Normalizer +import java.util.* + +object SmsCommunicatorPlugin : PluginBase(PluginDescription() + .mainType(PluginType.GENERAL) + .fragmentClass(SmsCommunicatorFragment::class.java.name) + .pluginName(R.string.smscommunicator) + .shortName(R.string.smscommunicator_shortname) + .preferencesId(R.xml.pref_smscommunicator) + .description(R.string.description_sms_communicator) +) { + private val log = LoggerFactory.getLogger(L.SMS) + private val disposable = CompositeDisposable() + var allowedNumbers: MutableList = ArrayList() + var messageToConfirm: AuthRequest? = null + var lastRemoteBolusTime: Long = 0 + var messages = ArrayList() + + val commands = mapOf( + "BG" to "BG", + "LOOP" to "LOOP STOP/DISABLE/START/ENABLE/RESUME/STATUS\nLOOP SUSPEND 20", + "TREATMENTS" to "TREATMENTS REFRESH", + "NSCLIENT" to "NSCLIENT RESTART", + "PUMP" to "PUMP", + "BASAL" to "BASAL STOP/CANCEL\nBASAL 0.3\nBASAL 0.3 20\nBASAL 30%\nBASAL 30% 20\n", + "BOLUS" to "BOLUS 1.2\nBOLUS 1.2 MEAL", + "EXTENDED" to "EXTENDED STOP/CANCEL\nEXTENDED 2 120", + "CAL" to "CAL 5.6", + "PROFILE" to "PROFILE STATUS/LIST\nPROFILE 1\nPROFILE 2 30", + "TARGET" to "TARGET MEAL/ACTIVITY/HYPO/STOP", + "SMS" to "SMS DISABLE/STOP", + "CARBS" to "CARBS 12\nCARBS 12 23:05\nCARBS 12 11:05PM", + "HELP" to "HELP\nHELP command" + ) + + init { + processSettings(null) + } + + override fun onStart() { + super.onStart() + disposable.add(toObservable(EventPreferenceChange::class.java) + .observeOn(Schedulers.io()) + .subscribe({ event: EventPreferenceChange? -> processSettings(event) }) { throwable: Throwable? -> FabricPrivacy.logException(throwable) } + ) + } + + override fun onStop() { + disposable.clear() + super.onStop() + } + + override fun preprocessPreferences(preferenceFragment: PreferenceFragment) { + super.preprocessPreferences(preferenceFragment) + val distance = preferenceFragment.findPreference(MainApp.gs(R.string.key_smscommunicator_remotebolusmindistance)) as ValidatingEditTextPreference? + ?: return + val allowedNumbers = preferenceFragment.findPreference(MainApp.gs(R.string.key_smscommunicator_allowednumbers)) as EditTextPreference? + ?: return + if (!areMoreNumbers(allowedNumbers.text)) { + distance.title = (MainApp.gs(R.string.smscommunicator_remotebolusmindistance) + + ".\n" + + MainApp.gs(R.string.smscommunicator_remotebolusmindistance_caveat)) + distance.isEnabled = false + } else { + distance.title = MainApp.gs(R.string.smscommunicator_remotebolusmindistance) + distance.isEnabled = true + } + allowedNumbers.onPreferenceChangeListener = OnPreferenceChangeListener { _: Preference?, newValue: Any -> + if (!areMoreNumbers(newValue as String)) { + distance.text = (Constants.remoteBolusMinDistance / (60 * 1000L)).toString() + distance.title = (MainApp.gs(R.string.smscommunicator_remotebolusmindistance) + + ".\n" + + MainApp.gs(R.string.smscommunicator_remotebolusmindistance_caveat)) + distance.isEnabled = false + } else { + distance.title = MainApp.gs(R.string.smscommunicator_remotebolusmindistance) + distance.isEnabled = true + } + true + } + } + + override fun updatePreferenceSummary(pref: Preference) { + super.updatePreferenceSummary(pref) + if (pref is EditTextPreference) { + val editTextPref = pref + if (pref.getKey().contains("smscommunicator_allowednumbers") && (editTextPref.text == null || TextUtils.isEmpty(editTextPref.text.trim { it <= ' ' }))) { + pref.setSummary(MainApp.gs(R.string.smscommunicator_allowednumbers_summary)) + } + } + } + + private fun processSettings(ev: EventPreferenceChange?) { + if (ev == null || ev.isChanged(R.string.key_smscommunicator_allowednumbers)) { + val settings = SP.getString(R.string.key_smscommunicator_allowednumbers, "") + allowedNumbers.clear() + val substrings = settings.split(";").toTypedArray() + for (number in substrings) { + val cleaned = number.replace("\\s+".toRegex(), "") + allowedNumbers.add(cleaned) + log.debug("Found allowed number: $cleaned") + } + } + } + + fun isCommand(command: String, number: String): Boolean { + var found = false + commands.forEach { (k, _) -> + if (k == command) found = true + } + return found || messageToConfirm?.requester?.phoneNumber == number + } + + fun isAllowedNumber(number: String): Boolean { + for (num in allowedNumbers) { + if (num == number) return true + } + return false + } + + fun handleNewData(intent: Intent) { + val bundle = intent.extras ?: return + val format = bundle.getString("format") ?: return + val pdus = bundle["pdus"] as Array<*> + for (pdu in pdus) { + val message = SmsMessage.createFromPdu(pdu as ByteArray, format) + processSms(Sms(message)) + } + } + + fun processSms(receivedSms: Sms) { + 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) + send(EventSmsCommunicatorUpdateGui()) + return + } + val pump = ConfigBuilderPlugin.getPlugin().activePump ?: return + messages.add(receivedSms) + log.debug(receivedSms.toString()) + val splitted = receivedSms.text.split(Regex("\\s+")).toTypedArray() + val remoteCommandsAllowed = SP.getBoolean(R.string.key_smscommunicator_remotecommandsallowed, false) + if (splitted.isNotEmpty() && isCommand(splitted[0].toUpperCase(Locale.getDefault()), receivedSms.phoneNumber)) { + when (splitted[0].toUpperCase(Locale.getDefault())) { + "BG" -> + if (splitted.size == 1) processBG(receivedSms) + else sendSMS(Sms(receivedSms.phoneNumber, R.string.wrongformat)) + "LOOP" -> + if (!remoteCommandsAllowed) sendSMS(Sms(receivedSms.phoneNumber, R.string.smscommunicator_remotecommandnotallowed)) + else if (splitted.size == 2 || splitted.size == 3) processLOOP(splitted, receivedSms) + else sendSMS(Sms(receivedSms.phoneNumber, R.string.wrongformat)) + "TREATMENTS" -> + if (splitted.size == 2) processTREATMENTS(splitted, receivedSms) + else sendSMS(Sms(receivedSms.phoneNumber, R.string.wrongformat)) + "NSCLIENT" -> + if (splitted.size == 2) processNSCLIENT(splitted, receivedSms) + else sendSMS(Sms(receivedSms.phoneNumber, R.string.wrongformat)) + "PUMP" -> + if (splitted.size == 1) processPUMP(receivedSms) + else sendSMS(Sms(receivedSms.phoneNumber, R.string.wrongformat)) + "PROFILE" -> + if (!remoteCommandsAllowed) sendSMS(Sms(receivedSms.phoneNumber, R.string.smscommunicator_remotecommandnotallowed)) + else if (splitted.size == 2 || splitted.size == 3) processPROFILE(splitted, receivedSms) + else sendSMS(Sms(receivedSms.phoneNumber, R.string.wrongformat)) + "BASAL" -> + if (!remoteCommandsAllowed) sendSMS(Sms(receivedSms.phoneNumber, R.string.smscommunicator_remotecommandnotallowed)) + else if (splitted.size == 2 || splitted.size == 3) processBASAL(splitted, receivedSms) + else sendSMS(Sms(receivedSms.phoneNumber, R.string.wrongformat)) + "EXTENDED" -> + if (!remoteCommandsAllowed) sendSMS(Sms(receivedSms.phoneNumber, R.string.smscommunicator_remotecommandnotallowed)) + else if (splitted.size == 2 || splitted.size == 3) processEXTENDED(splitted, receivedSms) + else sendSMS(Sms(receivedSms.phoneNumber, R.string.wrongformat)) + "BOLUS" -> + if (!remoteCommandsAllowed) sendSMS(Sms(receivedSms.phoneNumber, R.string.smscommunicator_remotecommandnotallowed)) + else if (splitted.size == 2 && DateUtil.now() - lastRemoteBolusTime < Constants.remoteBolusMinDistance) sendSMS(Sms(receivedSms.phoneNumber, R.string.smscommunicator_remotebolusnotallowed)) + else if (splitted.size == 2 && pump.isSuspended) sendSMS(Sms(receivedSms.phoneNumber, R.string.pumpsuspended)) + else if (splitted.size == 2 || splitted.size == 3) processBOLUS(splitted, receivedSms) + else sendSMS(Sms(receivedSms.phoneNumber, R.string.wrongformat)) + "CARBS" -> + if (!remoteCommandsAllowed) sendSMS(Sms(receivedSms.phoneNumber, R.string.smscommunicator_remotecommandnotallowed)) + else if (splitted.size == 2 || splitted.size == 3) processCARBS(splitted, receivedSms) + else sendSMS(Sms(receivedSms.phoneNumber, R.string.wrongformat)) + "CAL" -> + if (!remoteCommandsAllowed) sendSMS(Sms(receivedSms.phoneNumber, R.string.smscommunicator_remotecommandnotallowed)) + else if (splitted.size == 2) processCAL(splitted, receivedSms) + else sendSMS(Sms(receivedSms.phoneNumber, R.string.wrongformat)) + "TARGET" -> + if (!remoteCommandsAllowed) sendSMS(Sms(receivedSms.phoneNumber, R.string.smscommunicator_remotecommandnotallowed)) + else if (splitted.size == 2) processTARGET(splitted, receivedSms) + else sendSMS(Sms(receivedSms.phoneNumber, R.string.wrongformat)) + "SMS" -> + if (!remoteCommandsAllowed) sendSMS(Sms(receivedSms.phoneNumber, R.string.smscommunicator_remotecommandnotallowed)) + else if (splitted.size == 2) processSMS(splitted, receivedSms) + else sendSMS(Sms(receivedSms.phoneNumber, R.string.wrongformat)) + "HELP" -> + if (splitted.size == 1 || splitted.size == 2) processHELP(splitted, receivedSms) + else sendSMS(Sms(receivedSms.phoneNumber, R.string.wrongformat)) + else -> + if (messageToConfirm?.requester?.phoneNumber == receivedSms.phoneNumber) { + messageToConfirm?.action(splitted[0]) + messageToConfirm = null + } else sendSMS(Sms(receivedSms.phoneNumber, R.string.smscommunicator_unknowncommand)) + } + } + send(EventSmsCommunicatorUpdateGui()) + } + + private fun processBG(receivedSms: Sms) { + val actualBG = DatabaseHelper.actualBg() + val lastBG = DatabaseHelper.lastBg() + var reply = "" + val units = ProfileFunctions.getInstance().profileUnits + if (actualBG != null) { + reply = MainApp.gs(R.string.sms_actualbg) + " " + actualBG.valueToUnitsToString(units) + ", " + } else if (lastBG != null) { + val agoMsec = System.currentTimeMillis() - lastBG.date + val agoMin = (agoMsec / 60.0 / 1000.0).toInt() + reply = MainApp.gs(R.string.sms_lastbg) + " " + lastBG.valueToUnitsToString(units) + " " + String.format(MainApp.gs(R.string.sms_minago), agoMin) + ", " + } + val 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() + val bolusIob = TreatmentsPlugin.getPlugin().lastCalculationTreatments.round() + TreatmentsPlugin.getPlugin().updateTotalIOBTempBasals() + val basalIob = TreatmentsPlugin.getPlugin().lastCalculationTempBasals.round() + val 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(Sms(receivedSms.phoneNumber, reply)) + receivedSms.processed = true + } + + private fun processLOOP(splitted: Array, receivedSms: Sms) { + when (splitted[1].toUpperCase(Locale.getDefault())) { + "DISABLE", "STOP" -> { + val loopPlugin = LoopPlugin.getPlugin() + if (loopPlugin.isEnabled(PluginType.LOOP)) { + loopPlugin.setPluginEnabled(PluginType.LOOP, false) + ConfigBuilderPlugin.getPlugin().commandQueue.cancelTempBasal(true, object : Callback() { + override fun run() { + send(EventRefreshOverview("SMS_LOOP_STOP")) + val replyText = MainApp.gs(R.string.smscommunicator_loophasbeendisabled) + " " + + MainApp.gs(if (result.success) R.string.smscommunicator_tempbasalcanceled else R.string.smscommunicator_tempbasalcancelfailed) + sendSMS(Sms(receivedSms.phoneNumber, replyText)) + } + }) + } else + sendSMS(Sms(receivedSms.phoneNumber, R.string.smscommunicator_loopisdisabled)) + receivedSms.processed = true + } + "ENABLE", "START" -> { + val loopPlugin = LoopPlugin.getPlugin() + if (!loopPlugin.isEnabled(PluginType.LOOP)) { + loopPlugin.setPluginEnabled(PluginType.LOOP, true) + sendSMS(Sms(receivedSms.phoneNumber, R.string.smscommunicator_loophasbeenenabled)) + send(EventRefreshOverview("SMS_LOOP_START")) + } else + sendSMS(Sms(receivedSms.phoneNumber, R.string.smscommunicator_loopisenabled)) + receivedSms.processed = true + } + "STATUS" -> { + val loopPlugin = LoopPlugin.getPlugin() + val reply = if (loopPlugin.isEnabled(PluginType.LOOP)) { + if (loopPlugin.isSuspended()) String.format(MainApp.gs(R.string.loopsuspendedfor), loopPlugin.minutesToEndOfSuspend()) + else MainApp.gs(R.string.smscommunicator_loopisenabled) + } else + MainApp.gs(R.string.smscommunicator_loopisdisabled) + sendSMS(Sms(receivedSms.phoneNumber, reply)) + receivedSms.processed = true + } + "RESUME" -> { + LoopPlugin.getPlugin().suspendTo(0) + send(EventRefreshOverview("SMS_LOOP_RESUME")) + NSUpload.uploadOpenAPSOffline(0.0) + sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, R.string.smscommunicator_loopresumed)) + } + "SUSPEND" -> { + var duration = 0 + if (splitted.size == 3) duration = SafeParse.stringToInt(splitted[2]) + duration = Math.max(0, duration) + duration = Math.min(180, duration) + if (duration == 0) { + receivedSms.processed = true + sendSMS(Sms(receivedSms.phoneNumber, R.string.smscommunicator_wrongduration)) + return + } else { + val passCode = generatePasscode() + val reply = String.format(MainApp.gs(R.string.smscommunicator_suspendreplywithcode), duration, passCode) + receivedSms.processed = true + messageToConfirm = AuthRequest(this, receivedSms, reply, passCode, object : SmsAction(duration) { + override fun run() { + ConfigBuilderPlugin.getPlugin().commandQueue.cancelTempBasal(true, object : Callback() { + override fun run() { + if (result.success) { + LoopPlugin.getPlugin().suspendTo(System.currentTimeMillis() + anInteger() * 60L * 1000) + NSUpload.uploadOpenAPSOffline(anInteger() * 60.toDouble()) + send(EventRefreshOverview("SMS_LOOP_SUSPENDED")) + val replyText = MainApp.gs(R.string.smscommunicator_loopsuspended) + " " + + MainApp.gs(if (result.success) R.string.smscommunicator_tempbasalcanceled else R.string.smscommunicator_tempbasalcancelfailed) + sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText)) + } else { + var replyText = MainApp.gs(R.string.smscommunicator_tempbasalcancelfailed) + replyText += "\n" + ConfigBuilderPlugin.getPlugin().activePump?.shortStatus(true) + sendSMS(Sms(receivedSms.phoneNumber, replyText)) + } + } + }) + } + }) + } + } + else -> sendSMS(Sms(receivedSms.phoneNumber, R.string.wrongformat)) + } + } + + private fun processTREATMENTS(splitted: Array, receivedSms: Sms) { + if (splitted[1].toUpperCase(Locale.getDefault()) == "REFRESH") { + TreatmentsPlugin.getPlugin().service.resetTreatments() + send(EventNSClientRestart()) + sendSMS(Sms(receivedSms.phoneNumber, "TREATMENTS REFRESH SENT")) + receivedSms.processed = true + } else + sendSMS(Sms(receivedSms.phoneNumber, R.string.wrongformat)) + } + + private fun processNSCLIENT(splitted: Array, receivedSms: Sms) { + if (splitted[1].toUpperCase(Locale.getDefault()) == "RESTART") { + send(EventNSClientRestart()) + sendSMS(Sms(receivedSms.phoneNumber, "NSCLIENT RESTART SENT")) + receivedSms.processed = true + } else + sendSMS(Sms(receivedSms.phoneNumber, R.string.wrongformat)) + } + + private fun processHELP(splitted: Array, receivedSms: Sms) { + if (splitted.size == 1) { + sendSMS(Sms(receivedSms.phoneNumber, commands.keys.toString().replace("[", "").replace("]", ""))) + receivedSms.processed = true + } else if (isCommand(splitted[1].toUpperCase(Locale.getDefault()), receivedSms.phoneNumber)) { + commands[splitted[1].toUpperCase(Locale.getDefault())]?.let { + sendSMS(Sms(receivedSms.phoneNumber, it)) + receivedSms.processed = true + } + } else + sendSMS(Sms(receivedSms.phoneNumber, R.string.wrongformat)) + } + + private fun processPUMP(receivedSms: Sms) { + ConfigBuilderPlugin.getPlugin().commandQueue.readStatus("SMS", object : Callback() { + override fun run() { + val pump = ConfigBuilderPlugin.getPlugin().activePump + if (result.success) { + if (pump != null) { + val reply = pump.shortStatus(true) + sendSMS(Sms(receivedSms.phoneNumber, reply)) + } + } else { + val reply = MainApp.gs(R.string.readstatusfailed) + sendSMS(Sms(receivedSms.phoneNumber, reply)) + } + } + }) + receivedSms.processed = true + } + + private fun processPROFILE(splitted: Array, receivedSms: Sms) { // load profiles + val anInterface = ConfigBuilderPlugin.getPlugin().activeProfileInterface + if (anInterface == null) { + sendSMS(Sms(receivedSms.phoneNumber, R.string.notconfigured)) + receivedSms.processed = true + return + } + val store = anInterface.profile + if (store == null) { + sendSMS(Sms(receivedSms.phoneNumber, R.string.notconfigured)) + receivedSms.processed = true + return + } + val list = store.profileList + if (splitted[1].toUpperCase(Locale.getDefault()) == "STATUS") { + sendSMS(Sms(receivedSms.phoneNumber, ProfileFunctions.getInstance().profileName)) + } else if (splitted[1].toUpperCase(Locale.getDefault()) == "LIST") { + if (list.isEmpty()) sendSMS(Sms(receivedSms.phoneNumber, R.string.invalidprofile)) + else { + var reply = "" + for (i in list.indices) { + if (i > 0) reply += "\n" + reply += (i + 1).toString() + ". " + reply += list[i] + } + sendSMS(Sms(receivedSms.phoneNumber, reply)) + } + } else { + val pindex = SafeParse.stringToInt(splitted[1]) + var percentage = 100 + if (splitted.size > 2) percentage = SafeParse.stringToInt(splitted[2]) + if (pindex > list.size) sendSMS(Sms(receivedSms.phoneNumber, R.string.wrongformat)) + else if (percentage == 0) sendSMS(Sms(receivedSms.phoneNumber, R.string.wrongformat)) + else if (pindex == 0) sendSMS(Sms(receivedSms.phoneNumber, R.string.wrongformat)) + else { + val profile = store.getSpecificProfile(list[pindex - 1] as String) + if (profile == null) sendSMS(Sms(receivedSms.phoneNumber, R.string.noprofile)) + else { + val passCode = generatePasscode() + val reply = String.format(MainApp.gs(R.string.smscommunicator_profilereplywithcode), list[pindex - 1], percentage, passCode) + receivedSms.processed = true + val finalPercentage = percentage + messageToConfirm = AuthRequest(this, receivedSms, reply, passCode, object : SmsAction(list[pindex - 1] as String, finalPercentage) { + override fun run() { + ProfileFunctions.doProfileSwitch(store, list[pindex - 1] as String, 0, finalPercentage, 0) + sendSMS(Sms(receivedSms.phoneNumber, R.string.profileswitchcreated)) + } + }) + } + } + } + receivedSms.processed = true + } + + private fun processBASAL(splitted: Array, receivedSms: Sms) { + if (splitted[1].toUpperCase(Locale.getDefault()) == "CANCEL" || splitted[1].toUpperCase(Locale.getDefault()) == "STOP") { + val passCode = generatePasscode() + val reply = String.format(MainApp.gs(R.string.smscommunicator_basalstopreplywithcode), passCode) + receivedSms.processed = true + messageToConfirm = AuthRequest(this, receivedSms, reply, passCode, object : SmsAction() { + override fun run() { + ConfigBuilderPlugin.getPlugin().commandQueue.cancelTempBasal(true, object : Callback() { + override fun run() { + if (result.success) { + var replyText = MainApp.gs(R.string.smscommunicator_tempbasalcanceled) + replyText += "\n" + ConfigBuilderPlugin.getPlugin().activePump?.shortStatus(true) + sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText)) + } else { + var replyText = MainApp.gs(R.string.smscommunicator_tempbasalcancelfailed) + replyText += "\n" + ConfigBuilderPlugin.getPlugin().activePump?.shortStatus(true) + sendSMS(Sms(receivedSms.phoneNumber, replyText)) + } + } + }) + } + }) + } else if (splitted[1].endsWith("%")) { + var tempBasalPct = SafeParse.stringToInt(StringUtils.removeEnd(splitted[1], "%")) + var duration = 30 + if (splitted.size > 2) duration = SafeParse.stringToInt(splitted[2]) + val profile = ProfileFunctions.getInstance().profile + if (profile == null) sendSMS(Sms(receivedSms.phoneNumber, R.string.noprofile)) + else if (tempBasalPct == 0 && splitted[1] != "0%") sendSMS(Sms(receivedSms.phoneNumber, R.string.wrongformat)) + else if (duration == 0) sendSMS(Sms(receivedSms.phoneNumber, R.string.wrongformat)) + else { + tempBasalPct = MainApp.getConstraintChecker().applyBasalPercentConstraints(Constraint(tempBasalPct), profile).value() + val passCode = generatePasscode() + val reply = String.format(MainApp.gs(R.string.smscommunicator_basalpctreplywithcode), tempBasalPct, duration, passCode) + receivedSms.processed = true + messageToConfirm = AuthRequest(this, receivedSms, reply, passCode, object : SmsAction(tempBasalPct, duration) { + override fun run() { + ConfigBuilderPlugin.getPlugin().commandQueue.tempBasalPercent(anInteger(), secondInteger(), true, profile, object : Callback() { + override fun run() { + if (result.success) { + var replyText: String + replyText = if (result.isPercent) String.format(MainApp.gs(R.string.smscommunicator_tempbasalset_percent), result.percent, result.duration) else String.format(MainApp.gs(R.string.smscommunicator_tempbasalset), result.absolute, result.duration) + replyText += "\n" + ConfigBuilderPlugin.getPlugin().activePump?.shortStatus(true) + sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText)) + } else { + var replyText = MainApp.gs(R.string.smscommunicator_tempbasalfailed) + replyText += "\n" + ConfigBuilderPlugin.getPlugin().activePump?.shortStatus(true) + sendSMS(Sms(receivedSms.phoneNumber, replyText)) + } + } + }) + } + }) + } + } else { + var tempBasal = SafeParse.stringToDouble(splitted[1]) + var duration = 30 + if (splitted.size > 2) duration = SafeParse.stringToInt(splitted[2]) + val profile = ProfileFunctions.getInstance().profile + if (profile == null) sendSMS(Sms(receivedSms.phoneNumber, R.string.noprofile)) + else if (tempBasal == 0.0 && splitted[1] != "0") sendSMS(Sms(receivedSms.phoneNumber, R.string.wrongformat)) + else if (duration == 0) sendSMS(Sms(receivedSms.phoneNumber, R.string.wrongformat)) + else { + tempBasal = MainApp.getConstraintChecker().applyBasalConstraints(Constraint(tempBasal), profile).value() + val passCode = generatePasscode() + val reply = String.format(MainApp.gs(R.string.smscommunicator_basalreplywithcode), tempBasal, duration, passCode) + receivedSms.processed = true + messageToConfirm = AuthRequest(this, receivedSms, reply, passCode, object : SmsAction(tempBasal, duration) { + override fun run() { + ConfigBuilderPlugin.getPlugin().commandQueue.tempBasalAbsolute(aDouble(), secondInteger(), true, profile, object : Callback() { + override fun run() { + if (result.success) { + var replyText = if (result.isPercent) String.format(MainApp.gs(R.string.smscommunicator_tempbasalset_percent), result.percent, result.duration) + else String.format(MainApp.gs(R.string.smscommunicator_tempbasalset), result.absolute, result.duration) + replyText += "\n" + ConfigBuilderPlugin.getPlugin().activePump?.shortStatus(true) + sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText)) + } else { + var replyText = MainApp.gs(R.string.smscommunicator_tempbasalfailed) + replyText += "\n" + ConfigBuilderPlugin.getPlugin().activePump?.shortStatus(true) + sendSMS(Sms(receivedSms.phoneNumber, replyText)) + } + } + }) + } + }) + } + } + } + + private fun processEXTENDED(splitted: Array, receivedSms: Sms) { + if (splitted[1].toUpperCase(Locale.getDefault()) == "CANCEL" || splitted[1].toUpperCase(Locale.getDefault()) == "STOP") { + val passCode = generatePasscode() + val reply = String.format(MainApp.gs(R.string.smscommunicator_extendedstopreplywithcode), passCode) + receivedSms.processed = true + messageToConfirm = AuthRequest(this, receivedSms, reply, passCode, object : SmsAction() { + override fun run() { + ConfigBuilderPlugin.getPlugin().commandQueue.cancelExtended(object : Callback() { + override fun run() { + if (result.success) { + var replyText = MainApp.gs(R.string.smscommunicator_extendedcanceled) + replyText += "\n" + ConfigBuilderPlugin.getPlugin().activePump?.shortStatus(true) + sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText)) + } else { + var replyText = MainApp.gs(R.string.smscommunicator_extendedcancelfailed) + replyText += "\n" + ConfigBuilderPlugin.getPlugin().activePump?.shortStatus(true) + sendSMS(Sms(receivedSms.phoneNumber, replyText)) + } + } + }) + } + }) + } else if (splitted.size != 3) { + sendSMS(Sms(receivedSms.phoneNumber, R.string.wrongformat)) + } else { + var extended = SafeParse.stringToDouble(splitted[1]) + val duration = SafeParse.stringToInt(splitted[2]) + extended = MainApp.getConstraintChecker().applyExtendedBolusConstraints(Constraint(extended)).value() + if (extended == 0.0 || duration == 0) sendSMS(Sms(receivedSms.phoneNumber, R.string.wrongformat)) + else { + val passCode = generatePasscode() + val reply = String.format(MainApp.gs(R.string.smscommunicator_extendedreplywithcode), extended, duration, passCode) + receivedSms.processed = true + messageToConfirm = AuthRequest(this, receivedSms, reply, passCode, object : SmsAction(extended, duration) { + override fun run() { + ConfigBuilderPlugin.getPlugin().commandQueue.extendedBolus(aDouble(), secondInteger(), object : Callback() { + override fun run() { + if (result.success) { + var replyText = String.format(MainApp.gs(R.string.smscommunicator_extendedset), aDouble, duration) + replyText += "\n" + ConfigBuilderPlugin.getPlugin().activePump?.shortStatus(true) + sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText)) + } else { + var replyText = MainApp.gs(R.string.smscommunicator_extendedfailed) + replyText += "\n" + ConfigBuilderPlugin.getPlugin().activePump?.shortStatus(true) + sendSMS(Sms(receivedSms.phoneNumber, replyText)) + } + } + }) + } + }) + } + } + } + + private fun processBOLUS(splitted: Array, receivedSms: Sms) { + var bolus = SafeParse.stringToDouble(splitted[1]) + val isMeal = splitted.size > 2 && splitted[2].equals("MEAL", ignoreCase = true) + bolus = MainApp.getConstraintChecker().applyBolusConstraints(Constraint(bolus)).value() + if (splitted.size == 3 && !isMeal) { + sendSMS(Sms(receivedSms.phoneNumber, R.string.wrongformat)) + } else if (bolus > 0.0) { + val passCode = generatePasscode() + val reply = if (isMeal) + String.format(MainApp.gs(R.string.smscommunicator_mealbolusreplywithcode), bolus, passCode) + else + String.format(MainApp.gs(R.string.smscommunicator_bolusreplywithcode), bolus, passCode) + receivedSms.processed = true + messageToConfirm = AuthRequest(this, receivedSms, reply, passCode, object : SmsAction(bolus) { + override fun run() { + val detailedBolusInfo = DetailedBolusInfo() + detailedBolusInfo.insulin = aDouble() + detailedBolusInfo.source = Source.USER + ConfigBuilderPlugin.getPlugin().commandQueue.bolus(detailedBolusInfo, object : Callback() { + override fun run() { + val resultSuccess = result.success + val resultBolusDelivered = result.bolusDelivered + ConfigBuilderPlugin.getPlugin().commandQueue.readStatus("SMS", object : Callback() { + override fun run() { + if (resultSuccess) { + var replyText = if (isMeal) + String.format(MainApp.gs(R.string.smscommunicator_mealbolusdelivered), resultBolusDelivered) + else + String.format(MainApp.gs(R.string.smscommunicator_bolusdelivered), resultBolusDelivered) + replyText += "\n" + ConfigBuilderPlugin.getPlugin().activePump?.shortStatus(true) + lastRemoteBolusTime = DateUtil.now() + if (isMeal) { + ProfileFunctions.getInstance().profile?.let { currentProfile -> + var eatingSoonTTDuration = SP.getInt(R.string.key_eatingsoon_duration, Constants.defaultEatingSoonTTDuration) + eatingSoonTTDuration = + if (eatingSoonTTDuration > 0) eatingSoonTTDuration + else Constants.defaultEatingSoonTTDuration + var eatingSoonTT = SP.getDouble(R.string.key_eatingsoon_target, if (currentProfile.units == Constants.MMOL) Constants.defaultEatingSoonTTmmol else Constants.defaultEatingSoonTTmgdl) + eatingSoonTT = + if (eatingSoonTT > 0) eatingSoonTT + else if (currentProfile.units == Constants.MMOL) Constants.defaultEatingSoonTTmmol + else Constants.defaultEatingSoonTTmgdl + val tempTarget = TempTarget() + .date(System.currentTimeMillis()) + .duration(eatingSoonTTDuration) + .reason(MainApp.gs(R.string.eatingsoon)) + .source(Source.USER) + .low(Profile.toMgdl(eatingSoonTT, currentProfile.units)) + .high(Profile.toMgdl(eatingSoonTT, currentProfile.units)) + TreatmentsPlugin.getPlugin().addToHistoryTempTarget(tempTarget) + val tt = if (currentProfile.units == Constants.MMOL) { + DecimalFormatter.to1Decimal(eatingSoonTT) + } else DecimalFormatter.to0Decimal(eatingSoonTT) + replyText += "\n" + String.format(MainApp.gs(R.string.smscommunicator_mealbolusdelivered_tt), tt, eatingSoonTTDuration) + } + } + sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText)) + } else { + var replyText = MainApp.gs(R.string.smscommunicator_bolusfailed) + replyText += "\n" + ConfigBuilderPlugin.getPlugin().activePump?.shortStatus(true) + sendSMS(Sms(receivedSms.phoneNumber, replyText)) + } + } + }) + } + }) + } + }) + } else sendSMS(Sms(receivedSms.phoneNumber, R.string.wrongformat)) + } + + private fun processCARBS(splitted: Array, receivedSms: Sms) { + var grams = SafeParse.stringToInt(splitted[1]) + var time = DateUtil.now() + if (splitted.size > 2) { + val seconds = DateUtil.toSeconds(splitted[2].toUpperCase(Locale.getDefault())) + val midnight = MidnightTime.calc() + if (seconds == 0 && (!splitted[2].startsWith("00:00") || !splitted[2].startsWith("12:00"))) { + sendSMS(Sms(receivedSms.phoneNumber, R.string.wrongformat)) + return + } + time = midnight + T.secs(seconds.toLong()).msecs() + } + grams = MainApp.getConstraintChecker().applyCarbsConstraints(Constraint(grams)).value() + if (grams == 0) sendSMS(Sms(receivedSms.phoneNumber, R.string.wrongformat)) + else { + val passCode = generatePasscode() + val reply = String.format(MainApp.gs(R.string.smscommunicator_carbsreplywithcode), grams, DateUtil.timeString(time), passCode) + receivedSms.processed = true + messageToConfirm = AuthRequest(this, receivedSms, reply, passCode, object : SmsAction(grams, time) { + override fun run() { + val detailedBolusInfo = DetailedBolusInfo() + detailedBolusInfo.carbs = anInteger().toDouble() + detailedBolusInfo.date = secondLong() + ConfigBuilderPlugin.getPlugin().commandQueue.bolus(detailedBolusInfo, object : Callback() { + override fun run() { + if (result.success) { + var replyText = String.format(MainApp.gs(R.string.smscommunicator_carbsset), anInteger) + replyText += "\n" + ConfigBuilderPlugin.getPlugin().activePump?.shortStatus(true) + sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText)) + } else { + var replyText = MainApp.gs(R.string.smscommunicator_carbsfailed) + replyText += "\n" + ConfigBuilderPlugin.getPlugin().activePump?.shortStatus(true) + sendSMS(Sms(receivedSms.phoneNumber, replyText)) + } + } + }) + } + }) + } + } + + private fun processTARGET(splitted: Array, receivedSms: Sms) { + val isMeal = splitted[1].equals("MEAL", ignoreCase = true) + val isActivity = splitted[1].equals("ACTIVITY", ignoreCase = true) + val isHypo = splitted[1].equals("HYPO", ignoreCase = true) + val isStop = splitted[1].equals("STOP", ignoreCase = true) || splitted[1].equals("CANCEL", ignoreCase = true) + if (isMeal || isActivity || isHypo) { + val passCode = generatePasscode() + val reply = String.format(MainApp.gs(R.string.smscommunicator_temptargetwithcode), splitted[1].toUpperCase(Locale.getDefault()), passCode) + receivedSms.processed = true + messageToConfirm = AuthRequest(this, receivedSms, reply, passCode, object : SmsAction() { + override fun run() { + val currentProfile = ProfileFunctions.getInstance().profile + if (currentProfile != null) { + var keyDuration = 0 + var defaultTargetDuration = 0 + var keyTarget = 0 + var defaultTargetMMOL = 0.0 + var defaultTargetMGDL = 0.0 + if (isMeal) { + keyDuration = R.string.key_eatingsoon_duration + defaultTargetDuration = Constants.defaultEatingSoonTTDuration + keyTarget = R.string.key_eatingsoon_target + defaultTargetMMOL = Constants.defaultEatingSoonTTmmol + defaultTargetMGDL = Constants.defaultEatingSoonTTmgdl + } else if (isActivity) { + keyDuration = R.string.key_activity_duration + defaultTargetDuration = Constants.defaultActivityTTDuration + keyTarget = R.string.key_activity_target + defaultTargetMMOL = Constants.defaultActivityTTmmol + defaultTargetMGDL = Constants.defaultActivityTTmgdl + } else if (isHypo) { + keyDuration = R.string.key_hypo_duration + defaultTargetDuration = Constants.defaultHypoTTDuration + keyTarget = R.string.key_hypo_target + defaultTargetMMOL = Constants.defaultHypoTTmmol + defaultTargetMGDL = Constants.defaultHypoTTmgdl + } + var ttDuration = SP.getInt(keyDuration, defaultTargetDuration) + ttDuration = if (ttDuration > 0) ttDuration else defaultTargetDuration + var tt = SP.getDouble(keyTarget, if (currentProfile.units == Constants.MMOL) defaultTargetMMOL else defaultTargetMGDL) + tt = if (tt > 0) tt else if (currentProfile.units == Constants.MMOL) defaultTargetMMOL else defaultTargetMGDL + val tempTarget = TempTarget() + .date(System.currentTimeMillis()) + .duration(ttDuration) + .reason(MainApp.gs(R.string.eatingsoon)) + .source(Source.USER) + .low(Profile.toMgdl(tt, currentProfile.units)) + .high(Profile.toMgdl(tt, currentProfile.units)) + TreatmentsPlugin.getPlugin().addToHistoryTempTarget(tempTarget) + val ttString = if (currentProfile.units == Constants.MMOL) DecimalFormatter.to1Decimal(tt) else DecimalFormatter.to0Decimal(tt) + val replyText = String.format(MainApp.gs(R.string.smscommunicator_tt_set), ttString, ttDuration) + sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText)) + } else { + sendSMS(Sms(receivedSms.phoneNumber, R.string.smscommunicator_unknowncommand)) + } + } + }) + } else if (isStop) { + val passCode = generatePasscode() + val reply = String.format(MainApp.gs(R.string.smscommunicator_temptargetcancel), passCode) + receivedSms.processed = true + messageToConfirm = AuthRequest(this, receivedSms, reply, passCode, object : SmsAction() { + override fun run() { + val currentProfile = ProfileFunctions.getInstance().profile + if (currentProfile != null) { + val tempTarget = TempTarget() + .source(Source.USER) + .date(DateUtil.now()) + .duration(0) + .low(0.0) + .high(0.0) + TreatmentsPlugin.getPlugin().addToHistoryTempTarget(tempTarget) + val replyText = String.format(MainApp.gs(R.string.smscommunicator_tt_canceled)) + sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText)) + } else { + sendSMS(Sms(receivedSms.phoneNumber, R.string.smscommunicator_unknowncommand)) + } + } + }) + } else + sendSMS(Sms(receivedSms.phoneNumber, R.string.wrongformat)) + } + + private fun processSMS(splitted: Array, receivedSms: Sms) { + val isStop = (splitted[1].equals("STOP", ignoreCase = true) + || splitted[1].equals("DISABLE", ignoreCase = true)) + if (isStop) { + val passCode = generatePasscode() + val reply = String.format(MainApp.gs(R.string.smscommunicator_stopsmswithcode), passCode) + receivedSms.processed = true + messageToConfirm = AuthRequest(this, receivedSms, reply, passCode, object : SmsAction() { + override fun run() { + SP.putBoolean(R.string.key_smscommunicator_remotecommandsallowed, false) + val replyText = String.format(MainApp.gs(R.string.smscommunicator_stoppedsms)) + sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText)) + } + }) + } else sendSMS(Sms(receivedSms.phoneNumber, R.string.wrongformat)) + } + + private fun processCAL(splitted: Array, receivedSms: Sms) { + val cal = SafeParse.stringToDouble(splitted[1]) + if (cal > 0.0) { + val passCode = generatePasscode() + val reply = String.format(MainApp.gs(R.string.smscommunicator_calibrationreplywithcode), cal, passCode) + receivedSms.processed = true + messageToConfirm = AuthRequest(this, receivedSms, reply, passCode, object : SmsAction(cal) { + override fun run() { + val result = XdripCalibrations.sendIntent(aDouble) + if (result) sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, R.string.smscommunicator_calibrationsent)) else sendSMS(Sms(receivedSms.phoneNumber, R.string.smscommunicator_calibrationfailed)) + } + }) + } else sendSMS(Sms(receivedSms.phoneNumber, R.string.wrongformat)) + } + + fun sendNotificationToAllNumbers(text: String): Boolean { + var result = true + for (i in allowedNumbers.indices) { + val sms = Sms(allowedNumbers[i], text) + result = result && sendSMS(sms) + } + return result + } + + private fun sendSMSToAllNumbers(sms: Sms) { + for (number in allowedNumbers) { + sms.phoneNumber = number + sendSMS(sms) + } + } + + fun sendSMS(sms: Sms): Boolean { + val smsManager = SmsManager.getDefault() + sms.text = stripAccents(sms.text) + try { + if (L.isEnabled(L.SMS)) log.debug("Sending SMS to " + sms.phoneNumber + ": " + sms.text) + if (sms.text.toByteArray().size <= 140) smsManager.sendTextMessage(sms.phoneNumber, null, sms.text, null, null) + else { + val parts = smsManager.divideMessage(sms.text) + smsManager.sendMultipartTextMessage(sms.phoneNumber, null, parts, + null, null) + } + messages.add(sms) + } catch (e: IllegalArgumentException) { + return if (e.message == "Invalid message body") { + val notification = Notification(Notification.INVALID_MESSAGE_BODY, MainApp.gs(R.string.smscommunicator_messagebody), Notification.NORMAL) + send(EventNewNotification(notification)) + false + } else { + val notification = Notification(Notification.INVALID_PHONE_NUMBER, MainApp.gs(R.string.smscommunicator_invalidphonennumber), Notification.NORMAL) + send(EventNewNotification(notification)) + false + } + } catch (e: SecurityException) { + val notification = Notification(Notification.MISSING_SMS_PERMISSION, MainApp.gs(R.string.smscommunicator_missingsmspermission), Notification.NORMAL) + send(EventNewNotification(notification)) + return false + } + send(EventSmsCommunicatorUpdateGui()) + return true + } + + private fun generatePasscode(): String { + val startChar1 = 'A'.toInt() // on iphone 1st char is uppercase :) + var passCode = Character.toString((startChar1 + Math.random() * ('z' - 'a' + 1)).toChar()) + val startChar2: Int = if (Math.random() > 0.5) 'a'.toInt() else 'A'.toInt() + passCode += Character.toString((startChar2 + Math.random() * ('z' - 'a' + 1)).toChar()) + val startChar3: Int = if (Math.random() > 0.5) 'a'.toInt() else 'A'.toInt() + passCode += Character.toString((startChar3 + Math.random() * ('z' - 'a' + 1)).toChar()) + passCode = passCode.replace('l', 'k').replace('I', 'J') + return passCode + } + + private fun stripAccents(str: String): String { + var s = str + s = Normalizer.normalize(s, Normalizer.Form.NFD) + s = s.replace("[\\p{InCombiningDiacriticalMarks}]".toRegex(), "") + return s + } + + fun areMoreNumbers(allowednumbers: String?): Boolean { + return allowednumbers?.let { + var countNumbers = 0 + val substrings = it.split(";").toTypedArray() + for (number in substrings) { + var cleaned = number.replace(Regex("\\s+"), "") + if (cleaned.length < 4) continue + cleaned = cleaned.replace("+", "") + cleaned = cleaned.replace("-", "") + if (!cleaned.matches(Regex("[0-9]+"))) continue + countNumbers++ + } + countNumbers > 1 + } ?: false + } +} \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/TidepoolPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/TidepoolPlugin.kt index 78ad0ab37d..e8971ab9d5 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/TidepoolPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/TidepoolPlugin.kt @@ -1,5 +1,6 @@ package info.nightscout.androidaps.plugins.general.tidepool +import android.preference.PreferenceFragment import android.text.Spanned import info.nightscout.androidaps.Constants import info.nightscout.androidaps.MainApp @@ -34,7 +35,6 @@ object TidepoolPlugin : PluginBase(PluginDescription() .preferencesId(R.xml.pref_tidepool) .description(R.string.description_tidepool) ) { - private val log = LoggerFactory.getLogger(L.TIDEPOOL) private var disposable: CompositeDisposable = CompositeDisposable() @@ -111,6 +111,16 @@ object TidepoolPlugin : PluginBase(PluginDescription() super.onStop() } + override fun preprocessPreferences(preferenceFragment: PreferenceFragment) { + super.preprocessPreferences(preferenceFragment) + + val tidepoolTestLogin = preferenceFragment.findPreference(MainApp.gs(R.string.key_tidepool_test_login)) + tidepoolTestLogin?.setOnPreferenceClickListener { + TidepoolUploader.testLogin(preferenceFragment.getActivity()) + false + } + } + private fun doUpload() = when (TidepoolUploader.connectionStatus) { TidepoolUploader.ConnectionStatus.FAILED -> {} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/ble/data/encoding/Encoding4b6bLoop.java b/app/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/ble/data/encoding/Encoding4b6bLoop.java index 3e551b6ccf..a7b005b9b8 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/ble/data/encoding/Encoding4b6bLoop.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/ble/data/encoding/Encoding4b6bLoop.java @@ -16,6 +16,7 @@ import info.nightscout.androidaps.plugins.pump.common.utils.ByteUtil; */ public class Encoding4b6bLoop extends Encoding4b6bAbstract { + private static final Logger log = LoggerFactory.getLogger(Encoding4b6bLoop.class); public static final Logger LOG = LoggerFactory.getLogger(Encoding4b6bLoop.class); public Map codesRev = null; @@ -108,9 +109,8 @@ public class Encoding4b6bLoop extends Encoding4b6bAbstract { int index2 = ((bitAccumulator >> (availBits - 12)) & 0b111111); hiNibble = codesRev.get((bitAccumulator >> (availBits - 6))); loNibble = codesRev.get(((bitAccumulator >> (availBits - 12)) & 0b111111)); - } catch (Exception ex) { - System.out.println("Exception: " + ex.getMessage()); - ex.printStackTrace(); + } catch (Exception e) { + log.error("Unhandled exception", e); return null; } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/danaR/services/DanaRExecutionService.java b/app/src/main/java/info/nightscout/androidaps/plugins/pump/danaR/services/DanaRExecutionService.java index 0801d8a173..dba3b4ca77 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/danaR/services/DanaRExecutionService.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/danaR/services/DanaRExecutionService.java @@ -383,7 +383,7 @@ public class DanaRExecutionService extends AbstractDanaRExecutionService { try { o.wait(); } catch (InterruptedException e) { - e.printStackTrace(); + log.error("Unhandled exception", e); } } } else { diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/danaRS/DanaRSPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/pump/danaRS/DanaRSPlugin.java index 7b2668d45c..55be88996b 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/danaRS/DanaRSPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/danaRS/DanaRSPlugin.java @@ -5,10 +5,12 @@ import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.os.IBinder; +import android.preference.Preference; import androidx.annotation.Nullable; import androidx.fragment.app.FragmentActivity; +import org.jetbrains.annotations.NotNull; import org.json.JSONException; import org.json.JSONObject; import org.slf4j.Logger; @@ -110,6 +112,14 @@ public class DanaRSPlugin extends PluginBase implements PumpInterface, DanaRInte } } + @Override + public void updatePreferenceSummary(@NotNull Preference pref) { + super.updatePreferenceSummary(pref); + + if (pref.getKey().equals(MainApp.gs(R.string.key_danars_name))) + pref.setSummary(SP.getString(R.string.key_danars_name, "")); + } + @Override protected void onStart() { Context context = MainApp.instance().getApplicationContext(); diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/danaRS/comm/DanaRS_Packet.java b/app/src/main/java/info/nightscout/androidaps/plugins/pump/danaRS/comm/DanaRS_Packet.java index 3d59b34e16..55a2e0c51e 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/danaRS/comm/DanaRS_Packet.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/danaRS/comm/DanaRS_Packet.java @@ -4,11 +4,15 @@ import android.annotation.TargetApi; import android.os.Build; import com.cozmo.danar.util.BleCommandUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.nio.charset.StandardCharsets; import java.util.Date; public class DanaRS_Packet { + private static final Logger log = LoggerFactory.getLogger(DanaRS_Packet.class); + protected static final int TYPE_START = 0; protected static final int OPCODE_START = 1; protected static final int DATA_START = 2; @@ -73,7 +77,7 @@ public class DanaRS_Packet { return ret; } catch (Exception e) { - e.printStackTrace(); + log.error("Unhandled exception", e); } return null; } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/danaRS/services/BLEComm.java b/app/src/main/java/info/nightscout/androidaps/plugins/pump/danaRS/services/BLEComm.java index 8a43d6e35a..253b861811 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/danaRS/services/BLEComm.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/danaRS/services/BLEComm.java @@ -551,7 +551,7 @@ public class BLEComm { break; } } catch (Exception e) { - e.printStackTrace(); + log.error("Unhandled exception", e); } startSignatureFound = false; packetIsValid = false; @@ -635,7 +635,7 @@ public class BLEComm { message.wait(5000); } catch (InterruptedException e) { log.error("sendMessage InterruptedException", e); - e.printStackTrace(); + log.error("Unhandled exception", e); } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/insight/LocalInsightPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/pump/insight/LocalInsightPlugin.java index 7baf9458c9..5104e70fe8 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/insight/LocalInsightPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/insight/LocalInsightPlugin.java @@ -1526,7 +1526,7 @@ public class LocalInsightPlugin extends PluginBase implements PumpInterface, Con data.put("notes", note); NSUpload.uploadCareportalEntryToNS(data); } catch (JSONException e) { - e.printStackTrace(); + log.error("Unhandled exception", e); } } @@ -1554,7 +1554,7 @@ public class LocalInsightPlugin extends PluginBase implements PumpInterface, Con data.put("eventType", event); NSUpload.uploadCareportalEntryToNS(data); } catch (JSONException e) { - e.printStackTrace(); + log.error("Unhandled exception", e); } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/insight/app_layer/history/history_events/HistoryEvent.java b/app/src/main/java/info/nightscout/androidaps/plugins/pump/insight/app_layer/history/history_events/HistoryEvent.java index 874c908ca5..f6b3dc588c 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/insight/app_layer/history/history_events/HistoryEvent.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/insight/app_layer/history/history_events/HistoryEvent.java @@ -3,8 +3,11 @@ package info.nightscout.androidaps.plugins.pump.insight.app_layer.history.histor import info.nightscout.androidaps.plugins.pump.insight.ids.HistoryEventIDs; import info.nightscout.androidaps.plugins.pump.insight.utils.BOCUtil; import info.nightscout.androidaps.plugins.pump.insight.utils.ByteBuf; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class HistoryEvent implements Comparable { + private static final Logger log = LoggerFactory.getLogger(HistoryEvent.class); private int eventYear; private int eventMonth; @@ -22,10 +25,8 @@ public class HistoryEvent implements Comparable { else { try { event = eventClass.newInstance(); - } catch (IllegalAccessException e) { - e.printStackTrace(); - } catch (InstantiationException e) { - e.printStackTrace(); + } catch (IllegalAccessException | InstantiationException e) { + log.error("Unhandled exception", e); } } event.parseHeader(byteBuf); diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/MedtronicPumpPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/MedtronicPumpPlugin.java index 63e8366427..a039185aa1 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/MedtronicPumpPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/MedtronicPumpPlugin.java @@ -48,6 +48,7 @@ import info.nightscout.androidaps.plugins.general.overview.dialogs.ErrorHelperAc import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification; import info.nightscout.androidaps.plugins.general.overview.notifications.Notification; import info.nightscout.androidaps.plugins.pump.common.PumpPluginAbstract; +import info.nightscout.androidaps.plugins.pump.common.bolusInfo.DetailedBolusInfoStorage; import info.nightscout.androidaps.plugins.pump.common.defs.PumpDriverState; import info.nightscout.androidaps.plugins.pump.common.defs.PumpType; import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.RileyLinkConst; @@ -372,7 +373,7 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter refreshAnyStatusThatNeedsToBeRefreshed(); } - RxBus.INSTANCE.send(new EventMedtronicPumpValuesChanged()); + RxBus.INSTANCE.send(new EventMedtronicPumpValuesChanged()); } @@ -386,7 +387,7 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter RileyLinkServiceState rileyLinkServiceState = MedtronicUtil.getServiceState(); - if (rileyLinkServiceState==null) { + if (rileyLinkServiceState == null) { LOG.error("RileyLink unreachable. RileyLinkServiceState is null."); return false; } @@ -744,13 +745,13 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter ClockDTO clock = MedtronicUtil.getPumpTime(); - if (clock==null) { // retry + if (clock == null) { // retry medtronicUIComm.executeCommand(MedtronicCommandType.GetRealTimeClock); clock = MedtronicUtil.getPumpTime(); } - if (clock==null) + if (clock == null) return; int timeDiff = Math.abs(clock.timeDifference); @@ -866,6 +867,11 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter }).start(); } + long now = System.currentTimeMillis(); + + detailedBolusInfo.date = now; + detailedBolusInfo.deliverAt = now; // not sure about that one + TreatmentsPlugin.getPlugin().addToHistoryTreatment(detailedBolusInfo, true); // we subtract insulin, exact amount will be visible with next remainingInsulin update. @@ -877,7 +883,7 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter // calculate time for bolus and set driver to busy for that time int bolusTime = (int) (detailedBolusInfo.insulin * 42.0d); - long time = System.currentTimeMillis() + (bolusTime * 1000); + long time = now + (bolusTime * 1000); this.busyTimestamps.add(time); setEnableCustomAction(MedtronicCustomActionType.ClearBolusBlock, true); @@ -1065,10 +1071,10 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter @Override public PumpEnactResult setTempBasalPercent(Integer percent, Integer durationInMinutes, Profile profile, boolean enforceNew) { - if (percent==0) { + if (percent == 0) { return setTempBasalAbsolute(0.0d, durationInMinutes, profile, enforceNew); } else { - double absoluteValue = profile.getBasal() * (percent /100.0d); + double absoluteValue = profile.getBasal() * (percent / 100.0d); getMDTPumpStatus(); absoluteValue = pumpStatusLocal.pumpType.determineCorrectBasalSize(absoluteValue); LOG.warn("setTempBasalPercent [MedtronicPumpPlugin] - You are trying to use setTempBasalPercent with percent other then 0% (%d). This will start setTempBasalAbsolute, with calculated value (%.3f). Result might not be 100% correct.", percent, absoluteValue); diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/MedtronicPumpHistoryDecoder.java b/app/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/MedtronicPumpHistoryDecoder.java index 32ca320de2..71f387d176 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/MedtronicPumpHistoryDecoder.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/MedtronicPumpHistoryDecoder.java @@ -412,25 +412,18 @@ public class MedtronicPumpHistoryDecoder extends MedtronicHistoryDecoder validEntries; - // private Object validValues; - public PumpHistoryResult(PumpHistoryEntry searchEntry, Long targetDate) { if (searchEntry != null) { /* @@ -109,9 +105,8 @@ public class PumpHistoryResult { if (unprocessedEntry.isAfter(this.searchDate)) { this.validEntries.add(unprocessedEntry); } else { - LOG.debug("PE. PumpHistoryResult. Not after.. Unprocessed Entry [year={},entry={}]", - DateTimeUtil.getYear(unprocessedEntry.atechDateTime), unprocessedEntry); - +// LOG.debug("PE. PumpHistoryResult. Not after.. Unprocessed Entry [year={},entry={}]", +// DateTimeUtil.getYear(unprocessedEntry.atechDateTime), unprocessedEntry); if (DateTimeUtil.getYear(unprocessedEntry.atechDateTime) > 2015) olderEntries++; } @@ -131,14 +126,6 @@ public class PumpHistoryResult { } - private void clearOrPrepareList() { - if (this.validEntries == null) - this.validEntries = new ArrayList<>(); - else - this.validEntries.clear(); - } - - public String toString() { return "PumpHistoryResult [unprocessed=" + (unprocessedEntries != null ? "" + unprocessedEntries.size() : "0") + // ", valid=" + (validEntries != null ? "" + validEntries.size() : "0") + // diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/MedtronicHistoryData.java b/app/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/MedtronicHistoryData.java index 1eed440cdc..2e23d2a955 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/MedtronicHistoryData.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/MedtronicHistoryData.java @@ -49,6 +49,7 @@ import info.nightscout.androidaps.plugins.pump.medtronic.driver.MedtronicPumpSta import info.nightscout.androidaps.plugins.pump.medtronic.util.MedtronicConst; import info.nightscout.androidaps.plugins.pump.medtronic.util.MedtronicUtil; import info.nightscout.androidaps.plugins.treatments.Treatment; +import info.nightscout.androidaps.plugins.treatments.TreatmentService; import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin; import info.nightscout.androidaps.utils.DateUtil; import info.nightscout.androidaps.utils.SP; @@ -67,7 +68,6 @@ import info.nightscout.androidaps.utils.SP; // All things marked with "TODO: Fix db code" needs to be updated in new 2.5 database code public class MedtronicHistoryData { - private static final Logger LOG = LoggerFactory.getLogger(L.PUMP); private List allHistory = null; @@ -77,6 +77,7 @@ public class MedtronicHistoryData { private boolean isInit = false; private Gson gson; + private Gson gsonCore; private DatabaseHelper databaseHelper = MainApp.getDbHelper(); private ClockDTO pumpTime; @@ -94,10 +95,15 @@ public class MedtronicHistoryData { public MedtronicHistoryData() { this.allHistory = new ArrayList<>(); this.gson = MedtronicUtil.gsonInstance; + this.gsonCore = MedtronicUtil.getGsonInstanceCore(); if (this.gson == null) { this.gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create(); } + + if (this.gsonCore == null) { + this.gsonCore = new GsonBuilder().create(); + } } @@ -523,7 +529,7 @@ public class MedtronicHistoryData { data.put("eventType", event); NSUpload.uploadCareportalEntryToNS(data); } catch (JSONException e) { - e.printStackTrace(); + LOG.error("Unhandled exception", e); } } @@ -597,7 +603,7 @@ public class MedtronicHistoryData { if (doubleBolusDebug) LOG.debug("DoubleBolusDebug: List (before filter): {}, FromDb={}", gson.toJson(entryList), - gson.toJson(entriesFromHistory)); + gsonCore.toJson(entriesFromHistory)); filterOutAlreadyAddedEntries(entryList, entriesFromHistory); @@ -609,7 +615,7 @@ public class MedtronicHistoryData { if (doubleBolusDebug) LOG.debug("DoubleBolusDebug: List (after filter): {}, FromDb={}", gson.toJson(entryList), - gson.toJson(entriesFromHistory)); + gsonCore.toJson(entriesFromHistory)); if (isCollectionEmpty(entriesFromHistory)) { for (PumpHistoryEntry treatment : entryList) { @@ -862,6 +868,7 @@ public class MedtronicHistoryData { return; List removeTreatmentsFromHistory = new ArrayList<>(); + List removeTreatmentsFromPH = new ArrayList<>(); for (DbObjectBase treatment : treatmentsFromHistory) { @@ -879,11 +886,17 @@ public class MedtronicHistoryData { if (selectedBolus != null) { entryList.remove(selectedBolus); + removeTreatmentsFromPH.add(selectedBolus); removeTreatmentsFromHistory.add(treatment); } } } + if (doubleBolusDebug) + LOG.debug("DoubleBolusDebug: filterOutAlreadyAddedEntries: PumpHistory={}, Treatments={}", + gson.toJson(removeTreatmentsFromPH), + gsonCore.toJson(removeTreatmentsFromHistory)); + treatmentsFromHistory.removeAll(removeTreatmentsFromHistory); } @@ -947,36 +960,23 @@ public class MedtronicHistoryData { } else { - DetailedBolusInfo detailedBolusInfo = DetailedBolusInfoStorage.INSTANCE.findDetailedBolusInfo(treatment.date, bolusDTO.getDeliveredAmount()); + if (doubleBolusDebug) + LOG.debug("DoubleBolusDebug: addBolus(OldTreatment={}): Bolus={}", treatment, bolusDTO); + + treatment.source = Source.PUMP; + treatment.pumpId = bolus.getPumpId(); + treatment.insulin = bolusDTO.getDeliveredAmount(); + + TreatmentService.UpdateReturn updateReturn = TreatmentsPlugin.getPlugin().getService().createOrUpdateMedtronic(treatment, false); if (doubleBolusDebug) - LOG.debug("DoubleBolusDebug: addBolus(tretament={}): Bolus={}, DetailedBolusInfo={}", treatment, bolusDTO, detailedBolusInfo); - - if (detailedBolusInfo == null) { - detailedBolusInfo = new DetailedBolusInfo(); - - if (doubleBolusDebug) - LOG.debug("DoubleBolusDebug: detailedBolusInfoCouldNotBeRetrived !"); - } - - detailedBolusInfo.date = treatment.date; - detailedBolusInfo.source = Source.PUMP; - detailedBolusInfo.pumpId = bolus.getPumpId(); - detailedBolusInfo.insulin = bolusDTO.getDeliveredAmount(); - detailedBolusInfo.carbs = treatment.carbs; - - addCarbsFromEstimate(detailedBolusInfo, bolus); - - if (doubleBolusDebug) - LOG.debug("DoubleBolusDebug: addBolus(tretament!=null): DetailedBolusInfo(New)={}", detailedBolusInfo); - - boolean newRecord = TreatmentsPlugin.getPlugin().addToHistoryTreatment(detailedBolusInfo, false); - - bolus.setLinkedObject(detailedBolusInfo); + LOG.debug("DoubleBolusDebug: addBolus(tretament!=null): NewTreatment={}, UpdateReturn={}", treatment, updateReturn); if (isLogEnabled()) - LOG.debug("editBolus - [date={},pumpId={}, insulin={}, newRecord={}]", detailedBolusInfo.date, - detailedBolusInfo.pumpId, detailedBolusInfo.insulin, newRecord); + LOG.debug("editBolus - [date={},pumpId={}, insulin={}, newRecord={}]", treatment.date, + treatment.pumpId, treatment.insulin, updateReturn.toString()); + + bolus.setLinkedObject(treatment); } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/util/MedtronicUtil.java b/app/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/util/MedtronicUtil.java index 96bf0a5d44..2c7ee69c2f 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/util/MedtronicUtil.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/util/MedtronicUtil.java @@ -61,8 +61,7 @@ public class MedtronicUtil extends RileyLinkUtil { private static int doneBit = 1 << 7; private static ClockDTO pumpTime; public static Gson gsonInstance = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create(); - public static Gson gsonInstancePretty = new GsonBuilder().excludeFieldsWithoutExposeAnnotation() - .setPrettyPrinting().create(); + public static Gson gsonInstanceCore = new GsonBuilder().create(); private static BatteryType batteryType = BatteryType.None; @@ -70,8 +69,9 @@ public class MedtronicUtil extends RileyLinkUtil { return gsonInstance; } - public static Gson getGsonInstancePretty() { - return gsonInstancePretty; + + public static Gson getGsonInstanceCore() { + return gsonInstanceCore; } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/source/SourceDexcomPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/source/SourceDexcomPlugin.kt index dfbe2fff39..633f16cf10 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/source/SourceDexcomPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/source/SourceDexcomPlugin.kt @@ -17,6 +17,7 @@ import info.nightscout.androidaps.logging.L import info.nightscout.androidaps.plugins.general.nsclient.NSUpload import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.SP +import info.nightscout.androidaps.utils.T import org.json.JSONObject import org.slf4j.LoggerFactory @@ -51,7 +52,7 @@ object SourceDexcomPlugin : PluginBase(PluginDescription() } fun findDexcomPackageName(): String? { - val packageManager = MainApp.instance().packageManager; + val packageManager = MainApp.instance().packageManager for (packageInfo in packageManager.getInstalledPackages(0)) { if (PACKAGE_NAMES.contains(packageInfo.packageName)) return packageInfo.packageName } @@ -64,43 +65,53 @@ object SourceDexcomPlugin : PluginBase(PluginDescription() val sensorType = intent.getStringExtra("sensorType") ?: "" val glucoseValues = intent.getBundleExtra("glucoseValues") for (i in 0 until glucoseValues.size()) { - val glucoseValue = glucoseValues.getBundle(i.toString()) - val bgReading = BgReading() - bgReading.value = glucoseValue!!.getInt("glucoseValue").toDouble() - bgReading.direction = glucoseValue.getString("trendArrow") - bgReading.date = glucoseValue.getLong("timestamp") * 1000 - bgReading.raw = 0.0 - if (MainApp.getDbHelper().createIfNotExists(bgReading, "Dexcom$sensorType")) { - if (SP.getBoolean(R.string.key_dexcomg5_nsupload, false)) { - NSUpload.uploadBg(bgReading, "AndroidAPS-Dexcom$sensorType") - } - if (SP.getBoolean(R.string.key_dexcomg5_xdripupload, false)) { - NSUpload.sendToXdrip(bgReading) + glucoseValues.getBundle(i.toString())?.let { glucoseValue -> + val bgReading = BgReading() + bgReading.value = glucoseValue.getInt("glucoseValue").toDouble() + bgReading.direction = glucoseValue.getString("trendArrow") + bgReading.date = glucoseValue.getLong("timestamp") * 1000 + bgReading.raw = 0.0 + if (MainApp.getDbHelper().createIfNotExists(bgReading, "Dexcom$sensorType")) { + if (SP.getBoolean(R.string.key_dexcomg5_nsupload, false)) { + NSUpload.uploadBg(bgReading, "AndroidAPS-Dexcom$sensorType") + } + if (SP.getBoolean(R.string.key_dexcomg5_xdripupload, false)) { + NSUpload.sendToXdrip(bgReading) + } } } } val meters = intent.getBundleExtra("meters") for (i in 0 until meters.size()) { val meter = meters.getBundle(i.toString()) - val timestamp = meter!!.getLong("timestamp") * 1000 - if (MainApp.getDbHelper().getCareportalEventFromTimestamp(timestamp) != null) continue - val jsonObject = JSONObject() - jsonObject.put("enteredBy", "AndroidAPS-Dexcom$sensorType") - jsonObject.put("created_at", DateUtil.toISOString(timestamp)) - jsonObject.put("eventType", CareportalEvent.BGCHECK) - jsonObject.put("glucoseType", "Finger") - jsonObject.put("glucose", meter.getInt("meterValue")) - jsonObject.put("units", Constants.MGDL) - NSUpload.uploadCareportalEntryToNS(jsonObject) + meter?.let { + val timestamp = it.getLong("timestamp") * 1000 + val now = DateUtil.now() + if (timestamp > now - T.months(1).msecs() && timestamp < now) + if (MainApp.getDbHelper().getCareportalEventFromTimestamp(timestamp) == null) { + val jsonObject = JSONObject() + jsonObject.put("enteredBy", "AndroidAPS-Dexcom$sensorType") + jsonObject.put("created_at", DateUtil.toISOString(timestamp)) + jsonObject.put("eventType", CareportalEvent.BGCHECK) + jsonObject.put("glucoseType", "Finger") + jsonObject.put("glucose", meter.getInt("meterValue")) + jsonObject.put("units", Constants.MGDL) + NSUpload.uploadCareportalEntryToNS(jsonObject) + } + } } if (SP.getBoolean(R.string.key_dexcom_lognssensorchange, false) && intent.hasExtra("sensorInsertionTime")) { - val sensorInsertionTime = intent.extras!!.getLong("sensorInsertionTime") * 1000 - if (MainApp.getDbHelper().getCareportalEventFromTimestamp(sensorInsertionTime) == null) { - val jsonObject = JSONObject() - jsonObject.put("enteredBy", "AndroidAPS-Dexcom$sensorType") - jsonObject.put("created_at", DateUtil.toISOString(sensorInsertionTime)) - jsonObject.put("eventType", CareportalEvent.SENSORCHANGE) - NSUpload.uploadCareportalEntryToNS(jsonObject) + intent.extras?.let { + val sensorInsertionTime = it.getLong("sensorInsertionTime") * 1000 + val now = DateUtil.now() + if (sensorInsertionTime > now - T.months(1).msecs() && sensorInsertionTime < now) + if (MainApp.getDbHelper().getCareportalEventFromTimestamp(sensorInsertionTime) == null) { + val jsonObject = JSONObject() + jsonObject.put("enteredBy", "AndroidAPS-Dexcom$sensorType") + jsonObject.put("created_at", DateUtil.toISOString(sensorInsertionTime)) + jsonObject.put("eventType", CareportalEvent.SENSORCHANGE) + NSUpload.uploadCareportalEntryToNS(jsonObject) + } } } } catch (e: Exception) { diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/TreatmentService.java b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/TreatmentService.java index 7123b6c96b..1331c8eedf 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/TreatmentService.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/TreatmentService.java @@ -133,7 +133,7 @@ public class TreatmentService extends OrmLiteBaseService { try { getDao().executeRaw("ALTER TABLE `" + Treatment.TABLE_TREATMENTS + "` ADD COLUMN boluscalc STRING;"); } catch (SQLException e) { - e.printStackTrace(); + log.error("Unhandled exception", e); } } else { if (L.isEnabled(L.DATATREATMENTS)) @@ -147,7 +147,7 @@ public class TreatmentService extends OrmLiteBaseService { try { getDao().executeRaw("ALTER TABLE `" + Treatment.TABLE_TREATMENTS + "` DROP COLUMN boluscalc STRING;"); } catch (SQLException e) { - e.printStackTrace(); + log.error("Unhandled exception", e); } } } @@ -736,6 +736,14 @@ public class TreatmentService extends OrmLiteBaseService { boolean newRecord; boolean success; + + @Override + public String toString() { + return "UpdateReturn [" + + "newRecord=" + newRecord + + ", success=" + success + + ']'; + } } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/TreatmentsPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/TreatmentsPlugin.java index 28181da190..004f44858d 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/TreatmentsPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/TreatmentsPlugin.java @@ -349,7 +349,7 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface long time = System.currentTimeMillis(); synchronized (treatments) { if (MedtronicHistoryData.doubleBolusDebug) - log.debug("DoubleBolusDebug: AllTreatmentsInDb: {}", MedtronicUtil.getGsonInstance().toJson(treatments)); + log.debug("DoubleBolusDebug: AllTreatmentsInDb: {}", MedtronicUtil.getGsonInstanceCore().toJson(treatments)); for (Treatment t : treatments) { if (t.date <= time && t.date >= fromTimestamp) @@ -357,7 +357,7 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface } if (MedtronicHistoryData.doubleBolusDebug) - log.debug("DoubleBolusDebug: FilteredTreatments: AfterTime={}, Items={}", fromTimestamp, MedtronicUtil.getGsonInstance().toJson(in5minback)); + log.debug("DoubleBolusDebug: FilteredTreatments: AfterTime={}, Items={}", fromTimestamp, MedtronicUtil.getGsonInstanceCore().toJson(in5minback)); return in5minback; } diff --git a/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandSetProfile.java b/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandSetProfile.java index 62e14285eb..b69f3f4dc7 100644 --- a/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandSetProfile.java +++ b/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandSetProfile.java @@ -50,7 +50,7 @@ public class CommandSetProfile extends Command { // Send SMS notification if ProfileSwitch is comming from NS ProfileSwitch profileSwitch = TreatmentsPlugin.getPlugin().getProfileSwitchFromHistory(System.currentTimeMillis()); if (profileSwitch != null && r.enacted && profileSwitch.source == Source.NIGHTSCOUT) { - SmsCommunicatorPlugin smsCommunicatorPlugin = SmsCommunicatorPlugin.getPlugin(); + SmsCommunicatorPlugin smsCommunicatorPlugin = SmsCommunicatorPlugin.INSTANCE; if (smsCommunicatorPlugin.isEnabled(PluginType.GENERAL)) { smsCommunicatorPlugin.sendNotificationToAllNumbers(MainApp.gs(R.string.profile_set_ok)); } diff --git a/app/src/main/java/info/nightscout/androidaps/receivers/ChargingStateReceiver.java b/app/src/main/java/info/nightscout/androidaps/receivers/ChargingStateReceiver.java index 9af15e9ddc..cb49d8cf4e 100644 --- a/app/src/main/java/info/nightscout/androidaps/receivers/ChargingStateReceiver.java +++ b/app/src/main/java/info/nightscout/androidaps/receivers/ChargingStateReceiver.java @@ -21,7 +21,7 @@ public class ChargingStateReceiver extends BroadcastReceiver { lastEvent = event; } - public EventChargingState grabChargingState(Context context) { + public static EventChargingState grabChargingState(Context context) { BatteryManager bm = (BatteryManager) context.getSystemService(Context.BATTERY_SERVICE); if (bm == null) diff --git a/app/src/main/java/info/nightscout/androidaps/receivers/NetworkChangeReceiver.java b/app/src/main/java/info/nightscout/androidaps/receivers/NetworkChangeReceiver.java index 3f12d75fce..19cf12bc8a 100644 --- a/app/src/main/java/info/nightscout/androidaps/receivers/NetworkChangeReceiver.java +++ b/app/src/main/java/info/nightscout/androidaps/receivers/NetworkChangeReceiver.java @@ -26,11 +26,6 @@ public class NetworkChangeReceiver extends BroadcastReceiver { public static final NetworkChangeReceiver instance = new NetworkChangeReceiver(); - // TODO: Split NSClient into network state component that can be used by several plugins and logic for plugin - public static void fetch() { - new NetworkChangeReceiver().grabNetworkStatus(MainApp.instance().getApplicationContext()); - } - @Override public void onReceive(final Context context, final Intent intent) { EventNetworkChange event = grabNetworkStatus(context); @@ -39,7 +34,7 @@ public class NetworkChangeReceiver extends BroadcastReceiver { } @Nullable - public EventNetworkChange grabNetworkStatus(final Context context) { + public static EventNetworkChange grabNetworkStatus(final Context context) { EventNetworkChange event = new EventNetworkChange(); ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); diff --git a/app/src/main/java/info/nightscout/androidaps/services/DataService.java b/app/src/main/java/info/nightscout/androidaps/services/DataService.java index 80a42e145a..44050ece35 100644 --- a/app/src/main/java/info/nightscout/androidaps/services/DataService.java +++ b/app/src/main/java/info/nightscout/androidaps/services/DataService.java @@ -103,7 +103,7 @@ public class DataService extends IntentService { ) { handleNewDataFromNSClient(intent); } else if (Telephony.Sms.Intents.SMS_RECEIVED_ACTION.equals(action)) { - SmsCommunicatorPlugin.getPlugin().handleNewData(intent); + SmsCommunicatorPlugin.INSTANCE.handleNewData(intent); } if (L.isEnabled(L.DATASERVICE)) diff --git a/app/src/main/java/info/nightscout/androidaps/utils/DateUtil.java b/app/src/main/java/info/nightscout/androidaps/utils/DateUtil.java index d592347d1b..98c4d3a071 100644 --- a/app/src/main/java/info/nightscout/androidaps/utils/DateUtil.java +++ b/app/src/main/java/info/nightscout/androidaps/utils/DateUtil.java @@ -93,15 +93,15 @@ public class DateUtil { } public static int toSeconds(String hh_colon_mm) { - Pattern p = Pattern.compile("(\\d+):(\\d+)( a.m.| p.m.| AM | PM|)"); + Pattern p = Pattern.compile("(\\d+):(\\d+)( a.m.| p.m.| AM| PM|AM|PM|)"); Matcher m = p.matcher(hh_colon_mm); int retval = 0; if (m.find()) { retval = SafeParse.stringToInt(m.group(1)) * 60 * 60 + SafeParse.stringToInt(m.group(2)) * 60; - if ((m.group(3).equals(" a.m.") || m.group(3).equals(" AM")) && m.group(1).equals("12")) + if ((m.group(3).equals(" a.m.") || m.group(3).equals(" AM") || m.group(3).equals("AM")) && m.group(1).equals("12")) retval -= 12 * 60 * 60; - if ((m.group(3).equals(" p.m.") || m.group(3).equals(" PM")) && !(m.group(1).equals("12"))) + if ((m.group(3).equals(" p.m.") || m.group(3).equals(" PM") || m.group(3).equals("PM")) && !(m.group(1).equals("12"))) retval += 12 * 60 * 60; } return retval; @@ -185,7 +185,7 @@ public class DateUtil { long remainingTimeMinutes = timeInMillis / (1000 * 60); long remainingTimeHours = remainingTimeMinutes / 60; remainingTimeMinutes = remainingTimeMinutes % 60; - return "(" + ((remainingTimeHours > 0) ? (remainingTimeHours + "h ") : "") + remainingTimeMinutes + "')"; + return "(" + ((remainingTimeHours > 0) ? (remainingTimeHours + MainApp.gs(R.string.shorthour) + " ") : "") + remainingTimeMinutes + "')"; } public static String sinceString(long timestamp) { diff --git a/app/src/main/java/info/nightscout/androidaps/utils/Round.java b/app/src/main/java/info/nightscout/androidaps/utils/Round.java index b8e8d65ce4..bc3c5d8b9c 100644 --- a/app/src/main/java/info/nightscout/androidaps/utils/Round.java +++ b/app/src/main/java/info/nightscout/androidaps/utils/Round.java @@ -1,14 +1,23 @@ package info.nightscout.androidaps.utils; +import java.math.BigDecimal; + /** * Created by mike on 20.06.2016. */ public class Round { public static Double roundTo(double x, Double step) { - if (x != 0d) { - return Math.round(x / step) * step; + if (x == 0d) { + return 0d; } - return 0d; + + //Double oldCalc = Math.round(x / step) * step; + Double newCalc = BigDecimal.valueOf(Math.round(x / step)).multiply(BigDecimal.valueOf(step)).doubleValue(); + + // just for the tests, forcing failures + //newCalc = oldCalc; + + return newCalc; } public static Double floorTo(Double x, Double step) { diff --git a/app/src/main/java/info/nightscout/androidaps/utils/SntpClient.java b/app/src/main/java/info/nightscout/androidaps/utils/SntpClient.java index fcee3638b9..60de82a93c 100644 --- a/app/src/main/java/info/nightscout/androidaps/utils/SntpClient.java +++ b/app/src/main/java/info/nightscout/androidaps/utils/SntpClient.java @@ -16,12 +16,16 @@ package info.nightscout.androidaps.utils; */ import android.os.SystemClock; -import android.util.Log; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; +import info.nightscout.androidaps.logging.L; + /** * {@hide} *

@@ -35,7 +39,7 @@ import java.net.InetAddress; * */ public class SntpClient { - private static final String TAG = "SntpClient"; + private static Logger log = LoggerFactory.getLogger(L.CORE); //private static final int REFERENCE_TIME_OFFSET = 16; private static final int ORIGINATE_TIME_OFFSET = 24; @@ -76,8 +80,10 @@ public class SntpClient { } static void doNtpTime(final Callback callback) { + log.debug("Time detection started"); callback.success = requestTime("time.google.com", 5000); callback.time = getNtpTime() + SystemClock.elapsedRealtime() - getNtpTimeReference(); + log.debug("Time detection ended: " + callback.success + " " + DateUtil.dateAndTimeString(getNtpTime())); callback.run(); } @@ -138,7 +144,7 @@ public class SntpClient { mNtpTimeReference = responseTicks; mRoundTripTime = roundTripTime; } catch (Exception e) { - Log.d(TAG, "request time failed: " + e); + log.debug("request time failed: " + e); return false; } diff --git a/app/src/main/res/layout/objectives_item.xml b/app/src/main/res/layout/objectives_item.xml index 76adaeb015..4379ddddbf 100644 --- a/app/src/main/res/layout/objectives_item.xml +++ b/app/src/main/res/layout/objectives_item.xml @@ -68,11 +68,18 @@ android:text="@string/objectives_button_start" />