From aa9772228310e5ef06471bef863a5925362be455 Mon Sep 17 00:00:00 2001 From: Milos Kozak Date: Sun, 19 Jun 2016 13:17:16 +0200 Subject: [PATCH 1/2] loop & safety fragment --- .../info/nightscout/androidaps/Config.java | 4 + .../nightscout/androidaps/MainActivity.java | 22 +- .../androidaps/Services/DataService.java | 4 + .../nightscout/androidaps/data/Result.java | 47 ++- .../androidaps/db/DatabaseHelper.java | 19 +- .../interfaces/ConstrainsInterface.java | 6 + .../androidaps/interfaces/PluginBase.java | 1 + .../androidaps/interfaces/PumpInterface.java | 2 + .../interfaces/TempBasalsInterface.java | 2 +- .../interfaces/TreatmentsInterface.java | 3 +- .../androidaps/plugins/APSResult.java | 11 +- .../ConfigBuilder/ConfigBuilderFragment.java | 67 +++- .../androidaps/plugins/Loop/LoopFragment.java | 327 ++++++++++++++++++ .../LowSuspend/LowSuspendFragment.java | 106 +++--- .../plugins/LowSuspend/LowSuspendResult.java | 25 -- .../Objectives/ObjectivesFragment.java | 19 + .../OpenAPSMA/DetermineBasalResult.java | 67 +++- .../plugins/OpenAPSMA/OpenAPSMAFragment.java | 104 +++--- .../SafetyFragment/SafetyFragment.java | 197 +++++++++++ .../SimpleProfile/SimpleProfileFragment.java | 21 +- .../TempBasals/TempBasalsFragment.java | 41 +-- .../Dialogs/WizardDialogFragment.java | 8 +- .../Treatments/TreatmentsFragment.java | 49 ++- .../VirtualPump/VirtualPumpFragment.java | 147 +++++--- .../res/layout/configbuilder_fragment.xml | 83 +++-- app/src/main/res/layout/loop_fragment.xml | 136 ++++++++ .../main/res/layout/lowsuspend_fragment.xml | 8 +- .../main/res/layout/openapsma_fragment.xml | 8 +- app/src/main/res/layout/safety_fragment.xml | 161 +++++++++ app/src/main/res/values/colors.xml | 2 + app/src/main/res/values/strings.xml | 24 +- 31 files changed, 1423 insertions(+), 298 deletions(-) create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/Loop/LoopFragment.java delete mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/LowSuspend/LowSuspendResult.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/SafetyFragment/SafetyFragment.java create mode 100644 app/src/main/res/layout/loop_fragment.xml create mode 100644 app/src/main/res/layout/safety_fragment.xml diff --git a/app/src/main/java/info/nightscout/androidaps/Config.java b/app/src/main/java/info/nightscout/androidaps/Config.java index a9538c7572..8c45e9936f 100644 --- a/app/src/main/java/info/nightscout/androidaps/Config.java +++ b/app/src/main/java/info/nightscout/androidaps/Config.java @@ -12,4 +12,8 @@ public class Config { public static final boolean logPumpComm = true; public static final boolean logPrefsChange = true; public static final boolean logConfigBuilder = true; + public static final boolean logConstrainsChnages = true; + + // Developing mode only - never turn on + public static final boolean fakeGlucoseData = true; } diff --git a/app/src/main/java/info/nightscout/androidaps/MainActivity.java b/app/src/main/java/info/nightscout/androidaps/MainActivity.java index f45aa9c0ae..6964cef195 100644 --- a/app/src/main/java/info/nightscout/androidaps/MainActivity.java +++ b/app/src/main/java/info/nightscout/androidaps/MainActivity.java @@ -19,10 +19,12 @@ import java.util.Iterator; import info.nightscout.androidaps.events.EventRefreshGui; import info.nightscout.androidaps.interfaces.PluginBase; import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderFragment; +import info.nightscout.androidaps.plugins.Loop.LoopFragment; import info.nightscout.androidaps.plugins.LowSuspend.LowSuspendFragment; import info.nightscout.androidaps.plugins.NSProfileViewer.NSProfileViewerFragment; import info.nightscout.androidaps.plugins.OpenAPSMA.OpenAPSMAFragment; import info.nightscout.androidaps.plugins.Overview.OverviewFragment; +import info.nightscout.androidaps.plugins.SafetyFragment.SafetyFragment; import info.nightscout.androidaps.plugins.SimpleProfile.SimpleProfileFragment; import info.nightscout.androidaps.plugins.TempBasals.TempBasalsFragment; import info.nightscout.androidaps.plugins.Treatments.TreatmentsFragment; @@ -57,6 +59,7 @@ public class MainActivity extends AppCompatActivity { pluginsList = new ArrayList(); // Register all tabs in app here pluginsList.add(OverviewFragment.newInstance()); + pluginsList.add(LoopFragment.newInstance()); pluginsList.add(VirtualPumpFragment.newInstance()); pluginsList.add(LowSuspendFragment.newInstance()); pluginsList.add(OpenAPSMAFragment.newInstance()); @@ -64,6 +67,7 @@ public class MainActivity extends AppCompatActivity { pluginsList.add(SimpleProfileFragment.newInstance()); pluginsList.add(TreatmentsFragment.newInstance()); pluginsList.add(TempBasalsFragment.newInstance()); + pluginsList.add(SafetyFragment.newInstance()); pluginsList.add(ObjectivesFragment.newInstance()); pluginsList.add(configBuilderFragment = ConfigBuilderFragment.newInstance()); toolbar = (Toolbar) findViewById(R.id.toolbar); @@ -72,8 +76,8 @@ public class MainActivity extends AppCompatActivity { registerBus(); configBuilderFragment.initialize(); - setUpTabs(false); } + setUpTabs(false); } @Subscribe @@ -103,7 +107,23 @@ public class MainActivity extends AppCompatActivity { @Override public boolean onOptionsItemSelected(MenuItem item) { int id = item.getItemId(); + switch (id) { + case R.id.nav_resetdb: + MainApp.getDbHelper().resetDatabases(); + break; + case R.id.nav_exit: + log.debug("Exiting"); + //chancelAlarmManager(); + //MainApp.bus().post(new StopEvent()); + MainApp.closeDbHelper(); + + finish(); + System.runFinalization(); + System.exit(0); + + break; + } return super.onOptionsItemSelected(item); } 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 fc30c242b5..d39cf7eae4 100644 --- a/app/src/main/java/info/nightscout/androidaps/Services/DataService.java +++ b/app/src/main/java/info/nightscout/androidaps/Services/DataService.java @@ -136,6 +136,10 @@ public class DataService extends IntentService { String profile = bundles.getString("profile"); NSProfile nsProfile = new NSProfile(new JSONObject(profile), activeProfile); EventNewBasalProfile event = new EventNewBasalProfile(nsProfile); + if (MainActivity.getConfigBuilder() == null) { + log.error("Config builder not ready on receive profile"); + return; + } PumpInterface pump = MainActivity.getConfigBuilder().getActivePump(); if (pump != null) { pump.setNewBasalProfile(nsProfile); diff --git a/app/src/main/java/info/nightscout/androidaps/data/Result.java b/app/src/main/java/info/nightscout/androidaps/data/Result.java index 8af27791ac..f971096845 100644 --- a/app/src/main/java/info/nightscout/androidaps/data/Result.java +++ b/app/src/main/java/info/nightscout/androidaps/data/Result.java @@ -1,6 +1,9 @@ package info.nightscout.androidaps.data; -public class Result extends Object { +import android.os.Parcel; +import android.os.Parcelable; + +public class Result extends Object implements Parcelable{ public boolean success = false; public boolean enacted = false; public String comment = ""; @@ -13,4 +16,46 @@ public class Result extends Object { public String log() { return "Success: " + success + " Enacted: " + enacted + " Comment: " + comment + " Duration: " + duration + " Absolute: " + absolute + " Percent: " + percent; } + + public String toString() { + return "Success: " + success + "\nEnacted: " + enacted + "\nComment: " + comment + "\nDuration: " + duration + "\nAbsolute: " + absolute; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(success ? 1 : 0); + dest.writeInt(enacted ? 1 : 0); + dest.writeString(comment); + dest.writeInt(duration); + dest.writeDouble(absolute); + dest.writeInt(percent); + } + + public final Parcelable.Creator CREATOR = new Parcelable.Creator() { + public Result createFromParcel(Parcel in) { + return new Result(in); + } + + public Result[] newArray(int size) { + return new Result[size]; + } + }; + + protected Result(Parcel in) { + success = in.readInt() == 1 ? true : false; + enacted = in.readInt() == 1 ? true : false; + duration = in.readInt(); + comment = in.readString(); + absolute = in.readDouble(); + percent = in.readInt(); + + } + + public Result() {} + } diff --git a/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelper.java b/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelper.java index 6da9b48a8b..a5ef1bef47 100644 --- a/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelper.java +++ b/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelper.java @@ -23,8 +23,12 @@ import com.j256.ormlite.table.TableUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import info.nightscout.androidaps.Config; import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.R; +import info.nightscout.androidaps.events.EventNewBG; +import info.nightscout.androidaps.events.EventTempBasalChange; +import info.nightscout.androidaps.events.EventTreatmentChange; public class DatabaseHelper extends OrmLiteSqliteOpenHelper { private static Logger log = LoggerFactory.getLogger(DatabaseHelper.class); @@ -82,6 +86,9 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper { TableUtils.createTableIfNotExists(connectionSource, TempBasal.class); TableUtils.createTableIfNotExists(connectionSource, Treatment.class); TableUtils.createTableIfNotExists(connectionSource, BgReading.class); + MainApp.bus().post(new EventNewBG()); + MainApp.bus().post(new EventTreatmentChange()); + MainApp.bus().post(new EventTempBasalChange()); } catch (SQLException e) { e.printStackTrace(); } @@ -214,6 +221,12 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper { } public GlucoseStatus() {} + + public GlucoseStatus(Double glucose, Double delta, Double avgdelta) { + this.glucose = glucose; + this.delta = delta; + this.avgdelta = avgdelta; + } } @Nullable @@ -232,8 +245,12 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper { int sizeRecords = bgReadings.size(); - if (sizeRecords < 4 || bgReadings.get(sizeRecords - 4).timestamp < new Date().getTime() - 7 * 60 * 1000l) + if (sizeRecords < 4 || bgReadings.get(sizeRecords - 4).timestamp < new Date().getTime() - 7 * 60 * 1000l) { + if (Config.fakeGlucoseData) { + return new GlucoseStatus(Math.random() * 400, (Math. random() - 0.5)* 18, (Math. random() - 0.5)* 18); + } return null; + } int minutes = 5; double change; diff --git a/app/src/main/java/info/nightscout/androidaps/interfaces/ConstrainsInterface.java b/app/src/main/java/info/nightscout/androidaps/interfaces/ConstrainsInterface.java index e7094b7aa2..5e429a7872 100644 --- a/app/src/main/java/info/nightscout/androidaps/interfaces/ConstrainsInterface.java +++ b/app/src/main/java/info/nightscout/androidaps/interfaces/ConstrainsInterface.java @@ -1,7 +1,13 @@ package info.nightscout.androidaps.interfaces; +import info.nightscout.androidaps.plugins.APSResult; + /** * Created by mike on 15.06.2016. */ public interface ConstrainsInterface { + + boolean isAutomaticProcessingEnabled(); + boolean manualConfirmationNeeded(); + APSResult applyBasalConstrains(APSResult result); } 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 36897d0f7d..e4f3b10dcc 100644 --- a/app/src/main/java/info/nightscout/androidaps/interfaces/PluginBase.java +++ b/app/src/main/java/info/nightscout/androidaps/interfaces/PluginBase.java @@ -13,6 +13,7 @@ public interface PluginBase { int APS = 5; int PUMP = 6; int CONSTRAINS = 7; + int LOOP = 8; public int getType(); diff --git a/app/src/main/java/info/nightscout/androidaps/interfaces/PumpInterface.java b/app/src/main/java/info/nightscout/androidaps/interfaces/PumpInterface.java index 5081b8c919..96cbf43570 100644 --- a/app/src/main/java/info/nightscout/androidaps/interfaces/PumpInterface.java +++ b/app/src/main/java/info/nightscout/androidaps/interfaces/PumpInterface.java @@ -3,6 +3,7 @@ package info.nightscout.androidaps.interfaces; import org.json.JSONObject; import info.nightscout.androidaps.data.Result; +import info.nightscout.androidaps.plugins.APSResult; import info.nightscout.client.data.NSProfile; /** @@ -29,6 +30,7 @@ public interface PumpInterface { Result setExtendedBolus(Double insulin, Integer durationInMinutes); Result cancelTempBasal(); Result cancelExtendedBolus(); + Result applyAPSRequest(APSResult request); // Status to be passed to NS JSONObject getJSONStatus(); diff --git a/app/src/main/java/info/nightscout/androidaps/interfaces/TempBasalsInterface.java b/app/src/main/java/info/nightscout/androidaps/interfaces/TempBasalsInterface.java index 3676f0cd7e..d2cceaa78b 100644 --- a/app/src/main/java/info/nightscout/androidaps/interfaces/TempBasalsInterface.java +++ b/app/src/main/java/info/nightscout/androidaps/interfaces/TempBasalsInterface.java @@ -6,6 +6,6 @@ import info.nightscout.androidaps.plugins.OpenAPSMA.IobTotal; * Created by mike on 14.06.2016. */ public interface TempBasalsInterface { - void updateTotalIOBIfNeeded(); + void updateTotalIOB(); IobTotal getLastCalculation(); } diff --git a/app/src/main/java/info/nightscout/androidaps/interfaces/TreatmentsInterface.java b/app/src/main/java/info/nightscout/androidaps/interfaces/TreatmentsInterface.java index f13ff5dad7..215f33eedd 100644 --- a/app/src/main/java/info/nightscout/androidaps/interfaces/TreatmentsInterface.java +++ b/app/src/main/java/info/nightscout/androidaps/interfaces/TreatmentsInterface.java @@ -7,7 +7,8 @@ import info.nightscout.androidaps.plugins.Treatments.TreatmentsFragment; * Created by mike on 14.06.2016. */ public interface TreatmentsInterface { - void updateTotalIOBIfNeeded(); + + void updateTotalIOB(); IobTotal getLastCalculation(); TreatmentsFragment.MealData getMealData(); } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/APSResult.java b/app/src/main/java/info/nightscout/androidaps/plugins/APSResult.java index 80f702883c..c0e31174ee 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/APSResult.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/APSResult.java @@ -57,7 +57,7 @@ public class APSResult implements Parcelable { } }; - private APSResult(Parcel in) { + protected APSResult(Parcel in) { reason = in.readString(); rate = in.readDouble(); duration = in.readInt(); @@ -66,4 +66,13 @@ public class APSResult implements Parcelable { public APSResult() {} + public APSResult clone() { + APSResult newResult = new APSResult(); + newResult.reason = new String(reason); + newResult.rate = rate; + newResult.duration = duration; + newResult.changeRequested = changeRequested; + return newResult; + } + } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/ConfigBuilder/ConfigBuilderFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/ConfigBuilder/ConfigBuilderFragment.java index 9c8ea0d4bb..303a30d1a6 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/ConfigBuilder/ConfigBuilderFragment.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/ConfigBuilder/ConfigBuilderFragment.java @@ -31,12 +31,14 @@ import info.nightscout.androidaps.R; import info.nightscout.androidaps.data.Result; import info.nightscout.androidaps.db.TempBasal; import info.nightscout.androidaps.events.EventRefreshGui; +import info.nightscout.androidaps.interfaces.APSInterface; import info.nightscout.androidaps.interfaces.ConstrainsInterface; import info.nightscout.androidaps.interfaces.PluginBase; import info.nightscout.androidaps.interfaces.ProfileInterface; import info.nightscout.androidaps.interfaces.PumpInterface; import info.nightscout.androidaps.interfaces.TempBasalsInterface; import info.nightscout.androidaps.interfaces.TreatmentsInterface; +import info.nightscout.androidaps.plugins.APSResult; import info.nightscout.androidaps.plugins.TempBasals.TempBasalsFragment; import info.nightscout.androidaps.plugins.Treatments.TreatmentsFragment; import info.nightscout.client.data.NSProfile; @@ -47,6 +49,7 @@ public class ConfigBuilderFragment extends Fragment implements PluginBase, PumpI private static final String PREFS_NAME = "Settings"; ListView pumpListView; + ListView loopListView; ListView treatmentsListView; ListView tempsListView; ListView profileListView; @@ -55,6 +58,7 @@ public class ConfigBuilderFragment extends Fragment implements PluginBase, PumpI ListView generalListView; PluginCustomAdapter pumpDataAdapter = null; + PluginCustomAdapter loopDataAdapter = null; PluginCustomAdapter treatmentsDataAdapter = null; PluginCustomAdapter tempsDataAdapter = null; PluginCustomAdapter profileDataAdapter = null; @@ -99,6 +103,7 @@ public class ConfigBuilderFragment extends Fragment implements PluginBase, PumpI Bundle savedInstanceState) { View view = inflater.inflate(R.layout.configbuilder_fragment, container, false); pumpListView = (ListView) view.findViewById(R.id.configbuilder_pumplistview); + loopListView = (ListView) view.findViewById(R.id.configbuilder_looplistview); treatmentsListView = (ListView) view.findViewById(R.id.configbuilder_treatmentslistview); tempsListView = (ListView) view.findViewById(R.id.configbuilder_tempslistview); profileListView = (ListView) view.findViewById(R.id.configbuilder_profilelistview); @@ -114,6 +119,9 @@ public class ConfigBuilderFragment extends Fragment implements PluginBase, PumpI pumpDataAdapter = new PluginCustomAdapter(getContext(), R.layout.configbuilder_simpleitem, MainActivity.getSpecificPluginsList(PluginBase.PUMP)); pumpListView.setAdapter(pumpDataAdapter); setListViewHeightBasedOnChildren(pumpListView); + loopDataAdapter = new PluginCustomAdapter(getContext(), R.layout.configbuilder_simpleitem, MainActivity.getSpecificPluginsList(PluginBase.LOOP)); + loopListView.setAdapter(loopDataAdapter); + setListViewHeightBasedOnChildren(loopListView); treatmentsDataAdapter = new PluginCustomAdapter(getContext(), R.layout.configbuilder_simpleitem, MainActivity.getSpecificPluginsList(PluginBase.TREATMENT)); treatmentsListView.setAdapter(treatmentsDataAdapter); setListViewHeightBasedOnChildren(treatmentsListView); @@ -263,6 +271,11 @@ public class ConfigBuilderFragment extends Fragment implements PluginBase, PumpI return activePump.cancelExtendedBolus(); } + @Override + public Result applyAPSRequest(APSResult request) { + return activePump.applyAPSRequest(request); + } + @Override public JSONObject getJSONStatus() { return activePump.getJSONStatus(); @@ -392,6 +405,7 @@ public class ConfigBuilderFragment extends Fragment implements PluginBase, PumpI // Single selection allowed case PluginBase.PROFILE: case PluginBase.PUMP: + case PluginBase.LOOP: case PluginBase.TEMPBASAL: case PluginBase.TREATMENT: boolean newSelection = changedPlugin.isEnabled(); @@ -412,7 +426,7 @@ public class ConfigBuilderFragment extends Fragment implements PluginBase, PumpI } private void verifySelectionInCategories() { - for (int category : new int[]{PluginBase.GENERAL, PluginBase.APS, PluginBase.PROFILE, PluginBase.PUMP, PluginBase.TEMPBASAL, PluginBase.TREATMENT}) { + for (int category : new int[]{PluginBase.GENERAL, PluginBase.APS, PluginBase.PROFILE, PluginBase.PUMP, PluginBase.LOOP, PluginBase.TEMPBASAL, PluginBase.TREATMENT}) { ArrayList pluginsInCategory = MainActivity.getSpecificPluginsList(category); switch (category) { // Multiple selection allowed @@ -441,6 +455,16 @@ public class ConfigBuilderFragment extends Fragment implements PluginBase, PumpI } } break; + case PluginBase.LOOP: + PluginBase loop = getTheOneEnabledInArray(pluginsInCategory); + if (Config.logConfigBuilder) + log.debug("Selected loop interface: " + loop.getName()); + for (PluginBase p : pluginsInCategory) { + if (!p.getName().equals(loop.getName())) { + p.setFragmentVisible(false); + } + } + break; case PluginBase.TEMPBASAL: activeTempBasals = (TempBasalsInterface) getTheOneEnabledInArray(pluginsInCategory); if (Config.logConfigBuilder) @@ -535,4 +559,45 @@ public class ConfigBuilderFragment extends Fragment implements PluginBase, PumpI params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1)); listView.setLayoutParams(params); } + + /** + * Constrains interface + **/ + @Override + public boolean isAutomaticProcessingEnabled() { + boolean result = true; + + ArrayList constrainsPlugins = MainActivity.getSpecificPluginsList(PluginBase.CONSTRAINS); + for(PluginBase p: constrainsPlugins) { + ConstrainsInterface constrain = (ConstrainsInterface) p; + if (!p.isEnabled()) continue; + result = result && constrain.isAutomaticProcessingEnabled(); + } + return result; + } + + @Override + public boolean manualConfirmationNeeded() { + boolean result = false; + + ArrayList constrainsPlugins = MainActivity.getSpecificPluginsList(PluginBase.CONSTRAINS); + for(PluginBase p: constrainsPlugins) { + ConstrainsInterface constrain = (ConstrainsInterface) p; + if (!p.isEnabled()) continue; + result = result || constrain.manualConfirmationNeeded(); + } + return result; + } + + @Override + public APSResult applyBasalConstrains(APSResult result) { + ArrayList constrainsPlugins = MainActivity.getSpecificPluginsList(PluginBase.CONSTRAINS); + for(PluginBase p: constrainsPlugins) { + ConstrainsInterface constrain = (ConstrainsInterface) p; + if (!p.isEnabled()) continue; + constrain.applyBasalConstrains(result); + } + return result; + } + } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Loop/LoopFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/Loop/LoopFragment.java new file mode 100644 index 0000000000..e5a277ed6f --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/Loop/LoopFragment.java @@ -0,0 +1,327 @@ +package info.nightscout.androidaps.plugins.Loop; + + +import android.app.Activity; +import android.content.DialogInterface; +import android.os.Bundle; +import android.os.Parcel; +import android.os.Parcelable; +import android.support.v4.app.Fragment; +import android.support.v7.app.AlertDialog; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.WindowManager; +import android.widget.Button; +import android.widget.TextView; + +import com.squareup.otto.Subscribe; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.Date; + +import info.nightscout.androidaps.MainActivity; +import info.nightscout.androidaps.MainApp; +import info.nightscout.androidaps.R; +import info.nightscout.androidaps.data.Result; +import info.nightscout.androidaps.events.EventNewBG; +import info.nightscout.androidaps.events.EventTreatmentChange; +import info.nightscout.androidaps.interfaces.APSInterface; +import info.nightscout.androidaps.interfaces.ConstrainsInterface; +import info.nightscout.androidaps.interfaces.PluginBase; +import info.nightscout.androidaps.interfaces.PumpInterface; +import info.nightscout.androidaps.plugins.APSResult; + +public class LoopFragment extends Fragment implements View.OnClickListener, PluginBase { + private static Logger log = LoggerFactory.getLogger(LoopFragment.class); + + Button runNowButton; + TextView lastRunView; + TextView lastEnactView; + TextView sourceView; + TextView requestView; + TextView constrainsProcessedView; + TextView setByPumpView; + + boolean confirmed; + + class LastRun implements Parcelable { + public APSResult request = null; + public APSResult constrainsProcessed = null; + public Result setByPump = null; + public String source = null; + public Date lastAPSRun = null; + public Date lastEnact = null; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeParcelable(request, 0); + dest.writeParcelable(constrainsProcessed, 0); + dest.writeParcelable(setByPump, 0); + dest.writeString(source); + dest.writeLong(lastAPSRun.getTime()); + dest.writeLong(lastEnact.getTime()); + } + + public final Parcelable.Creator CREATOR = new Parcelable.Creator() { + public LastRun createFromParcel(Parcel in) { + return new LastRun(in); + } + + public LastRun[] newArray(int size) { + return new LastRun[size]; + } + }; + + private LastRun(Parcel in) { + request = in.readParcelable(APSResult.class.getClassLoader()); + constrainsProcessed = in.readParcelable(APSResult.class.getClassLoader()); + setByPump = in.readParcelable(Result.class.getClassLoader()); + source = in.readString(); + lastAPSRun = new Date(in.readLong()); + lastEnact = new Date(in.readLong()); + } + + public LastRun() { + } + } + + static LastRun lastRun = null; + + private boolean fragmentEnabled = false; + private boolean fragmentVisible = true; + + @Override + public int getType() { + return PluginBase.LOOP; + } + + @Override + public String getName() { + return MainApp.instance().getString(R.string.loop); + } + + @Override + public boolean isEnabled() { + return fragmentEnabled; + } + + @Override + public boolean isVisibleInTabs() { + return fragmentVisible; + } + + @Override + public boolean canBeHidden() { + return true; + } + + @Override + public void setFragmentEnabled(boolean fragmentEnabled) { + this.fragmentEnabled = fragmentEnabled; + } + + @Override + public void setFragmentVisible(boolean fragmentVisible) { + this.fragmentVisible = fragmentVisible; + } + + public LoopFragment() { + super(); + registerBus(); + } + + public static LoopFragment newInstance() { + LoopFragment fragment = new LoopFragment(); + return fragment; + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.loop_fragment, container, false); + + lastRunView = (TextView) view.findViewById(R.id.loop_lastrun); + lastEnactView = (TextView) view.findViewById(R.id.loop_lastenact); + sourceView = (TextView) view.findViewById(R.id.loop_source); + requestView = (TextView) view.findViewById(R.id.loop_request); + constrainsProcessedView = (TextView) view.findViewById(R.id.loop_constrainsprocessed); + setByPumpView = (TextView) view.findViewById(R.id.loop_setbypump); + runNowButton = (Button) view.findViewById(R.id.loop_run); + runNowButton.setOnClickListener(this); + + if (savedInstanceState != null) { + lastRun = savedInstanceState.getParcelable("lastrun"); + } + updateGUI(); + return view; + } + + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + outState.putParcelable("lastrun", lastRun); + } + + private void registerBus() { + try { + MainApp.bus().unregister(this); + } catch (RuntimeException x) { + // Ignore + } + MainApp.bus().register(this); + } + + @Override + public void onClick(View view) { + switch (view.getId()) { + case R.id.loop_run: + invoke(); + break; + } + + } + + @Subscribe + public void onStatusEvent(final EventTreatmentChange ev) { + Activity activity = getActivity(); + if (activity != null) + activity.runOnUiThread(new Runnable() { + @Override + public void run() { +// invoke(); + } + }); + else + log.debug("EventTreatmentChange: Activity is null"); + } + + @Subscribe + public void onStatusEvent(final EventNewBG ev) { + ConstrainsInterface constrainsInterface = MainActivity.getConfigBuilder(); + if (constrainsInterface.isAutomaticProcessingEnabled()) { + invoke(); + updateGUI(); + } + } + + private void invoke() { + ConstrainsInterface constrainsInterface = MainActivity.getConfigBuilder(); + PumpInterface pumpInterface = MainActivity.getConfigBuilder().getActivePump(); + APSResult result = null; + + if (constrainsInterface == null || pumpInterface == null) + return; + + APSInterface usedAPS = null; + ArrayList apsPlugins = MainActivity.getSpecificPluginsList(PluginBase.APS); + for (PluginBase p : apsPlugins) { + APSInterface aps = (APSInterface) p; + if (!p.isEnabled()) continue; + aps.invoke(); + result = aps.getLastAPSResult(); + if (result == null) continue; + if (result.changeRequested) { + // APS plugin is requesting change, stop processing + usedAPS = aps; + break; + } + } + + // Check if we have any result + if (result == null) { + clearGUI(); + final Activity activity = getActivity(); + if (activity != null) + activity.runOnUiThread(new Runnable() { + @Override + public void run() { + lastRunView.setText(activity.getString(R.string.noapsselected)); + } + }); + return; + } + + confirmed = false; + if (constrainsInterface.manualConfirmationNeeded()) { + // TODO: user notification here + confirmed = true; + } else { + confirmed = true; + } + + // check rate for constrais + APSResult resultAfterConstrains = result.clone(); + + if (result.changeRequested) { + constrainsInterface.applyBasalConstrains(resultAfterConstrains); + Result applyResult = pumpInterface.applyAPSRequest(resultAfterConstrains); + Date lastEnact = lastRun != null ? lastRun.lastEnact : new Date(0, 0, 0); + lastRun = new LastRun(); + lastRun.request = result; + lastRun.constrainsProcessed = resultAfterConstrains; + lastRun.setByPump = applyResult; + lastRun.source = ((PluginBase) usedAPS).getName(); + lastRun.lastAPSRun = new Date(); + if (applyResult.enacted) + lastRun.lastEnact = lastRun.lastAPSRun; + else + lastRun.lastEnact = lastEnact; + } else { + if (lastRun == null) lastRun = new LastRun(); + lastRun.request = result; + lastRun.constrainsProcessed = resultAfterConstrains; + lastRun.setByPump = null; + lastRun.source = null; + lastRun.lastAPSRun = new Date(); + } + updateGUI(); + } + + void updateGUI() { + Activity activity = getActivity(); + if (activity != null) + activity.runOnUiThread(new Runnable() { + @Override + public void run() { + if (lastRun != null) { + requestView.setText(lastRun.request != null ? lastRun.request.toString() : ""); + constrainsProcessedView.setText(lastRun.constrainsProcessed != null ? lastRun.constrainsProcessed.toString() : ""); + setByPumpView.setText(lastRun.setByPump != null ? lastRun.setByPump.toString() : ""); + sourceView.setText(lastRun.source != null ? lastRun.source.toString() : ""); + lastRunView.setText(lastRun.lastAPSRun != null && lastRun.lastAPSRun.getTime() != 0 ? lastRun.lastAPSRun.toLocaleString() : ""); + lastEnactView.setText(lastRun.lastEnact!= null && lastRun.lastEnact.getTime() != 0 ? lastRun.lastEnact.toLocaleString() : ""); + } + } + }); + } + + void clearGUI() { + Activity activity = getActivity(); + if (activity != null) + activity.runOnUiThread(new Runnable() { + @Override + public void run() { + requestView.setText(""); + constrainsProcessedView.setText(""); + setByPumpView.setText(""); + sourceView.setText(""); + lastRunView.setText(""); + lastEnactView.setText(""); + } + }); + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/LowSuspend/LowSuspendFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/LowSuspend/LowSuspendFragment.java index 1b1733ffbe..c8d08a2dd8 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/LowSuspend/LowSuspendFragment.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/LowSuspend/LowSuspendFragment.java @@ -13,8 +13,6 @@ import android.view.ViewGroup; import android.widget.Button; import android.widget.TextView; -import com.squareup.otto.Subscribe; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -28,12 +26,23 @@ import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.R; import info.nightscout.androidaps.interfaces.PumpInterface; import info.nightscout.androidaps.db.DatabaseHelper; -import info.nightscout.androidaps.events.EventNewBG; import info.nightscout.androidaps.interfaces.APSInterface; import info.nightscout.androidaps.plugins.APSResult; import info.nightscout.androidaps.interfaces.PluginBase; import info.nightscout.client.data.NSProfile; +/** + * LOW SUSPEND ALGORITHM + * + * Define projection as BG + 6 * avgdelta (estimated BG in 30 min) + * + * If BG is bellow low threshold and projection too: set basal rate to 0 U/h if low temp is not running + * else if projection is bellow low threshold: set basal rate to 0 U/h if low temp is not running + * else if exists low temp: cancel it + * else no change + * + */ + public class LowSuspendFragment extends Fragment implements View.OnClickListener, PluginBase, APSInterface { private static Logger log = LoggerFactory.getLogger(LowSuspendFragment.class); @@ -90,7 +99,8 @@ public class LowSuspendFragment extends Fragment implements View.OnClickListener lastAPSResult = in.readParcelable(APSResult.class.getClassLoader()); } - public LastRun() {} + public LastRun() { + } } static LastRun lastRun = null; @@ -124,8 +134,8 @@ public class LowSuspendFragment extends Fragment implements View.OnClickListener } @Override - public void setFragmentEnabled(boolean selected) { - this.fragmentEnabled = selected; + public void setFragmentEnabled(boolean fragmentEnabled) { + this.fragmentEnabled = fragmentEnabled; } @Override @@ -207,20 +217,6 @@ public class LowSuspendFragment extends Fragment implements View.OnClickListener } - @Subscribe - public void onStatusEvent(final EventNewBG ev) { - Activity activity = getActivity(); - if (activity != null) - activity.runOnUiThread(new Runnable() { - @Override - public void run() { - invoke(); - } - }); - else - log.debug("EventNewBG: Activity is null"); - } - @Override public void invoke() { SharedPreferences SP = PreferenceManager.getDefaultSharedPreferences(MainApp.instance().getApplicationContext()); @@ -229,20 +225,20 @@ public class LowSuspendFragment extends Fragment implements View.OnClickListener PumpInterface pump = MainActivity.getConfigBuilder().getActivePump(); if (glucoseStatus == null) { - resultView.setText(getString(R.string.openapsma_noglucosedata)); - if (Config.logAPSResult) log.debug(getString(R.string.openapsma_noglucosedata)); + updateResultGUI(MainApp.instance().getString(R.string.openapsma_noglucosedata)); + if (Config.logAPSResult) log.debug(MainApp.instance().getString(R.string.openapsma_noglucosedata)); return; } if (profile == null) { - resultView.setText(getString(R.string.openapsma_noprofile)); - if (Config.logAPSResult) log.debug(getString(R.string.openapsma_noprofile)); + updateResultGUI(MainApp.instance().getString(R.string.openapsma_noprofile)); + if (Config.logAPSResult) log.debug(MainApp.instance().getString(R.string.openapsma_noprofile)); return; } if (pump == null) { - resultView.setText(getString(R.string.openapsma_nopump)); - if (Config.logAPSResult) log.debug(getString(R.string.openapsma_nopump)); + updateResultGUI(MainApp.instance().getString(R.string.openapsma_nopump)); + if (Config.logAPSResult) log.debug(MainApp.instance().getString(R.string.openapsma_nopump)); return; } @@ -267,29 +263,29 @@ public class LowSuspendFragment extends Fragment implements View.OnClickListener request.changeRequested = true; request.rate = 0d; request.duration = 30; - request.reason = getString(R.string.lowsuspend_lowmessage); + request.reason = MainApp.instance().getString(R.string.lowsuspend_lowmessage); } else { request.changeRequested = false; - request.reason = getString(R.string.nochangerequested); + request.reason = MainApp.instance().getString(R.string.nochangerequested); } } else if (lowProjected) { if (!isTempBasalInProgress || tempBasalRate != 0d) { request.changeRequested = true; request.rate = 0d; request.duration = 30; - request.reason = getString(R.string.lowsuspend_lowprojectedmessage); + request.reason = MainApp.instance().getString(R.string.lowsuspend_lowprojectedmessage); } else { request.changeRequested = false; - request.reason = getString(R.string.nochangerequested); + request.reason = MainApp.instance().getString(R.string.nochangerequested); } - } else if (tempBasalRate == 0d) { + } else if (isTempBasalInProgress && tempBasalRate == 0d) { request.changeRequested = true; request.rate = baseBasalRate; request.duration = 30; - request.reason = getString(R.string.lowsuspend_cancelmessage); + request.reason = MainApp.instance().getString(R.string.lowsuspend_cancelmessage); } else { request.changeRequested = false; - request.reason = getString(R.string.nochangerequested); + request.reason = MainApp.instance().getString(R.string.nochangerequested); } lastRun = new LastRun(); @@ -304,13 +300,41 @@ public class LowSuspendFragment extends Fragment implements View.OnClickListener } void updateGUI() { - if (lastRun != null) { - DecimalFormat formatNumber1decimalplaces = new DecimalFormat("0.0"); - glucoseStatusView.setText(lastRun.lastGlucoseStatus.toString()); - minBgView.setText(formatNumber1decimalplaces.format(lastRun.lastMinBg) + " " + lastRun.lastUnits); - resultView.setText(getString(R.string.lowsuspend_low) + " " + lastRun.lastLow + "\n" + getString(R.string.lowsuspend_lowprojected) + " " + lastRun.lastLowProjected); - requestView.setText(lastRun.lastAPSResult.toString()); - lastRunView.setText(lastRun.lastAPSRun.toLocaleString()); - } + Activity activity = getActivity(); + if (activity != null) + activity.runOnUiThread(new Runnable() { + @Override + public void run() { + if (lastRun != null) { + DecimalFormat formatNumber1decimalplaces = new DecimalFormat("0.0"); + glucoseStatusView.setText(lastRun.lastGlucoseStatus.toString()); + minBgView.setText(formatNumber1decimalplaces.format(lastRun.lastMinBg) + " " + lastRun.lastUnits); + resultView.setText(getString(R.string.lowsuspend_low) + " " + lastRun.lastLow + "\n" + getString(R.string.lowsuspend_lowprojected) + " " + lastRun.lastLowProjected); + requestView.setText(lastRun.lastAPSResult.toString()); + lastRunView.setText(lastRun.lastAPSRun.toLocaleString()); + } + } + }); + else + log.debug("EventNewBG: Activity is null"); + } + + void updateResultGUI(final String text) { + Activity activity = getActivity(); + if (activity != null) + activity.runOnUiThread(new Runnable() { + @Override + public void run() { + if (lastRun != null) { + resultView.setText(text); + glucoseStatusView.setText(""); + minBgView.setText(""); + requestView.setText(""); + lastRunView.setText(""); + } + } + }); + else + log.debug("EventNewBG: Activity is null"); } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/LowSuspend/LowSuspendResult.java b/app/src/main/java/info/nightscout/androidaps/plugins/LowSuspend/LowSuspendResult.java deleted file mode 100644 index d301b735e1..0000000000 --- a/app/src/main/java/info/nightscout/androidaps/plugins/LowSuspend/LowSuspendResult.java +++ /dev/null @@ -1,25 +0,0 @@ -package info.nightscout.androidaps.plugins.LowSuspend; - -import org.json.JSONException; -import org.json.JSONObject; - -public class LowSuspendResult { - public boolean lowProjected; - public boolean low; - public String reason; - - public int percent; - - public JSONObject json() { - JSONObject json = new JSONObject(); - try { - json.put("low", low); - json.put("lowProjected", lowProjected); - json.put("reason", reason); - json.put("percent", percent); - } catch (JSONException e) { - e.printStackTrace(); - } - return json; - } -} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Objectives/ObjectivesFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/Objectives/ObjectivesFragment.java index a85b111486..bfc301dab8 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/Objectives/ObjectivesFragment.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/Objectives/ObjectivesFragment.java @@ -27,6 +27,7 @@ import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.R; import info.nightscout.androidaps.interfaces.ConstrainsInterface; import info.nightscout.androidaps.interfaces.PluginBase; +import info.nightscout.androidaps.plugins.APSResult; public class ObjectivesFragment extends Fragment implements View.OnClickListener, PluginBase, ConstrainsInterface { private static Logger log = LoggerFactory.getLogger(ObjectivesFragment.class); @@ -312,4 +313,22 @@ public class ObjectivesFragment extends Fragment implements View.OnClickListener recyclerView.setAdapter(adapter); } + /** + * Constrains interface + **/ + @Override + public boolean isAutomaticProcessingEnabled() { + return objectives.get(3).started.getTime() > 0; + } + + @Override + public boolean manualConfirmationNeeded() { + return objectives.get(3).started.getTime() < 0; + } + + @Override + public APSResult applyBasalConstrains(APSResult result) { + return result; + } + } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSMA/DetermineBasalResult.java b/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSMA/DetermineBasalResult.java index b7927035a3..c023bad6b5 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSMA/DetermineBasalResult.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSMA/DetermineBasalResult.java @@ -1,7 +1,11 @@ package info.nightscout.androidaps.plugins.OpenAPSMA; +import android.os.Parcel; +import android.os.Parcelable; + import com.eclipsesource.v8.V8Object; +import org.json.JSONException; import org.json.JSONObject; import info.nightscout.androidaps.plugins.APSResult; @@ -9,16 +13,16 @@ import info.nightscout.androidaps.plugins.APSResult; public class DetermineBasalResult extends APSResult { public JSONObject json = new JSONObject(); - public final double eventualBG; - public final double snoozeBG; - public final String mealAssist; + public double eventualBG; + public double snoozeBG; + public String mealAssist; public DetermineBasalResult(V8Object result, JSONObject j) { json = j; reason = result.getString("reason"); eventualBG = result.getDouble("eventualBG"); snoozeBG = result.getDouble("snoozeBG"); - if(result.contains("rate")) { + if (result.contains("rate")) { rate = result.getDouble("rate"); if (rate < 0d) rate = 0d; changeRequested = true; @@ -26,17 +30,68 @@ public class DetermineBasalResult extends APSResult { rate = -1; changeRequested = false; } - if(result.contains("duration")) { + if (result.contains("duration")) { duration = result.getInteger("duration"); changeRequested = changeRequested & true; } else { duration = -1; changeRequested = false; } - if(result.contains("mealAssist")) { + if (result.contains("mealAssist")) { mealAssist = result.getString("mealAssist"); } else mealAssist = ""; result.release(); } + + @Override + public void writeToParcel(Parcel dest, int flags) { + super.writeToParcel(dest, flags); + dest.writeString(json.toString()); + dest.writeDouble(eventualBG); + dest.writeDouble(snoozeBG); + dest.writeString(mealAssist); + } + + public final Parcelable.Creator CREATOR = new Parcelable.Creator() { + public DetermineBasalResult createFromParcel(Parcel in) { + return new DetermineBasalResult(in); + } + + public DetermineBasalResult[] newArray(int size) { + return new DetermineBasalResult[size]; + } + }; + + private DetermineBasalResult(Parcel in) { + super(in); + try { + json = new JSONObject(in.readString()); + } catch (JSONException e) { + e.printStackTrace(); + } + eventualBG = in.readDouble(); + snoozeBG = in.readDouble(); + mealAssist = in.readString(); + } + + public DetermineBasalResult() {} + + @Override + public DetermineBasalResult clone() { + DetermineBasalResult newResult = new DetermineBasalResult(); + newResult.rate = rate; + newResult.duration = duration; + newResult.changeRequested = changeRequested; + + try { + newResult.json = new JSONObject(json.toString()); + } catch (JSONException e) { + e.printStackTrace(); + } + newResult.eventualBG = eventualBG; + newResult.snoozeBG = snoozeBG; + newResult.mealAssist = new String(mealAssist); + return newResult; + } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSMA/OpenAPSMAFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSMA/OpenAPSMAFragment.java index 52337b82bb..60cc70d9f1 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSMA/OpenAPSMAFragment.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSMA/OpenAPSMAFragment.java @@ -13,8 +13,6 @@ import android.view.ViewGroup; import android.widget.Button; import android.widget.TextView; -import com.squareup.otto.Subscribe; - import org.json.JSONException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -27,11 +25,8 @@ import info.nightscout.androidaps.Constants; import info.nightscout.androidaps.MainActivity; import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.R; -import info.nightscout.androidaps.db.TempBasal; import info.nightscout.androidaps.interfaces.PumpInterface; import info.nightscout.androidaps.db.DatabaseHelper; -import info.nightscout.androidaps.events.EventNewBG; -import info.nightscout.androidaps.events.EventTreatmentChange; import info.nightscout.androidaps.interfaces.APSInterface; import info.nightscout.androidaps.interfaces.TempBasalsInterface; import info.nightscout.androidaps.interfaces.TreatmentsInterface; @@ -73,6 +68,7 @@ public class OpenAPSMAFragment extends Fragment implements View.OnClickListener, dest.writeLong(lastAPSRun.getTime()); dest.writeParcelable(lastAPSResult, 0); } + public final Parcelable.Creator CREATOR = new Parcelable.Creator() { public LastRun createFromParcel(Parcel in) { return new LastRun(in); @@ -90,7 +86,8 @@ public class OpenAPSMAFragment extends Fragment implements View.OnClickListener, lastAPSResult = in.readParcelable(APSResult.class.getClassLoader()); } - public LastRun() {} + public LastRun() { + } } LastRun lastRun = null; @@ -140,6 +137,7 @@ public class OpenAPSMAFragment extends Fragment implements View.OnClickListener, @Override public APSResult getLastAPSResult() { + if (lastRun == null) return null; return lastRun.lastAPSResult; } @@ -206,34 +204,6 @@ public class OpenAPSMAFragment extends Fragment implements View.OnClickListener, } - @Subscribe - public void onStatusEvent(final EventTreatmentChange ev) { - Activity activity = getActivity(); - if (activity != null) - activity.runOnUiThread(new Runnable() { - @Override - public void run() { - invoke(); - } - }); - else - log.debug("EventTreatmentChange: Activity is null"); - } - - @Subscribe - public void onStatusEvent(final EventNewBG ev) { - Activity activity = getActivity(); - if (activity != null) - activity.runOnUiThread(new Runnable() { - @Override - public void run() { - invoke(); - } - }); - else - log.debug("EventNewBG: Activity is null"); - } - @Override public void invoke() { DetermineBasalAdapterJS determineBasalAdapterJS = null; @@ -249,20 +219,20 @@ public class OpenAPSMAFragment extends Fragment implements View.OnClickListener, PumpInterface pump = MainActivity.getConfigBuilder().getActivePump(); if (glucoseStatus == null) { - resultView.setText(getString(R.string.openapsma_noglucosedata)); - if (Config.logAPSResult) log.debug(getString(R.string.openapsma_noglucosedata)); + updateResultGUI(MainApp.instance().getString(R.string.openapsma_noglucosedata)); + if (Config.logAPSResult) log.debug(MainApp.instance().getString(R.string.openapsma_noglucosedata)); return; } if (profile == null) { - resultView.setText(getString(R.string.openapsma_noprofile)); - if (Config.logAPSResult) log.debug(getString(R.string.openapsma_noprofile)); + updateResultGUI(MainApp.instance().getString(R.string.openapsma_noprofile)); + if (Config.logAPSResult) log.debug(MainApp.instance().getString(R.string.openapsma_noprofile)); return; } if (pump == null) { - resultView.setText(getString(R.string.openapsma_nopump)); - if (Config.logAPSResult) log.debug(getString(R.string.openapsma_nopump)); + updateResultGUI(getString(R.string.openapsma_nopump)); + if (Config.logAPSResult) log.debug(MainApp.instance().getString(R.string.openapsma_nopump)); return; } @@ -287,8 +257,8 @@ public class OpenAPSMAFragment extends Fragment implements View.OnClickListener, TreatmentsInterface treatments = MainActivity.getConfigBuilder().getActiveTreatments(); TempBasalsInterface tempBasals = MainActivity.getConfigBuilder().getActiveTempBasals(); - treatments.updateTotalIOBIfNeeded(); - tempBasals.updateTotalIOBIfNeeded(); + treatments.updateTotalIOB(); + tempBasals.updateTotalIOB(); IobTotal bolusIob = treatments.getLastCalculation(); IobTotal basalIob = tempBasals.getLastCalculation(); @@ -319,16 +289,46 @@ public class OpenAPSMAFragment extends Fragment implements View.OnClickListener, } void updateGUI() { - if (lastRun != null) { - glucoseStatusView.setText(lastRun.lastDetermineBasalAdapterJS.getGlucoseStatusParam()); - currentTempView.setText(lastRun.lastDetermineBasalAdapterJS.getCurrentTempParam()); - iobDataView.setText(lastRun.lastDetermineBasalAdapterJS.getIobDataParam()); - profileView.setText(lastRun.lastDetermineBasalAdapterJS.getProfileParam()); - mealDataView.setText(lastRun.lastDetermineBasalAdapterJS.getMealDataParam()); - resultView.setText(lastRun.lastAPSResult.json.toString()); - requestView.setText(lastRun.lastAPSResult.toString()); - lastRunView.setText(lastRun.lastAPSRun.toLocaleString()); - } + Activity activity = getActivity(); + if (activity != null) + activity.runOnUiThread(new Runnable() { + @Override + public void run() { + if (lastRun != null) { + glucoseStatusView.setText(lastRun.lastDetermineBasalAdapterJS.getGlucoseStatusParam()); + currentTempView.setText(lastRun.lastDetermineBasalAdapterJS.getCurrentTempParam()); + iobDataView.setText(lastRun.lastDetermineBasalAdapterJS.getIobDataParam()); + profileView.setText(lastRun.lastDetermineBasalAdapterJS.getProfileParam()); + mealDataView.setText(lastRun.lastDetermineBasalAdapterJS.getMealDataParam()); + resultView.setText(lastRun.lastAPSResult.json.toString()); + requestView.setText(lastRun.lastAPSResult.toString()); + lastRunView.setText(lastRun.lastAPSRun.toLocaleString()); + } + } + }); + else + log.debug("EventNewBG: Activity is null"); + } + void updateResultGUI(final String text) { + Activity activity = getActivity(); + if (activity != null) + activity.runOnUiThread(new Runnable() { + @Override + public void run() { + if (lastRun != null) { + resultView.setText(text); + glucoseStatusView.setText(""); + currentTempView.setText(""); + iobDataView.setText(""); + profileView.setText(""); + mealDataView.setText(""); + requestView.setText(""); + lastRunView.setText(""); + } + } + }); + else + log.debug("EventNewBG: Activity is null"); } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/SafetyFragment/SafetyFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/SafetyFragment/SafetyFragment.java new file mode 100644 index 0000000000..7632c77ab7 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/SafetyFragment/SafetyFragment.java @@ -0,0 +1,197 @@ +package info.nightscout.androidaps.plugins.SafetyFragment; + + +import android.content.SharedPreferences; +import android.os.Bundle; +import android.preference.PreferenceFragment; +import android.support.v4.app.Fragment; +import android.text.Editable; +import android.text.TextWatcher; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.EditText; +import android.widget.TextView; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import info.nightscout.androidaps.Config; +import info.nightscout.androidaps.MainActivity; +import info.nightscout.androidaps.MainApp; +import info.nightscout.androidaps.R; +import info.nightscout.androidaps.interfaces.ConstrainsInterface; +import info.nightscout.androidaps.interfaces.PluginBase; +import info.nightscout.androidaps.interfaces.ProfileInterface; +import info.nightscout.androidaps.plugins.APSResult; +import info.nightscout.client.data.NSProfile; + +public class SafetyFragment extends Fragment implements PluginBase, ConstrainsInterface { + private static Logger log = LoggerFactory.getLogger(SafetyFragment.class); + + private static final String PREFS_NAME = "Safety"; + + EditText maxBolusEdit; + EditText maxCarbsEdit; + EditText maxBasalEdit; + EditText maxBasalIOBEdit; + + Double maxBolus; + Double maxCarbs; + Double maxBasal; + Double maxBasalIOB; + + boolean fragmentVisible = true; + + public SafetyFragment() { + super(); + loadSettings(); + } + + @Override + public int getType() { + return PluginBase.CONSTRAINS; + } + + @Override + public String getName() { + return MainApp.instance().getString(R.string.safety); + } + + @Override + public boolean isEnabled() { + return true; + } + + @Override + public boolean isVisibleInTabs() { + return fragmentVisible; + } + + @Override + public boolean canBeHidden() { + return true; + } + + @Override + public void setFragmentEnabled(boolean fragmentEnabled) { + + } + + @Override + public void setFragmentVisible(boolean fragmentVisible) { + this.fragmentVisible = fragmentVisible; + } + + public static SafetyFragment newInstance() { + SafetyFragment fragment = new SafetyFragment(); + return fragment; + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + View layout = inflater.inflate(R.layout.safety_fragment, container, false); + maxBolusEdit = (EditText) layout.findViewById(R.id.safety_maxbolus); + maxCarbsEdit = (EditText) layout.findViewById(R.id.safety_maxcarbs); + maxBasalEdit = (EditText) layout.findViewById(R.id.safety_maxbasal); + maxBasalIOBEdit = (EditText) layout.findViewById(R.id.safety_maxiob); + + maxBolusEdit.setText(maxBolus.toString()); + maxCarbsEdit.setText(maxCarbs.toString()); + maxBasalEdit.setText(maxBasal.toString()); + maxBasalIOBEdit.setText(maxBasalIOB.toString()); + + TextWatcher textWatch = new TextWatcher() { + + @Override + public void afterTextChanged(Editable s) { + } + + @Override + public void beforeTextChanged(CharSequence s, int start, + int count, int after) { + } + + @Override + public void onTextChanged(CharSequence s, int start, + int before, int count) { + try { maxBolus = Double.parseDouble(maxBolusEdit.getText().toString().replace(",", ".")); } catch (Exception e) {}; + try { maxCarbs = Double.parseDouble(maxCarbsEdit.getText().toString().replace(",", ".")); } catch (Exception e) {}; + try { maxBasal = Double.parseDouble(maxBasalEdit.getText().toString().replace(",", ".")); } catch (Exception e) {}; + try { maxBasalIOB = Double.parseDouble(maxBasalIOBEdit.getText().toString().replace(",", ".")); } catch (Exception e) {}; + storeSettings(); + } + }; + maxBolusEdit.addTextChangedListener(textWatch); + maxCarbsEdit.addTextChangedListener(textWatch); + maxBasalEdit.addTextChangedListener(textWatch); + maxBasalIOBEdit.addTextChangedListener(textWatch); + + return layout; + } + + private void storeSettings() { + if (Config.logPrefsChange) + log.debug("Storing settings"); + SharedPreferences settings = MainApp.instance().getApplicationContext().getSharedPreferences(PREFS_NAME, 0); + SharedPreferences.Editor editor = settings.edit(); + editor.putFloat("maxBolus", new Float(maxBolus)); + editor.putFloat("maxCarbs", new Float(maxCarbs)); + editor.putFloat("maxBasal", new Float(maxBasal)); + editor.putFloat("maxBasalIOB", new Float(maxBasalIOB)); + editor.commit(); + } + + private void loadSettings() { + if (Config.logPrefsChange) + log.debug("Loading stored settings"); + SharedPreferences settings = MainApp.instance().getApplicationContext().getSharedPreferences(PREFS_NAME, 0); + + if (settings.contains("maxBolus")) maxBolus = (double) settings.getFloat("maxBolus", 3); else maxBolus = 3d; + if (settings.contains("maxCarbs")) maxCarbs = (double) settings.getFloat("maxCarbs", 48); else maxCarbs = 48d; + if (settings.contains("maxBasal")) maxBasal = (double) settings.getFloat("maxBasal", 1); else maxBasal = 1d; + if (settings.contains("maxBasalIOB")) maxBasalIOB = (double) settings.getFloat("maxBasalIOB", 1); else maxBasalIOB = 1d; + } + + /** + * Constrains interface + **/ + @Override + public boolean isAutomaticProcessingEnabled() { + return true; + } + + @Override + public boolean manualConfirmationNeeded() { + return false; + } + + @Override + public APSResult applyBasalConstrains(APSResult result) { + NSProfile profile = MainActivity.getConfigBuilder().getActiveProfile().getProfile(); + if (result.rate < 0) result.rate = 0; + + Integer maxBasalMult = 4; + Integer maxBasalFromDaily = 3; + // Check percentRate but absolute rate too, because we know real current basal in pump + Double origRate = result.rate; + if (result.rate > maxBasal) { + result.rate = maxBasal; + if (Config.logConstrainsChnages) + log.debug("Limiting rate " + origRate + " by maxBasal to " + result.rate + "U/h"); + } + if (result.rate > maxBasalMult * profile.getBasal(NSProfile.secondsFromMidnight())) { + result.rate = Math.floor(maxBasalMult * profile.getBasal(NSProfile.secondsFromMidnight()) * 100) / 100; + if (Config.logConstrainsChnages) + log.debug("Limiting rate " + origRate + " by maxBasalMult to " + result.rate + "U/h"); + } + if (result.rate > profile.getMaxDailyBasal() * maxBasalFromDaily) { + result.rate = profile.getMaxDailyBasal() * maxBasalFromDaily; + if (Config.logConstrainsChnages) + log.debug("Limiting rate " + origRate + " by 3 * maxDailyBasal to " + result.rate + "U/h"); + } + return result; + } + +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/SimpleProfile/SimpleProfileFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/SimpleProfile/SimpleProfileFragment.java index 20b852b904..0ce100b324 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/SimpleProfile/SimpleProfileFragment.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/SimpleProfile/SimpleProfileFragment.java @@ -4,6 +4,7 @@ package info.nightscout.androidaps.plugins.SimpleProfile; import android.content.SharedPreferences; import android.os.Bundle; import android.support.v4.app.Fragment; +import android.support.v4.app.NotificationCompat; import android.text.Editable; import android.text.TextWatcher; import android.view.LayoutInflater; @@ -98,11 +99,6 @@ public class SimpleProfileFragment extends Fragment implements PluginBase, Profi this.fragmentVisible = fragmentVisible; } - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - } - @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { @@ -160,13 +156,14 @@ public class SimpleProfileFragment extends Fragment implements PluginBase, Profi @Override public void onTextChanged(CharSequence s, int start, int before, int count) { - dia = Double.parseDouble(diaView.getText().toString().replace(",", ".")); - ic = Double.parseDouble(icView.getText().toString().replace(",", ".")); - isf = Double.parseDouble(isfView.getText().toString().replace(",", ".")); - car = Double.parseDouble(carView.getText().toString().replace(",", ".")); - basal = Double.parseDouble(basalView.getText().toString().replace(",", ".")); - targetLow = Double.parseDouble(targetlowView.getText().toString().replace(",", ".")); - targetHigh = Double.parseDouble(targethighView.getText().toString().replace(",", ".")); + try { dia = Double.parseDouble(diaView.getText().toString().replace(",", ".")); } catch (Exception e) {}; + try { ic = Double.parseDouble(icView.getText().toString().replace(",", ".")); } catch (Exception e) {}; + try { isf = Double.parseDouble(isfView.getText().toString().replace(",", ".")); } catch (Exception e) {}; + try { car = Double.parseDouble(carView.getText().toString().replace(",", ".")); } catch (Exception e) {}; + try { basal = Double.parseDouble(basalView.getText().toString().replace(",", ".")); } catch (Exception e) {}; + try { targetLow = Double.parseDouble(targetlowView.getText().toString().replace(",", ".")); } catch (Exception e) {}; + try { targetHigh = Double.parseDouble(targethighView.getText().toString().replace(",", ".")); } catch (Exception e) {}; + storeSettings(); } }; diaView.addTextChangedListener(textWatch); diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/TempBasals/TempBasalsFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/TempBasals/TempBasalsFragment.java index e0c82fe344..ad37cd3ed4 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/TempBasals/TempBasalsFragment.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/TempBasals/TempBasalsFragment.java @@ -56,6 +56,7 @@ public class TempBasalsFragment extends Fragment implements PluginBase, TempBasa boolean fragmentEnabled = true; boolean fragmentVisible = true; + boolean visibleNow = false; @Override public String getName() { @@ -95,7 +96,7 @@ public class TempBasalsFragment extends Fragment implements PluginBase, TempBasa private void initializeData() { try { Dao dao = MainApp.getDbHelper().getDaoTempBasals(); - +/* // **************** TESTING CREATE FAKE RECORD ***************** TempBasal fake = new TempBasal(); fake.timeStart = new Date(new Date().getTime() - 45 * 40 * 1000); @@ -106,7 +107,7 @@ public class TempBasalsFragment extends Fragment implements PluginBase, TempBasa fake.isExtended = false; dao.createOrUpdate(fake); // **************** TESTING CREATE FAKE RECORD ***************** - +*/ QueryBuilder queryBuilder = dao.queryBuilder(); queryBuilder.orderBy("timeIndex", false); queryBuilder.limit(30l); @@ -116,9 +117,6 @@ public class TempBasalsFragment extends Fragment implements PluginBase, TempBasa log.debug(e.getMessage(), e); tempBasals = new ArrayList(); } - if (recyclerView != null) { - recyclerView.swapAdapter(new RecyclerViewAdapter(tempBasals), false); - } } /* @@ -135,7 +133,8 @@ public class TempBasalsFragment extends Fragment implements PluginBase, TempBasa return lastCalculation; } - private void updateTotalIOB() { + @Override + public void updateTotalIOB() { Date now = new Date(); IobTotal total = new IobTotal(); for (Integer pos = 0; pos < tempBasals.size(); pos++) { @@ -230,6 +229,7 @@ public class TempBasalsFragment extends Fragment implements PluginBase, TempBasa super(); registerBus(); initializeData(); + updateGUI(); } public static TempBasalsFragment newInstance() { @@ -271,39 +271,30 @@ public class TempBasalsFragment extends Fragment implements PluginBase, TempBasa @Subscribe public void onStatusEvent(final EventTempBasalChange ev) { - Activity activity = getActivity(); - if (activity != null && recyclerView != null) - activity.runOnUiThread(new Runnable() { - @Override - public void run() { - updateTotalIOB(); - recyclerView.getAdapter().notifyDataSetChanged(); - } - }); - else - log.debug("EventTempBasalChange: Activity is null"); + initializeData(); } - @Subscribe - public void onStatusEvent(final EventNewBG ev) { + public void updateGUI() { Activity activity = getActivity(); - if (activity != null && recyclerView != null) + if (visibleNow && activity != null && recyclerView != null) activity.runOnUiThread(new Runnable() { @Override public void run() { - updateTotalIOB(); - recyclerView.getAdapter().notifyDataSetChanged(); + recyclerView.swapAdapter(new RecyclerViewAdapter(tempBasals), false); } }); - else - log.debug("EventNewBG: Activity is null"); } @Override public void setUserVisibleHint(boolean isVisibleToUser) { super.setUserVisibleHint(isVisibleToUser); - if (isVisibleToUser) + if (isVisibleToUser) { + visibleNow = true; updateTotalIOBIfNeeded(); + updateGUI(); + } else + visibleNow = false; } + } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Treatments/Dialogs/WizardDialogFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/Treatments/Dialogs/WizardDialogFragment.java index bb7280f214..58f251176c 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/Treatments/Dialogs/WizardDialogFragment.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/Treatments/Dialogs/WizardDialogFragment.java @@ -162,8 +162,8 @@ public class WizardDialogFragment extends DialogFragment implements OnClickListe // IOB calculation TreatmentsInterface treatments = MainActivity.getConfigBuilder().getActiveTreatments(); TempBasalsInterface tempBasals = MainActivity.getConfigBuilder().getActiveTempBasals(); - treatments.updateTotalIOBIfNeeded(); - tempBasals.updateTotalIOBIfNeeded(); + treatments.updateTotalIOB(); + tempBasals.updateTotalIOB(); IobTotal bolusIob = treatments.getLastCalculation(); IobTotal basalIob = tempBasals.getLastCalculation(); @@ -229,8 +229,8 @@ public class WizardDialogFragment extends DialogFragment implements OnClickListe // Insulin from IOB TreatmentsInterface treatments = MainActivity.getConfigBuilder().getActiveTreatments(); TempBasalsInterface tempBasals = MainActivity.getConfigBuilder().getActiveTempBasals(); - treatments.updateTotalIOBIfNeeded(); - tempBasals.updateTotalIOBIfNeeded(); + treatments.updateTotalIOB(); + tempBasals.updateTotalIOB(); IobTotal bolusIob = treatments.getLastCalculation(); IobTotal basalIob = tempBasals.getLastCalculation(); diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Treatments/TreatmentsFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/Treatments/TreatmentsFragment.java index 7e0e596ef3..04274d11cf 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/Treatments/TreatmentsFragment.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/Treatments/TreatmentsFragment.java @@ -65,6 +65,7 @@ public class TreatmentsFragment extends Fragment implements View.OnClickListener boolean fragmentEnabled = true; boolean fragmentVisible = true; + boolean visibleNow = false; @Override public String getName() { @@ -113,15 +114,11 @@ public class TreatmentsFragment extends Fragment implements View.OnClickListener log.debug(e.getMessage(), e); treatments = new ArrayList(); } - if (recyclerView != null) { - recyclerView.swapAdapter(new RecyclerViewAdapter(treatments), false); - } } /* * Recalculate IOB if value is older than 1 minute */ - @Override public void updateTotalIOBIfNeeded() { if (lastCalculationTimestamp > new Date().getTime() - 60 * 1000) return; @@ -133,10 +130,11 @@ public class TreatmentsFragment extends Fragment implements View.OnClickListener return lastCalculation; } - private void updateTotalIOB() { + @Override + public void updateTotalIOB() { IobTotal total = new IobTotal(); - if (MainActivity.getConfigBuilder() == null || MainActivity.getConfigBuilder().getActiveProfile() == null) // app not initialized yet + if (MainActivity.getConfigBuilder() == null || MainActivity.getConfigBuilder().getActiveProfile() == null) // app not initialized yet return; NSProfile profile = MainActivity.getConfigBuilder().getActiveProfile().getProfile(); if (profile == null) { @@ -209,7 +207,7 @@ public class TreatmentsFragment extends Fragment implements View.OnClickListener @Override public void onBindViewHolder(TreatmentsViewHolder holder, int position) { - if (MainActivity.getConfigBuilder() == null || MainActivity.getConfigBuilder().getActiveProfile() == null) // app not initialized yet + if (MainActivity.getConfigBuilder() == null || MainActivity.getConfigBuilder().getActiveProfile() == null) // app not initialized yet return; NSProfile profile = MainActivity.getConfigBuilder().getActiveProfile().getProfile(); if (profile == null) @@ -258,6 +256,7 @@ public class TreatmentsFragment extends Fragment implements View.OnClickListener super(); registerBus(); initializeData(); + updateGUI(); } public static TreatmentsFragment newInstance() { @@ -297,17 +296,18 @@ public class TreatmentsFragment extends Fragment implements View.OnClickListener switch (view.getId()) { case R.id.treatments_reshreshfromnightscout: AlertDialog.Builder builder = new AlertDialog.Builder(this.getContext()); - builder.setTitle("Dialog"); - builder.setMessage("Do you want to refresh treatments from Nightscout"); - builder.setPositiveButton("OK", new DialogInterface.OnClickListener() { + builder.setTitle(this.getContext().getString(R.string.dialog)); + builder.setMessage(this.getContext().getString(R.string.refreshfromnightscout)); + builder.setPositiveButton(this.getContext().getString(R.string.ok), new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { MainApp.getDbHelper().resetTreatments(); initializeData(); + updateGUI(); Intent restartNSClient = new Intent(Intents.ACTION_RESTART); MainApp.instance().getApplicationContext().sendBroadcast(restartNSClient); } }); - builder.setNegativeButton("Cancel", null); + builder.setNegativeButton(this.getContext().getString(R.string.cancel), null); builder.show(); break; @@ -325,38 +325,29 @@ public class TreatmentsFragment extends Fragment implements View.OnClickListener @Subscribe public void onStatusEvent(final EventTreatmentChange ev) { - Activity activity = getActivity(); - if (activity != null && recyclerView != null) - activity.runOnUiThread(new Runnable() { - @Override - public void run() { - initializeData(); - } - }); - else - log.debug("EventTreatmentChange: Activity is null"); + initializeData(); } - @Subscribe - public void onStatusEvent(final EventNewBG ev) { + public void updateGUI() { Activity activity = getActivity(); - if (activity != null && recyclerView != null) + if (visibleNow && activity != null && recyclerView != null) activity.runOnUiThread(new Runnable() { @Override public void run() { - updateTotalIOB(); - recyclerView.getAdapter().notifyDataSetChanged(); + recyclerView.swapAdapter(new RecyclerViewAdapter(treatments), false); } }); - else - log.debug("EventNewBG: Activity is null"); } @Override public void setUserVisibleHint(boolean isVisibleToUser) { super.setUserVisibleHint(isVisibleToUser); - if (isVisibleToUser) + if (isVisibleToUser) { + visibleNow = true; updateTotalIOBIfNeeded(); + updateGUI(); + } else + visibleNow = false; } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/VirtualPump/VirtualPumpFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/VirtualPump/VirtualPumpFragment.java index 345e093501..8d3ae3c9db 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/VirtualPump/VirtualPumpFragment.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/VirtualPump/VirtualPumpFragment.java @@ -1,6 +1,7 @@ package info.nightscout.androidaps.plugins.VirtualPump; +import android.app.Activity; import android.os.Bundle; import android.support.v4.app.Fragment; import android.view.LayoutInflater; @@ -28,6 +29,7 @@ import info.nightscout.androidaps.data.Result; import info.nightscout.androidaps.db.TempBasal; import info.nightscout.androidaps.db.Treatment; import info.nightscout.androidaps.interfaces.PluginBase; +import info.nightscout.androidaps.plugins.APSResult; import info.nightscout.client.data.NSProfile; import info.nightscout.utils.DateUtil; @@ -49,6 +51,7 @@ public class VirtualPumpFragment extends Fragment implements PluginBase, PumpInt boolean fragmentEnabled = true; boolean fragmentVisible = true; + boolean visibleNow = false; @Override public String getName() { @@ -89,11 +92,6 @@ public class VirtualPumpFragment extends Fragment implements PluginBase, PumpInt return fragment; } - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - } - @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { @@ -104,48 +102,10 @@ public class VirtualPumpFragment extends Fragment implements PluginBase, PumpInt batteryView = (TextView) view.findViewById(R.id.virtualpump_battery); reservoirView = (TextView) view.findViewById(R.id.virtualpump_reservoir); + updateGUI(); return view; } - public void updateView() { - DateFormat formatDateToJustTime = new SimpleDateFormat("HH:mm"); - DecimalFormat formatNumber2decimalplaces = new DecimalFormat("0.00"); - - checkForExpiredTempsAndExtended(); - - basaBasalRateView.setText(getBaseBasalRate() + "U"); - if (isTempBasalInProgress()) { - if (tempBasal.isAbsolute) { - tempBasalView.setText(formatNumber2decimalplaces.format(tempBasal.absolute) + "U/h @" + - formatDateToJustTime.format(tempBasal.timeStart) + - " " + tempBasal.getRemainingMinutes() + "/" + tempBasal.duration + "min"); - } else { // percent - tempBasalView.setText(tempBasal.percent + "% @" + - formatDateToJustTime.format(tempBasal.timeStart) + - " " + tempBasal.getRemainingMinutes() + "/" + tempBasal.duration + "min"); - } - } else { - tempBasalView.setText(""); - } - if (isExtendedBoluslInProgress()) { - extendedBolusView.setText(formatNumber2decimalplaces.format(extendedBolus.absolute) + "U/h @" + - formatDateToJustTime.format(extendedBolus.timeStart) + - " " + extendedBolus.getRemainingMinutes() + "/" + extendedBolus.duration + "min"); - } else { - extendedBolusView.setText(""); - } - batteryView.setText(getBatteryPercent() + "%"); - reservoirView.setText(getReservoirValue() + "U"); - } - - @Override - public void setUserVisibleHint(boolean isVisibleToUser) { - super.setUserVisibleHint(isVisibleToUser); - - if (isVisibleToUser) - updateView(); - } - void checkForExpiredTempsAndExtended() { long now = new Date().getTime(); if (isTempBasalInProgress()) { @@ -256,7 +216,7 @@ public class VirtualPumpFragment extends Fragment implements PluginBase, PumpInt } if (Config.logPumpComm) log.debug("Delivering treatment: " + t + " " + result); - updateView(); + updateGUI(); return result; } @@ -272,6 +232,7 @@ public class VirtualPumpFragment extends Fragment implements PluginBase, PumpInt tempBasal.absolute = absoluteRate; tempBasal.duration = durationInMinutes; result.success = true; + result.enacted = true; result.comment = getString(R.string.virtualpump_resultok); try { MainApp.instance().getDbHelper().getDaoTempBasals().create(tempBasal); @@ -282,22 +243,26 @@ public class VirtualPumpFragment extends Fragment implements PluginBase, PumpInt } if (Config.logPumpComm) log.debug("Setting temp basal absolute: " + result); - updateView(); + updateGUI(); return result; } @Override public Result setTempBasalPercent(Integer percent, Integer durationInMinutes) { checkForExpiredTempsAndExtended(); - Result result = cancelTempBasal(); - if (!result.success) - return result; + Result result = new Result(); + if (isTempBasalInProgress()) { + result = cancelTempBasal(); + if (!result.success) + return result; + } tempBasal = new TempBasal(); tempBasal.timeStart = new Date(); tempBasal.isAbsolute = false; tempBasal.percent = percent; tempBasal.duration = durationInMinutes; result.success = true; + result.enacted = true; result.comment = getString(R.string.virtualpump_resultok); try { MainApp.instance().getDbHelper().getDaoTempBasals().create(tempBasal); @@ -308,7 +273,7 @@ public class VirtualPumpFragment extends Fragment implements PluginBase, PumpInt } if (Config.logPumpComm) log.debug("Settings temp basal percent: " + result); - updateView(); + updateGUI(); return result; } @@ -324,6 +289,7 @@ public class VirtualPumpFragment extends Fragment implements PluginBase, PumpInt extendedBolus.absolute = insulin * 60d / durationInMinutes; extendedBolus.duration = durationInMinutes; result.success = true; + result.enacted = true; result.comment = getString(R.string.virtualpump_resultok); try { MainApp.instance().getDbHelper().getDaoTempBasals().create(extendedBolus); @@ -334,7 +300,7 @@ public class VirtualPumpFragment extends Fragment implements PluginBase, PumpInt } if (Config.logPumpComm) log.debug("Setting extended bolus: " + result); - updateView(); + updateGUI(); return result; } @@ -353,11 +319,12 @@ public class VirtualPumpFragment extends Fragment implements PluginBase, PumpInt } } result.success = true; + result.enacted = true; result.comment = getString(R.string.virtualpump_resultok); tempBasal = null; if (Config.logPumpComm) log.debug("Canceling temp basal: " + result); - updateView(); + updateGUI(); return result; } @@ -376,14 +343,39 @@ public class VirtualPumpFragment extends Fragment implements PluginBase, PumpInt } } result.success = true; + result.enacted = true; result.comment = getString(R.string.virtualpump_resultok); extendedBolus = null; if (Config.logPumpComm) log.debug("Canceling extended basal: " + result); - updateView(); + updateGUI(); return result; } + @Override + public Result applyAPSRequest(APSResult request) { + if (isTempBasalInProgress()) { + if (request.rate == getTempBasalAbsoluteRate()) { + Result noChange = new Result(); + noChange.enacted = false; + noChange.comment = "Temp basal set correctly"; + noChange.success = true; + return noChange; + } else { + return setTempBasalAbsolute(request.rate, request.duration); + } + } + if (request.rate == getBaseBasalRate()) { + Result noChange = new Result(); + noChange.enacted = false; + noChange.comment = "Basal set correctly"; + noChange.success = true; + return noChange; + } + + return setTempBasalAbsolute(request.rate, request.duration); + } + @Override public JSONObject getJSONStatus() { JSONObject pump = new JSONObject(); @@ -410,4 +402,53 @@ public class VirtualPumpFragment extends Fragment implements PluginBase, PumpInt return pump; } + @Override + public void setUserVisibleHint(boolean isVisibleToUser) { + super.setUserVisibleHint(isVisibleToUser); + + if (isVisibleToUser) { + visibleNow = true; + updateGUI(); + } else + visibleNow = false; + + } + + public void updateGUI() { + checkForExpiredTempsAndExtended(); + Activity activity = getActivity(); + if (activity != null && visibleNow && basaBasalRateView != null) + activity.runOnUiThread(new Runnable() { + @Override + public void run() { + DateFormat formatDateToJustTime = new SimpleDateFormat("HH:mm"); + DecimalFormat formatNumber2decimalplaces = new DecimalFormat("0.00"); + + + basaBasalRateView.setText(getBaseBasalRate() + "U"); + if (isTempBasalInProgress()) { + if (tempBasal.isAbsolute) { + tempBasalView.setText(formatNumber2decimalplaces.format(tempBasal.absolute) + "U/h @" + + formatDateToJustTime.format(tempBasal.timeStart) + + " " + tempBasal.getRemainingMinutes() + "/" + tempBasal.duration + "min"); + } else { // percent + tempBasalView.setText(tempBasal.percent + "% @" + + formatDateToJustTime.format(tempBasal.timeStart) + + " " + tempBasal.getRemainingMinutes() + "/" + tempBasal.duration + "min"); + } + } else { + tempBasalView.setText(""); + } + if (isExtendedBoluslInProgress()) { + extendedBolusView.setText(formatNumber2decimalplaces.format(extendedBolus.absolute) + "U/h @" + + formatDateToJustTime.format(extendedBolus.timeStart) + + " " + extendedBolus.getRemainingMinutes() + "/" + extendedBolus.duration + "min"); + } else { + extendedBolusView.setText(""); + } + batteryView.setText(getBatteryPercent() + "%"); + reservoirView.setText(getReservoirValue() + "U"); + } + }); + } } diff --git a/app/src/main/res/layout/configbuilder_fragment.xml b/app/src/main/res/layout/configbuilder_fragment.xml index 6a603ab526..e40cd070e0 100644 --- a/app/src/main/res/layout/configbuilder_fragment.xml +++ b/app/src/main/res/layout/configbuilder_fragment.xml @@ -16,10 +16,10 @@ + android:textStyle="bold" /> + + android:textStyle="bold" /> - - - - + + + + + + android:textStyle="bold" /> + android:textStyle="bold" /> + + + + + + android:textStyle="bold" /> + android:textStyle="bold" /> + + + + + +