diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Loop/LoopPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/Loop/LoopPlugin.java index 392f98a5e9..ec3fdc32a0 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/Loop/LoopPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/Loop/LoopPlugin.java @@ -32,6 +32,7 @@ import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.Loop.events.EventLoopSetLastRunGui; import info.nightscout.androidaps.plugins.Loop.events.EventLoopUpdateGui; import info.nightscout.androidaps.plugins.Loop.events.EventNewOpenLoopNotification; +import info.nightscout.utils.SP; /** * Created by mike on 05.08.2016. @@ -45,6 +46,8 @@ public class LoopPlugin implements PluginBase { private boolean fragmentEnabled = false; private boolean fragmentVisible = true; + private long loopSuspendedTill = 0L; // end of manual loop suspend + public class LastRun { public APSResult request = null; public APSResult constraintsProcessed = null; @@ -64,6 +67,7 @@ public class LoopPlugin implements PluginBase { sHandler = new Handler(sHandlerThread.getLooper()); } MainApp.bus().register(this); + loopSuspendedTill = SP.getLong("loopSuspendedTill", 0L); } @Override @@ -127,6 +131,44 @@ public class LoopPlugin implements PluginBase { invoke("EventNewBG", true); } + public long suspendedTo() { + return loopSuspendedTill; + } + + public void suspendTo(long endTime) { + loopSuspendedTill = endTime; + SP.putLong("loopSuspendedTill", loopSuspendedTill); + } + + public int minutesToEndOfSuspend() { + if (loopSuspendedTill == 0) + return 0; + + long now = new Date().getTime(); + long msecDiff = loopSuspendedTill - now; + + if (loopSuspendedTill <= now) { // time exceeded + suspendTo(0L); + return 0; + } + + return (int) (msecDiff / 60d / 1000d); + } + + public boolean isSuspended() { + if (loopSuspendedTill == 0) + return false; + + long now = new Date().getTime(); + + if (loopSuspendedTill <= now) { // time exceeded + suspendTo(0L); + return false; + } + + return true; + } + public void invoke(String initiator, boolean allowNotification) { try { if (Config.logFunctionCalls) @@ -140,15 +182,21 @@ public class LoopPlugin implements PluginBase { final ConfigBuilderPlugin configBuilder = MainApp.getConfigBuilder(); APSResult result = null; + if (configBuilder == null || !isEnabled(PluginBase.LOOP)) + return; + + if (isSuspended()) { + log.debug(MainApp.sResources.getString(R.string.loopsuspended)); + MainApp.bus().post(new EventLoopSetLastRunGui(MainApp.sResources.getString(R.string.loopsuspended))); + return; + } + if (configBuilder.isSuspended()) { log.debug(MainApp.sResources.getString(R.string.pumpsuspended)); MainApp.bus().post(new EventLoopSetLastRunGui(MainApp.sResources.getString(R.string.pumpsuspended))); return; } - if (configBuilder == null || !isEnabled(PluginBase.LOOP)) - return; - // Check if pump info is loaded if (configBuilder.getBaseBasalRate() < 0.01d) return; 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 a10fbca206..f449dc18d1 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 @@ -18,8 +18,10 @@ import android.support.v7.app.AlertDialog; import android.support.v7.widget.CardView; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; +import android.view.ContextMenu; import android.view.HapticFeedbackConstants; import android.view.LayoutInflater; +import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.Button; @@ -95,6 +97,7 @@ import info.nightscout.utils.DateUtil; import info.nightscout.utils.DecimalFormatter; import info.nightscout.utils.Round; import info.nightscout.utils.SP; +import info.nightscout.utils.ToastUtils; public class OverviewFragment extends Fragment { @@ -310,6 +313,133 @@ public class OverviewFragment extends Fragment { return view; } + @Override + public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) { + super.onCreateContextMenu(menu, v, menuInfo); + final LoopPlugin activeloop = MainApp.getConfigBuilder().getActiveLoop(); + if (activeloop == null) + return; + menu.setHeaderTitle(MainApp.sResources.getString(R.string.loop)); + if (activeloop.isEnabled(PluginBase.LOOP)) { + menu.add(MainApp.sResources.getString(R.string.disabledloop)); + if (!activeloop.isSuspended()) { + menu.add(MainApp.sResources.getString(R.string.suspendloopfor1h)); + menu.add(MainApp.sResources.getString(R.string.suspendloopfor2h)); + menu.add(MainApp.sResources.getString(R.string.suspendloopfor3h)); + menu.add(MainApp.sResources.getString(R.string.suspendloopfor10h)); + menu.add(MainApp.sResources.getString(R.string.disconnectpumpfor30m)); + menu.add(MainApp.sResources.getString(R.string.disconnectpumpfor1h)); + menu.add(MainApp.sResources.getString(R.string.disconnectpumpfor2h)); + menu.add(MainApp.sResources.getString(R.string.disconnectpumpfor3h)); + } else { + menu.add(MainApp.sResources.getString(R.string.resume)); + } + } + if (!activeloop.isEnabled(PluginBase.LOOP)) + menu.add(MainApp.sResources.getString(R.string.enabledloop)); + } + + @Override + public boolean onContextItemSelected(MenuItem item) { + final LoopPlugin activeloop = MainApp.getConfigBuilder().getActiveLoop(); + if (item.getTitle() == MainApp.sResources.getString(R.string.disabledloop)) { + activeloop.setFragmentEnabled(PluginBase.LOOP, false); + activeloop.setFragmentVisible(PluginBase.LOOP, false); + MainApp.getConfigBuilder().storeSettings(); + MainApp.bus().post(new EventRefreshGui(false)); + return true; + } else if (item.getTitle() == MainApp.sResources.getString(R.string.enabledloop)) { + activeloop.setFragmentEnabled(PluginBase.LOOP, true); + activeloop.setFragmentVisible(PluginBase.LOOP, true); + MainApp.getConfigBuilder().storeSettings(); + MainApp.bus().post(new EventRefreshGui(false)); + return true; + } else if (item.getTitle() == MainApp.sResources.getString(R.string.resume)) { + activeloop.suspendTo(0L); + sHandler.post(new Runnable() { + @Override + public void run() { + PumpEnactResult result = MainApp.getConfigBuilder().cancelTempBasal(); + if (!result.success) { + ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), MainApp.sResources.getString(R.string.tempbasaldeliveryerror)); + } + MainApp.bus().post(new EventRefreshGui(false)); + } + }); + return true; + } else if (item.getTitle() == MainApp.sResources.getString(R.string.suspendloopfor1h)) { + activeloop.suspendTo(new Date().getTime() + 60L * 60 * 1000); + MainApp.bus().post(new EventRefreshGui(false)); + return true; + } else if (item.getTitle() == MainApp.sResources.getString(R.string.suspendloopfor2h)) { + activeloop.suspendTo(new Date().getTime() + 2 * 60L * 60 * 1000); + MainApp.bus().post(new EventRefreshGui(false)); + return true; + } else if (item.getTitle() == MainApp.sResources.getString(R.string.suspendloopfor3h)) { + activeloop.suspendTo(new Date().getTime() + 3 * 60L * 60 * 1000); + MainApp.bus().post(new EventRefreshGui(false)); + return true; + } else if (item.getTitle() == MainApp.sResources.getString(R.string.suspendloopfor10h)) { + activeloop.suspendTo(new Date().getTime() + 10 * 60L * 60 * 1000); + MainApp.bus().post(new EventRefreshGui(false)); + return true; + } else if (item.getTitle() == MainApp.sResources.getString(R.string.disconnectpumpfor30m)) { + activeloop.suspendTo(new Date().getTime() + 30L * 60 * 1000); + sHandler.post(new Runnable() { + @Override + public void run() { + PumpEnactResult result = MainApp.getConfigBuilder().setTempBasalAbsolute(0d, 30); + if (!result.success) { + ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), MainApp.sResources.getString(R.string.tempbasaldeliveryerror)); + } + MainApp.bus().post(new EventRefreshGui(false)); + } + }); + return true; + } else if (item.getTitle() == MainApp.sResources.getString(R.string.disconnectpumpfor1h)) { + activeloop.suspendTo(new Date().getTime() + 1 * 60L * 60 * 1000); + sHandler.post(new Runnable() { + @Override + public void run() { + PumpEnactResult result = MainApp.getConfigBuilder().setTempBasalAbsolute(0d, 60); + if (!result.success) { + ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), MainApp.sResources.getString(R.string.tempbasaldeliveryerror)); + } + MainApp.bus().post(new EventRefreshGui(false)); + } + }); + return true; + } else if (item.getTitle() == MainApp.sResources.getString(R.string.disconnectpumpfor2h)) { + activeloop.suspendTo(new Date().getTime() + 2 * 60L * 60 * 1000); + sHandler.post(new Runnable() { + @Override + public void run() { + PumpEnactResult result = MainApp.getConfigBuilder().setTempBasalAbsolute(0d, 2 * 60); + if (!result.success) { + ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), MainApp.sResources.getString(R.string.tempbasaldeliveryerror)); + } + MainApp.bus().post(new EventRefreshGui(false)); + } + }); + return true; + } else if (item.getTitle() == MainApp.sResources.getString(R.string.disconnectpumpfor3h)) { + activeloop.suspendTo(new Date().getTime() + 3 * 60L * 60 * 1000); + sHandler.post(new Runnable() { + @Override + public void run() { + PumpEnactResult result = MainApp.getConfigBuilder().setTempBasalAbsolute(0d, 3 * 60); + if (!result.success) { + ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), MainApp.sResources.getString(R.string.tempbasaldeliveryerror)); + } + MainApp.bus().post(new EventRefreshGui(false)); + } + }); + return true; + } + + return super.onContextItemSelected(item); + } + void processQuickWizard() { final BgReading actualBg = GlucoseStatus.actualBg(); if (MainApp.getConfigBuilder() == null || ConfigBuilderPlugin.getActiveProfile() == null) // app not initialized yet @@ -410,6 +540,7 @@ public class OverviewFragment extends Fragment { super.onPause(); MainApp.bus().unregister(this); sLoopHandler.removeCallbacksAndMessages(null); + unregisterForContextMenu(apsModeView); } @Override @@ -424,6 +555,7 @@ public class OverviewFragment extends Fragment { } }; sLoopHandler.postDelayed(sRefreshLoop, 60 * 1000L); + registerForContextMenu(apsModeView); updateGUIIfVisible(); } @@ -562,7 +694,11 @@ public class OverviewFragment extends Fragment { apsModeView.setBackgroundResource(R.drawable.loopmodeborder); apsModeView.setTextColor(Color.BLACK); final LoopPlugin activeloop = MainApp.getConfigBuilder().getActiveLoop(); - if (pump.isSuspended()) { + if (activeloop != null && activeloop.isEnabled(activeloop.getType()) && activeloop.isSuspended()) { + apsModeView.setBackgroundResource(R.drawable.loopmodesuspendedborder); + apsModeView.setText(String.format(MainApp.sResources.getString(R.string.loopsuspendedfor), activeloop.minutesToEndOfSuspend())); + apsModeView.setTextColor(Color.WHITE); + } else if (pump.isSuspended()) { apsModeView.setBackgroundResource(R.drawable.loopmodesuspendedborder); apsModeView.setText(MainApp.sResources.getString(R.string.pumpsuspended)); apsModeView.setTextColor(Color.WHITE); @@ -576,10 +712,8 @@ public class OverviewFragment extends Fragment { apsModeView.setBackgroundResource(R.drawable.loopmodedisabledborder); apsModeView.setText(MainApp.sResources.getString(R.string.disabledloop)); apsModeView.setTextColor(Color.WHITE); - } - - +/* apsModeView.setOnLongClickListener(new View.OnLongClickListener() { @Override public boolean onLongClick(View view) { @@ -600,7 +734,7 @@ public class OverviewFragment extends Fragment { } }); apsModeView.setLongClickable(true); - +*/ } else { apsModeView.setVisibility(View.GONE); } diff --git a/app/src/main/java/info/nightscout/utils/SP.java b/app/src/main/java/info/nightscout/utils/SP.java index cce1df9474..9bed316195 100644 --- a/app/src/main/java/info/nightscout/utils/SP.java +++ b/app/src/main/java/info/nightscout/utils/SP.java @@ -61,7 +61,11 @@ public class SP { } static public long getLong(String key, Long defaultValue) { - return SafeParse.stringToLong(sharedPreferences.getString(key, defaultValue.toString())); + try { + return sharedPreferences.getLong(key, defaultValue); + } catch (Exception e) { + return SafeParse.stringToLong(sharedPreferences.getString(key, defaultValue.toString())); + } } static public void putBoolean(String key, boolean value) { @@ -82,9 +86,9 @@ public class SP { editor.apply(); } - static public void putString(String key, String value) { + static public void putLong(String key, long value) { SharedPreferences.Editor editor = sharedPreferences.edit(); - editor.putString(key, value); + editor.putLong(key, value); editor.apply(); } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 955c02017f..8c79783784 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -139,6 +139,7 @@ Closed Loop Open Loop Loop Disabled + Loop Enabled New suggestion available Unsupported version of NSClient @@ -557,4 +558,17 @@ Device does not appear to support battery optimization whitelisting! Please Allow Permission %s needs battery optimalization whitelisting for proper performance + Loop suspended + Suspended (%d m) + Loop menu + Suspend loop for 1h + Suspend loop for 2h + Suspend loop for 3h + Suspend loop for 10h + Disconnect pump for 30 min + Disconnect pump for 1 h + Disconnect pump for 2 h + Disconnect pump for 3 h + Disconnect pump for 10 h + Resume