diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 7de867c70c..49d9835d85 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -60,8 +60,9 @@ + android:exported="false" /> + \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/Config.java b/app/src/main/java/info/nightscout/androidaps/Config.java index a9538c7572..20dd4a77bf 100644 --- a/app/src/main/java/info/nightscout/androidaps/Config.java +++ b/app/src/main/java/info/nightscout/androidaps/Config.java @@ -4,6 +4,13 @@ package info.nightscout.androidaps; * Created by mike on 07.06.2016. */ public class Config { + // MAIN FUCTIONALITY + public static final boolean APS = true; + // PLUGINS + public static final boolean LOWSUSPEDENABLED = APS && true; + public static final boolean OPENAPSMAENABLED = APS && true; + public static final boolean LOOPENABLED = APS && true; + public static final boolean detailedLog = true; public static final boolean logFunctionCalls = true; public static final boolean logIncommingBG = true; @@ -12,4 +19,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..8cfc357768 100644 --- a/app/src/main/java/info/nightscout/androidaps/MainActivity.java +++ b/app/src/main/java/info/nightscout/androidaps/MainActivity.java @@ -1,5 +1,6 @@ package info.nightscout.androidaps; +import android.content.Intent; import android.support.v4.app.Fragment; import android.support.v4.view.ViewPager; import android.support.v7.app.AppCompatActivity; @@ -19,10 +20,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; @@ -58,12 +61,17 @@ public class MainActivity extends AppCompatActivity { // Register all tabs in app here pluginsList.add(OverviewFragment.newInstance()); pluginsList.add(VirtualPumpFragment.newInstance()); - pluginsList.add(LowSuspendFragment.newInstance()); - pluginsList.add(OpenAPSMAFragment.newInstance()); + if (Config.LOOPENABLED) + pluginsList.add(LoopFragment.newInstance()); + if (Config.LOWSUSPEDENABLED) + pluginsList.add(LowSuspendFragment.newInstance()); + if (Config.OPENAPSMAENABLED) + pluginsList.add(OpenAPSMAFragment.newInstance()); pluginsList.add(NSProfileViewerFragment.newInstance()); 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 +80,8 @@ public class MainActivity extends AppCompatActivity { registerBus(); configBuilderFragment.initialize(); - setUpTabs(false); } + setUpTabs(false); } @Subscribe @@ -103,7 +111,28 @@ public class MainActivity extends AppCompatActivity { @Override public boolean onOptionsItemSelected(MenuItem item) { int id = item.getItemId(); + switch (id) { + case R.id.nav_preferences: { + Intent i = new Intent(getApplicationContext(), PreferencesActivity.class); + startActivity(i); + break; + } + 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/PreferencesActivity.java b/app/src/main/java/info/nightscout/androidaps/PreferencesActivity.java new file mode 100644 index 0000000000..d8d638af92 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/PreferencesActivity.java @@ -0,0 +1,37 @@ +package info.nightscout.androidaps; + +import android.content.SharedPreferences; +import android.preference.PreferenceActivity; +import android.preference.PreferenceFragment; +import android.preference.PreferenceManager; +import android.support.v7.app.AppCompatActivity; +import android.os.Bundle; + +import info.nightscout.androidaps.events.EventPreferenceChange; + +public class PreferencesActivity extends PreferenceActivity implements SharedPreferences.OnSharedPreferenceChangeListener { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + getFragmentManager().beginTransaction().replace(android.R.id.content, new MyPreferenceFragment()).commit(); + PreferenceManager.getDefaultSharedPreferences(this).registerOnSharedPreferenceChangeListener(this); + } + + @Override + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { + MainApp.bus().post(new EventPreferenceChange()); + } + + public static class MyPreferenceFragment extends PreferenceFragment { + @Override + public void onCreate(final Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + addPreferencesFromResource(R.xml.pref_treatments); + if (Config.OPENAPSMAENABLED) + addPreferencesFromResource(R.xml.pref_openapsma); + if (Config.LOWSUSPEDENABLED) + addPreferencesFromResource(R.xml.pref_lowsuspend); + + } + } +} \ No newline at end of file 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..421775f78f 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); @@ -178,6 +182,7 @@ public class DataService extends IntentService { stored._id = _id; MainApp.getDbHelper().getDaoTreatments().update(stored); } + MainApp.bus().post(new EventTreatmentChange()); return; } else { if (Config.logIncommingData) @@ -192,10 +197,10 @@ public class DataService extends IntentService { MainApp.getDbHelper().getDaoTreatments().create(treatment); if (Config.logIncommingData) log.debug("ADD: Stored treatment: " + treatment.log()); - MainApp.bus().post(new EventTreatmentChange()); } catch (SQLException e) { e.printStackTrace(); } + MainApp.bus().post(new EventTreatmentChange()); } } catch (JSONException e) { @@ -251,10 +256,10 @@ public class DataService extends IntentService { MainApp.getDbHelper().getDaoTreatments().create(treatment); if (Config.logIncommingData) log.debug("CHANGE: Stored treatment: " + treatment.log()); - MainApp.bus().post(new EventTreatmentChange()); } catch (SQLException e) { e.printStackTrace(); } + MainApp.bus().post(new EventTreatmentChange()); } } catch (JSONException e) { 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..28661890fa 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,52 @@ public class Result extends Object { public String log() { return "Success: " + success + " Enacted: " + enacted + " Comment: " + comment + " Duration: " + duration + " Absolute: " + absolute + " Percent: " + percent; } + + public String toString() { + String ret = "Success: " + success; + if (enacted) { + ret += "\nEnacted: " + enacted + "\nComment: " + comment + "\nDuration: " + duration + " min\nAbsolute: " + absolute + " U/h"; + } else { + ret += "\nComment: " + comment; + } + return ret; + } + + @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/db/TempBasal.java b/app/src/main/java/info/nightscout/androidaps/db/TempBasal.java index 071f1b28af..fd1426149a 100644 --- a/app/src/main/java/info/nightscout/androidaps/db/TempBasal.java +++ b/app/src/main/java/info/nightscout/androidaps/db/TempBasal.java @@ -6,6 +6,9 @@ import com.j256.ormlite.table.DatabaseTable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.text.DateFormat; +import java.text.DecimalFormat; +import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import java.util.TimeZone; @@ -183,8 +186,7 @@ public class TempBasal { return (remainingMin < 0) ? 0 : (int) remainingMin; } - @Override - public String toString() { + public String log() { return "TempBasal{" + "timeIndex=" + timeIndex + ", timeStart=" + timeStart + @@ -196,4 +198,20 @@ public class TempBasal { ", isExtended=" + isExtended + '}'; } + + public String toString() { + DateFormat formatDateToJustTime = new SimpleDateFormat("HH:mm"); + DecimalFormat formatNumber2decimalplaces = new DecimalFormat("0.00"); + + if (isAbsolute) { + return formatNumber2decimalplaces.format(absolute) + "U/h @" + + formatDateToJustTime.format(timeStart) + + " " + getRealDuration() + "/" + duration + "min"; + } else { // percent + return percent + "% @" + + formatDateToJustTime.format(timeStart) + + " " + getRealDuration() + "/" + duration + "min"; + } + } + } diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventPreferenceChange.java b/app/src/main/java/info/nightscout/androidaps/events/EventPreferenceChange.java new file mode 100644 index 0000000000..b4b430bb1e --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/events/EventPreferenceChange.java @@ -0,0 +1,7 @@ +package info.nightscout.androidaps.events; + +/** + * Created by mike on 19.06.2016. + */ +public class EventPreferenceChange { +} 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..e64241a1cb 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,8 @@ package info.nightscout.androidaps.interfaces; import org.json.JSONObject; import info.nightscout.androidaps.data.Result; +import info.nightscout.androidaps.db.TempBasal; +import info.nightscout.androidaps.plugins.APSResult; import info.nightscout.client.data.NSProfile; /** @@ -22,6 +24,7 @@ public interface PumpInterface { double getBaseBasalRate(); // base basal rate, not temp basal double getTempBasalAbsoluteRate(); double getTempBasalRemainingMinutes(); + TempBasal getTempBasal(); Result deliverTreatment(Double insulin, Double carbs); Result setTempBasalAbsolute(Double absoluteRate, Integer durationInMinutes); @@ -29,6 +32,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..f3de63c552 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 @@ -2,8 +2,11 @@ package info.nightscout.androidaps.plugins.ConfigBuilder; import android.content.Context; +import android.content.Intent; import android.content.SharedPreferences; +import android.content.pm.ResolveInfo; import android.os.Bundle; +import android.preference.PreferenceManager; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.view.LayoutInflater; @@ -22,24 +25,33 @@ import org.json.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.sql.SQLException; import java.util.ArrayList; +import java.util.Date; +import java.util.List; import info.nightscout.androidaps.Config; import info.nightscout.androidaps.MainActivity; import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.R; +import info.nightscout.androidaps.Services.Intents; import info.nightscout.androidaps.data.Result; import info.nightscout.androidaps.db.TempBasal; +import info.nightscout.androidaps.db.Treatment; import info.nightscout.androidaps.events.EventRefreshGui; +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.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; +import info.nightscout.utils.DateUtil; public class ConfigBuilderFragment extends Fragment implements PluginBase, PumpInterface, ConstrainsInterface { private static Logger log = LoggerFactory.getLogger(ConfigBuilderFragment.class); @@ -47,6 +59,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 +68,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 +113,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 +129,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); @@ -229,10 +247,40 @@ public class ConfigBuilderFragment extends Fragment implements PluginBase, PumpI return activePump.getTempBasalRemainingMinutes(); } + @Override + public TempBasal getTempBasal() { + return activePump.getTempBasal(); + } + @Override public Result deliverTreatment(Double insulin, Double carbs) { - // TODO: constrains here - return activePump.deliverTreatment(insulin, carbs); + SharedPreferences SP = PreferenceManager.getDefaultSharedPreferences(MainApp.instance().getApplicationContext()); + Double maxbolus = Double.parseDouble(SP.getString("treatmentssafety_maxbolus", "3")); + Double maxcarbs = Double.parseDouble(SP.getString("treatmentssafety_maxcarbs", "48")); + + if (insulin > maxbolus || carbs > maxcarbs) { + Result failResult = new Result(); + failResult.success = false; + failResult.comment = MainApp.instance().getString(R.string.constrains_violation); + return failResult; + } + Result result = activePump.deliverTreatment(insulin, carbs); + + if (result.success) { + Treatment t = new Treatment(); + t.insulin = result.bolusDelivered; + t.carbs = carbs; + t.created_at = new Date(); + try { + MainApp.instance().getDbHelper().getDaoTreatments().create(t); + } catch (SQLException e) { + e.printStackTrace(); + } + t.setTimeIndex(t.getTimeIndex()); + t.sendToNSClient(); + MainApp.bus().post(new EventTreatmentChange()); + } + return result; } @Override @@ -255,7 +303,10 @@ public class ConfigBuilderFragment extends Fragment implements PluginBase, PumpI @Override public Result cancelTempBasal() { - return activePump.cancelTempBasal(); + Result result = activePump.cancelTempBasal(); + if (result.enacted) + uploadTempBasalEnd(); + return result; } @Override @@ -263,6 +314,14 @@ public class ConfigBuilderFragment extends Fragment implements PluginBase, PumpI return activePump.cancelExtendedBolus(); } + @Override + public Result applyAPSRequest(APSResult request) { + Result result = activePump.applyAPSRequest(request); + if (result.enacted) + uploadTempBasalStart(result.absolute, result.duration); + return result; + } + @Override public JSONObject getJSONStatus() { return activePump.getJSONStatus(); @@ -392,6 +451,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 +472,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 +501,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 +605,99 @@ 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; + } + + public static void uploadTempBasalStart(Double absolute, double durationInMinutes) { + try { + //SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(MainApp.instance().getApplicationContext()); + //boolean useAbsoluteForUpload = sp.getBoolean("ns_sync_use_absolute", false); + + Context context = MainApp.instance().getApplicationContext(); + JSONObject data = new JSONObject(); + data.put("eventType", "Temp Basal"); + data.put("duration", durationInMinutes); + //if (useAbsoluteForUpload && absolute != null) + data.put("absolute", absolute); + //else + // data.put("percent", percent - 100); + data.put("created_at", DateUtil.toISOString(new Date())); + data.put("enteredBy", MainApp.instance().getString(R.string.app_name)); + Bundle bundle = new Bundle(); + bundle.putString("action", "dbAdd"); + bundle.putString("collection", "treatments"); + bundle.putString("data", data.toString()); + Intent intent = new Intent(Intents.ACTION_DATABASE); + intent.putExtras(bundle); + intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES); + context.sendBroadcast(intent); + List q = context.getPackageManager().queryBroadcastReceivers(intent, 0); + if (q.size() < 1) { + log.error("DBADD No receivers"); + } else log.debug("DBADD dbAdd " + q.size() + " receivers " + data.toString()); + } catch (JSONException e) { + } + } + + public static void uploadTempBasalEnd() { + try { + Context context = MainApp.instance().getApplicationContext(); + JSONObject data = new JSONObject(); + data.put("eventType", "Temp Basal"); + data.put("created_at", DateUtil.toISOString(new Date())); + data.put("enteredBy", MainApp.instance().getString(R.string.app_name)); + Bundle bundle = new Bundle(); + bundle.putString("action", "dbAdd"); + bundle.putString("collection", "treatments"); + bundle.putString("data", data.toString()); + Intent intent = new Intent(Intents.ACTION_DATABASE); + intent.putExtras(bundle); + intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES); + context.sendBroadcast(intent); + List q = context.getPackageManager().queryBroadcastReceivers(intent, 0); + if (q.size() < 1) { + log.error("DBADD No receivers"); + } else log.debug("DBADD dbAdd " + q.size() + " receivers " + data.toString()); + } catch (JSONException e) { + } + } + } 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..5ab9eb5501 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/Loop/LoopFragment.java @@ -0,0 +1,326 @@ +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.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 || !isEnabled()) + 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..2f920d84e2 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,22 @@ 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 +98,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 +133,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 +216,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()); @@ -228,21 +223,31 @@ public class LowSuspendFragment extends Fragment implements View.OnClickListener NSProfile profile = MainActivity.getConfigBuilder().getActiveProfile().getProfile(); PumpInterface pump = MainActivity.getConfigBuilder().getActivePump(); + if (!isEnabled()) { + updateResultGUI(MainApp.instance().getString(R.string.openapsma_disabled)); + if (Config.logAPSResult) + log.debug(MainApp.instance().getString(R.string.openapsma_disabled)); + return; + } + 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; } @@ -251,7 +256,7 @@ public class LowSuspendFragment extends Fragment implements View.OnClickListener minBgDefault = "5"; } - double minBg = NSProfile.toMgdl(Double.parseDouble(SP.getString("min_bg", minBgDefault).replace(",", ".")), profile.getUnits()); + double minBg = NSProfile.toMgdl(Double.parseDouble(SP.getString("lowsuspend_lowthreshold", minBgDefault).replace(",", ".")), profile.getUnits()); boolean lowProjected = (glucoseStatus.glucose + 6.0 * glucoseStatus.avgdelta) < minBg; boolean low = glucoseStatus.glucose < minBg; @@ -267,29 +272,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 +309,37 @@ 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() { + resultView.setText(text); + glucoseStatusView.setText(""); + minBgView.setText(""); + requestView.setText(""); + lastRunView.setText(""); + } + }); } } 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..bdae0f057c 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; @@ -248,21 +218,31 @@ public class OpenAPSMAFragment extends Fragment implements View.OnClickListener, NSProfile profile = MainActivity.getConfigBuilder().getActiveProfile().getProfile(); PumpInterface pump = MainActivity.getConfigBuilder().getActivePump(); + if (!isEnabled()) { + updateResultGUI(MainApp.instance().getString(R.string.openapsma_disabled)); + if (Config.logAPSResult) + log.debug(MainApp.instance().getString(R.string.openapsma_disabled)); + return; + } + 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; } @@ -278,17 +258,15 @@ public class OpenAPSMAFragment extends Fragment implements View.OnClickListener, Date now = new Date(); - // TODO: objectives limits - double maxIob = Double.parseDouble(SP.getString("max_iob", "1.5").replace(",", ".")); - double maxBasal = Double.parseDouble(SP.getString("max_basal", "1").replace(",", ".")); - // TODO: min_bg, max_bg in prefs - double minBg = NSProfile.toMgdl(Double.parseDouble(SP.getString("min_bg", minBgDefault).replace(",", ".")), units); - double maxBg = NSProfile.toMgdl(Double.parseDouble(SP.getString("max_bg", maxBgDefault).replace(",", ".")), units); + double maxIob = Double.parseDouble(SP.getString("openapsma_max_iob", "1.5").replace(",", ".")); + double maxBasal = Double.parseDouble(SP.getString("openapsma_max_basal", "1").replace(",", ".")); + double minBg = NSProfile.toMgdl(Double.parseDouble(SP.getString("openapsma_min_bg", minBgDefault).replace(",", ".")), units); + double maxBg = NSProfile.toMgdl(Double.parseDouble(SP.getString("openapsma_max_bg", maxBgDefault).replace(",", ".")), units); 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 +297,40 @@ 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()); + } + } + }); + } + void updateResultGUI(final String text) { + Activity activity = getActivity(); + if (activity != null) + activity.runOnUiThread(new Runnable() { + @Override + public void run() { + resultView.setText(text); + glucoseStatusView.setText(""); + currentTempView.setText(""); + iobDataView.setText(""); + profileView.setText(""); + mealDataView.setText(""); + requestView.setText(""); + lastRunView.setText(""); + } + }); } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Treatments/Dialogs/NewTreatmentDialogFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/Overview/Dialogs/NewTreatmentDialogFragment.java similarity index 71% rename from app/src/main/java/info/nightscout/androidaps/plugins/Treatments/Dialogs/NewTreatmentDialogFragment.java rename to app/src/main/java/info/nightscout/androidaps/plugins/Overview/Dialogs/NewTreatmentDialogFragment.java index ac5bbb336d..23439b4c42 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/Treatments/Dialogs/NewTreatmentDialogFragment.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/Overview/Dialogs/NewTreatmentDialogFragment.java @@ -1,10 +1,12 @@ -package info.nightscout.androidaps.plugins.Treatments.Dialogs; +package info.nightscout.androidaps.plugins.Overview.Dialogs; -import android.app.Activity; -import android.app.DialogFragment; +import android.content.DialogInterface; +import android.content.Intent; import android.content.SharedPreferences; import android.os.Bundle; import android.preference.PreferenceManager; +import android.support.v4.app.DialogFragment; +import android.support.v7.app.AlertDialog; import android.view.*; import android.view.View.OnClickListener; import android.widget.Button; @@ -13,6 +15,8 @@ import android.widget.TextView; import info.nightscout.androidaps.MainActivity; import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.R; +import info.nightscout.androidaps.Services.Intents; +import info.nightscout.androidaps.data.Result; public class NewTreatmentDialogFragment extends DialogFragment implements OnClickListener { @@ -41,8 +45,8 @@ public class NewTreatmentDialogFragment extends DialogFragment implements OnClic switch (view.getId()) { case R.id.treatments_newtreatment_deliverbutton: SharedPreferences SP = PreferenceManager.getDefaultSharedPreferences(MainApp.instance().getApplicationContext()); - Double maxbolus = Double.parseDouble(SP.getString("safety_maxbolus", "3")); - Double maxcarbs = Double.parseDouble(SP.getString("safety_maxcarbs", "48")); + Double maxbolus = Double.parseDouble(SP.getString("treatmentssafety_maxbolus", "3")); + Double maxcarbs = Double.parseDouble(SP.getString("treatmentssafety_maxcarbs", "48")); String insulinText = this.insulin.getText().toString().replace(",", "."); @@ -55,7 +59,15 @@ public class NewTreatmentDialogFragment extends DialogFragment implements OnClic this.carbs.setText(""); } else if (insulin > 0d || carbs > 0d) { dismiss(); - MainActivity.getConfigBuilder().getActivePump().deliverTreatment(insulin, carbs); + Result result = MainActivity.getConfigBuilder().getActivePump().deliverTreatment(insulin, carbs); + if (!result.success) { + AlertDialog.Builder builder = new AlertDialog.Builder(this.getContext()); + builder.setTitle(this.getContext().getString(R.string.bolusdeliveryerror)); + builder.setMessage(result.comment); + builder.setPositiveButton(this.getContext().getString(R.string.ok), null); + builder.show(); + + } } break; } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Treatments/Dialogs/WizardDialogFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/Overview/Dialogs/WizardDialogFragment.java similarity index 91% rename from app/src/main/java/info/nightscout/androidaps/plugins/Treatments/Dialogs/WizardDialogFragment.java rename to app/src/main/java/info/nightscout/androidaps/plugins/Overview/Dialogs/WizardDialogFragment.java index bb7280f214..6188808545 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/Treatments/Dialogs/WizardDialogFragment.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/Overview/Dialogs/WizardDialogFragment.java @@ -1,10 +1,9 @@ -package info.nightscout.androidaps.plugins.Treatments.Dialogs; +package info.nightscout.androidaps.plugins.Overview.Dialogs; -import android.app.Activity; -import android.app.DialogFragment; import android.content.SharedPreferences; import android.os.Bundle; import android.preference.PreferenceManager; +import android.support.v4.app.DialogFragment; import android.text.Editable; import android.text.TextWatcher; import android.view.*; @@ -15,19 +14,15 @@ import android.widget.CompoundButton; import android.widget.TextView; import java.text.DecimalFormat; -import java.util.Date; import info.nightscout.androidaps.Constants; import info.nightscout.androidaps.MainActivity; import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.R; -import info.nightscout.androidaps.data.Iob; import info.nightscout.androidaps.db.BgReading; -import info.nightscout.androidaps.db.Treatment; import info.nightscout.androidaps.interfaces.TempBasalsInterface; import info.nightscout.androidaps.interfaces.TreatmentsInterface; import info.nightscout.androidaps.plugins.OpenAPSMA.IobTotal; -import info.nightscout.androidaps.plugins.Treatments.TreatmentsFragment; import info.nightscout.client.data.NSProfile; import info.nightscout.utils.*; @@ -123,8 +118,6 @@ public class WizardDialogFragment extends DialogFragment implements OnClickListe } private void initDialog() { - SharedPreferences SP = PreferenceManager.getDefaultSharedPreferences(MainApp.instance().getApplicationContext()); - String units = SP.getString("ns_units", Constants.MGDL); NSProfile profile = MainActivity.getConfigBuilder().getActiveProfile().getProfile(); if (profile == null) { @@ -133,6 +126,7 @@ public class WizardDialogFragment extends DialogFragment implements OnClickListe return; } + String units = profile.getUnits(); bgUnits.setText(units); // Set BG if not old @@ -162,8 +156,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(); @@ -177,9 +171,8 @@ public class WizardDialogFragment extends DialogFragment implements OnClickListe private void calculateInsulin() { SharedPreferences SP = PreferenceManager.getDefaultSharedPreferences(MainApp.instance().getApplicationContext()); - Double maxbolus = Double.parseDouble(SP.getString("safety_maxbolus", "3")); - Double maxcarbs = Double.parseDouble(SP.getString("safety_maxcarbs", "48")); - String units = SP.getString("ns_units", Constants.MGDL); + Double maxbolus = Double.parseDouble(SP.getString("treatmentssafety_maxbolus", "3")); + Double maxcarbs = Double.parseDouble(SP.getString("treatmentssafety_maxcarbs", "48")); NSProfile profile = MainActivity.getConfigBuilder().getActiveProfile().getProfile(); @@ -229,8 +222,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(); @@ -268,11 +261,6 @@ public class WizardDialogFragment extends DialogFragment implements OnClickListe } } - private double fromMgdl(Double value, String units) { - if (units.equals(Constants.MGDL)) return value; - else return value / 18; - } - private Double roundTo(Double x, Double step) { if (x != 0d) { return Math.round(x / step) * step; diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Overview/OverviewFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/Overview/OverviewFragment.java index 11388091a0..b090788f0d 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/Overview/OverviewFragment.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/Overview/OverviewFragment.java @@ -6,9 +6,12 @@ import android.graphics.Paint; import android.os.Bundle; import android.os.Handler; import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentManager; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.Button; +import android.widget.LinearLayout; import android.widget.TextView; import com.jjoe64.graphview.GraphView; @@ -32,9 +35,13 @@ import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.R; import info.nightscout.androidaps.db.BgReading; import info.nightscout.androidaps.db.DatabaseHelper; +import info.nightscout.androidaps.db.TempBasal; import info.nightscout.androidaps.events.EventNewBG; import info.nightscout.androidaps.events.EventTempBasalChange; import info.nightscout.androidaps.interfaces.PluginBase; +import info.nightscout.androidaps.interfaces.PumpInterface; +import info.nightscout.androidaps.plugins.Overview.Dialogs.NewTreatmentDialogFragment; +import info.nightscout.androidaps.plugins.Overview.Dialogs.WizardDialogFragment; import info.nightscout.client.data.NSProfile; @@ -46,6 +53,10 @@ public class OverviewFragment extends Fragment implements PluginBase { TextView deltaView; GraphView bgGraph; + Button cancelTempButton; + Button treatmentButton; + Button wizardButton; + boolean visibleNow = false; Handler loopHandler = new Handler(); Runnable refreshLoop = null; @@ -108,7 +119,7 @@ public class OverviewFragment extends Fragment implements PluginBase { activity.runOnUiThread(new Runnable() { @Override public void run() { - updateData(); + updateGUI(); } }); } @@ -127,8 +138,39 @@ public class OverviewFragment extends Fragment implements PluginBase { timeAgoView = (TextView) view.findViewById(R.id.overview_timeago); deltaView = (TextView) view.findViewById(R.id.overview_delta); bgGraph = (GraphView) view.findViewById(R.id.overview_bggraph); + cancelTempButton = (Button) view.findViewById(R.id.overview_canceltemp); + treatmentButton = (Button) view.findViewById(R.id.overview_treatment); + wizardButton = (Button) view.findViewById(R.id.overview_wizard); - updateData(); + treatmentButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + FragmentManager manager = getFragmentManager(); + NewTreatmentDialogFragment treatmentDialogFragment = new NewTreatmentDialogFragment(); + treatmentDialogFragment.show(manager, "TreatmentDialog"); + } + }); + + wizardButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + FragmentManager manager = getFragmentManager(); + WizardDialogFragment wizardDialogFragment = new WizardDialogFragment(); + wizardDialogFragment.show(manager, "WizardDialog"); + } + }); + + cancelTempButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + PumpInterface pump = MainActivity.getConfigBuilder().getActivePump(); + if (pump.isTempBasalInProgress()) { + pump.cancelTempBasal(); + MainApp.bus().post(new EventTempBasalChange()); + } + } + }); + updateGUI(); return view; } @@ -141,7 +183,47 @@ public class OverviewFragment extends Fragment implements PluginBase { MainApp.bus().register(this); } - public void updateData() { + @Subscribe + public void onStatusEvent(final EventTempBasalChange ev) { + Activity activity = getActivity(); + if (activity != null) + activity.runOnUiThread(new Runnable() { + @Override + public void run() { + updateGUI(); + } + }); + else + log.debug("EventTempBasalChange: Activity is null"); + } + + @Subscribe + public void onStatusEvent(final EventNewBG ev) { + Activity activity = getActivity(); + if (activity != null) + activity.runOnUiThread(new Runnable() { + @Override + public void run() { + updateGUI(); + } + }); + else + log.debug("EventNewBG: Activity is null"); + } + + @Override + public void setUserVisibleHint(boolean isVisibleToUser) { + super.setUserVisibleHint(isVisibleToUser); + + if (isVisibleToUser) { + updateGUI(); + visibleNow = true; + } else { + visibleNow = false; + } + } + + public void updateGUI() { BgReading actualBG = MainApp.getDbHelper().actualBg(); BgReading lastBG = MainApp.getDbHelper().lastBg(); if (MainActivity.getConfigBuilder() == null || MainActivity.getConfigBuilder().getActiveProfile() == null) // app not initialized yet @@ -156,6 +238,17 @@ public class OverviewFragment extends Fragment implements PluginBase { if (bgGraph == null) return; + // **** Temp button **** + PumpInterface pump = MainActivity.getConfigBuilder().getActivePump(); + + if (pump.isTempBasalInProgress()) { + TempBasal activeTemp = pump.getTempBasal(); + cancelTempButton.setVisibility(View.VISIBLE); + cancelTempButton.setText(MainApp.instance().getString(R.string.cancel) + ": " + activeTemp.toString()); + } else { + cancelTempButton.setVisibility(View.INVISIBLE); + } + // **** BG value **** if (profile != null && lastBG != null && bgView != null) { bgView.setText(lastBG.valueToUnitsToString(profile.getUnits())); @@ -260,44 +353,4 @@ public class OverviewFragment extends Fragment implements PluginBase { bgGraph.getGridLabelRenderer().setNumVerticalLabels(11); } - @Subscribe - public void onStatusEvent(final EventTempBasalChange ev) { - Activity activity = getActivity(); - if (activity != null) - activity.runOnUiThread(new Runnable() { - @Override - public void run() { - updateData(); - } - }); - else - log.debug("EventTempBasalChange: Activity is null"); - } - - @Subscribe - public void onStatusEvent(final EventNewBG ev) { - Activity activity = getActivity(); - if (activity != null) - activity.runOnUiThread(new Runnable() { - @Override - public void run() { - updateData(); - } - }); - else - log.debug("EventNewBG: Activity is null"); - } - - @Override - public void setUserVisibleHint(boolean isVisibleToUser) { - super.setUserVisibleHint(isVisibleToUser); - - if (isVisibleToUser) { - updateData(); - visibleNow = true; - } else { - visibleNow = false; - } - } - } 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..70ec045682 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/SafetyFragment/SafetyFragment.java @@ -0,0 +1,116 @@ +package info.nightscout.androidaps.plugins.SafetyFragment; + + +import android.content.SharedPreferences; +import android.os.Bundle; +import android.preference.PreferenceFragment; +import android.preference.PreferenceManager; +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); + + + @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 false; + } + + @Override + public boolean canBeHidden() { + return true; + } + + @Override + public void setFragmentEnabled(boolean fragmentEnabled) { + + } + + @Override + public void setFragmentVisible(boolean fragmentVisible) { + } + + public static SafetyFragment newInstance() { + SafetyFragment fragment = new SafetyFragment(); + return fragment; + } + + /** + * Constrains interface + **/ + @Override + public boolean isAutomaticProcessingEnabled() { + return true; + } + + @Override + public boolean manualConfirmationNeeded() { + return false; + } + + @Override + public APSResult applyBasalConstrains(APSResult result) { + SharedPreferences SP = PreferenceManager.getDefaultSharedPreferences(MainApp.instance().getApplicationContext()); + Double maxBasal = Double.parseDouble(SP.getString("openapsma_max_basal", "1").replace(",", ".")); + + 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 preference 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/TreatmentsFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/Treatments/TreatmentsFragment.java index 7e0e596ef3..8f43380ac4 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,30 @@ 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(); + updateGUI(); } - @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..04e8dc0dc8 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,7 +1,10 @@ package info.nightscout.androidaps.plugins.VirtualPump; +import android.app.Activity; import android.os.Bundle; +import android.os.Handler; +import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; @@ -23,11 +26,13 @@ import info.nightscout.androidaps.Config; import info.nightscout.androidaps.MainActivity; import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.R; +import info.nightscout.androidaps.events.EventTreatmentChange; import info.nightscout.androidaps.interfaces.PumpInterface; 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; @@ -47,8 +52,12 @@ public class VirtualPumpFragment extends Fragment implements PluginBase, PumpInt TextView batteryView; TextView reservoirView; + Handler loopHandler = new Handler(); + Runnable refreshLoop = null; + boolean fragmentEnabled = true; boolean fragmentVisible = true; + boolean visibleNow = false; @Override public String getName() { @@ -90,8 +99,18 @@ public class VirtualPumpFragment extends Fragment implements PluginBase, PumpInt } @Override - public void onCreate(Bundle savedInstanceState) { + public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); + if (refreshLoop == null) { + refreshLoop = new Runnable() { + @Override + public void run() { + updateGUI(); + loopHandler.postDelayed(refreshLoop, 60 * 1000l); + } + }; + loopHandler.postDelayed(refreshLoop, 60 * 1000l); + } } @Override @@ -104,48 +123,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()) { @@ -161,6 +142,7 @@ public class VirtualPumpFragment extends Fragment implements PluginBase, PumpInt if (Config.logPumpComm) log.debug("Canceling expired temp: " + tempBasal); tempBasal = null; + MainApp.bus().post(new EventTreatmentChange()); } } if (isExtendedBoluslInProgress()) { @@ -229,6 +211,11 @@ public class VirtualPumpFragment extends Fragment implements PluginBase, PumpInt } } + @Override + public TempBasal getTempBasal() { + return tempBasal; + } + @Override public double getTempBasalRemainingMinutes() { if (!isTempBasalInProgress()) @@ -243,20 +230,9 @@ public class VirtualPumpFragment extends Fragment implements PluginBase, PumpInt result.bolusDelivered = insulin; result.comment = getString(R.string.virtualpump_resultok); - Treatment t = new Treatment(); - t.insulin = insulin; - t.carbs = carbs; - t.created_at = new Date(); - try { - MainApp.instance().getDbHelper().getDaoTreatments().create(t); - } catch (SQLException e) { - e.printStackTrace(); - result.success = false; - result.comment = getString(R.string.virtualpump_sqlerror); - } if (Config.logPumpComm) - log.debug("Delivering treatment: " + t + " " + result); - updateView(); + log.debug("Delivering treatment insulin: " + insulin + "U carbs: " + carbs + "g " + result); + updateGUI(); return result; } @@ -272,6 +248,9 @@ public class VirtualPumpFragment extends Fragment implements PluginBase, PumpInt tempBasal.absolute = absoluteRate; tempBasal.duration = durationInMinutes; result.success = true; + result.enacted = true; + result.absolute = absoluteRate; + result.duration = durationInMinutes; result.comment = getString(R.string.virtualpump_resultok); try { MainApp.instance().getDbHelper().getDaoTempBasals().create(tempBasal); @@ -282,22 +261,28 @@ 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.percent = percent; + result.duration = durationInMinutes; result.comment = getString(R.string.virtualpump_resultok); try { MainApp.instance().getDbHelper().getDaoTempBasals().create(tempBasal); @@ -308,7 +293,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 +309,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 +320,7 @@ public class VirtualPumpFragment extends Fragment implements PluginBase, PumpInt } if (Config.logPumpComm) log.debug("Setting extended bolus: " + result); - updateView(); + updateGUI(); return result; } @@ -342,22 +328,24 @@ public class VirtualPumpFragment extends Fragment implements PluginBase, PumpInt public Result cancelTempBasal() { checkForExpiredTempsAndExtended(); Result result = new Result(); + result.success = true; + result.comment = getString(R.string.virtualpump_resultok); if (isTempBasalInProgress()) { + result.enacted = true; tempBasal.timeEnd = new Date(); try { MainApp.instance().getDbHelper().getDaoTempBasals().update(tempBasal); } catch (SQLException e) { e.printStackTrace(); result.success = false; + result.enacted = false; result.comment = getString(R.string.virtualpump_sqlerror); } } - result.success = 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 +364,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 +423,40 @@ 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() { + + basaBasalRateView.setText(getBaseBasalRate() + "U"); + if (isTempBasalInProgress()) { + tempBasalView.setText(tempBasal.toString()); + } else { + tempBasalView.setText(""); + } + if (isExtendedBoluslInProgress()) { + extendedBolusView.setText(extendedBolus.toString()); + } 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" /> + + + + + +