diff --git a/app/build.gradle b/app/build.gradle index 23a50d324f..7275218a57 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -54,7 +54,7 @@ def generateGitBuild = { -> } def generateGitRemote = { -> - StringBuilder stringBuilder = new StringBuilder(); + StringBuilder stringBuilder = new StringBuilder() try { def stdout = new ByteArrayOutputStream() exec { @@ -70,7 +70,7 @@ def generateGitRemote = { -> } def generateDate = { -> - StringBuilder stringBuilder = new StringBuilder(); + StringBuilder stringBuilder = new StringBuilder() stringBuilder.append((new Date()).format('yyyy.MM.dd-HH:mm')) return stringBuilder.toString() } @@ -80,7 +80,7 @@ def isMaster = { -> } def allCommited = { -> - StringBuilder stringBuilder = new StringBuilder(); + StringBuilder stringBuilder = new StringBuilder() try { def stdout = new ByteArrayOutputStream() exec { @@ -90,7 +90,7 @@ def allCommited = { -> String commitObject = stdout.toString().trim() stringBuilder.append(commitObject) } catch (ignored) { - return false; // NoGitSystemAvailable + return false // NoGitSystemAvailable } return stringBuilder.toString().isEmpty() @@ -109,7 +109,7 @@ android { targetSdkVersion 28 multiDexEnabled true versionCode 1500 - version "2.4-dev-a" + version "2.4-dev-e" buildConfigField "String", "VERSION", '"' + version + '"' buildConfigField "String", "BUILDVERSION", '"' + generateGitBuild() + '-' + generateDate() + '"' buildConfigField "String", "REMOTE", '"' + generateGitRemote() + '"' @@ -225,7 +225,7 @@ dependencies { implementation fileTree(include: ['*.jar'], dir: 'libs') implementation 'com.google.android.gms:play-services-wearable:17.0.0' - implementation 'com.google.firebase:firebase-core:17.0.1' + implementation 'com.google.firebase:firebase-core:17.1.0' implementation("com.crashlytics.sdk.android:crashlytics:2.9.9@aar") { transitive = true; } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 8b6173e5eb..afd60d4126 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -124,7 +124,7 @@ - @@ -155,7 +155,7 @@ + android:permission="android.permission.BIND_JOB_SERVICE"/> diff --git a/app/src/main/assets/OpenAPSAMA/loggerhelper.js b/app/src/main/assets/OpenAPSAMA/loggerhelper.js index e790f465c8..81c19b5a38 100644 --- a/app/src/main/assets/OpenAPSAMA/loggerhelper.js +++ b/app/src/main/assets/OpenAPSAMA/loggerhelper.js @@ -1,12 +1,33 @@ var console = { }; console.error = function error(){ + var s = ''; for (var i = 0, len = arguments.length; i < len; i++) { - console2.log(arguments[i]); + if (i > 0) s = s + ' '; + if (typeof arguments[i] === 'undefined') { + s = s + 'undefined'; + } else if (typeof arguments[i] === 'object') { + s = s + JSON.stringify(arguments[i]); + } else { + s = s + arguments[i].toString(); + } } + s = s + "\n"; + console2.log(s); }; console.log = function log(){ + var s = ''; for (var i = 0, len = arguments.length; i < len; i++) { - console2.log(arguments[i]); + if (i > 0) s = s + ' '; + if (typeof arguments[i] === 'undefined') { + s = s + 'undefined'; + } else if (typeof arguments[i] === 'object') { + s = s + JSON.stringify(arguments[i]); + } else { + s = s + arguments[i].toString(); + } + //console2.log(arguments[i]); } + s = s + "\n"; + console2.log(s); }; diff --git a/app/src/main/java/info/nightscout/androidaps/Constants.java b/app/src/main/java/info/nightscout/androidaps/Constants.java index f87e13d41f..adb3be4dc0 100644 --- a/app/src/main/java/info/nightscout/androidaps/Constants.java +++ b/app/src/main/java/info/nightscout/androidaps/Constants.java @@ -50,6 +50,11 @@ public class Constants { public static final double defaultHypoTTmgdl = 120d; public static final double defaultHypoTTmmol = 6.5d; + public static final double MIN_TT_MGDL = 72d; + public static final double MAX_TT_MGDL = 180d; + public static final double MIN_TT_MMOL = 4d; + public static final double MAX_TT_MMOL = 10d; + //NSClientInternal public static final int MAX_LOG_LINES = 100; diff --git a/app/src/main/java/info/nightscout/androidaps/MainApp.java b/app/src/main/java/info/nightscout/androidaps/MainApp.java index c0d544e145..ac83e93307 100644 --- a/app/src/main/java/info/nightscout/androidaps/MainApp.java +++ b/app/src/main/java/info/nightscout/androidaps/MainApp.java @@ -134,6 +134,8 @@ public class MainApp extends Application { sConstraintsChecker = new ConstraintChecker(); sDatabaseHelper = OpenHelperManager.getHelper(sInstance, DatabaseHelper.class); + Thread.setDefaultUncaughtExceptionHandler((thread, ex) -> log.error("Uncaught exception crashing app", ex)); + try { if (FabricPrivacy.fabricEnabled()) { Fabric.with(this, new Crashlytics()); diff --git a/app/src/main/java/info/nightscout/androidaps/activities/HistoryBrowseActivity.java b/app/src/main/java/info/nightscout/androidaps/activities/HistoryBrowseActivity.java index 75767ec974..db7a86e7f4 100644 --- a/app/src/main/java/info/nightscout/androidaps/activities/HistoryBrowseActivity.java +++ b/app/src/main/java/info/nightscout/androidaps/activities/HistoryBrowseActivity.java @@ -39,6 +39,7 @@ import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorP import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventAutosensCalculationFinished; import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventIobCalculationProgress; import info.nightscout.androidaps.utils.DateUtil; +import info.nightscout.androidaps.utils.SP; import info.nightscout.androidaps.utils.T; public class HistoryBrowseActivity extends NoSplashActivity { @@ -194,7 +195,7 @@ public class HistoryBrowseActivity extends NoSplashActivity { @Subscribe public void onStatusEvent(final EventAutosensCalculationFinished e) { - if (e.cause == eventCustomCalculationFinished) { + if (e.getCause() == eventCustomCalculationFinished) { log.debug("EventAutosensCalculationFinished"); runOnUiThread(() -> { synchronized (HistoryBrowseActivity.this) { @@ -237,6 +238,15 @@ public class HistoryBrowseActivity extends NoSplashActivity { final boolean showPrediction = false; + showBasal = SP.getBoolean("hist_showbasals", true); + showIob = SP.getBoolean("hist_showiob", true); + showCob = SP.getBoolean("hist_showcob", true); + showDev = SP.getBoolean("hist_showdeviations", false); + showRat = SP.getBoolean("hist_showratios", false); + showActPrim = SP.getBoolean("hist_showactivityprimary", false); + showActSec = SP.getBoolean("hist_showactivitysecondary", false); + showDevslope = SP.getBoolean("hist_showdevslope", false); + int hoursToFetch; final long toTime; final long fromTime; @@ -442,21 +452,21 @@ public class HistoryBrowseActivity extends NoSplashActivity { popup.setOnMenuItemClickListener(item1 -> { if (item1.getItemId() == OverviewFragment.CHARTTYPE.BAS.ordinal()) { - showBasal = !item1.isChecked(); + SP.putBoolean("hist_showbasals", !item1.isChecked()); } else if (item1.getItemId() == OverviewFragment.CHARTTYPE.IOB.ordinal()) { - showIob = !item1.isChecked(); + SP.putBoolean("hist_showiob", !item1.isChecked()); } else if (item1.getItemId() == OverviewFragment.CHARTTYPE.COB.ordinal()) { - showCob = !item1.isChecked(); + SP.putBoolean("hist_showcob", !item1.isChecked()); } else if (item1.getItemId() == OverviewFragment.CHARTTYPE.DEV.ordinal()) { - showDev = !item1.isChecked(); + SP.putBoolean("hist_showdeviations", !item1.isChecked()); } else if (item1.getItemId() == OverviewFragment.CHARTTYPE.SEN.ordinal()) { - showRat = !item1.isChecked(); + SP.putBoolean("hist_showratios", !item1.isChecked()); } else if (item1.getItemId() == OverviewFragment.CHARTTYPE.ACTPRIM.ordinal()) { - showActPrim = !item1.isChecked(); + SP.putBoolean("hist_showactivityprimary", !item1.isChecked()); } else if (item1.getItemId() == OverviewFragment.CHARTTYPE.ACTSEC.ordinal()) { - showActSec = !item1.isChecked(); + SP.putBoolean("hist_showactivitysecondary", !item1.isChecked()); } else if (item1.getItemId() == OverviewFragment.CHARTTYPE.DEVSLOPE.ordinal()) { - showDevslope = !item1.isChecked(); + SP.putBoolean("hist_showdevslope", !item1.isChecked()); } updateGUI("onGraphCheckboxesCheckedChanged"); return true; diff --git a/app/src/main/java/info/nightscout/androidaps/data/Profile.java b/app/src/main/java/info/nightscout/androidaps/data/Profile.java index cfb6a88114..626d5775e0 100644 --- a/app/src/main/java/info/nightscout/androidaps/data/Profile.java +++ b/app/src/main/java/info/nightscout/androidaps/data/Profile.java @@ -166,17 +166,18 @@ public class Profile { final JSONObject o = array.getJSONObject(index); long tas = 0; try { - tas = getShitfTimeSecs((int) o.getLong("timeAsSeconds")); - } catch (JSONException e) { String time = o.getString("time"); tas = getShitfTimeSecs(DateUtil.toSeconds(time)); + } catch (JSONException e) { //log.debug(">>>>>>>>>>>> Used recalculated timeAsSecons: " + time + " " + tas); + tas = getShitfTimeSecs((int) o.getLong("timeAsSeconds")); } double value = o.getDouble("value") * multiplier; sparse.put(tas, value); - } catch (JSONException e) { + } catch (Exception e) { log.error("Unhandled exception", e); log.error(json.toString()); + FabricPrivacy.logException(e); } } diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventChargingState.java b/app/src/main/java/info/nightscout/androidaps/events/EventChargingState.java deleted file mode 100644 index bcd9061133..0000000000 --- a/app/src/main/java/info/nightscout/androidaps/events/EventChargingState.java +++ /dev/null @@ -1,13 +0,0 @@ -package info.nightscout.androidaps.events; - -public class EventChargingState { - - public boolean isCharging = false; - - public EventChargingState() {} - - public EventChargingState(boolean isCharging) { - this.isCharging = isCharging; - } - -} diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventChargingState.kt b/app/src/main/java/info/nightscout/androidaps/events/EventChargingState.kt new file mode 100644 index 0000000000..f9ff60a71d --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/events/EventChargingState.kt @@ -0,0 +1,3 @@ +package info.nightscout.androidaps.events + +class EventChargingState(val isCharging: Boolean) : Event() diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/LoopFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/LoopFragment.kt index b4aa6b0991..2ab594c2a2 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/LoopFragment.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/LoopFragment.kt @@ -15,19 +15,15 @@ import info.nightscout.androidaps.plugins.bus.RxBus import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.HtmlHelper +import info.nightscout.androidaps.utils.plusAssign import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.disposables.CompositeDisposable -import io.reactivex.disposables.Disposable import kotlinx.android.synthetic.main.loop_fragment.* class LoopFragment : Fragment() { private var disposable: CompositeDisposable = CompositeDisposable() - operator fun CompositeDisposable.plusAssign(disposable: Disposable) { - add(disposable) - } - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { return inflater.inflate(R.layout.loop_fragment, container, false) @@ -40,10 +36,9 @@ class LoopFragment : Fragment() { loop_lastrun.text = MainApp.gs(R.string.executing) Thread { LoopPlugin.getPlugin().invoke("Loop button", true) }.start() } - - updateGUI() } + @Synchronized override fun onResume() { super.onResume() disposable += RxBus @@ -64,14 +59,19 @@ class LoopFragment : Fragment() { }, { FabricPrivacy.logException(it) }) + + updateGUI() } + @Synchronized override fun onPause() { super.onPause() disposable.clear() } + @Synchronized fun updateGUI() { + if (loop_request == null) return LoopPlugin.lastRun?.let { loop_request.text = it.request?.toSpanned() ?: "" loop_constraintsprocessed.text = it.constraintsProcessed?.toSpanned() ?: "" @@ -96,7 +96,9 @@ class LoopFragment : Fragment() { } } + @Synchronized private fun clearGUI() { + if (loop_request == null) return loop_request.text = "" loop_constraints.text = "" loop_constraintsprocessed.text = "" diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/LoopPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/LoopPlugin.java index e68bf9c30d..0425190723 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/LoopPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/LoopPlugin.java @@ -155,7 +155,7 @@ public class LoopPlugin extends PluginBase { */ @Subscribe public void onStatusEvent(final EventAutosensCalculationFinished ev) { - if (!(ev.cause instanceof EventNewBG)) { + if (!(ev.getCause() instanceof EventNewBG)) { // Autosens calculation not triggered by a new BG return; } @@ -416,7 +416,7 @@ public class LoopPlugin extends PluginBase { .setAutoCancel(true) .setPriority(Notification.PRIORITY_HIGH) .setCategory(Notification.CATEGORY_ALARM) - .setVisibility(Notification.VISIBILITY_PUBLIC); + .setVisibility(NotificationCompat.VISIBILITY_PUBLIC); if (SP.getBoolean("wearcontrol", false)) { builder.setLocalOnly(true); } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSAMA/OpenAPSAMAFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSAMA/OpenAPSAMAFragment.kt index 763c93aa8c..94747a4597 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSAMA/OpenAPSAMAFragment.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSAMA/OpenAPSAMAFragment.kt @@ -15,9 +15,9 @@ import info.nightscout.androidaps.plugins.bus.RxBus import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.JSONFormatter +import info.nightscout.androidaps.utils.plusAssign import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.disposables.CompositeDisposable -import io.reactivex.disposables.Disposable import kotlinx.android.synthetic.main.openapsama_fragment.* import org.json.JSONArray import org.json.JSONException @@ -27,10 +27,6 @@ class OpenAPSAMAFragment : Fragment() { private val log = LoggerFactory.getLogger(L.APS) private var disposable: CompositeDisposable = CompositeDisposable() - operator fun CompositeDisposable.plusAssign(disposable: Disposable) { - add(disposable) - } - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { return inflater.inflate(R.layout.openapsama_fragment, container, false) @@ -42,10 +38,9 @@ class OpenAPSAMAFragment : Fragment() { openapsma_run.setOnClickListener { OpenAPSAMAPlugin.getPlugin().invoke("OpenAPSAMA button", false) } - - updateGUI() } + @Synchronized override fun onResume() { super.onResume() @@ -65,14 +60,19 @@ class OpenAPSAMAFragment : Fragment() { }, { FabricPrivacy.logException(it) }) + + updateGUI() } + @Synchronized override fun onPause() { super.onPause() disposable.clear() } + @Synchronized private fun updateGUI() { + if (openapsma_result == null) return OpenAPSAMAPlugin.getPlugin().lastAPSResult?.let { lastAPSResult -> openapsma_result.text = JSONFormatter.format(lastAPSResult.json) openapsma_request.text = lastAPSResult.toSpanned() diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSMA/LoggerCallback.java b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSMA/LoggerCallback.java index 30ce388f5d..a2596d9174 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSMA/LoggerCallback.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSMA/LoggerCallback.java @@ -36,16 +36,14 @@ public class LoggerCallback extends ScriptableObject { public void jsFunction_log(Object obj1) { if (L.isEnabled(L.APS)) - log.debug(obj1.toString()); + log.debug(obj1.toString().trim()); logBuffer.append(obj1.toString()); - logBuffer.append(' '); } public void jsFunction_error(Object obj1) { if (L.isEnabled(L.APS)) - log.error(obj1.toString()); + log.error(obj1.toString().trim()); errorBuffer.append(obj1.toString()); - errorBuffer.append(' '); } @@ -60,4 +58,4 @@ public class LoggerCallback extends ScriptableObject { } return ret; } -} \ No newline at end of file +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSMA/OpenAPSMAFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSMA/OpenAPSMAFragment.kt index 6525641332..1b72f57365 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSMA/OpenAPSMAFragment.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSMA/OpenAPSMAFragment.kt @@ -13,9 +13,9 @@ import info.nightscout.androidaps.plugins.bus.RxBus import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.JSONFormatter +import info.nightscout.androidaps.utils.plusAssign import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.disposables.CompositeDisposable -import io.reactivex.disposables.Disposable import kotlinx.android.synthetic.main.openapsama_fragment.* import org.slf4j.LoggerFactory @@ -23,10 +23,6 @@ class OpenAPSMAFragment : Fragment() { private val log = LoggerFactory.getLogger(L.APS) private var disposable: CompositeDisposable = CompositeDisposable() - operator fun CompositeDisposable.plusAssign(disposable: Disposable) { - add(disposable) - } - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { return inflater.inflate(R.layout.openapsma_fragment, container, false) @@ -39,9 +35,9 @@ class OpenAPSMAFragment : Fragment() { OpenAPSMAPlugin.getPlugin().invoke("OpenAPSMA button", false) } - updateGUI() } + @Synchronized override fun onResume() { super.onResume() @@ -61,14 +57,18 @@ class OpenAPSMAFragment : Fragment() { }, { FabricPrivacy.logException(it) }) + updateGUI() } + @Synchronized override fun onPause() { super.onPause() disposable.clear() } - fun updateGUI() { + @Synchronized + private fun updateGUI() { + if (openapsma_result == null) return OpenAPSMAPlugin.getPlugin().lastAPSResult?.let { lastAPSResult -> openapsma_result.text = JSONFormatter.format(lastAPSResult.json) openapsma_request.text = lastAPSResult.toSpanned() @@ -85,7 +85,9 @@ class OpenAPSMAFragment : Fragment() { } } + @Synchronized private fun updateResultGUI(text: String) { + if (openapsma_result == null) return openapsma_result.text = text openapsma_glucosestatus.text = "" openapsma_currenttemp.text = "" diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMB/OpenAPSSMBFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMB/OpenAPSSMBFragment.kt index c102b65173..06ad0d01fd 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMB/OpenAPSSMBFragment.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMB/OpenAPSSMBFragment.kt @@ -1,5 +1,6 @@ package info.nightscout.androidaps.plugins.aps.openAPSSMB +import android.annotation.SuppressLint import android.os.Bundle import android.text.TextUtils import android.view.LayoutInflater @@ -15,9 +16,9 @@ import info.nightscout.androidaps.plugins.bus.RxBus import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.JSONFormatter +import info.nightscout.androidaps.utils.plusAssign import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.disposables.CompositeDisposable -import io.reactivex.disposables.Disposable import kotlinx.android.synthetic.main.openapsama_fragment.* import org.json.JSONArray import org.json.JSONException @@ -27,10 +28,6 @@ class OpenAPSSMBFragment : Fragment() { private val log = LoggerFactory.getLogger(L.APS) private var disposable: CompositeDisposable = CompositeDisposable() - operator fun CompositeDisposable.plusAssign(disposable: Disposable) { - add(disposable) - } - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { return inflater.inflate(R.layout.openapsama_fragment, container, false) @@ -42,10 +39,9 @@ class OpenAPSSMBFragment : Fragment() { openapsma_run.setOnClickListener { OpenAPSSMBPlugin.getPlugin().invoke("OpenAPSSMB button", false) } - - updateGUI() } + @Synchronized override fun onResume() { super.onResume() disposable += RxBus @@ -64,14 +60,19 @@ class OpenAPSSMBFragment : Fragment() { }, { FabricPrivacy.logException(it) }) + + updateGUI() } + @Synchronized override fun onPause() { super.onPause() disposable.clear() } + @Synchronized fun updateGUI() { + if (openapsma_result == null) return val plugin = OpenAPSSMBPlugin.getPlugin() plugin.lastAPSResult?.let { lastAPSResult -> openapsma_result.text = JSONFormatter.format(lastAPSResult.json) @@ -85,6 +86,7 @@ class OpenAPSSMBFragment : Fragment() { openapsma_iobdata.text = TextUtils.concat(String.format(MainApp.gs(R.string.array_of_elements), iobArray.length()) + "\n", JSONFormatter.format(iobArray.getString(0))) } catch (e: JSONException) { log.error("Unhandled exception", e) + @SuppressLint("SetTextl18n") openapsma_iobdata.text = "JSONException see log for details" } @@ -103,7 +105,9 @@ class OpenAPSSMBFragment : Fragment() { } } + @Synchronized private fun updateResultGUI(text: String) { + if (openapsma_result == null) return openapsma_result.text = text openapsma_glucosestatus.text = "" openapsma_currenttemp.text = "" diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/configBuilder/ConfigBuilderFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/configBuilder/ConfigBuilderFragment.kt index a8bcda3944..f011ac57cf 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/configBuilder/ConfigBuilderFragment.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/configBuilder/ConfigBuilderFragment.kt @@ -44,10 +44,9 @@ class ConfigBuilderFragment : Fragment() { unlock.visibility = View.GONE }, null) } - - updateGUI() } + @Synchronized override fun onResume() { super.onResume() disposable.add(RxBus @@ -58,13 +57,16 @@ class ConfigBuilderFragment : Fragment() { }, { FabricPrivacy.logException(it) })) + updateGUI() } + @Synchronized override fun onPause() { super.onPause() disposable.clear() } + @Synchronized private fun updateGUI() { createViewsForPlugins(R.string.configbuilder_profile, R.string.configbuilder_profile_description, PluginType.PROFILE, MainApp.getSpecificPluginsVisibleInListByInterface(ProfileInterface::class.java, PluginType.PROFILE)) createViewsForPlugins(R.string.configbuilder_insulin, R.string.configbuilder_insulin_description, PluginType.INSULIN, MainApp.getSpecificPluginsVisibleInListByInterface(InsulinInterface::class.java, PluginType.INSULIN)) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationEvent.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationEvent.java index b92dadc89b..6eb3be382b 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationEvent.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationEvent.java @@ -16,6 +16,7 @@ public class AutomationEvent { private Trigger trigger = new TriggerConnector(); private List actions = new ArrayList<>(); private String title; + private boolean enabled = true; public void setTitle(String title) { this.title = title; @@ -33,6 +34,14 @@ public class AutomationEvent { return actions; } + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean newState) { + enabled = newState; + } + public TriggerConnector getPreconditions() { TriggerConnector trigger = new TriggerConnector(TriggerConnector.Type.AND); for (Action action : actions) { @@ -55,6 +64,7 @@ public class AutomationEvent { try { // title o.put("title", title); + o.put("enabled", enabled); // trigger o.put("trigger", trigger.toJSON()); // actions @@ -72,11 +82,9 @@ public class AutomationEvent { public AutomationEvent fromJSON(String data) { try { JSONObject d = new JSONObject(data); - // title title = d.optString("title", ""); - // trigger + enabled = d.optBoolean("enabled", true); trigger = Trigger.instantiate(d.getString("trigger")); - // actions JSONArray array = d.getJSONArray("actions"); actions.clear(); for (int i = 0; i < array.length(); i++) { diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationFragment.kt index 0bf996bd52..8a0789acea 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationFragment.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationFragment.kt @@ -12,9 +12,9 @@ import info.nightscout.androidaps.plugins.general.automation.dialogs.EditEventDi import info.nightscout.androidaps.plugins.general.automation.events.EventAutomationDataChanged import info.nightscout.androidaps.plugins.general.automation.events.EventAutomationUpdateGui import info.nightscout.androidaps.utils.FabricPrivacy +import info.nightscout.androidaps.utils.plusAssign import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.disposables.CompositeDisposable -import io.reactivex.disposables.Disposable import kotlinx.android.synthetic.main.automation_fragment.* class AutomationFragment : Fragment() { @@ -22,10 +22,6 @@ class AutomationFragment : Fragment() { private var disposable: CompositeDisposable = CompositeDisposable() private var eventListAdapter: EventListAdapter? = null - operator fun CompositeDisposable.plusAssign(disposable: Disposable) { - add(disposable) - } - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { return inflater.inflate(R.layout.automation_fragment, container, false) } @@ -48,19 +44,14 @@ class AutomationFragment : Fragment() { } + @Synchronized override fun onResume() { super.onResume() disposable += RxBus .toObservable(EventAutomationUpdateGui::class.java) .observeOn(AndroidSchedulers.mainThread()) .subscribe({ - eventListAdapter?.notifyDataSetChanged() - val sb = StringBuilder() - for (l in AutomationPlugin.executionLog) { - sb.append(l) - sb.append("\n") - } - automation_logView.text = sb.toString() + updateGui() }, { FabricPrivacy.logException(it) }) @@ -72,11 +63,25 @@ class AutomationFragment : Fragment() { }, { FabricPrivacy.logException(it) }) + updateGui() } + @Synchronized override fun onPause() { super.onPause() disposable.clear() } + @Synchronized + private fun updateGui() { + if (eventListAdapter == null) return + eventListAdapter?.notifyDataSetChanged() + val sb = StringBuilder() + for (l in AutomationPlugin.executionLog) { + sb.append(l) + sb.append("\n") + } + automation_logView.text = sb.toString() + } + } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationPlugin.kt index 2ab2c91411..00a76778d8 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationPlugin.kt @@ -21,12 +21,8 @@ import info.nightscout.androidaps.plugins.general.automation.triggers.* import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventAutosensCalculationFinished import info.nightscout.androidaps.queue.Callback import info.nightscout.androidaps.services.LocationService -import info.nightscout.androidaps.utils.DateUtil -import info.nightscout.androidaps.utils.FabricPrivacy -import info.nightscout.androidaps.utils.SP -import info.nightscout.androidaps.utils.T +import info.nightscout.androidaps.utils.* import io.reactivex.disposables.CompositeDisposable -import io.reactivex.disposables.Disposable import io.reactivex.schedulers.Schedulers import org.json.JSONArray import org.json.JSONException @@ -60,10 +56,6 @@ object AutomationPlugin : PluginBase(PluginDescription() } } - operator fun CompositeDisposable.plusAssign(disposable: Disposable) { - add(disposable) - } - override fun onStart() { val context = MainApp.instance().applicationContext if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) @@ -131,6 +123,7 @@ object AutomationPlugin : PluginBase(PluginDescription() loopHandler.removeCallbacks(refreshLoop) val context = MainApp.instance().applicationContext context.stopService(Intent(context, LocationService::class.java)) + super.onStop() } private fun storeToSP() { @@ -171,7 +164,7 @@ object AutomationPlugin : PluginBase(PluginDescription() if (L.isEnabled(L.AUTOMATION)) log.debug("processActions") for (event in automationEvents) { - if (event.trigger.shouldRun() && event.preconditions.shouldRun()) { + if (event.isEnabled() && event.trigger.shouldRun() && event.preconditions.shouldRun()) { val actions = event.actions for (action in actions) { action.doAction(object : Callback() { diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/EventListAdapter.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/EventListAdapter.java index 4bbd4a0959..b4c6fb1f11 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/EventListAdapter.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/EventListAdapter.java @@ -5,6 +5,7 @@ import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.CheckBox; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.RelativeLayout; @@ -20,8 +21,10 @@ import java.util.List; import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.R; +import info.nightscout.androidaps.plugins.bus.RxBus; import info.nightscout.androidaps.plugins.general.automation.actions.Action; import info.nightscout.androidaps.plugins.general.automation.dialogs.EditEventDialog; +import info.nightscout.androidaps.plugins.general.automation.events.EventAutomationDataChanged; import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerConnector; class EventListAdapter extends RecyclerView.Adapter { @@ -51,6 +54,7 @@ class EventListAdapter extends RecyclerView.Adapter public void onBindViewHolder(@NonNull ViewHolder holder, int position) { final AutomationEvent event = mEventList.get(position); holder.eventTitle.setText(event.getTitle()); + holder.enabled.setChecked(event.isEnabled()); holder.iconLayout.removeAllViews(); // trigger icons @@ -77,6 +81,13 @@ class EventListAdapter extends RecyclerView.Adapter addImage(res, holder.context, holder.iconLayout); } + // enabled event + holder.enabled.setOnCheckedChangeListener((buttonView, isChecked) -> { + event.setEnabled(isChecked); + notifyDataSetChanged(); + RxBus.INSTANCE.send(new EventAutomationDataChanged()); + }); + // remove event holder.iconTrash.setOnClickListener(v -> { mEventList.remove(event); @@ -107,6 +118,7 @@ class EventListAdapter extends RecyclerView.Adapter final TextView eventTitle; final Context context; final ImageView iconTrash; + final CheckBox enabled; ViewHolder(View view, Context context) { super(view); @@ -115,6 +127,7 @@ class EventListAdapter extends RecyclerView.Adapter rootLayout = view.findViewById(R.id.rootLayout); iconLayout = view.findViewById(R.id.iconLayout); iconTrash = view.findViewById(R.id.iconTrash); + enabled = view.findViewById(R.id.automation_enabled); } } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionStartTempTarget.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionStartTempTarget.java index 66f262485b..05d06f0b3a 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionStartTempTarget.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionStartTempTarget.java @@ -15,8 +15,8 @@ import info.nightscout.androidaps.data.PumpEnactResult; import info.nightscout.androidaps.db.Source; import info.nightscout.androidaps.db.TempTarget; import info.nightscout.androidaps.plugins.general.automation.elements.ComparatorExists; -import info.nightscout.androidaps.plugins.general.automation.elements.InputBg; import info.nightscout.androidaps.plugins.general.automation.elements.InputDuration; +import info.nightscout.androidaps.plugins.general.automation.elements.InputTempTarget; import info.nightscout.androidaps.plugins.general.automation.elements.LabelWithElement; import info.nightscout.androidaps.plugins.general.automation.elements.LayoutBuilder; import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerTempTarget; @@ -27,7 +27,7 @@ import info.nightscout.androidaps.utils.JsonHelper; public class ActionStartTempTarget extends Action { String reason = ""; - InputBg value = new InputBg(); + InputTempTarget value = new InputTempTarget(); InputDuration duration = new InputDuration(0, InputDuration.TimeUnit.MINUTES); private TempTarget tempTarget; diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputBg.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputBg.java index 7e1ff75962..0809ed96d8 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputBg.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputBg.java @@ -11,27 +11,10 @@ import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions; import info.nightscout.androidaps.utils.NumberPicker; public class InputBg extends Element { - - final TextWatcher textWatcher = new TextWatcher() { - @Override - public void afterTextChanged(Editable s) { - if (units.equals(Constants.MMOL)) { - value = Math.max(value, 4d); - value = Math.min(value, 15d); - } else { - value = Math.max(value, 72d); - value = Math.min(value, 270d); - } - } - - @Override - public void beforeTextChanged(CharSequence s, int start, int count, int after) { - } - - @Override - public void onTextChanged(CharSequence s, int start, int before, int count) { - } - }; + static final int MMOL_MIN = 3; + static final int MMOL_MAX = 20; + static final int MGDL_MIN = 54; + static final int MGDL_MAX = 360; private String units = Constants.MGDL; private double value; @@ -43,6 +26,10 @@ public class InputBg extends Element { public InputBg() { super(); setUnits(ProfileFunctions.getInstance().getProfileUnits()); + if (getUnits().equals(Constants.MMOL)) + value = MMOL_MIN; + else + value = MGDL_MIN; } public InputBg(InputBg another) { @@ -55,7 +42,7 @@ public class InputBg extends Element { @Override public void addToLayout(LinearLayout root) { NumberPicker numberPicker = new NumberPicker(root.getContext(), null); - numberPicker.setParams(value, minValue, maxValue, step, decimalFormat, true, null, textWatcher); + numberPicker.setParams(value, minValue, maxValue, step, decimalFormat, true, null, null); numberPicker.setOnValueChangedListener(value -> this.value = value); root.addView(numberPicker); } @@ -68,21 +55,18 @@ public class InputBg extends Element { // set default initial value if (units.equals(Constants.MMOL)) { // mmol - minValue = 2; - maxValue = 30; + minValue = MMOL_MIN; + maxValue = MMOL_MAX; step = 0.1; decimalFormat = new DecimalFormat("0.0"); } else { // mg/dL - minValue = 40; - maxValue = 540; + minValue = MGDL_MIN; + maxValue = MGDL_MAX; step = 1; decimalFormat = new DecimalFormat("0"); } - // make sure that value is in range - textWatcher.afterTextChanged(null); - this.units = units; return this; } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputDelta.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputDelta.java index 10910220c3..ad0e84bec4 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputDelta.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputDelta.java @@ -21,19 +21,6 @@ import info.nightscout.androidaps.utils.NumberPicker; public class InputDelta extends Element { private Comparator.Compare compare = Comparator.Compare.IS_EQUAL; - final TextWatcher textWatcher = new TextWatcher() { - @Override - public void afterTextChanged(Editable s) { - } - - @Override - public void beforeTextChanged(CharSequence s, int start, int count, int after) { - } - - @Override - public void onTextChanged(CharSequence s, int start, int before, int count) { - } - }; public enum DeltaType { DELTA, @@ -122,7 +109,7 @@ public class InputDelta extends Element { spinner.setSelection(this.deltaType.ordinal()); // root.addView(spinner); numberPicker = new NumberPicker(root.getContext(), null); - numberPicker.setParams(value, minValue, maxValue, step, decimalFormat, true, null, textWatcher); + numberPicker.setParams(value, minValue, maxValue, step, decimalFormat, true, null, null); numberPicker.setOnValueChangedListener(value -> this.value = value); LinearLayout l = new LinearLayout(root.getContext()); l.setOrientation(LinearLayout.VERTICAL); diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputTempTarget.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputTempTarget.java new file mode 100644 index 0000000000..8175c496a5 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputTempTarget.java @@ -0,0 +1,77 @@ +package info.nightscout.androidaps.plugins.general.automation.elements; + +import android.widget.LinearLayout; + +import java.text.DecimalFormat; + +import info.nightscout.androidaps.Constants; +import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions; +import info.nightscout.androidaps.utils.NumberPicker; + +public class InputTempTarget extends Element { + + private String units = Constants.MGDL; + private double value; + double minValue; + private double maxValue; + private double step; + private DecimalFormat decimalFormat; + + public InputTempTarget() { + super(); + setUnits(ProfileFunctions.getInstance().getProfileUnits()); + if (getUnits().equals(Constants.MMOL)) + value = Constants.MIN_TT_MMOL; + else + value = Constants.MIN_TT_MGDL; + } + + public InputTempTarget(InputTempTarget another) { + super(); + value = another.getValue(); + setUnits(another.getUnits()); + } + + + @Override + public void addToLayout(LinearLayout root) { + NumberPicker numberPicker = new NumberPicker(root.getContext(), null); + numberPicker.setParams(value, minValue, maxValue, step, decimalFormat, true, null, null); + numberPicker.setOnValueChangedListener(value -> this.value = value); + root.addView(numberPicker); + } + + public String getUnits() { + return units; + } + + public InputTempTarget setUnits(String units) { + // set default initial value + if (units.equals(Constants.MMOL)) { + // mmol + minValue = Constants.MIN_TT_MMOL; + maxValue = Constants.MAX_TT_MMOL; + step = 0.1; + decimalFormat = new DecimalFormat("0.0"); + } else { + // mg/dL + minValue = Constants.MIN_TT_MGDL; + maxValue = Constants.MAX_TT_MGDL; + step = 1; + decimalFormat = new DecimalFormat("0"); + } + + this.units = units; + return this; + } + + public InputTempTarget setValue(double value) { + this.value = value; + return this; + } + + public double getValue() { + return value; + } + +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerDelta.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerDelta.java index 00c3e21921..0b9edf148a 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerDelta.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerDelta.java @@ -33,15 +33,15 @@ import info.nightscout.androidaps.utils.T; public class TriggerDelta extends Trigger { private static Logger log = LoggerFactory.getLogger(L.AUTOMATION); - private double minValue = 0d; - private double maxValue = 1d; - private double step = 1; - private DecimalFormat decimalFormat = new DecimalFormat("1"); + + private final int MMOL_MAX = 4; + private final int MGDL_MAX = 72; + private String units; private DeltaType deltaType; - private InputDelta value = new InputDelta( (double) minValue,(double) minValue, (double) maxValue, step, decimalFormat, deltaType); - private Comparator comparator = new Comparator(); + private InputDelta value; + private Comparator comparator; public TriggerDelta() { super(); @@ -62,6 +62,16 @@ public class TriggerDelta extends Trigger { return value.getValue(); } + private void initializer() { + this.deltaType = DeltaType.DELTA; + comparator = new Comparator(); + if (units.equals(Constants.MMOL)) + value = new InputDelta(0, -MMOL_MAX, MMOL_MAX, 0.1d, new DecimalFormat("0.1"), DeltaType.DELTA); + else + value = new InputDelta(0, -MGDL_MAX, MGDL_MAX, 0.1d, new DecimalFormat("1"), DeltaType.DELTA); + } + + public DeltaType getType() { return deltaType; } @@ -150,7 +160,7 @@ public class TriggerDelta extends Trigger { @Override public Optional icon() { - return Optional.of(R.drawable.icon_auto_delta); + return Optional.of(R.drawable.icon_auto_delta); } @Override @@ -169,23 +179,6 @@ public class TriggerDelta extends Trigger { return this; } - void initializer(){ - if (this.units.equals(Constants.MMOL)) { - this.maxValue = 4d; - this.minValue = -4d; - this.step = 0.1d; - this.decimalFormat = new DecimalFormat("0.1"); - this.deltaType = DeltaType.DELTA; - } else { - this.maxValue = 72d; - this.minValue = -72d; - this.step = 1d; - this.deltaType = DeltaType.DELTA; - } - value = new InputDelta( (double) minValue,(double) minValue, (double) maxValue, step, decimalFormat, deltaType); - } - - TriggerDelta lastRun(long lastRun) { this.lastRun = lastRun; return this; @@ -201,7 +194,7 @@ public class TriggerDelta extends Trigger { new LayoutBuilder() .add(new StaticLabel(R.string.deltalabel)) .add(comparator) - .add(new LabelWithElement(MainApp.gs(R.string.deltalabel) + ": ", "", value)) + .add(new LabelWithElement(MainApp.gs(R.string.deltalabel_u, getUnits()) + ": ", "", value)) .build(root); } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/careportal/Dialogs/NewNSTreatmentDialog.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/careportal/Dialogs/NewNSTreatmentDialog.java index 91cabe35c1..3489180d9d 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/careportal/Dialogs/NewNSTreatmentDialog.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/careportal/Dialogs/NewNSTreatmentDialog.java @@ -263,17 +263,17 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick if (sensorRadioButton.isChecked()) meterRadioButton.setChecked(true); } }; - editBg = (NumberPicker) view.findViewById(R.id.careportal_newnstreatment_bginput); - editTemptarget = (NumberPicker) view.findViewById(R.id.careportal_newnstreatment_temptarget); + editBg = view.findViewById(R.id.careportal_newnstreatment_bginput); + editTemptarget = view.findViewById(R.id.careportal_newnstreatment_temptarget); if (profile == null) { - editBg.setParams(bg, 0d, 500d, 0.1d, new DecimalFormat("0.0"), false, view.findViewById(R.id.ok), bgTextWatcher); - editTemptarget.setParams(bg, 0d, 500d, 0.1d, new DecimalFormat("0.0"), false, view.findViewById(R.id.ok)); + editBg.setParams(bg, 0d, 500d, 0.1d, new DecimalFormat("0"), false, view.findViewById(R.id.ok), bgTextWatcher); + editTemptarget.setParams(Constants.MIN_TT_MGDL, Constants.MIN_TT_MGDL, Constants.MAX_TT_MGDL, 0.1d, new DecimalFormat("0.0"), false, view.findViewById(R.id.ok)); } else if (units.equals(Constants.MMOL)) { editBg.setParams(bg, 0d, 30d, 0.1d, new DecimalFormat("0.0"), false, view.findViewById(R.id.ok), bgTextWatcher); - editTemptarget.setParams(bg, 0d, 30d, 0.1d, new DecimalFormat("0.0"), false, view.findViewById(R.id.ok)); + editTemptarget.setParams(Constants.MIN_TT_MMOL, Constants.MIN_TT_MMOL, Constants.MAX_TT_MMOL, 0.1d, new DecimalFormat("0.0"), false, view.findViewById(R.id.ok)); } else { editBg.setParams(bg, 0d, 500d, 1d, new DecimalFormat("0"), false, view.findViewById(R.id.ok), bgTextWatcher); - editTemptarget.setParams(bg, 0d, 500d, 1d, new DecimalFormat("0"), false, view.findViewById(R.id.ok)); + editTemptarget.setParams(Constants.MIN_TT_MGDL, Constants.MIN_TT_MGDL, Constants.MAX_TT_MGDL, 1d, new DecimalFormat("0"), false, view.findViewById(R.id.ok)); } sensorRadioButton.setOnCheckedChangeListener((buttonView, isChecked) -> { diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientPlugin.java index b5ff92ee0e..4b6072ee1e 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientPlugin.java @@ -113,6 +113,7 @@ public class NSClientPlugin extends PluginBase { context.unbindService(mConnection); nsClientReceiverDelegate.unregisterReceivers(); + super.onStop(); } @Subscribe diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NsClientReceiverDelegate.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NsClientReceiverDelegate.java index 00d8d933ec..072ad6cd56 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NsClientReceiverDelegate.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NsClientReceiverDelegate.java @@ -109,7 +109,7 @@ class NsClientReceiverDelegate { boolean newAllowedState = true; - if (!ev.isCharging && chargingOnly) { + if (!ev.isCharging() && chargingOnly) { newAllowedState = false; } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewFragment.java index 63e06253a1..41c0611ce4 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewFragment.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewFragment.java @@ -3,7 +3,9 @@ package info.nightscout.androidaps.plugins.general.overview; import android.annotation.SuppressLint; import android.app.Activity; import android.app.NotificationManager; + import androidx.arch.core.util.Function; + import android.content.ActivityNotFoundException; import android.content.Context; import android.content.Intent; @@ -12,6 +14,7 @@ import android.graphics.Color; import android.graphics.Paint; import android.os.Bundle; import android.os.Handler; + import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentActivity; import androidx.fragment.app.FragmentManager; @@ -20,6 +23,7 @@ import androidx.appcompat.app.AlertDialog; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.appcompat.widget.PopupMenu; import androidx.recyclerview.widget.RecyclerView; + import android.text.SpannableString; import android.text.style.ForegroundColorSpan; import android.util.DisplayMetrics; @@ -350,7 +354,7 @@ public class OverviewFragment extends Fragment implements View.OnClickListener, else predictionsAvailable = false; - MenuItem item,dividerItem; + MenuItem item, dividerItem; CharSequence title; int titleMaxChars = 0; SpannableString s; @@ -358,7 +362,7 @@ public class OverviewFragment extends Fragment implements View.OnClickListener, if (predictionsAvailable) { item = popup.getMenu().add(Menu.NONE, CHARTTYPE.PRE.ordinal(), Menu.NONE, "Predictions"); title = item.getTitle(); - if (titleMaxChars < title.length()) titleMaxChars = title.length(); + if (titleMaxChars < title.length()) titleMaxChars = title.length(); s = new SpannableString(title); s.setSpan(new ForegroundColorSpan(ResourcesCompat.getColor(getResources(), R.color.prediction, null)), 0, s.length(), 0); item.setTitle(s); @@ -368,7 +372,7 @@ public class OverviewFragment extends Fragment implements View.OnClickListener, item = popup.getMenu().add(Menu.NONE, CHARTTYPE.BAS.ordinal(), Menu.NONE, MainApp.gs(R.string.overview_show_basals)); title = item.getTitle(); - if (titleMaxChars < title.length()) titleMaxChars = title.length(); + if (titleMaxChars < title.length()) titleMaxChars = title.length(); s = new SpannableString(title); s.setSpan(new ForegroundColorSpan(ResourcesCompat.getColor(getResources(), R.color.basal, null)), 0, s.length(), 0); item.setTitle(s); @@ -377,7 +381,7 @@ public class OverviewFragment extends Fragment implements View.OnClickListener, item = popup.getMenu().add(Menu.NONE, CHARTTYPE.ACTPRIM.ordinal(), Menu.NONE, MainApp.gs(R.string.overview_show_activity)); title = item.getTitle(); - if (titleMaxChars < title.length()) titleMaxChars = title.length(); + if (titleMaxChars < title.length()) titleMaxChars = title.length(); s = new SpannableString(title); s.setSpan(new ForegroundColorSpan(ResourcesCompat.getColor(getResources(), R.color.activity, null)), 0, s.length(), 0); item.setTitle(s); @@ -389,7 +393,7 @@ public class OverviewFragment extends Fragment implements View.OnClickListener, item = popup.getMenu().add(Menu.NONE, CHARTTYPE.IOB.ordinal(), Menu.NONE, MainApp.gs(R.string.overview_show_iob)); title = item.getTitle(); - if (titleMaxChars < title.length()) titleMaxChars = title.length(); + if (titleMaxChars < title.length()) titleMaxChars = title.length(); s = new SpannableString(title); s.setSpan(new ForegroundColorSpan(ResourcesCompat.getColor(getResources(), R.color.iob, null)), 0, s.length(), 0); item.setTitle(s); @@ -398,7 +402,7 @@ public class OverviewFragment extends Fragment implements View.OnClickListener, item = popup.getMenu().add(Menu.NONE, CHARTTYPE.COB.ordinal(), Menu.NONE, MainApp.gs(R.string.overview_show_cob)); title = item.getTitle(); - if (titleMaxChars < title.length()) titleMaxChars = title.length(); + if (titleMaxChars < title.length()) titleMaxChars = title.length(); s = new SpannableString(title); s.setSpan(new ForegroundColorSpan(ResourcesCompat.getColor(getResources(), R.color.cob, null)), 0, s.length(), 0); item.setTitle(s); @@ -407,7 +411,7 @@ public class OverviewFragment extends Fragment implements View.OnClickListener, item = popup.getMenu().add(Menu.NONE, CHARTTYPE.DEV.ordinal(), Menu.NONE, MainApp.gs(R.string.overview_show_deviations)); title = item.getTitle(); - if (titleMaxChars < title.length()) titleMaxChars = title.length(); + if (titleMaxChars < title.length()) titleMaxChars = title.length(); s = new SpannableString(title); s.setSpan(new ForegroundColorSpan(ResourcesCompat.getColor(getResources(), R.color.deviations, null)), 0, s.length(), 0); item.setTitle(s); @@ -416,7 +420,7 @@ public class OverviewFragment extends Fragment implements View.OnClickListener, item = popup.getMenu().add(Menu.NONE, CHARTTYPE.SEN.ordinal(), Menu.NONE, MainApp.gs(R.string.overview_show_sensitivity)); title = item.getTitle(); - if (titleMaxChars < title.length()) titleMaxChars = title.length(); + if (titleMaxChars < title.length()) titleMaxChars = title.length(); s = new SpannableString(title); s.setSpan(new ForegroundColorSpan(ResourcesCompat.getColor(getResources(), R.color.ratio, null)), 0, s.length(), 0); item.setTitle(s); @@ -425,7 +429,7 @@ public class OverviewFragment extends Fragment implements View.OnClickListener, item = popup.getMenu().add(Menu.NONE, CHARTTYPE.ACTSEC.ordinal(), Menu.NONE, MainApp.gs(R.string.overview_show_activity)); title = item.getTitle(); - if (titleMaxChars < title.length()) titleMaxChars = title.length(); + if (titleMaxChars < title.length()) titleMaxChars = title.length(); s = new SpannableString(title); s.setSpan(new ForegroundColorSpan(ResourcesCompat.getColor(getResources(), R.color.activity, null)), 0, s.length(), 0); item.setTitle(s); @@ -435,7 +439,7 @@ public class OverviewFragment extends Fragment implements View.OnClickListener, if (MainApp.devBranch) { item = popup.getMenu().add(Menu.NONE, CHARTTYPE.DEVSLOPE.ordinal(), Menu.NONE, "Deviation slope"); title = item.getTitle(); - if (titleMaxChars < title.length()) titleMaxChars = title.length(); + if (titleMaxChars < title.length()) titleMaxChars = title.length(); s = new SpannableString(title); s.setSpan(new ForegroundColorSpan(ResourcesCompat.getColor(getResources(), R.color.devslopepos, null)), 0, s.length(), 0); item.setTitle(s); @@ -444,7 +448,7 @@ public class OverviewFragment extends Fragment implements View.OnClickListener, } // Fairly good guestimate for required divider text size... - title = new String(new char[titleMaxChars+10]).replace("\0", "_"); + title = new String(new char[titleMaxChars + 10]).replace("\0", "_"); dividerItem.setTitle(title); popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { @@ -1465,13 +1469,13 @@ public class OverviewFragment extends Fragment implements View.OnClickListener, // set manual x bounds to have nice steps graphData.formatAxis(fromTime, endTime); - if(SP.getBoolean("showactivityprimary", true)) { - graphData.addActivity(fromTime, endTime, false,1d); - } - // Treatments graphData.addTreatments(fromTime, endTime); + if (SP.getBoolean("showactivityprimary", true)) { + graphData.addActivity(fromTime, endTime, false, 0.8d); + } + // add basal data if (pump.getPumpDescription().isTempBasalCapable && SP.getBoolean("showbasals", true)) { graphData.addBasals(fromTime, now, lowLine / graphData.maxY / 1.2d); @@ -1518,8 +1522,8 @@ public class OverviewFragment extends Fragment implements View.OnClickListener, secondGraphData.addDeviations(fromTime, now, useDevForScale, 1d); if (SP.getBoolean("showratios", false)) secondGraphData.addRatio(fromTime, now, useRatioForScale, 1d); - if(SP.getBoolean("showactivitysecondary", true)) - secondGraphData.addActivity(fromTime, endTime, useIAForScale,useIAForScale ? 2d: 1d); + if (SP.getBoolean("showactivitysecondary", true)) + secondGraphData.addActivity(fromTime, endTime, useIAForScale, 0.8d); if (SP.getBoolean("showdevslope", false) && MainApp.devBranch) secondGraphData.addDeviationSlope(fromTime, now, useDSForScale, 1d); diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewPlugin.java index 9633c8fbbe..4301ad6ec0 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewPlugin.java @@ -71,6 +71,7 @@ public class OverviewPlugin extends PluginBase { @Override protected void onStop() { MainApp.bus().unregister(this); + super.onStop(); } @Subscribe diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/dialogs/EditQuickWizardDialog.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/dialogs/EditQuickWizardDialog.java index 248ab30d7c..f4a689e34e 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/dialogs/EditQuickWizardDialog.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/dialogs/EditQuickWizardDialog.java @@ -8,6 +8,7 @@ import android.view.View; import android.view.ViewGroup; import android.view.Window; import android.view.WindowManager; +import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.EditText; import android.widget.Spinner; @@ -59,17 +60,17 @@ public class EditQuickWizardDialog extends DialogFragment implements View.OnClic getDialog().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN); View view = inflater.inflate(R.layout.overview_editquickwizard_dialog, container, false); - buttonEdit = (EditText) view.findViewById(R.id.overview_editquickwizard_button_edit); - carbsEdit = (EditText) view.findViewById(R.id.overview_editquickwizard_carbs_edit); - fromSpinner = (Spinner) view.findViewById(R.id.overview_editquickwizard_from_spinner); - toSpinner = (Spinner) view.findViewById(R.id.overview_editquickwizard_to_spinner); - useBGSpinner = (Spinner) view.findViewById(R.id.overview_editquickwizard_usebg_spinner); - useCOBSpinner = (Spinner) view.findViewById(R.id.overview_editquickwizard_usecob_spinner); - useBolusIOBSpinner = (Spinner) view.findViewById(R.id.overview_editquickwizard_usebolusiob_spinner); - useBasalIOBSpinner = (Spinner) view.findViewById(R.id.overview_editquickwizard_usebasaliob_spinner); - useTrendSpinner = (Spinner) view.findViewById(R.id.overview_editquickwizard_usetrend_spinner); - useSuperBolusSpinner = (Spinner) view.findViewById(R.id.overview_editquickwizard_usesuperbolus_spinner); - useTempTargetSpinner = (Spinner) view.findViewById(R.id.overview_editquickwizard_usetemptarget_spinner); + buttonEdit = view.findViewById(R.id.overview_editquickwizard_button_edit); + carbsEdit = view.findViewById(R.id.overview_editquickwizard_carbs_edit); + fromSpinner = view.findViewById(R.id.overview_editquickwizard_from_spinner); + toSpinner = view.findViewById(R.id.overview_editquickwizard_to_spinner); + useBGSpinner = view.findViewById(R.id.overview_editquickwizard_usebg_spinner); + useCOBSpinner = view.findViewById(R.id.overview_editquickwizard_usecob_spinner); + useBolusIOBSpinner = view.findViewById(R.id.overview_editquickwizard_usebolusiob_spinner); + useBasalIOBSpinner = view.findViewById(R.id.overview_editquickwizard_usebasaliob_spinner); + useTrendSpinner = view.findViewById(R.id.overview_editquickwizard_usetrend_spinner); + useSuperBolusSpinner = view.findViewById(R.id.overview_editquickwizard_usesuperbolus_spinner); + useTempTargetSpinner = view.findViewById(R.id.overview_editquickwizard_usetemptarget_spinner); view.findViewById(R.id.ok).setOnClickListener(this); view.findViewById(R.id.cancel).setOnClickListener(this); @@ -104,6 +105,19 @@ public class EditQuickWizardDialog extends DialogFragment implements View.OnClic setSelection(useSuperBolusSpinner, entry.useSuperBolus()); setSelection(useTempTargetSpinner, entry.useTempTarget()); + useCOBSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { + @Override + public void onItemSelected(AdapterView parent, View view, int position, long id) { + processCob(); + } + + @Override + public void onNothingSelected(AdapterView parent) { + + } + }); + processCob(); + return view; } @@ -147,6 +161,18 @@ public class EditQuickWizardDialog extends DialogFragment implements View.OnClic } } + private void processCob() { + if (getSelection(useCOBSpinner) == QuickWizardEntry.YES) { + useBolusIOBSpinner.setEnabled(false); + useBasalIOBSpinner.setEnabled(false); + setSelection(useBolusIOBSpinner, QuickWizardEntry.YES); + setSelection(useBasalIOBSpinner, QuickWizardEntry.YES); + } else { + useBolusIOBSpinner.setEnabled(true); + useBasalIOBSpinner.setEnabled(true); + } + } + int getSelection(Spinner spinner) { String value = spinner.getSelectedItem().toString(); if (value.equals(MainApp.gs(R.string.yes))) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/dialogs/NewCarbsDialog.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/dialogs/NewCarbsDialog.java index 3f7fd53c02..23352f3d5b 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/dialogs/NewCarbsDialog.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/dialogs/NewCarbsDialog.java @@ -75,8 +75,6 @@ public class NewCarbsDialog extends DialogFragment implements OnClickListener, C private boolean okClicked; public NewCarbsDialog() { - HandlerThread mHandlerThread = new HandlerThread(NewCarbsDialog.class.getSimpleName()); - mHandlerThread.start(); } final private TextWatcher textWatcher = new TextWatcher() { diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/dialogs/NewInsulinDialog.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/dialogs/NewInsulinDialog.java index a03bb6e882..d5d4308f63 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/dialogs/NewInsulinDialog.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/dialogs/NewInsulinDialog.java @@ -75,8 +75,6 @@ public class NewInsulinDialog extends DialogFragment implements OnClickListener private boolean okClicked; public NewInsulinDialog() { - HandlerThread mHandlerThread = new HandlerThread(NewInsulinDialog.class.getSimpleName()); - mHandlerThread.start(); } final private TextWatcher textWatcher = new TextWatcher() { diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/dialogs/WizardDialog.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/dialogs/WizardDialog.java deleted file mode 100644 index fb903f3bae..0000000000 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/dialogs/WizardDialog.java +++ /dev/null @@ -1,450 +0,0 @@ -package info.nightscout.androidaps.plugins.general.overview.dialogs; - -import android.app.Activity; -import android.content.Context; -import android.os.Bundle; -import androidx.fragment.app.DialogFragment; -import androidx.appcompat.app.AlertDialog; -import android.text.Editable; -import android.text.TextWatcher; -import android.view.LayoutInflater; -import android.view.View; -import android.view.View.OnClickListener; -import android.view.ViewGroup; -import android.view.Window; -import android.view.WindowManager; -import android.widget.AdapterView; -import android.widget.ArrayAdapter; -import android.widget.Button; -import android.widget.CheckBox; -import android.widget.CompoundButton; -import android.widget.EditText; -import android.widget.LinearLayout; -import android.widget.Spinner; -import android.widget.TextView; - -import com.squareup.otto.Subscribe; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.text.DecimalFormat; -import java.util.ArrayList; - -import info.nightscout.androidaps.Constants; -import info.nightscout.androidaps.MainApp; -import info.nightscout.androidaps.R; -import info.nightscout.androidaps.data.IobTotal; -import info.nightscout.androidaps.data.Profile; -import info.nightscout.androidaps.data.ProfileStore; -import info.nightscout.androidaps.db.BgReading; -import info.nightscout.androidaps.db.DatabaseHelper; -import info.nightscout.androidaps.db.TempTarget; -import info.nightscout.androidaps.events.EventFeatureRunning; -import info.nightscout.androidaps.interfaces.Constraint; -import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin; -import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions; -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.CobInfo; -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin; -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventAutosensCalculationFinished; -import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin; -import info.nightscout.androidaps.utils.BolusWizard; -import info.nightscout.androidaps.utils.DecimalFormatter; -import info.nightscout.androidaps.utils.NumberPicker; -import info.nightscout.androidaps.utils.SP; -import info.nightscout.androidaps.utils.SafeParse; -import info.nightscout.androidaps.utils.StringUtils; -import info.nightscout.androidaps.utils.ToastUtils; - -public class WizardDialog extends DialogFragment implements OnClickListener, CompoundButton.OnCheckedChangeListener, Spinner.OnItemSelectedListener { - private static Logger log = LoggerFactory.getLogger(WizardDialog.class); - - Button okButton; - TextView bg; - TextView bgInsulin; - TextView bgUnits; - CheckBox bgCheckbox; - CheckBox ttCheckbox; - TextView carbs; - TextView carbsInsulin; - TextView bolusIobInsulin; - TextView basalIobInsulin; - CheckBox bolusIobCheckbox; - CheckBox basalIobCheckbox; - TextView correctionInsulin; - TextView total; - Spinner profileSpinner; - CheckBox superbolusCheckbox; - TextView superbolus; - TextView superbolusInsulin; - CheckBox bgtrendCheckbox; - TextView bgTrend; - TextView bgTrendInsulin; - LinearLayout cobLayout; - CheckBox cobCheckbox; - TextView cob; - TextView cobInsulin; - - NumberPicker editBg; - NumberPicker editCarbs; - NumberPicker editCorr; - NumberPicker editCarbTime; - - LinearLayout notesLayout; - EditText notesEdit; - - Integer calculatedCarbs = 0; - BolusWizard wizard; - - Context context; - - //one shot guards - private boolean accepted; - private boolean okClicked; - - public WizardDialog() { - super(); - } - - @Override - public void onAttach(Context context) { - super.onAttach(context); - this.context = context; - } - - @Override - public void onDetach() { - super.onDetach(); - this.context = null; - } - - @Override - public void onResume() { - super.onResume(); - MainApp.bus().register(this); - MainApp.bus().post(new EventFeatureRunning(EventFeatureRunning.Feature.WIZARD)); - } - - @Override - public void onPause() { - super.onPause(); - MainApp.bus().unregister(this); - } - - @Override - public void onSaveInstanceState(Bundle savedInstanceState) { - savedInstanceState.putBoolean("bgCheckbox", bgCheckbox.isChecked()); - savedInstanceState.putBoolean("ttCheckbox", ttCheckbox.isChecked()); - savedInstanceState.putBoolean("bolusIobCheckbox", bolusIobCheckbox.isChecked()); - savedInstanceState.putBoolean("basalIobCheckbox", basalIobCheckbox.isChecked()); - savedInstanceState.putBoolean("bgtrendCheckbox", bgtrendCheckbox.isChecked()); - savedInstanceState.putBoolean("cobCheckbox", cobCheckbox.isChecked()); - savedInstanceState.putDouble("editBg", editBg.getValue()); - savedInstanceState.putDouble("editCarbs", editCarbs.getValue()); - savedInstanceState.putDouble("editCorr", editCorr.getValue()); - savedInstanceState.putDouble("editCarbTime", editCarbTime.getValue()); - super.onSaveInstanceState(savedInstanceState); - } - - - @Subscribe - public void onStatusEvent(final EventAutosensCalculationFinished e) { - Activity activity = getActivity(); - if (activity != null) - activity.runOnUiThread(new Runnable() { - @Override - public void run() { - calculateInsulin(); - } - }); - } - - final private TextWatcher textWatcher = new TextWatcher() { - @Override - public void afterTextChanged(Editable s) { - } - - @Override - public void beforeTextChanged(CharSequence s, int start, int count, int after) { - } - - @Override - public void onTextChanged(CharSequence s, int start, int before, int count) { - calculateInsulin(); - } - }; - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.overview_wizard_dialog, container, false); - - getDialog().getWindow().requestFeature(Window.FEATURE_NO_TITLE); - getDialog().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN); - - okButton = (Button) view.findViewById(R.id.ok); - okButton.setOnClickListener(this); - view.findViewById(R.id.cancel).setOnClickListener(this); - - bg = (TextView) view.findViewById(R.id.treatments_wizard_bg); - bgInsulin = (TextView) view.findViewById(R.id.treatments_wizard_bginsulin); - bgUnits = (TextView) view.findViewById(R.id.treatments_wizard_bgunits); - carbs = (TextView) view.findViewById(R.id.treatments_wizard_carbs); - carbsInsulin = (TextView) view.findViewById(R.id.treatments_wizard_carbsinsulin); - bolusIobInsulin = (TextView) view.findViewById(R.id.treatments_wizard_bolusiobinsulin); - basalIobInsulin = (TextView) view.findViewById(R.id.treatments_wizard_basaliobinsulin); - correctionInsulin = (TextView) view.findViewById(R.id.treatments_wizard_correctioninsulin); - total = (TextView) view.findViewById(R.id.treatments_wizard_total); - superbolus = (TextView) view.findViewById(R.id.treatments_wizard_sb); - superbolusInsulin = (TextView) view.findViewById(R.id.treatments_wizard_sbinsulin); - - notesLayout = view.findViewById(R.id.treatments_wizard_notes_layout); - notesLayout.setVisibility(SP.getBoolean(R.string.key_show_notes_entry_dialogs, false) ? View.VISIBLE : View.GONE); - notesEdit = (EditText) view.findViewById(R.id.treatment_wizard_notes); - - bgTrend = (TextView) view.findViewById(R.id.treatments_wizard_bgtrend); - bgTrendInsulin = (TextView) view.findViewById(R.id.treatments_wizard_bgtrendinsulin); - cobLayout = (LinearLayout) view.findViewById(R.id.treatments_wizard_cob_layout); - cob = (TextView) view.findViewById(R.id.treatments_wizard_cob); - cobInsulin = (TextView) view.findViewById(R.id.treatments_wizard_cobinsulin); - - bgCheckbox = (CheckBox) view.findViewById(R.id.treatments_wizard_bgcheckbox); - ttCheckbox = (CheckBox) view.findViewById(R.id.treatments_wizard_ttcheckbox); - bgtrendCheckbox = (CheckBox) view.findViewById(R.id.treatments_wizard_bgtrendcheckbox); - cobCheckbox = (CheckBox) view.findViewById(R.id.treatments_wizard_cobcheckbox); - bolusIobCheckbox = (CheckBox) view.findViewById(R.id.treatments_wizard_bolusiobcheckbox); - basalIobCheckbox = (CheckBox) view.findViewById(R.id.treatments_wizard_basaliobcheckbox); - superbolusCheckbox = (CheckBox) view.findViewById(R.id.treatments_wizard_sbcheckbox); - loadCheckedStates(); - - bgCheckbox.setOnCheckedChangeListener(this); - ttCheckbox.setOnCheckedChangeListener(this); - bgtrendCheckbox.setOnCheckedChangeListener(this); - cobCheckbox.setOnCheckedChangeListener(this); - basalIobCheckbox.setOnCheckedChangeListener(this); - bolusIobCheckbox.setOnCheckedChangeListener(this); - superbolusCheckbox.setOnCheckedChangeListener(this); - - profileSpinner = (Spinner) view.findViewById(R.id.treatments_wizard_profile); - profileSpinner.setOnItemSelectedListener(this); - - editCarbTime = (NumberPicker) view.findViewById(R.id.treatments_wizard_carbtimeinput); - editCorr = (NumberPicker) view.findViewById(R.id.treatments_wizard_correctioninput); - editCarbs = (NumberPicker) view.findViewById(R.id.treatments_wizard_carbsinput); - editBg = (NumberPicker) view.findViewById(R.id.treatments_wizard_bginput); - - superbolusCheckbox.setVisibility(SP.getBoolean(R.string.key_usesuperbolus, false) ? View.VISIBLE : View.GONE); - - Integer maxCarbs = MainApp.getConstraintChecker().getMaxCarbsAllowed().value(); - Double maxCorrection = MainApp.getConstraintChecker().getMaxBolusAllowed().value(); - - editBg.setParams(0d, 0d, 500d, 0.1d, new DecimalFormat("0.0"), false, view.findViewById(R.id.ok), textWatcher); - editCarbs.setParams(0d, 0d, (double) maxCarbs, 1d, new DecimalFormat("0"), false, view.findViewById(R.id.ok), textWatcher); - double bolusstep = ConfigBuilderPlugin.getPlugin().getActivePump().getPumpDescription().bolusStep; - editCorr.setParams(0d, -maxCorrection, maxCorrection, bolusstep, DecimalFormatter.pumpSupportedBolusFormat(), false, view.findViewById(R.id.ok), textWatcher); - editCarbTime.setParams(0d, -60d, 60d, 5d, new DecimalFormat("0"), false, view.findViewById(R.id.ok), textWatcher); - initDialog(); - - setCancelable(true); - getDialog().setCanceledOnTouchOutside(false); - //recovering state if there is something - if (savedInstanceState != null) { - editCarbs.setValue(savedInstanceState.getDouble("editCarbs")); - editBg.setValue(savedInstanceState.getDouble("editBg")); - editCarbTime.setValue(savedInstanceState.getDouble("editCarbTime")); - editCorr.setValue(savedInstanceState.getDouble("editCorr")); - } - return view; - } - - @Override - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - saveCheckedStates(); - ttCheckbox.setEnabled(bgCheckbox.isChecked() && TreatmentsPlugin.getPlugin().getTempTargetFromHistory() != null); - calculateInsulin(); - } - - private void saveCheckedStates() { - SP.putBoolean(MainApp.gs(R.string.key_wizard_include_cob), cobCheckbox.isChecked()); - SP.putBoolean(MainApp.gs(R.string.key_wizard_include_trend_bg), bgtrendCheckbox.isChecked()); - } - - private void loadCheckedStates() { - bgtrendCheckbox.setChecked(SP.getBoolean(MainApp.gs(R.string.key_wizard_include_trend_bg), false)); - cobCheckbox.setChecked(SP.getBoolean(MainApp.gs(R.string.key_wizard_include_cob), false)); - } - - @Override - public void onItemSelected(AdapterView parent, View view, int position, long id) { - calculateInsulin(); - okButton.setVisibility(View.VISIBLE); - } - - @Override - public void onNothingSelected(AdapterView parent) { - ToastUtils.showToastInUiThread(context, MainApp.gs(R.string.noprofileselected)); - okButton.setVisibility(View.GONE); - } - - @Override - public synchronized void onClick(View view) { - switch (view.getId()) { - case R.id.ok: - if (okClicked) { - log.debug("guarding: ok already clicked"); - dismiss(); - return; - } - okClicked = true; - wizard.confirmAndExecute(context); - dismiss(); - break; - case R.id.cancel: - dismiss(); - break; - } - } - - private void initDialog() { - Profile profile = ProfileFunctions.getInstance().getProfile(); - ProfileStore profileStore = ConfigBuilderPlugin.getPlugin().getActiveProfileInterface() != null ? ConfigBuilderPlugin.getPlugin().getActiveProfileInterface().getProfile() : null; - - if (profile == null || profileStore == null) { - ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), MainApp.gs(R.string.noprofile)); - dismiss(); - return; - } - - ArrayList profileList; - profileList = profileStore.getProfileList(); - profileList.add(0, MainApp.gs(R.string.active)); - ArrayAdapter adapter = new ArrayAdapter<>(getContext(), - R.layout.spinner_centered, profileList); - - profileSpinner.setAdapter(adapter); - - String units = profile.getUnits(); - bgUnits.setText(units); - if (units.equals(Constants.MGDL)) editBg.setStep(1d); - else editBg.setStep(0.1d); - - // Set BG if not old - BgReading lastBg = DatabaseHelper.actualBg(); - - if (lastBg != null) { - editBg.setValue(lastBg.valueToUnits(units)); - } else { - editBg.setValue(0d); - } - ttCheckbox.setEnabled(TreatmentsPlugin.getPlugin().getTempTargetFromHistory() != null); - - // IOB calculation - TreatmentsPlugin.getPlugin().updateTotalIOBTreatments(); - IobTotal bolusIob = TreatmentsPlugin.getPlugin().getLastCalculationTreatments().round(); - TreatmentsPlugin.getPlugin().updateTotalIOBTempBasals(); - IobTotal basalIob = TreatmentsPlugin.getPlugin().getLastCalculationTempBasals().round(); - - bolusIobInsulin.setText(StringUtils.formatInsulin(-bolusIob.iob)); - basalIobInsulin.setText(StringUtils.formatInsulin(-basalIob.basaliob)); - - calculateInsulin(); - } - - private void calculateInsulin() { - ProfileStore profileStore = ConfigBuilderPlugin.getPlugin().getActiveProfileInterface().getProfile(); - if (profileSpinner == null || profileSpinner.getSelectedItem() == null || profileStore == null) - return; // not initialized yet - String profileName = profileSpinner.getSelectedItem().toString(); - Profile specificProfile; - if (profileName.equals(MainApp.gs(R.string.active))) { - specificProfile = ProfileFunctions.getInstance().getProfile(); - profileName = ProfileFunctions.getInstance().getProfileName(); - } else - specificProfile = profileStore.getSpecificProfile(profileName); - - // Entered values - Double c_bg = SafeParse.stringToDouble(editBg.getText()); - Integer c_carbs = SafeParse.stringToInt(editCarbs.getText()); - Double c_correction = SafeParse.stringToDouble(editCorr.getText()); - Double corrAfterConstraint = c_correction; - if (c_correction > 0) - c_correction = MainApp.getConstraintChecker().applyBolusConstraints(new Constraint<>(c_correction)).value(); - if (Math.abs(c_correction - corrAfterConstraint) > 0.01d) { // c_correction != corrAfterConstraint doesn't work - editCorr.setValue(0d); - ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), MainApp.gs(R.string.bolusconstraintapplied)); - return; - } - Integer carbsAfterConstraint = MainApp.getConstraintChecker().applyCarbsConstraints(new Constraint<>(c_carbs)).value(); - if (Math.abs(c_carbs - carbsAfterConstraint) > 0.01d) { - editCarbs.setValue(0d); - ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), MainApp.gs(R.string.carbsconstraintapplied)); - return; - } - - c_bg = bgCheckbox.isChecked() ? c_bg : 0d; - TempTarget tempTarget = ttCheckbox.isChecked() ? TreatmentsPlugin.getPlugin().getTempTargetFromHistory() : null; - - // COB - Double c_cob = 0d; - if (cobCheckbox.isChecked()) { - CobInfo cobInfo = IobCobCalculatorPlugin.getPlugin().getCobInfo(false, "Wizard COB"); - if (cobInfo.displayCob != null) - c_cob = cobInfo.displayCob; - } - - int carbTime = SafeParse.stringToInt(editCarbTime.getText()); - - wizard = new BolusWizard(specificProfile, profileName, tempTarget, carbsAfterConstraint, c_cob, c_bg, corrAfterConstraint, 100d, bgCheckbox.isChecked(), cobCheckbox.isChecked(), bolusIobCheckbox.isChecked(), basalIobCheckbox.isChecked(), superbolusCheckbox.isChecked(), ttCheckbox.isChecked(), bgtrendCheckbox.isChecked(), notesEdit.getText().toString(), carbTime); - - bg.setText(c_bg + " ISF: " + DecimalFormatter.to1Decimal(wizard.getSens())); - bgInsulin.setText(StringUtils.formatInsulin(wizard.getInsulinFromBG())); - - carbs.setText(DecimalFormatter.to0Decimal(c_carbs) + "g IC: " + DecimalFormatter.to1Decimal(wizard.getIc())); - carbsInsulin.setText(StringUtils.formatInsulin(wizard.getInsulinFromCarbs())); - - bolusIobInsulin.setText(StringUtils.formatInsulin(wizard.getInsulinFromBolusIOB())); - basalIobInsulin.setText(StringUtils.formatInsulin(wizard.getInsulinFromBasalsIOB())); - - correctionInsulin.setText(StringUtils.formatInsulin(wizard.getInsulinFromCorrection())); - - calculatedCarbs = carbsAfterConstraint; - - // Superbolus - superbolus.setText(superbolusCheckbox.isChecked() ? MainApp.gs(R.string.twohours) : ""); - superbolusInsulin.setText(StringUtils.formatInsulin(wizard.getInsulinFromSuperBolus())); - - // Trend - if (bgtrendCheckbox.isChecked() && wizard.getGlucoseStatus() != null) { - bgTrend.setText( - (wizard.getTrend() > 0 ? "+" : "") - + Profile.toUnitsString(wizard.getTrend() * 3, wizard.getTrend() * 3 / Constants.MMOLL_TO_MGDL, specificProfile.getUnits()) - + " " + specificProfile.getUnits()); - } else { - bgTrend.setText(""); - } - bgTrendInsulin.setText(StringUtils.formatInsulin(wizard.getInsulinFromTrend())); - - // COB - if (cobCheckbox.isChecked()) { - cob.setText(DecimalFormatter.to2Decimal(c_cob) + "g IC: " + DecimalFormatter.to1Decimal(wizard.getIc())); - cobInsulin.setText(StringUtils.formatInsulin(wizard.getInsulinFromCOB())); - } else { - cob.setText(""); - cobInsulin.setText(""); - } - - if (wizard.getCalculatedTotalInsulin() > 0d || calculatedCarbs > 0d) { - String insulinText = wizard.getCalculatedTotalInsulin() > 0d ? (DecimalFormatter.toPumpSupportedBolus(wizard.getCalculatedTotalInsulin()) + "U") : ""; - String carbsText = calculatedCarbs > 0d ? (DecimalFormatter.to0Decimal(calculatedCarbs) + "g") : ""; - total.setText(MainApp.gs(R.string.result) + ": " + insulinText + " " + carbsText); - okButton.setVisibility(View.VISIBLE); - } else { - // TODO this should also be run when loading the dialog as the OK button is initially visible - // but does nothing if neither carbs nor insulin is > 0 - total.setText(MainApp.gs(R.string.missing) + " " + DecimalFormatter.to0Decimal(wizard.getCarbsEquivalent()) + "g"); - okButton.setVisibility(View.INVISIBLE); - } - - } - -} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/dialogs/WizardDialog.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/dialogs/WizardDialog.kt new file mode 100644 index 0000000000..1b54b0c69c --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/dialogs/WizardDialog.kt @@ -0,0 +1,344 @@ +package info.nightscout.androidaps.plugins.general.overview.dialogs + +import android.content.Context +import android.os.Bundle +import android.text.Editable +import android.text.TextWatcher +import android.view.* +import android.widget.AdapterView +import android.widget.AdapterView.* +import android.widget.ArrayAdapter +import android.widget.CompoundButton +import androidx.fragment.app.DialogFragment +import info.nightscout.androidaps.Constants +import info.nightscout.androidaps.MainApp +import info.nightscout.androidaps.R +import info.nightscout.androidaps.data.Profile +import info.nightscout.androidaps.db.DatabaseHelper +import info.nightscout.androidaps.events.EventFeatureRunning +import info.nightscout.androidaps.interfaces.Constraint +import info.nightscout.androidaps.plugins.bus.RxBus +import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin +import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions +import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin +import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventAutosensCalculationFinished +import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin +import info.nightscout.androidaps.utils.* +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.disposables.CompositeDisposable +import kotlinx.android.synthetic.main.okcancel.* +import kotlinx.android.synthetic.main.overview_wizard_dialog.* +import org.slf4j.LoggerFactory +import java.text.DecimalFormat +import java.util.* + +class WizardDialog : DialogFragment() { + private val log = LoggerFactory.getLogger(WizardDialog::class.java) + + private var wizard: BolusWizard? = null + private var parentContext: Context? = null + + //one shot guards + private var okClicked: Boolean = false + + private val textWatcher = object : TextWatcher { + override fun afterTextChanged(s: Editable) {} + + override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {} + + override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) { + calculateInsulin() + } + } + + private var disposable: CompositeDisposable = CompositeDisposable() + + override fun onAttach(context: Context?) { + super.onAttach(context) + this.parentContext = context + } + + override fun onDetach() { + super.onDetach() + this.parentContext = null + } + + override fun onResume() { + super.onResume() + MainApp.bus().post(EventFeatureRunning(EventFeatureRunning.Feature.WIZARD)) + } + + override fun onSaveInstanceState(savedInstanceState: Bundle) { + super.onSaveInstanceState(savedInstanceState) + savedInstanceState.putDouble("treatments_wizard_bginput", treatments_wizard_bginput.value) + savedInstanceState.putDouble("treatments_wizard_carbsinput", treatments_wizard_carbsinput.value) + savedInstanceState.putDouble("treatments_wizard_correctioninput", treatments_wizard_correctioninput.value) + savedInstanceState.putDouble("treatments_wizard_carbtimeinput", treatments_wizard_carbtimeinput.value) + } + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle?): View? { + dialog.window?.requestFeature(Window.FEATURE_NO_TITLE) + dialog.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN) + isCancelable = true + dialog.setCanceledOnTouchOutside(false) + + return inflater.inflate(R.layout.overview_wizard_dialog, container, false) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + loadCheckedStates() + processCobCheckBox() + treatments_wizard_sbcheckbox.visibility = if (SP.getBoolean(R.string.key_usesuperbolus, false)) View.VISIBLE else View.GONE + treatments_wizard_notes_layout.visibility = if (SP.getBoolean(R.string.key_show_notes_entry_dialogs, false)) View.VISIBLE else View.GONE + + val maxCarbs = MainApp.getConstraintChecker().maxCarbsAllowed.value() + val maxCorrection = MainApp.getConstraintChecker().maxBolusAllowed.value() + + treatments_wizard_bginput.setParams(savedInstanceState?.getDouble("treatments_wizard_bginput") + ?: 0.0, 0.0, 500.0, 0.1, DecimalFormat("0.0"), false, ok, textWatcher) + treatments_wizard_carbsinput.setParams(savedInstanceState?.getDouble("treatments_wizard_carbsinput") + ?: 0.0, 0.0, maxCarbs.toDouble(), 1.0, DecimalFormat("0"), false, ok, textWatcher) + val bolusstep = ConfigBuilderPlugin.getPlugin().activePump?.pumpDescription?.bolusStep + ?: 0.1 + treatments_wizard_correctioninput.setParams(savedInstanceState?.getDouble("treatments_wizard_correctioninput") + ?: 0.0, -maxCorrection, maxCorrection, bolusstep, DecimalFormatter.pumpSupportedBolusFormat(), false, ok, textWatcher) + treatments_wizard_carbtimeinput.setParams(savedInstanceState?.getDouble("treatments_wizard_carbtimeinput") + ?: 0.0, -60.0, 60.0, 5.0, DecimalFormat("0"), false, ok, textWatcher) + initDialog() + + // ok button + ok.setOnClickListener { + if (okClicked) { + log.debug("guarding: ok already clicked") + } else { + okClicked = true + parentContext?.let { context -> + wizard?.confirmAndExecute(context) + } + } + dismiss() + } + // cancel button + cancel.setOnClickListener { dismiss() } + // checkboxes + treatments_wizard_bgcheckbox.setOnCheckedChangeListener { buttonView, _ -> onCheckedChanged(buttonView) } + treatments_wizard_ttcheckbox.setOnCheckedChangeListener { buttonView, _ -> onCheckedChanged(buttonView) } + treatments_wizard_cobcheckbox.setOnCheckedChangeListener { buttonView, _ -> onCheckedChanged(buttonView) } + treatments_wizard_basaliobcheckbox.setOnCheckedChangeListener { buttonView, _ -> onCheckedChanged(buttonView) } + treatments_wizard_bolusiobcheckbox.setOnCheckedChangeListener { buttonView, _ -> onCheckedChanged(buttonView) } + treatments_wizard_bgtrendcheckbox.setOnCheckedChangeListener { buttonView, _ -> onCheckedChanged(buttonView) } + // profile spinner + treatments_wizard_profile.onItemSelectedListener = object : OnItemSelectedListener { + override fun onNothingSelected(parent: AdapterView<*>?) { + ToastUtils.showToastInUiThread(MainApp.instance().applicationContext, MainApp.gs(R.string.noprofileselected)) + ok.visibility = View.GONE + } + + override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) { + calculateInsulin() + ok.visibility = View.VISIBLE + } + } + // bus + disposable.add(RxBus + .toObservable(EventAutosensCalculationFinished::class.java) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe({ + activity?.runOnUiThread { calculateInsulin() } + }, { + FabricPrivacy.logException(it) + }) + ) + + } + + override fun onDestroyView() { + super.onDestroyView() + disposable.clear() + } + + fun onCheckedChanged(buttonView: CompoundButton) { + saveCheckedStates() + treatments_wizard_ttcheckbox.isEnabled = treatments_wizard_bgcheckbox.isChecked && TreatmentsPlugin.getPlugin().tempTargetFromHistory != null + if (buttonView.id == treatments_wizard_cobcheckbox.id) + processCobCheckBox() + calculateInsulin() + } + + private fun processCobCheckBox() { + if (treatments_wizard_cobcheckbox.isChecked) { + treatments_wizard_bolusiobcheckbox.isEnabled = false + treatments_wizard_basaliobcheckbox.isEnabled = false + treatments_wizard_bolusiobcheckbox.isChecked = true + treatments_wizard_basaliobcheckbox.isChecked = true + } else { + treatments_wizard_bolusiobcheckbox.isEnabled = true + treatments_wizard_basaliobcheckbox.isEnabled = true + } + } + + private fun saveCheckedStates() { + SP.putBoolean(MainApp.gs(R.string.key_wizard_include_cob), treatments_wizard_cobcheckbox.isChecked) + SP.putBoolean(MainApp.gs(R.string.key_wizard_include_trend_bg), treatments_wizard_bgtrendcheckbox.isChecked) + } + + private fun loadCheckedStates() { + treatments_wizard_bgtrendcheckbox.isChecked = SP.getBoolean(MainApp.gs(R.string.key_wizard_include_trend_bg), false) + treatments_wizard_cobcheckbox.isChecked = SP.getBoolean(MainApp.gs(R.string.key_wizard_include_cob), false) + } + + private fun initDialog() { + val profile = ProfileFunctions.getInstance().profile + val profileStore = ConfigBuilderPlugin.getPlugin().activeProfileInterface?.profile + + if (profile == null || profileStore == null) { + ToastUtils.showToastInUiThread(MainApp.instance().applicationContext, MainApp.gs(R.string.noprofile)) + dismiss() + return + } + + val profileList: ArrayList + profileList = profileStore.profileList + profileList.add(0, MainApp.gs(R.string.active)) + context?.let { context -> + val adapter = ArrayAdapter(context, R.layout.spinner_centered, profileList) + treatments_wizard_profile.adapter = adapter + } ?: return + + + val units = profile.units + treatments_wizard_bgunits.text = units + if (units == Constants.MGDL) + treatments_wizard_bginput.setStep(1.0) + else + treatments_wizard_bginput.setStep(0.1) + + // Set BG if not old + val lastBg = DatabaseHelper.actualBg() + + if (lastBg != null) { + treatments_wizard_bginput.value = lastBg.valueToUnits(units) + } else { + treatments_wizard_bginput.value = 0.0 + } + treatments_wizard_ttcheckbox.isEnabled = TreatmentsPlugin.getPlugin().tempTargetFromHistory != null + + // IOB calculation + TreatmentsPlugin.getPlugin().updateTotalIOBTreatments() + val bolusIob = TreatmentsPlugin.getPlugin().lastCalculationTreatments.round() + TreatmentsPlugin.getPlugin().updateTotalIOBTempBasals() + val basalIob = TreatmentsPlugin.getPlugin().lastCalculationTempBasals.round() + + treatments_wizard_bolusiobinsulin.text = StringUtils.formatInsulin(-bolusIob.iob) + treatments_wizard_basaliobinsulin.text = StringUtils.formatInsulin(-basalIob.basaliob) + + calculateInsulin() + + treatments_wizard_percent_used.visibility = if (SP.getInt(R.string.key_boluswizard_percentage, 100) != 100) View.VISIBLE else View.GONE + } + + private fun calculateInsulin() { + val profileStore = ConfigBuilderPlugin.getPlugin().activeProfileInterface?.profile + if (treatments_wizard_profile.selectedItem == null || profileStore == null) + return // not initialized yet + var profileName = treatments_wizard_profile.selectedItem.toString() + val specificProfile: Profile? + if (profileName == MainApp.gs(R.string.active)) { + specificProfile = ProfileFunctions.getInstance().profile + profileName = ProfileFunctions.getInstance().profileName + } else + specificProfile = profileStore.getSpecificProfile(profileName) + + if (specificProfile == null) return + + // Entered values + var c_bg = SafeParse.stringToDouble(treatments_wizard_bginput.text) + val c_carbs = SafeParse.stringToInt(treatments_wizard_carbsinput.text) + var c_correction = SafeParse.stringToDouble(treatments_wizard_correctioninput.text) + val corrAfterConstraint = c_correction + if (c_correction > 0) + c_correction = MainApp.getConstraintChecker().applyBolusConstraints(Constraint(c_correction)).value() + if (Math.abs(c_correction - corrAfterConstraint) > 0.01) { // c_correction != corrAfterConstraint doesn't work + treatments_wizard_correctioninput.value = 0.0 + ToastUtils.showToastInUiThread(MainApp.instance().applicationContext, MainApp.gs(R.string.bolusconstraintapplied)) + return + } + val carbsAfterConstraint = MainApp.getConstraintChecker().applyCarbsConstraints(Constraint(c_carbs)).value() + if (Math.abs(c_carbs - carbsAfterConstraint) > 0.01) { + treatments_wizard_carbsinput.value = 0.0 + ToastUtils.showToastInUiThread(MainApp.instance().applicationContext, MainApp.gs(R.string.carbsconstraintapplied)) + return + } + + c_bg = if (treatments_wizard_bgcheckbox.isChecked) c_bg else 0.0 + val tempTarget = if (treatments_wizard_ttcheckbox.isChecked) TreatmentsPlugin.getPlugin().tempTargetFromHistory else null + + // COB + var c_cob = 0.0 + if (treatments_wizard_cobcheckbox.isChecked) { + val cobInfo = IobCobCalculatorPlugin.getPlugin().getCobInfo(false, "Wizard COB") + cobInfo.displayCob?.let { c_cob = it } + } + + val carbTime = SafeParse.stringToInt(treatments_wizard_carbtimeinput.text) + + wizard = BolusWizard(specificProfile, profileName, tempTarget, carbsAfterConstraint, c_cob, c_bg, corrAfterConstraint, + SP.getInt(R.string.key_boluswizard_percentage, 100).toDouble(), + treatments_wizard_bgcheckbox.isChecked, + treatments_wizard_cobcheckbox.isChecked, + treatments_wizard_bolusiobcheckbox.isChecked, + treatments_wizard_basaliobcheckbox.isChecked, + treatments_wizard_sbcheckbox.isChecked, + treatments_wizard_ttcheckbox.isChecked, + treatments_wizard_bgtrendcheckbox.isChecked, + treatment_wizard_notes.text.toString(), carbTime) + + wizard?.let { wizard -> + treatments_wizard_bg.text = c_bg.toString() + " ISF: " + DecimalFormatter.to1Decimal(wizard.sens) + treatments_wizard_bginsulin.text = StringUtils.formatInsulin(wizard.insulinFromBG) + + treatments_wizard_carbs.text = DecimalFormatter.to0Decimal(c_carbs.toDouble()) + "g IC: " + DecimalFormatter.to1Decimal(wizard.ic) + treatments_wizard_carbsinsulin.text = StringUtils.formatInsulin(wizard.insulinFromCarbs) + + treatments_wizard_bolusiobinsulin.text = StringUtils.formatInsulin(wizard.insulinFromBolusIOB) + treatments_wizard_basaliobinsulin.text = StringUtils.formatInsulin(wizard.insulinFromBasalsIOB) + + treatments_wizard_correctioninsulin.text = StringUtils.formatInsulin(wizard.insulinFromCorrection) + + // Superbolus + treatments_wizard_sb.text = if (treatments_wizard_sbcheckbox.isChecked) MainApp.gs(R.string.twohours) else "" + treatments_wizard_sbinsulin.text = StringUtils.formatInsulin(wizard.insulinFromSuperBolus) + + // Trend + if (treatments_wizard_bgtrendcheckbox.isChecked && wizard.glucoseStatus != null) { + treatments_wizard_bgtrend.text = ((if (wizard.trend > 0) "+" else "") + + Profile.toUnitsString(wizard.trend * 3, wizard.trend * 3 / Constants.MMOLL_TO_MGDL, specificProfile.units) + + " " + specificProfile.units) + } else { + treatments_wizard_bgtrend.text = "" + } + treatments_wizard_bgtrendinsulin.text = StringUtils.formatInsulin(wizard.insulinFromTrend) + + // COB + if (treatments_wizard_cobcheckbox.isChecked) { + treatments_wizard_cob.text = DecimalFormatter.to2Decimal(c_cob) + "g IC: " + DecimalFormatter.to1Decimal(wizard.ic) + treatments_wizard_cobinsulin.text = StringUtils.formatInsulin(wizard.insulinFromCOB) + } else { + treatments_wizard_cob.text = "" + treatments_wizard_cobinsulin.text = "" + } + + if (wizard.calculatedTotalInsulin > 0.0 || carbsAfterConstraint > 0.0) { + val insulinText = if (wizard.calculatedTotalInsulin > 0.0) DecimalFormatter.toPumpSupportedBolus(wizard.calculatedTotalInsulin) + "U" else "" + val carbsText = if (carbsAfterConstraint > 0.0) DecimalFormatter.to0Decimal(carbsAfterConstraint.toDouble()) + "g" else "" + treatments_wizard_total.text = MainApp.gs(R.string.result) + ": " + insulinText + " " + carbsText + ok.visibility = View.VISIBLE + } else { + treatments_wizard_total.text = MainApp.gs(R.string.missing) + " " + DecimalFormatter.to0Decimal(wizard.carbsEquivalent) + "g" + ok.visibility = View.INVISIBLE + } + } + + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/graphData/GraphData.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/graphData/GraphData.java index 0e2a7ead25..6de3e2c335 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/graphData/GraphData.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/graphData/GraphData.java @@ -357,7 +357,8 @@ public class GraphData { double now = System.currentTimeMillis(); Scale actScale = new Scale(); - IobTotal total = null; + IobTotal total; + double maxIAValue = 0; for (long time = fromTime; time <= toTime; time += 5 * 60 * 1000L) { Profile profile = ProfileFunctions.getInstance().getProfile(time); @@ -370,6 +371,7 @@ public class GraphData { actArrayHist.add(new ScaledDataPoint(time, act, actScale)); else actArrayPred.add(new ScaledDataPoint(time, act, actScale)); + if (act > maxIAValue) maxIAValue = act; } ScaledDataPoint[] actData = new ScaledDataPoint[actArrayHist.size()]; @@ -392,7 +394,6 @@ public class GraphData { paint.setColor(MainApp.gc(R.color.activity)); actSeriesPred.setCustomPaint(paint); - double maxIAValue = SP.getDouble(R.string.key_scale_insulin_activity, 0.05); if (useForScale) { maxY = maxIAValue; minY = -maxIAValue; diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/notifications/NotificationRecyclerViewAdapter.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/notifications/NotificationRecyclerViewAdapter.java index 6cb5c2fdf4..beea4c3733 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/notifications/NotificationRecyclerViewAdapter.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/notifications/NotificationRecyclerViewAdapter.java @@ -1,14 +1,16 @@ package info.nightscout.androidaps.plugins.general.overview.notifications; -import androidx.core.content.ContextCompat; -import androidx.cardview.widget.CardView; -import androidx.recyclerview.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Button; import android.widget.TextView; +import androidx.annotation.NonNull; +import androidx.cardview.widget.CardView; +import androidx.core.content.ContextCompat; +import androidx.recyclerview.widget.RecyclerView; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -29,10 +31,11 @@ public class NotificationRecyclerViewAdapter extends RecyclerView.Adapter notificationsList; - public NotificationRecyclerViewAdapter(List notificationsList) { + NotificationRecyclerViewAdapter(List notificationsList) { this.notificationsList = notificationsList; } + @NonNull @Override public NotificationsViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) { View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.overview_notification_item, viewGroup, false); @@ -46,10 +49,9 @@ public class NotificationRecyclerViewAdapter extends RecyclerView.Adapter= Build.VERSION_CODES.O) { NotificationManager mNotificationManager = - (NotificationManager) ctx.getSystemService(Context.NOTIFICATION_SERVICE); + (NotificationManager) MainApp.instance().getSystemService(Context.NOTIFICATION_SERVICE); @SuppressLint("WrongConstant") NotificationChannel channel = new NotificationChannel(CHANNEL_ID, CHANNEL_ID, NotificationManager.IMPORTANCE_HIGH); @@ -113,23 +111,26 @@ public class PersistentNotificationPlugin extends PluginBase { protected void onStop() { MainApp.bus().unregister(this); MainApp.instance().stopService(new Intent(MainApp.instance(), DummyService.class)); + super.onStop(); } - private void triggerNotificationUpdate() { + private void triggerNotificationUpdate(boolean boot) { + updateNotification(boot); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) MainApp.instance().startForegroundService(new Intent(MainApp.instance(), DummyService.class)); else MainApp.instance().startService(new Intent(MainApp.instance(), DummyService.class)); } - @Nonnull - public Notification updateNotification() { - String line1 = null; + private void updateNotification(boolean boot) { + String line1; String line2 = null; String line3 = null; NotificationCompat.CarExtender.UnreadConversation.Builder unreadConversationBuilder = null; - if (ConfigBuilderPlugin.getPlugin().getActiveProfileInterface() != null && ProfileFunctions.getInstance().isProfileValid("Notification")) { + if (boot) { + line1 = MainApp.gs(R.string.loading); + } else if (ConfigBuilderPlugin.getPlugin().getActiveProfileInterface() != null && ProfileFunctions.getInstance().isProfileValid("Notification")) { String line1_aa; String units = ProfileFunctions.getInstance().getProfileUnits(); @@ -185,7 +186,7 @@ public class PersistentNotificationPlugin extends PluginBase { .setPackage(PACKAGE); PendingIntent msgReadPendingIntent = - PendingIntent.getBroadcast(ctx, + PendingIntent.getBroadcast(MainApp.instance(), ONGOING_NOTIFICATION_ID, msgReadIntent, PendingIntent.FLAG_UPDATE_CURRENT); @@ -197,7 +198,7 @@ public class PersistentNotificationPlugin extends PluginBase { .setPackage(PACKAGE); PendingIntent msgReplyPendingIntent = PendingIntent.getBroadcast( - ctx, + MainApp.instance(), ONGOING_NOTIFICATION_ID, msgReplyIntent, PendingIntent.FLAG_UPDATE_CURRENT); @@ -215,18 +216,20 @@ public class PersistentNotificationPlugin extends PluginBase { /// Add dot to produce a "more natural sounding result" unreadConversationBuilder.addMessage(line3_aa); /// End Android Auto + } else { + line1 = MainApp.gs(R.string.noprofileset); } - NotificationCompat.Builder builder = new NotificationCompat.Builder(ctx, CHANNEL_ID); + NotificationCompat.Builder builder = new NotificationCompat.Builder(MainApp.instance(), CHANNEL_ID); builder.setOngoing(true); builder.setOnlyAlertOnce(true); builder.setCategory(NotificationCompat.CATEGORY_STATUS); builder.setSmallIcon(MainApp.getNotificationIcon()); - Bitmap largeIcon = BitmapFactory.decodeResource(ctx.getResources(), MainApp.getIcon()); + Bitmap largeIcon = BitmapFactory.decodeResource(MainApp.instance().getResources(), MainApp.getIcon()); builder.setLargeIcon(largeIcon); - builder.setContentTitle(line1 != null ? line1 : MainApp.gs(R.string.noprofileset)); - builder.setContentText(line2 != null ? line2 : MainApp.gs(R.string.noprofileset)); - builder.setSubText(line3 != null ? line3 : MainApp.gs(R.string.noprofileset)); + if (line1 != null) builder.setContentTitle(line1); + if (line2 != null) builder.setContentText(line2); + if (line3 != null) builder.setSubText(line3); /// Android Auto if (unreadConversationBuilder != null) { builder.extend(new NotificationCompat.CarExtender() @@ -235,9 +238,9 @@ public class PersistentNotificationPlugin extends PluginBase { /// End Android Auto - Intent resultIntent = new Intent(ctx, MainActivity.class); + Intent resultIntent = new Intent(MainApp.instance(), MainActivity.class); - TaskStackBuilder stackBuilder = TaskStackBuilder.create(ctx); + TaskStackBuilder stackBuilder = TaskStackBuilder.create(MainApp.instance()); stackBuilder.addParentStack(MainActivity.class); stackBuilder.addNextIntent(resultIntent); PendingIntent resultPendingIntent = @@ -247,12 +250,11 @@ public class PersistentNotificationPlugin extends PluginBase { ); builder.setContentIntent(resultPendingIntent); NotificationManager mNotificationManager = - (NotificationManager) ctx.getSystemService(Context.NOTIFICATION_SERVICE); + (NotificationManager) MainApp.instance().getSystemService(Context.NOTIFICATION_SERVICE); android.app.Notification notification = builder.build(); mNotificationManager.notify(ONGOING_NOTIFICATION_ID, notification); this.notification = notification; - return notification; } private String deltastring(double deltaMGDL, double deltaMMOL, String units) { @@ -279,48 +281,50 @@ public class PersistentNotificationPlugin extends PluginBase { public Notification getLastNotification() { if (notification != null) return notification; - else return new Notification(); + else { + throw new IllegalStateException("Notification is null"); + } } @Subscribe public void onStatusEvent(final EventPreferenceChange ev) { - triggerNotificationUpdate(); + triggerNotificationUpdate(false); } @Subscribe public void onStatusEvent(final EventTreatmentChange ev) { - triggerNotificationUpdate(); + triggerNotificationUpdate(false); } @Subscribe public void onStatusEvent(final EventTempBasalChange ev) { - triggerNotificationUpdate(); + triggerNotificationUpdate(false); } @Subscribe public void onStatusEvent(final EventExtendedBolusChange ev) { - triggerNotificationUpdate(); + triggerNotificationUpdate(false); } @Subscribe public void onStatusEvent(final EventAutosensCalculationFinished ev) { - triggerNotificationUpdate(); + triggerNotificationUpdate(false); } @Subscribe public void onStatusEvent(final EventNewBasalProfile ev) { - triggerNotificationUpdate(); + triggerNotificationUpdate(false); } @Subscribe public void onStatusEvent(final EventInitializationChanged ev) { - triggerNotificationUpdate(); + triggerNotificationUpdate(false); } @Subscribe public void onStatusEvent(final EventRefreshOverview ev) { - triggerNotificationUpdate(); + triggerNotificationUpdate(false); } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/SmsCommunicatorPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/SmsCommunicatorPlugin.java index 14dcb169c4..095997daf9 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/SmsCommunicatorPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/SmsCommunicatorPlugin.java @@ -98,6 +98,7 @@ public class SmsCommunicatorPlugin extends PluginBase { @Override protected void onStop() { MainApp.bus().unregister(this); + super.onStop(); } @Subscribe diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/TidepoolFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/TidepoolFragment.kt index 86eb704bab..f83b9cc243 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/TidepoolFragment.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/TidepoolFragment.kt @@ -16,17 +16,12 @@ import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.SP import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.disposables.CompositeDisposable -import io.reactivex.disposables.Disposable import kotlinx.android.synthetic.main.tidepool_fragment.* class TidepoolFragment : Fragment() { private var disposable: CompositeDisposable = CompositeDisposable() - operator fun CompositeDisposable.plusAssign(disposable: Disposable) { - add(disposable) - } - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { return inflater.inflate(R.layout.tidepool_fragment, container, false) } @@ -39,6 +34,7 @@ class TidepoolFragment : Fragment() { tidepool_resertstart.setOnClickListener { SP.putLong(R.string.key_tidepool_last_end, 0) } } + @Synchronized override fun onResume() { super.onResume() disposable.add(RxBus @@ -46,16 +42,17 @@ class TidepoolFragment : Fragment() { .observeOn(AndroidSchedulers.mainThread()) .subscribe({ TidepoolPlugin.updateLog() - tidepool_log.text = TidepoolPlugin.textLog - tidepool_status.text = TidepoolUploader.connectionStatus.name - tidepool_log.text = TidepoolPlugin.textLog - tidepool_logscrollview.fullScroll(ScrollView.FOCUS_DOWN) + tidepool_log?.text = TidepoolPlugin.textLog + tidepool_status?.text = TidepoolUploader.connectionStatus.name + tidepool_log?.text = TidepoolPlugin.textLog + tidepool_logscrollview?.fullScroll(ScrollView.FOCUS_DOWN) }, { FabricPrivacy.logException(it) }) ) } + @Synchronized override fun onPause() { super.onPause() disposable.clear() diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/TidepoolPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/TidepoolPlugin.kt index b7896d7e56..78ad0ab37d 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/TidepoolPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/TidepoolPlugin.kt @@ -1,6 +1,5 @@ package info.nightscout.androidaps.plugins.general.tidepool -import android.text.Html import android.text.Spanned import info.nightscout.androidaps.Constants import info.nightscout.androidaps.MainApp @@ -23,7 +22,6 @@ import info.nightscout.androidaps.receivers.ChargingStateReceiver import info.nightscout.androidaps.receivers.NetworkChangeReceiver import info.nightscout.androidaps.utils.* import io.reactivex.disposables.CompositeDisposable -import io.reactivex.disposables.Disposable import io.reactivex.schedulers.Schedulers import org.slf4j.LoggerFactory import java.util.* @@ -43,10 +41,6 @@ object TidepoolPlugin : PluginBase(PluginDescription() private val listLog = ArrayList() var textLog: Spanned = HtmlHelper.fromHtml("") - operator fun CompositeDisposable.plusAssign(disposable: Disposable) { - add(disposable) - } - override fun onStart() { super.onStart() disposable += RxBus diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/ActionStringHandler.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/ActionStringHandler.java index addc6517ec..1f1dd90463 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/ActionStringHandler.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/ActionStringHandler.java @@ -69,12 +69,6 @@ public class ActionStringHandler { private static String lastConfirmActionString = null; private static BolusWizard lastBolusWizard = null; - private static HandlerThread handlerThread = new HandlerThread(FillDialog.class.getSimpleName()); - - static { - handlerThread.start(); - } - public synchronized static void handleInitiate(String actionstring) { if (!SP.getBoolean("wearcontrol", false)) return; diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/WearPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/WearPlugin.java index 69e327a21b..53b421ace3 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/WearPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/WearPlugin.java @@ -91,6 +91,7 @@ public class WearPlugin extends PluginBase { protected void onStop() { MainApp.bus().unregister(this); disposable.clear(); + super.onStop(); } private void sendDataToWatch(boolean status, boolean basals, boolean bgValue) { diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobThread.java b/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobThread.java index 943637fd4e..4694685ea6 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobThread.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobThread.java @@ -22,6 +22,7 @@ import info.nightscout.androidaps.events.Event; import info.nightscout.androidaps.interfaces.PluginType; import info.nightscout.androidaps.logging.L; import info.nightscout.androidaps.plugins.aps.openAPSSMB.SMBDefaults; +import info.nightscout.androidaps.plugins.bus.RxBus; import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions; import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification; @@ -312,6 +313,7 @@ public class IobCobThread extends Thread { new Thread(() -> { SystemClock.sleep(1000); MainApp.bus().post(new EventAutosensCalculationFinished(cause)); + RxBus.INSTANCE.send(new EventAutosensCalculationFinished(cause)); }).start(); } finally { if (mWakeLock != null) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/events/EventAutosensCalculationFinished.java b/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/events/EventAutosensCalculationFinished.java deleted file mode 100644 index 25622843e7..0000000000 --- a/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/events/EventAutosensCalculationFinished.java +++ /dev/null @@ -1,16 +0,0 @@ -package info.nightscout.androidaps.plugins.iob.iobCobCalculator.events; - -import info.nightscout.androidaps.events.Event; -import info.nightscout.androidaps.events.EventLoop; - -/** - * Created by mike on 30.04.2017. - */ - -public class EventAutosensCalculationFinished extends EventLoop { - public Event cause; - - public EventAutosensCalculationFinished(Event cause) { - this.cause = cause; - } -} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/events/EventAutosensCalculationFinished.kt b/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/events/EventAutosensCalculationFinished.kt new file mode 100644 index 0000000000..aa96aaf0b0 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/events/EventAutosensCalculationFinished.kt @@ -0,0 +1,6 @@ +package info.nightscout.androidaps.plugins.iob.iobCobCalculator.events + +import info.nightscout.androidaps.events.Event +import info.nightscout.androidaps.events.EventLoop + +class EventAutosensCalculationFinished(var cause: Event) : EventLoop() diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/profile/ns/NSProfileFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/profile/ns/NSProfileFragment.kt index 56abf0008c..7a76283074 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/profile/ns/NSProfileFragment.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/profile/ns/NSProfileFragment.kt @@ -90,9 +90,9 @@ class NSProfileFragment : Fragment() { } } } - updateGUI() } + @Synchronized override fun onResume() { super.onResume() disposable.add(RxBus @@ -104,14 +104,18 @@ class NSProfileFragment : Fragment() { FabricPrivacy.logException(it) }) ) + updateGUI() } + @Synchronized override fun onPause() { super.onPause() disposable.clear() } + @Synchronized fun updateGUI() { + if (profileview_noprofile == null) return profileview_noprofile.visibility = View.VISIBLE NSProfilePlugin.getPlugin().profile?.let { profileStore -> diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/profile/ns/NSProfilePlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/profile/ns/NSProfilePlugin.java index 88faee377a..a6088f5515 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/profile/ns/NSProfilePlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/profile/ns/NSProfilePlugin.java @@ -65,6 +65,7 @@ public class NSProfilePlugin extends PluginBase implements ProfileInterface { @Override protected void onStop() { MainApp.bus().unregister(this); + super.onStop(); } public void handleNewData(Intent intent) { diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/common/PumpPluginAbstract.java b/app/src/main/java/info/nightscout/androidaps/plugins/pump/common/PumpPluginAbstract.java index 5badf23adc..cadfe82b22 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/common/PumpPluginAbstract.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/common/PumpPluginAbstract.java @@ -106,6 +106,7 @@ public abstract class PumpPluginAbstract extends PluginBase implements PumpInter serviceRunning = false; MainApp.bus().unregister(this); + super.onStop(); } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/RileyLinkConst.java b/app/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/RileyLinkConst.java index 1f6f9c7541..bff2a39240 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/RileyLinkConst.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/RileyLinkConst.java @@ -31,7 +31,7 @@ public class RileyLinkConst { //public static final String PrefPrefix = "pref_rileylink_"; //public static final String RileyLinkAddress = PrefPrefix + "mac_address"; // pref_rileylink_mac_address - public static final int RileyLinkAddress = R.string.pref_key_rileylink_mac_address; + public static final int RileyLinkAddress = R.string.key_rileylink_mac_address; public static final String LastGoodDeviceCommunicationTime = Prefix + "lastGoodDeviceCommunicationTime"; public static final String LastGoodDeviceFrequency = Prefix + "LastGoodDeviceFrequency"; } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/ble/RFSpy.java b/app/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/ble/RFSpy.java index 2911d97d67..1fb24821e1 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/ble/RFSpy.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/ble/RFSpy.java @@ -367,7 +367,7 @@ public class RFSpy { RileyLinkEncodingType encoding = RileyLinkEncodingType.FourByteSixByteLocal; if (RileyLinkFirmwareVersion.isSameVersion(this.firmwareVersion, RileyLinkFirmwareVersion.Version2AndHigher)) { - if (SP.getString(MedtronicConst.Prefs.Encoding, "None").equals(MainApp.gs(R.string.medtronic_pump_encoding_4b6b_rileylink))) { + if (SP.getString(MedtronicConst.Prefs.Encoding, "None").equals(MainApp.gs(R.string.key_medtronic_pump_encoding_4b6b_rileylink))) { encoding = RileyLinkEncodingType.FourByteSixByteRileyLink; } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/ble/defs/RileyLinkEncodingType.java b/app/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/ble/defs/RileyLinkEncodingType.java index 64691c924f..5482e224e3 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/ble/defs/RileyLinkEncodingType.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/ble/defs/RileyLinkEncodingType.java @@ -10,8 +10,8 @@ public enum RileyLinkEncodingType { None(0x00, null), // No encoding on RL Manchester(0x01, null), // Manchester encoding on RL (for Omnipod) - FourByteSixByteRileyLink(0x02, R.string.medtronic_pump_encoding_4b6b_rileylink), // 4b6b encoding on RL (for Medtronic) - FourByteSixByteLocal(0x00, R.string.medtronic_pump_encoding_4b6b_local), // No encoding on RL, but 4b6b encoding in code + FourByteSixByteRileyLink(0x02, R.string.key_medtronic_pump_encoding_4b6b_rileylink), // 4b6b encoding on RL (for Medtronic) + FourByteSixByteLocal(0x00, R.string.key_medtronic_pump_encoding_4b6b_local), // No encoding on RL, but 4b6b encoding in code ; public byte value; diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/danaR/DanaRFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/pump/danaR/DanaRFragment.kt index 377e417274..b01bb22104 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/danaR/DanaRFragment.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/danaR/DanaRFragment.kt @@ -27,13 +27,9 @@ import info.nightscout.androidaps.plugins.pump.danaRKorean.DanaRKoreanPlugin import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin import info.nightscout.androidaps.plugins.treatments.fragments.ProfileViewerDialog import info.nightscout.androidaps.queue.events.EventQueueChanged -import info.nightscout.androidaps.utils.DateUtil -import info.nightscout.androidaps.utils.FabricPrivacy -import info.nightscout.androidaps.utils.SetWarnColor -import info.nightscout.androidaps.utils.T +import info.nightscout.androidaps.utils.* import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.disposables.CompositeDisposable -import io.reactivex.disposables.Disposable import kotlinx.android.synthetic.main.danar_fragment.* import org.slf4j.LoggerFactory @@ -41,10 +37,6 @@ class DanaRFragment : Fragment() { private val log = LoggerFactory.getLogger(L.PUMP) private var disposable: CompositeDisposable = CompositeDisposable() - operator fun CompositeDisposable.plusAssign(disposable: Disposable) { - add(disposable) - } - private val loopHandler = Handler() private lateinit var refreshLoop: Runnable @@ -84,9 +76,9 @@ class DanaRFragment : Fragment() { DanaRPump.getInstance().lastConnection = 0 ConfigBuilderPlugin.getPlugin().commandQueue.readStatus("Clicked connect to pump", null) } - updateGUI() } + @Synchronized override fun onResume() { super.onResume() MainApp.bus().register(this) @@ -95,8 +87,10 @@ class DanaRFragment : Fragment() { .toObservable(EventDanaRNewStatus::class.java) .observeOn(AndroidSchedulers.mainThread()) .subscribe({ updateGUI() }, { FabricPrivacy.logException(it) }) + updateGUI() } + @Synchronized override fun onPause() { super.onPause() disposable.clear() @@ -105,38 +99,40 @@ class DanaRFragment : Fragment() { } @Subscribe - public fun onStatusEvent(c: EventPumpStatusChanged) { + fun onStatusEvent(c: EventPumpStatusChanged) { activity?.runOnUiThread { when { - c.sStatus == EventPumpStatusChanged.CONNECTING -> danar_btconnection.text = "{fa-bluetooth-b spin} " + c.sSecondsElapsed + "s" - c.sStatus == EventPumpStatusChanged.CONNECTED -> danar_btconnection.text = "{fa-bluetooth}" - c.sStatus == EventPumpStatusChanged.DISCONNECTED -> danar_btconnection.text = "{fa-bluetooth-b}" + c.sStatus == EventPumpStatusChanged.CONNECTING -> danar_btconnection?.text = "{fa-bluetooth-b spin} " + c.sSecondsElapsed + "s" + c.sStatus == EventPumpStatusChanged.CONNECTED -> danar_btconnection?.text = "{fa-bluetooth}" + c.sStatus == EventPumpStatusChanged.DISCONNECTED -> danar_btconnection?.text = "{fa-bluetooth-b}" } if (c.textStatus() != "") { - dana_pumpstatus.text = c.textStatus() - dana_pumpstatuslayout.visibility = View.VISIBLE + dana_pumpstatus?.text = c.textStatus() + dana_pumpstatuslayout?.visibility = View.VISIBLE } else { - dana_pumpstatuslayout.visibility = View.GONE + dana_pumpstatuslayout?.visibility = View.GONE } } } @Subscribe - public fun onStatusEvent(s: EventTempBasalChange) = + fun onStatusEvent(s: EventTempBasalChange) = activity?.runOnUiThread { updateGUI() } @Subscribe - public fun onStatusEvent(s: EventExtendedBolusChange) = + fun onStatusEvent(s: EventExtendedBolusChange) = activity?.runOnUiThread { updateGUI() } @Subscribe - public fun onStatusEvent(s: EventQueueChanged) = + fun onStatusEvent(s: EventQueueChanged) = activity?.runOnUiThread { updateGUI() } // GUI functions + @Synchronized internal fun updateGUI() { + if (danar_dailyunits == null) return val pump = DanaRPump.getInstance() val plugin: PumpInterface = ConfigBuilderPlugin.getPlugin().activePump ?: return if (pump.lastConnection != 0L) { diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/danaR/DanaRPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/pump/danaR/DanaRPlugin.java index 80d0390390..6a01c5fed8 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/danaR/DanaRPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/danaR/DanaRPlugin.java @@ -65,6 +65,7 @@ public class DanaRPlugin extends AbstractDanaRPlugin { context.unbindService(mConnection); MainApp.bus().unregister(this); + super.onStop(); } private ServiceConnection mConnection = new ServiceConnection() { diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/danaR/activities/DanaRHistoryActivity.java b/app/src/main/java/info/nightscout/androidaps/plugins/pump/danaR/activities/DanaRHistoryActivity.java index dd28c632a7..2d31510e71 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/danaR/activities/DanaRHistoryActivity.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/danaR/activities/DanaRHistoryActivity.java @@ -1,12 +1,6 @@ package info.nightscout.androidaps.plugins.pump.danaR.activities; -import android.app.Activity; import android.os.Bundle; -import android.os.Handler; -import android.os.HandlerThread; -import androidx.cardview.widget.CardView; -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -16,6 +10,11 @@ import android.widget.Button; import android.widget.Spinner; import android.widget.TextView; +import androidx.annotation.NonNull; +import androidx.cardview.widget.CardView; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + import com.squareup.otto.Subscribe; import org.slf4j.Logger; @@ -47,14 +46,11 @@ import info.nightscout.androidaps.utils.ToastUtils; public class DanaRHistoryActivity extends NoSplashActivity { private static Logger log = LoggerFactory.getLogger(L.PUMP); - private Handler mHandler; - static Profile profile = null; Spinner historyTypeSpinner; TextView statusView; Button reloadButton; - Button syncButton; RecyclerView recyclerView; LinearLayoutManager llm; @@ -70,6 +66,7 @@ public class DanaRHistoryActivity extends NoSplashActivity { this.name = name; } + @NonNull @Override public String toString() { return name; @@ -78,9 +75,6 @@ public class DanaRHistoryActivity extends NoSplashActivity { public DanaRHistoryActivity() { super(); - HandlerThread mHandlerThread = new HandlerThread(DanaRHistoryActivity.class.getSimpleName()); - mHandlerThread.start(); - this.mHandler = new Handler(mHandlerThread.getLooper()); } @@ -101,11 +95,10 @@ public class DanaRHistoryActivity extends NoSplashActivity { super.onCreate(savedInstanceState); setContentView(R.layout.danar_historyactivity); - historyTypeSpinner = (Spinner) findViewById(R.id.danar_historytype); - statusView = (TextView) findViewById(R.id.danar_historystatus); - reloadButton = (Button) findViewById(R.id.danar_historyreload); - syncButton = (Button) findViewById(R.id.danar_historysync); - recyclerView = (RecyclerView) findViewById(R.id.danar_history_recyclerview); + historyTypeSpinner = findViewById(R.id.danar_historytype); + statusView = findViewById(R.id.danar_historystatus); + reloadButton = findViewById(R.id.danar_historyreload); + recyclerView = findViewById(R.id.danar_history_recyclerview); recyclerView.setHasFixedSize(true); llm = new LinearLayoutManager(this); @@ -145,7 +138,6 @@ public class DanaRHistoryActivity extends NoSplashActivity { final TypeList selected = (TypeList) historyTypeSpinner.getSelectedItem(); runOnUiThread(() -> { reloadButton.setVisibility(View.GONE); - syncButton.setVisibility(View.GONE); statusView.setVisibility(View.VISIBLE); }); clearCardView(); @@ -155,37 +147,12 @@ public class DanaRHistoryActivity extends NoSplashActivity { loadDataFromDB(selected.type); runOnUiThread(() -> { reloadButton.setVisibility(View.VISIBLE); - syncButton.setVisibility(View.VISIBLE); statusView.setVisibility(View.GONE); }); } }); }); - syncButton.setOnClickListener(v -> mHandler.post(new Runnable() { - @Override - public void run() { - runOnUiThread(new Runnable() { - @Override - public void run() { - reloadButton.setVisibility(View.GONE); - syncButton.setVisibility(View.GONE); - statusView.setVisibility(View.VISIBLE); - } - }); - DanaRNSHistorySync sync = new DanaRNSHistorySync(historyList); - sync.sync(DanaRNSHistorySync.SYNC_ALL); - runOnUiThread(new Runnable() { - @Override - public void run() { - reloadButton.setVisibility(View.VISIBLE); - syncButton.setVisibility(View.VISIBLE); - statusView.setVisibility(View.GONE); - } - }); - } - })); - historyTypeSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { @Override public void onItemSelected(AdapterView parent, View view, int position, long id) { @@ -214,14 +181,15 @@ public class DanaRHistoryActivity extends NoSplashActivity { this.historyList = historyList; } + @NonNull @Override - public HistoryViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) { + public HistoryViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int viewType) { View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.danar_history_item, viewGroup, false); return new HistoryViewHolder(v); } @Override - public void onBindViewHolder(HistoryViewHolder holder, int position) { + public void onBindViewHolder(@NonNull HistoryViewHolder holder, int position) { DanaRHistoryRecord record = historyList.get(position); holder.time.setText(DateUtil.dateAndTimeString(record.recordDate)); holder.value.setText(DecimalFormatter.to2Decimal(record.recordValue)); @@ -306,7 +274,7 @@ public class DanaRHistoryActivity extends NoSplashActivity { } @Override - public void onAttachedToRecyclerView(RecyclerView recyclerView) { + public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) { super.onAttachedToRecyclerView(recyclerView); } @@ -324,16 +292,16 @@ public class DanaRHistoryActivity extends NoSplashActivity { HistoryViewHolder(View itemView) { super(itemView); - cv = (CardView) itemView.findViewById(R.id.danar_history_cardview); - time = (TextView) itemView.findViewById(R.id.danar_history_time); - value = (TextView) itemView.findViewById(R.id.danar_history_value); - bolustype = (TextView) itemView.findViewById(R.id.danar_history_bolustype); - stringvalue = (TextView) itemView.findViewById(R.id.danar_history_stringvalue); - duration = (TextView) itemView.findViewById(R.id.danar_history_duration); - dailybasal = (TextView) itemView.findViewById(R.id.danar_history_dailybasal); - dailybolus = (TextView) itemView.findViewById(R.id.danar_history_dailybolus); - dailytotal = (TextView) itemView.findViewById(R.id.danar_history_dailytotal); - alarm = (TextView) itemView.findViewById(R.id.danar_history_alarm); + cv = itemView.findViewById(R.id.danar_history_cardview); + time = itemView.findViewById(R.id.danar_history_time); + value = itemView.findViewById(R.id.danar_history_value); + bolustype = itemView.findViewById(R.id.danar_history_bolustype); + stringvalue = itemView.findViewById(R.id.danar_history_stringvalue); + duration = itemView.findViewById(R.id.danar_history_duration); + dailybasal = itemView.findViewById(R.id.danar_history_dailybasal); + dailybolus = itemView.findViewById(R.id.danar_history_dailybolus); + dailytotal = itemView.findViewById(R.id.danar_history_dailytotal); + alarm = itemView.findViewById(R.id.danar_history_alarm); } } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/danaRKorean/DanaRKoreanPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/pump/danaRKorean/DanaRKoreanPlugin.java index 07df7fb29f..64eccf05f1 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/danaRKorean/DanaRKoreanPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/danaRKorean/DanaRKoreanPlugin.java @@ -68,6 +68,7 @@ public class DanaRKoreanPlugin extends AbstractDanaRPlugin { context.unbindService(mConnection); MainApp.bus().unregister(this); + super.onStop(); } private ServiceConnection mConnection = new ServiceConnection() { diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/danaRS/DanaRSPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/pump/danaRS/DanaRSPlugin.java index 1e38ccc312..19005509cb 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/danaRS/DanaRSPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/danaRS/DanaRSPlugin.java @@ -123,6 +123,7 @@ public class DanaRSPlugin extends PluginBase implements PumpInterface, DanaRInte context.unbindService(mConnection); MainApp.bus().unregister(this); + super.onStop(); } @Override diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/danaRv2/DanaRv2Plugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/pump/danaRv2/DanaRv2Plugin.java index 65fb602ff4..607f7346b6 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/danaRv2/DanaRv2Plugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/danaRv2/DanaRv2Plugin.java @@ -71,6 +71,7 @@ public class DanaRv2Plugin extends AbstractDanaRPlugin { context.unbindService(mConnection); MainApp.bus().unregister(this); + super.onStop(); } private ServiceConnection mConnection = new ServiceConnection() { diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/MedtronicFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/MedtronicFragment.kt index 2efafde16c..d60a639106 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/MedtronicFragment.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/MedtronicFragment.kt @@ -35,13 +35,9 @@ import info.nightscout.androidaps.plugins.pump.medtronic.util.MedtronicUtil import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin import info.nightscout.androidaps.queue.Callback import info.nightscout.androidaps.queue.events.EventQueueChanged -import info.nightscout.androidaps.utils.DateUtil -import info.nightscout.androidaps.utils.FabricPrivacy -import info.nightscout.androidaps.utils.SetWarnColor -import info.nightscout.androidaps.utils.T +import info.nightscout.androidaps.utils.* import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.disposables.CompositeDisposable -import io.reactivex.disposables.Disposable import kotlinx.android.synthetic.main.medtronic_fragment.* import org.slf4j.LoggerFactory @@ -50,10 +46,6 @@ class MedtronicFragment : Fragment() { private val log = LoggerFactory.getLogger(L.PUMP) private var disposable: CompositeDisposable = CompositeDisposable() - operator fun CompositeDisposable.plusAssign(disposable: Disposable) { - add(disposable) - } - private val loopHandler = Handler() private lateinit var refreshLoop: Runnable @@ -94,7 +86,7 @@ class MedtronicFragment : Fragment() { MedtronicPumpPlugin.getPlugin().resetStatusState() ConfigBuilderPlugin.getPlugin().commandQueue.readStatus("Clicked refresh", object : Callback() { override fun run() { - activity?.runOnUiThread { medtronic_refresh.isEnabled = true } + activity?.runOnUiThread { medtronic_refresh?.isEnabled = true } } }) } @@ -107,10 +99,9 @@ class MedtronicFragment : Fragment() { MedtronicUtil.displayNotConfiguredDialog(context) } } - - updateGUI() } + @Synchronized override fun onResume() { super.onResume() MainApp.bus().register(this) @@ -140,8 +131,11 @@ class MedtronicFragment : Fragment() { MedtronicUtil.getPumpStatus().verifyConfiguration() updateGUI() }, { FabricPrivacy.logException(it) }) + + updateGUI() } + @Synchronized override fun onPause() { super.onPause() disposable.clear() @@ -249,7 +243,9 @@ class MedtronicFragment : Fragment() { } // GUI functions + @Synchronized fun updateGUI() { + if (medtronic_rl_status == null) return val plugin = MedtronicPumpPlugin.getPlugin() val pumpStatus = MedtronicUtil.getPumpStatus() diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/MedtronicPumpPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/MedtronicPumpPlugin.java index 026d44f3e6..6afcb87d4c 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/MedtronicPumpPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/MedtronicPumpPlugin.java @@ -211,17 +211,17 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter private void migrateSettings() { if ("US (916 MHz)".equals(SP.getString(MedtronicConst.Prefs.PumpFrequency, null))) { - SP.putString(MedtronicConst.Prefs.PumpFrequency, MainApp.gs(R.string.medtronic_pump_frequency_us_ca)); + SP.putString(MedtronicConst.Prefs.PumpFrequency, MainApp.gs(R.string.key_medtronic_pump_frequency_us_ca)); } String encoding = SP.getString(MedtronicConst.Prefs.Encoding, null); if ("RileyLink 4b6b Encoding".equals(encoding)) { - SP.putString(MedtronicConst.Prefs.Encoding, MainApp.gs(R.string.medtronic_pump_encoding_4b6b_rileylink)); + SP.putString(MedtronicConst.Prefs.Encoding, MainApp.gs(R.string.key_medtronic_pump_encoding_4b6b_rileylink)); } if ("Local 4b6b Encoding".equals(encoding)) { - SP.putString(MedtronicConst.Prefs.Encoding, MainApp.gs(R.string.medtronic_pump_encoding_4b6b_local)); + SP.putString(MedtronicConst.Prefs.Encoding, MainApp.gs(R.string.key_medtronic_pump_encoding_4b6b_local)); } } @@ -790,6 +790,17 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter setRefreshButtonEnabled(false); + MedtronicPumpStatus mdtPumpStatus = getMDTPumpStatus(); + + if (detailedBolusInfo.insulin > mdtPumpStatus.reservoirRemainingUnits) { + return new PumpEnactResult() // + .success(false) // + .enacted(false) // + .comment(MainApp.gs(R.string.medtronic_cmd_bolus_could_not_be_delivered_no_insulin, + mdtPumpStatus.reservoirRemainingUnits, + detailedBolusInfo.insulin)); + } + bolusDeliveryType = BolusDeliveryType.DeliveryPrepared; if (isPumpNotReachable()) { @@ -1050,6 +1061,21 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter } + @Override + public PumpEnactResult setTempBasalPercent(Integer percent, Integer durationInMinutes, Profile profile, + boolean enforceNew) { + if (percent==0) { + return setTempBasalAbsolute(0.0d, durationInMinutes, profile, enforceNew); + } else { + double absoluteValue = profile.getBasal() * (percent /100.0d); + getMDTPumpStatus(); + absoluteValue = pumpStatusLocal.pumpType.determineCorrectBasalSize(absoluteValue); + LOG.warn("setTempBasalPercent [MedtronicPumpPlugin] - You are trying to use setTempBasalPercent with percent other then 0% (%d). This will start setTempBasalAbsolute, with calculated value (%.3f). Result might not be 100% correct.", percent, absoluteValue); + return setTempBasalAbsolute(absoluteValue, durationInMinutes, profile, enforceNew); + } + } + + private void finishAction(String overviewKey) { if (overviewKey != null) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/BatteryType.java b/app/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/BatteryType.java index ba6e656acc..0d228d43ec 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/BatteryType.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/defs/BatteryType.java @@ -12,9 +12,9 @@ import info.nightscout.androidaps.R; public enum BatteryType { - None(R.string.medtronic_pump_battery_no, 0, 0), - Alkaline(R.string.medtronic_pump_battery_alkaline, 1.20d, 1.47d), // - Lithium(R.string.medtronic_pump_battery_lithium, 1.22d, 1.64d); + None(R.string.key_medtronic_pump_battery_no, 0, 0), + Alkaline(R.string.key_medtronic_pump_battery_alkaline, 1.20d, 1.47d), // + Lithium(R.string.key_medtronic_pump_battery_lithium, 1.22d, 1.64d); private final String description; public double lowVoltage; diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/dialog/MedtronicHistoryActivity.java b/app/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/dialog/MedtronicHistoryActivity.java index e5cf10f765..9f148ac02e 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/dialog/MedtronicHistoryActivity.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/dialog/MedtronicHistoryActivity.java @@ -1,18 +1,7 @@ package info.nightscout.androidaps.plugins.pump.medtronic.dialog; -import java.util.ArrayList; -import java.util.List; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import android.app.Activity; import android.os.Bundle; -import android.os.Handler; -import android.os.HandlerThread; import android.os.SystemClock; -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -21,6 +10,15 @@ import android.widget.ArrayAdapter; import android.widget.Spinner; import android.widget.TextView; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.List; + import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.R; import info.nightscout.androidaps.activities.NoSplashActivity; @@ -33,10 +31,6 @@ public class MedtronicHistoryActivity extends NoSplashActivity { private static Logger LOG = LoggerFactory.getLogger(L.PUMP); - private Handler mHandler; - - // static Profile profile = null; - Spinner historyTypeSpinner; TextView statusView; RecyclerView recyclerView; @@ -54,10 +48,6 @@ public class MedtronicHistoryActivity extends NoSplashActivity { public MedtronicHistoryActivity() { super(); - HandlerThread mHandlerThread = new HandlerThread(MedtronicHistoryActivity.class.getSimpleName()); - mHandlerThread.start(); - filterHistory(PumpHistoryEntryGroup.All); - this.mHandler = new Handler(mHandlerThread.getLooper()); } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/driver/MedtronicPumpStatus.java b/app/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/driver/MedtronicPumpStatus.java index 46647e832e..ff7ff9f608 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/driver/MedtronicPumpStatus.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/driver/MedtronicPumpStatus.java @@ -134,8 +134,8 @@ public class MedtronicPumpStatus extends PumpStatus { medtronicPumpMap.put("754", PumpType.Medtronic_554_754_Veo); frequencies = new String[2]; - frequencies[0] = MainApp.gs(R.string.medtronic_pump_frequency_us_ca); - frequencies[1] = MainApp.gs(R.string.medtronic_pump_frequency_worldwide); + frequencies[0] = MainApp.gs(R.string.key_medtronic_pump_frequency_us_ca); + frequencies[1] = MainApp.gs(R.string.key_medtronic_pump_frequency_worldwide); } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/util/MedtronicConst.java b/app/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/util/MedtronicConst.java index d867ec2d31..b5bd2f1f64 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/util/MedtronicConst.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/util/MedtronicConst.java @@ -22,14 +22,14 @@ public class MedtronicConst { // public static final String Encoding = PrefPrefix + "encoding"; // public static final String BatteryType = PrefPrefix + "battery_type"; - public static final int PumpSerial = R.string.pref_key_medtronic_serial; - public static final int PumpType = R.string.pref_key_medtronic_pump_type; - public static final int PumpFrequency = R.string.pref_key_medtronic_frequency; - public static final int MaxBolus = R.string.pref_key_medtronic_max_bolus; - public static final int MaxBasal = R.string.pref_key_medtronic_max_basal; - public static final int BolusDelay = R.string.pref_key_medtronic_bolus_delay; - public static final int Encoding = R.string.pref_key_medtronic_encoding; - public static final int BatteryType = R.string.pref_key_medtronic_battery_type; + public static final int PumpSerial = R.string.key_medtronic_serial; + public static final int PumpType = R.string.key_medtronic_pump_type; + public static final int PumpFrequency = R.string.key_medtronic_frequency; + public static final int MaxBolus = R.string.key_medtronic_max_bolus; + public static final int MaxBasal = R.string.key_medtronic_max_basal; + public static final int BolusDelay = R.string.key_medtronic_bolus_delay; + public static final int Encoding = R.string.key_medtronic_encoding; + public static final int BatteryType = R.string.key_medtronic_battery_type; } public class Statistics { diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/OmnipodManager.java b/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/OmnipodManager.java index ab40f1e1a4..bd8097cfa2 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/OmnipodManager.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/OmnipodManager.java @@ -11,6 +11,8 @@ import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import info.nightscout.androidaps.data.Profile; +import info.nightscout.androidaps.data.PumpEnactResult; +import info.nightscout.androidaps.plugins.pump.common.data.TempBasalPair; import info.nightscout.androidaps.plugins.pump.omnipod.comm.OmnipodCommunicationService; import info.nightscout.androidaps.plugins.pump.omnipod.comm.action.AcknowledgeAlertsAction; import info.nightscout.androidaps.plugins.pump.omnipod.comm.action.BolusAction; @@ -28,20 +30,25 @@ import info.nightscout.androidaps.plugins.pump.omnipod.comm.action.service.PairS import info.nightscout.androidaps.plugins.pump.omnipod.comm.action.service.PrimeService; import info.nightscout.androidaps.plugins.pump.omnipod.comm.action.service.SetTempBasalService; import info.nightscout.androidaps.plugins.pump.omnipod.comm.message.response.StatusResponse; -import info.nightscout.androidaps.plugins.pump.omnipod.comm.message.response.podinfo.PodInfo; import info.nightscout.androidaps.plugins.pump.omnipod.comm.message.response.podinfo.PodInfoResponse; import info.nightscout.androidaps.plugins.pump.omnipod.defs.DeliveryType; +import info.nightscout.androidaps.plugins.pump.omnipod.defs.OmnipodCommunicationManagerInterface; import info.nightscout.androidaps.plugins.pump.omnipod.defs.PodInfoType; import info.nightscout.androidaps.plugins.pump.omnipod.defs.SetupProgress; -import info.nightscout.androidaps.plugins.pump.omnipod.defs.schedule.BasalSchedule; import info.nightscout.androidaps.plugins.pump.omnipod.defs.schedule.BasalScheduleMapper; import info.nightscout.androidaps.plugins.pump.omnipod.defs.state.PodSessionState; import info.nightscout.androidaps.plugins.pump.omnipod.util.OmnipodConst; import info.nightscout.androidaps.utils.SP; -public class OmnipodManager { +public class OmnipodManager implements OmnipodCommunicationManagerInterface { private final OmnipodCommunicationService communicationService; private PodSessionState podState; + private static OmnipodManager instance; + + // FIXME this is dirty + public static OmnipodManager getInstance() { + return instance; + } public OmnipodManager(OmnipodCommunicationService communicationService, PodSessionState podState) { if (communicationService == null) { @@ -49,150 +56,300 @@ public class OmnipodManager { } this.communicationService = communicationService; this.podState = podState; + instance = this; } - public OmnipodManager(OmnipodCommunicationService communicationService) { - this(communicationService, null); + @Override + public PumpEnactResult insertCannula(Profile profile) { + if (podState == null || podState.getSetupProgress().isBefore(SetupProgress.PRIMING_FINISHED)) { + // TODO use string resource + return new PumpEnactResult().success(false).enacted(false).comment("Pod should be paired and primed first"); + } else if (podState.getSetupProgress().isAfter(SetupProgress.CANNULA_INSERTING)) { + // TODO use string resource + return new PumpEnactResult().success(false).enacted(false).comment("Illegal setup state: " + podState.getSetupProgress().name()); + } + + try { + communicationService.executeAction(new InsertCannulaAction(new InsertCannulaService(), podState, + BasalScheduleMapper.mapProfileToBasalSchedule(profile))); + + executeDelayed(() -> { + StatusResponse delayedStatusResponse = communicationService.executeAction(new GetStatusAction(podState)); + InsertCannulaAction.updateCannulaInsertionStatus(podState, delayedStatusResponse); + }, OmnipodConst.POD_CANNULA_INSERTION_DURATION); + } catch (Exception ex) { + // TODO distinguish between certain and uncertain failures + // TODO user friendly error messages (string resources) + return new PumpEnactResult().success(false).enacted(false).comment(ex.getMessage()); + } + + return new PumpEnactResult().success(true).enacted(true); + } + + @Override + public PumpEnactResult pairAndPrime() { + try { + if (podState == null) { + podState = communicationService.executeAction(new PairAction(new PairService())); + } + if (podState.getSetupProgress().isBefore(SetupProgress.PRIMING_FINISHED)) { + communicationService.executeAction(new PrimeAction(new PrimeService(), podState)); + + executeDelayed(() -> { + StatusResponse delayedStatusResponse = communicationService.executeAction(new GetStatusAction(podState)); + PrimeAction.updatePrimingStatus(podState, delayedStatusResponse); + }, OmnipodConst.POD_PRIME_DURATION); + } else { + // TODO use string resource + return new PumpEnactResult().success(false).enacted(false).comment("Illegal setup state: " + podState.getSetupProgress().name()); + } + } catch (Exception ex) { + // TODO distinguish between certain and uncertain failures + // TODO user friendly error messages (string resources) + return new PumpEnactResult().success(false).enacted(false).comment(ex.getMessage()); + } + + return new PumpEnactResult().success(true).enacted(true); + } + + @Override + public PumpEnactResult cancelBolus() { + if (!isInitialized()) { + return createNotInitializedResult(); + } + + try { + communicationService.executeAction(new CancelDeliveryAction(podState, DeliveryType.BOLUS, true)); + } catch (Exception ex) { + // TODO distinguish between certain and uncertain failures + // TODO user friendly error messages (string resources) + return new PumpEnactResult().success(false).enacted(false).comment(ex.getMessage()); + } + + return new PumpEnactResult().success(true).enacted(true); + } + + @Override + public PumpEnactResult getPodStatus() { + if (podState == null) { + // TODO use string resource + return new PumpEnactResult().success(false).enacted(false).comment("Pod should be paired and primed first"); + } + + try { + // TODO how can we return the status response? Also refer to TODO in interface + StatusResponse statusResponse = communicationService.executeAction(new GetStatusAction(podState)); + } catch (Exception ex) { + // TODO distinguish between certain and uncertain failures + // TODO user friendly error messages (string resources) + return new PumpEnactResult().success(false).enacted(false).comment(ex.getMessage()); + } + + return new PumpEnactResult().success(true).enacted(true); + } + + @Override + public PumpEnactResult deactivatePod() { + if (podState == null) { + // TODO use string resource + return new PumpEnactResult().success(false).enacted(false).comment("Pod should be paired and primed first"); + } + + try { + communicationService.executeAction(new DeactivatePodAction(podState, true)); + resetPodState(); + } catch (Exception ex) { + // TODO distinguish between certain and uncertain failures + // TODO user friendly error messages (string resources) + return new PumpEnactResult().success(false).enacted(false).comment(ex.getMessage()); + } + + return new PumpEnactResult().success(true).enacted(true); + } + + @Override + public PumpEnactResult setBasalProfile(Profile basalProfile) { + if (!isInitialized()) { + return createNotInitializedResult(); + } + + try { + communicationService.executeAction(new SetBasalScheduleAction(podState, + BasalScheduleMapper.mapProfileToBasalSchedule(basalProfile), + false, podState.getScheduleOffset(), true)); + } catch (Exception ex) { + // TODO distinguish between certain and uncertain failures + // TODO user friendly error messages (string resources) + return new PumpEnactResult().success(false).enacted(false).comment(ex.getMessage()); + } + + return new PumpEnactResult().success(true).enacted(true); + } + + @Override + public PumpEnactResult resetPodState() { + podState = null; + SP.remove(OmnipodConst.Prefs.PodState); + + return new PumpEnactResult().success(true).enacted(true); + } + + @Override + public PumpEnactResult bolus(Double units) { + if (!isInitialized()) { + return createNotInitializedResult(); + } + + try { + communicationService.executeAction(new BolusAction(podState, units, true, true)); + } catch (Exception ex) { + // TODO distinguish between certain and uncertain failures + // TODO user friendly error messages (string resources) + return new PumpEnactResult().success(false).enacted(false).comment(ex.getMessage()); + } + + return new PumpEnactResult().success(true).enacted(true); + } + + @Override + public PumpEnactResult setTemporaryBasal(TempBasalPair tempBasalPair) { + if (!isInitialized()) { + return createNotInitializedResult(); + } + + try { + communicationService.executeAction(new SetTempBasalAction(new SetTempBasalService(), + podState, tempBasalPair.getInsulinRate(), Duration.standardMinutes(tempBasalPair.getDurationMinutes()), + true, true)); + } catch (Exception ex) { + // TODO distinguish between certain and uncertain failures + // TODO user friendly error messages (string resources) + return new PumpEnactResult().success(false).enacted(false).comment(ex.getMessage()); + } + + return new PumpEnactResult().success(true).enacted(true); + } + + @Override + public PumpEnactResult cancelTemporaryBasal() { + if (!isInitialized()) { + return createNotInitializedResult(); + } + + try { + communicationService.executeAction(new CancelDeliveryAction(podState, DeliveryType.TEMP_BASAL, true)); + } catch (Exception ex) { + // TODO distinguish between certain and uncertain failures + // TODO user friendly error messages (string resources) + return new PumpEnactResult().success(false).enacted(false).comment(ex.getMessage()); + } + + return new PumpEnactResult().success(true).enacted(true); + } + + @Override + public PumpEnactResult acknowledgeAlerts() { + if (!isInitialized()) { + return createNotInitializedResult(); + } + + try { + communicationService.executeAction(new AcknowledgeAlertsAction(podState, podState.getActiveAlerts())); + } catch (Exception ex) { + // TODO distinguish between certain and uncertain failures + // TODO user friendly error messages (string resources) + return new PumpEnactResult().success(false).enacted(false).comment(ex.getMessage()); + } + return new PumpEnactResult().success(true).enacted(true); + } + + // TODO should we add this to the OmnipodCommunicationManager interface? + public PumpEnactResult getPodInfo(PodInfoType podInfoType) { + if (!isInitialized()) { + return createNotInitializedResult(); + } + + try { + // TODO how can we return the PodInfo response? + PodInfoResponse podInfoResponse = communicationService.executeAction(new GetPodInfoAction(podState, podInfoType)); + } catch (Exception ex) { + // TODO distinguish between certain and uncertain failures + // TODO user friendly error messages (string resources) + return new PumpEnactResult().success(false).enacted(false).comment(ex.getMessage()); + } + + return new PumpEnactResult().success(true).enacted(true); + } + + // TODO should we add this to the OmnipodCommunicationManager interface? + public PumpEnactResult suspendDelivery() { + if (!isInitialized()) { + return createNotInitializedResult(); + } + + try { + communicationService.executeAction(new CancelDeliveryAction(podState, EnumSet.allOf(DeliveryType.class), true)); + } catch (Exception ex) { + // TODO distinguish between certain and uncertain failures + // TODO user friendly error messages (string resources) + return new PumpEnactResult().success(false).enacted(false).comment(ex.getMessage()); + } + + return new PumpEnactResult().success(true).enacted(true); + } + + // TODO should we add this to the OmnipodCommunicationManager interface? + public PumpEnactResult resumeDelivery() { + if (!isInitialized()) { + return createNotInitializedResult(); + } + + try { + communicationService.executeAction(new SetBasalScheduleAction(podState, podState.getBasalSchedule(), + true, podState.getScheduleOffset(), true)); + } catch (Exception ex) { + // TODO distinguish between certain and uncertain failures + // TODO user friendly error messages (string resources) + return new PumpEnactResult().success(false).enacted(false).comment(ex.getMessage()); + } + + return new PumpEnactResult().success(true).enacted(true); + } + + // TODO should we add this to the OmnipodCommunicationManager interface? + public PumpEnactResult setTime() { + if (!isInitialized()) { + return createNotInitializedResult(); + } + + try { + // Suspend delivery + communicationService.executeAction(new CancelDeliveryAction(podState, EnumSet.allOf(DeliveryType.class), false)); + + // Joda seems to cache the default time zone, so we use the JVM's + DateTimeZone.setDefault(DateTimeZone.forTimeZone(TimeZone.getDefault())); + podState.setTimeZone(DateTimeZone.getDefault()); + + // Resume delivery + communicationService.executeAction(new SetBasalScheduleAction(podState, podState.getBasalSchedule(), + true, podState.getScheduleOffset(), true)); + } catch (Exception ex) { + // TODO distinguish between certain and uncertain failures + // TODO user friendly error messages (string resources) + return new PumpEnactResult().success(false).enacted(false).comment(ex.getMessage()); + } + + return new PumpEnactResult().success(true).enacted(true); } public OmnipodCommunicationService getCommunicationService() { return communicationService; } - public T getPodInfo(PodInfoType podInfoType) { - if (!isInitialized()) { - throw new IllegalStateException("Pod should be initialized first"); - } - PodInfoResponse podInfoResponse = communicationService.executeAction(new GetPodInfoAction(podState, podInfoType)); - return podInfoResponse.getPodInfo(); - } - - public StatusResponse getStatus() { - if (podState == null) { - throw new IllegalStateException("Pod should be paired first"); - } - return communicationService.executeAction(new GetStatusAction(podState)); - } - - public void acknowledgeAlerts() { - if (!isInitialized()) { - throw new IllegalStateException("Pod should be initialized first"); - } - communicationService.executeAction(new AcknowledgeAlertsAction(podState, podState.getActiveAlerts())); - } - - public void pairAndPrime() { - if (podState == null) { - podState = communicationService.executeAction(new PairAction(new PairService())); - } - if (podState.getSetupProgress().isBefore(SetupProgress.PRIMING_FINISHED)) { - communicationService.executeAction(new PrimeAction(new PrimeService(), podState)); - - executeDelayed(() -> { - StatusResponse delayedStatusResponse = communicationService.executeAction(new GetStatusAction(podState)); - PrimeAction.updatePrimingStatus(podState, delayedStatusResponse); - }, OmnipodConst.POD_PRIME_DURATION); - } else { - throw new IllegalStateException("Illegal setup state: " + podState.getSetupProgress().name()); - } - } - - public void insertCannula(Profile profile) { - if (podState == null || podState.getSetupProgress().isBefore(SetupProgress.PRIMING_FINISHED)) { - throw new IllegalArgumentException("Pod should be paired and primed first"); - } else if (podState.getSetupProgress().isAfter(SetupProgress.CANNULA_INSERTING)) { - throw new IllegalStateException("Illegal setup state: " + podState.getSetupProgress().name()); - } - - communicationService.executeAction(new InsertCannulaAction(new InsertCannulaService(), podState, - BasalScheduleMapper.mapProfileToBasalSchedule(profile))); - - executeDelayed(() -> { - StatusResponse delayedStatusResponse = communicationService.executeAction(new GetStatusAction(podState)); - InsertCannulaAction.updateCannulaInsertionStatus(podState, delayedStatusResponse); - }, OmnipodConst.POD_CANNULA_INSERTION_DURATION); - } - - public void setBasalSchedule(BasalSchedule basalSchedule, boolean confidenceReminder) { - if (!isInitialized()) { - throw new IllegalStateException("Pod should be initialized first"); - } - communicationService.executeAction(new SetBasalScheduleAction(podState, basalSchedule, - confidenceReminder, podState.getScheduleOffset(), true)); - } - - public void setTempBasal(double rate, Duration duration) { - if (!isInitialized()) { - throw new IllegalStateException("Pod should be initialized first"); - } - communicationService.executeAction(new SetTempBasalAction(new SetTempBasalService(), - podState, rate, duration, true, true)); - } - - public void cancelTempBasal() { - if (!isInitialized()) { - throw new IllegalStateException("Pod should be initialized first"); - } - communicationService.executeAction(new CancelDeliveryAction(podState, DeliveryType.TEMP_BASAL, true)); - } - - public void bolus(double units) { - if (!isInitialized()) { - throw new IllegalStateException("Pod should be initialized first"); - } - communicationService.executeAction(new BolusAction(podState, units, true, true)); - } - - public void cancelBolus() { - if (!isInitialized()) { - throw new IllegalStateException("Pod should be initialized first"); - } - communicationService.executeAction(new CancelDeliveryAction(podState, DeliveryType.BOLUS, true)); - } - - public void suspendDelivery() { - if (!isInitialized()) { - throw new IllegalStateException("Pod should be initialized first"); - } - communicationService.executeAction(new CancelDeliveryAction(podState, EnumSet.allOf(DeliveryType.class), true)); - } - - public void resumeDelivery() { - if (!isInitialized()) { - throw new IllegalStateException("Pod should be initialized first"); - } - communicationService.executeAction(new SetBasalScheduleAction(podState, podState.getBasalSchedule(), - true, podState.getScheduleOffset(), true)); - } - - public void setTime() { - if (!isInitialized()) { - throw new IllegalStateException("Pod should be initialized first"); - } - // Suspend delivery - communicationService.executeAction(new CancelDeliveryAction(podState, EnumSet.allOf(DeliveryType.class), false)); - - // Joda seems to cache the default time zone, so we use the JVM's - DateTimeZone.setDefault(DateTimeZone.forTimeZone(TimeZone.getDefault())); - podState.setTimeZone(DateTimeZone.getDefault()); - - // Resume delivery - communicationService.executeAction(new SetBasalScheduleAction(podState, podState.getBasalSchedule(), - true, podState.getScheduleOffset(), true)); - } - public DateTime getTime() { return podState.getTime(); } - public void deactivatePod() { - if (podState == null) { - throw new IllegalStateException("Pod should be paired first"); - } - communicationService.executeAction(new DeactivatePodAction(podState, true)); - resetPodState(); - } - public boolean isInitialized() { return podState != null && podState.getSetupProgress() == SetupProgress.COMPLETED; } @@ -201,13 +358,13 @@ public class OmnipodManager { return podState == null ? "null" : podState.toString(); } - public void resetPodState() { - podState = null; - SP.remove(OmnipodConst.Prefs.PodState); - } - private void executeDelayed(Runnable r, Duration timeout) { ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1); scheduledExecutorService.schedule(r, timeout.getMillis(), TimeUnit.MILLISECONDS); } + + private PumpEnactResult createNotInitializedResult() { + // TODO use string resource + return new PumpEnactResult().success(false).enacted(false).comment("Pod should be initialized first"); + } } \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/OmnipodPumpPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/OmnipodPumpPlugin.java index 9282cd91eb..bbe9bb60e0 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/OmnipodPumpPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/OmnipodPumpPlugin.java @@ -43,7 +43,6 @@ import info.nightscout.androidaps.plugins.pump.common.defs.PumpType; import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.RileyLinkConst; import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.tasks.ResetRileyLinkConfigurationTask; import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.tasks.ServiceTaskExecutor; -import info.nightscout.androidaps.plugins.pump.omnipod.comm.OmnipodCommunicationManager; import info.nightscout.androidaps.plugins.pump.omnipod.comm.ui.OmnipodUIComm; import info.nightscout.androidaps.plugins.pump.omnipod.comm.ui.OmnipodUITask; import info.nightscout.androidaps.plugins.pump.omnipod.defs.OmnipodCommandType; @@ -108,7 +107,7 @@ public class OmnipodPumpPlugin extends PumpPluginAbstract implements PumpInterfa OmnipodUtil.setOmnipodPodType(OmnipodPodType.Eros); if (omnipodCommunicationManager == null) { - omnipodCommunicationManager = OmnipodCommunicationManager.getInstance(); + omnipodCommunicationManager = OmnipodManager.getInstance(); } omnipodUIComm = new OmnipodUIComm(omnipodCommunicationManager); @@ -117,12 +116,14 @@ public class OmnipodPumpPlugin extends PumpPluginAbstract implements PumpInterfa serviceConnection = new ServiceConnection() { + @Override public void onServiceDisconnected(ComponentName name) { if (isLoggingEnabled()) LOG.debug("RileyLinkOmnipodService is disconnected"); omnipodService = null; } + @Override public void onServiceConnected(ComponentName name, IBinder service) { if (isLoggingEnabled()) LOG.debug("RileyLinkOmnipodService is connected"); @@ -147,12 +148,10 @@ public class OmnipodPumpPlugin extends PumpPluginAbstract implements PumpInterfa }; } - protected OmnipodPumpPlugin(PluginDescription pluginDescription, PumpType pumpType) { super(pluginDescription, pumpType); } - public static OmnipodPumpPlugin getPlugin() { if (plugin == null) plugin = new OmnipodPumpPlugin(); @@ -190,6 +189,7 @@ public class OmnipodPumpPlugin extends PumpPluginAbstract implements PumpInterfa } + @Override public void onStartCustomActions() { // check status every minute (if any status needs refresh we send readStatus command) @@ -208,6 +208,7 @@ public class OmnipodPumpPlugin extends PumpPluginAbstract implements PumpInterfa } + @Override public Class getServiceClass() { return RileyLinkOmnipodService.class; } @@ -439,11 +440,13 @@ public class OmnipodPumpPlugin extends PumpPluginAbstract implements PumpInterfa } + @Override protected void triggerUIChange() { RxBus.INSTANCE.send(new EventOmnipodPumpValuesChanged()); } + @Override @NonNull protected PumpEnactResult deliverBolus(final DetailedBolusInfo detailedBolusInfo) { @@ -456,11 +459,11 @@ public class OmnipodPumpPlugin extends PumpPluginAbstract implements PumpInterfa OmnipodUITask responseTask = omnipodUIComm.executeCommand(OmnipodCommandType.SetBolus, detailedBolusInfo.insulin); - Boolean response = responseTask.wasCommandSuccessful(); + PumpEnactResult result = responseTask.getResult(); setRefreshButtonEnabled(true); - if (response) { + if (result.success) { TreatmentsPlugin.getPlugin().addToHistoryTreatment(detailedBolusInfo, true); @@ -478,50 +481,36 @@ public class OmnipodPumpPlugin extends PumpPluginAbstract implements PumpInterfa long time = System.currentTimeMillis() + (bolusTime * 1000); this.busyTimestamps.add(time); - - return new PumpEnactResult().success(true) // - .enacted(true) // - .bolusDelivered(detailedBolusInfo.insulin) // - .carbsDelivered(detailedBolusInfo.carbs); - - } else { - return new PumpEnactResult() // - .success(false) // - .enacted(false) // - .comment(MainApp.gs(R.string.medtronic_cmd_bolus_could_not_be_delivered)); + result.bolusDelivered(detailedBolusInfo.insulin).carbsDelivered(detailedBolusInfo.carbs); } + return result; } finally { finishAction("Bolus"); } } - + @Override public void stopBolusDelivering() { - LOG.info(getLogPrefix() + "stopBolusDelivering"); setRefreshButtonEnabled(false); - try { + OmnipodUITask responseTask = omnipodUIComm.executeCommand(OmnipodCommandType.CancelBolus); - OmnipodUITask responseTask = omnipodUIComm.executeCommand(OmnipodCommandType.CancelBolus); + PumpEnactResult result = responseTask.getResult(); - Boolean response = responseTask.wasCommandSuccessful(); + setRefreshButtonEnabled(true); - setRefreshButtonEnabled(true); + LOG.info(getLogPrefix() + "stopBolusDelivering - wasSuccess={}", result.success); - LOG.info(getLogPrefix() + "stopBolusDelivering - wasSuccess={}", response); + if (result.success) { + // TODO fix bolus record with cancel - if (response) { - // TODO fix bolus record with cancel - - //TreatmentsPlugin.getPlugin().addToHistoryTreatment(detailedBolusInfo, true); - } - - } finally { - finishAction("Bolus"); + //TreatmentsPlugin.getPlugin().addToHistoryTreatment(detailedBolusInfo, true); } + + finishAction("Bolus"); } @@ -555,7 +544,6 @@ public class OmnipodPumpPlugin extends PumpPluginAbstract implements PumpInterfa } if (tbrCurrent != null && !enforceNew) { - if (OmnipodUtil.isSame(tbrCurrent.getInsulinRate(), absoluteRate)) { if (isLoggingEnabled()) LOG.info(getLogPrefix() + "setTempBasalAbsolute - No enforceNew and same rate. Exiting."); @@ -572,10 +560,9 @@ public class OmnipodPumpPlugin extends PumpPluginAbstract implements PumpInterfa // CANCEL OmnipodUITask responseTask2 = omnipodUIComm.executeCommand(OmnipodCommandType.CancelTemporaryBasal); - Boolean response = responseTask2.wasCommandSuccessful(); - ; + PumpEnactResult result = responseTask2.getResult(); - if (response) { + if (result.success) { if (isLoggingEnabled()) LOG.info(getLogPrefix() + "setTempBasalAbsolute - Current TBR cancelled."); } else { @@ -584,8 +571,7 @@ public class OmnipodPumpPlugin extends PumpPluginAbstract implements PumpInterfa finishAction("TBR"); - return new PumpEnactResult().success(false).enacted(false) - .comment(MainApp.gs(R.string.medtronic_cmd_cant_cancel_tbr_stop_op)); + return result; } } @@ -593,12 +579,12 @@ public class OmnipodPumpPlugin extends PumpPluginAbstract implements PumpInterfa OmnipodUITask responseTask = omnipodUIComm.executeCommand(OmnipodCommandType.SetTemporaryBasal, absoluteRate, durationInMinutes); - Boolean response = responseTask.wasCommandSuccessful(); + PumpEnactResult result = responseTask.getResult(); if (isLoggingEnabled()) - LOG.info(getLogPrefix() + "setTempBasalAbsolute - setTBR. Response: " + response); + LOG.info(getLogPrefix() + "setTempBasalAbsolute - setTBR. Response: " + result.success); - if (response) { + if (result.success) { pumpStatusLocal.tempBasalStart = System.currentTimeMillis(); pumpStatusLocal.tempBasalAmount = absoluteRate; pumpStatusLocal.tempBasalLength = durationInMinutes; @@ -613,19 +599,10 @@ public class OmnipodPumpPlugin extends PumpPluginAbstract implements PumpInterfa TreatmentsPlugin.getPlugin().addToHistoryTempBasal(tempStart); incrementStatistics(OmnipodConst.Statistics.TBRsSet); - - finishAction("TBR"); - - return new PumpEnactResult().success(true).enacted(true) // - .absolute(absoluteRate).duration(durationInMinutes); - - } else { - finishAction("TBR"); - - return new PumpEnactResult().success(false).enacted(false) // - .comment(MainApp.gs(R.string.medtronic_cmd_tbr_could_not_be_delivered)); } + finishAction("TBR"); + return result; } protected TempBasalPair readTBR() { @@ -686,11 +663,11 @@ public class OmnipodPumpPlugin extends PumpPluginAbstract implements PumpInterfa OmnipodUITask responseTask2 = omnipodUIComm.executeCommand(OmnipodCommandType.CancelTemporaryBasal); - Boolean response = responseTask2.wasCommandSuccessful(); + PumpEnactResult result = responseTask2.getResult(); finishAction("TBR"); - if (response) { + if (result.success) { if (isLoggingEnabled()) LOG.info(getLogPrefix() + "cancelTempBasal - Cancel TBR successful."); @@ -700,17 +677,12 @@ public class OmnipodPumpPlugin extends PumpPluginAbstract implements PumpInterfa .source(Source.USER); TreatmentsPlugin.getPlugin().addToHistoryTempBasal(tempBasal); - - return new PumpEnactResult().success(true).enacted(true) // - .isTempCancel(true); } else { if (isLoggingEnabled()) LOG.info(getLogPrefix() + "cancelTempBasal - Cancel TBR failed."); - - return new PumpEnactResult().success(response).enacted(response) // - .comment(MainApp.gs(R.string.medtronic_cmd_cant_cancel_tbr)); } + return result; } @Override @@ -736,19 +708,16 @@ public class OmnipodPumpPlugin extends PumpPluginAbstract implements PumpInterfa OmnipodUITask responseTask = omnipodUIComm.executeCommand(OmnipodCommandType.SetBasalProfile, profile); - Boolean response = responseTask.wasCommandSuccessful(); + PumpEnactResult result = responseTask.getResult(); if (isLoggingEnabled()) - LOG.info(getLogPrefix() + "Basal Profile was set: " + response); + LOG.info(getLogPrefix() + "Basal Profile was set: " + result.success); - if (response) { + if (result.success) { this.currentProfile = profile; - return new PumpEnactResult().success(true).enacted(true); - } else { - return new PumpEnactResult().success(response).enacted(response) // - .comment(MainApp.gs(R.string.medtronic_cmd_basal_profile_could_not_be_set)); } + return result; } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/comm/OmnipodCommunicationManager.java b/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/comm/OmnipodCommunicationManager.java deleted file mode 100644 index f6285b8a87..0000000000 --- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/comm/OmnipodCommunicationManager.java +++ /dev/null @@ -1,144 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.omnipod.comm; - -import android.content.Context; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import info.nightscout.androidaps.data.Profile; -import info.nightscout.androidaps.data.PumpEnactResult; -import info.nightscout.androidaps.logging.L; -import info.nightscout.androidaps.plugins.pump.common.data.TempBasalPair; -import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.RileyLinkCommunicationManager; -import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.RileyLinkConst; -import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.ble.RFSpy; -import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.ble.data.RLMessage; -import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.ble.defs.RLMessageType; -import info.nightscout.androidaps.plugins.pump.omnipod.OmnipodManager; -import info.nightscout.androidaps.plugins.pump.omnipod.defs.OmnipodCommunicationManagerInterface; -import info.nightscout.androidaps.plugins.pump.omnipod.defs.state.PodSessionState; -import info.nightscout.androidaps.plugins.pump.omnipod.util.OmnipodUtil; -import info.nightscout.androidaps.utils.SP; - -/** - * Created by andy on 4.8.2019 - */ -public class OmnipodCommunicationManager extends RileyLinkCommunicationManager implements OmnipodCommunicationManagerInterface { - - private static final Logger LOG = LoggerFactory.getLogger(L.PUMPCOMM); - - private static OmnipodCommunicationManager omnipodCommunicationManager; - String errorMessage; - OmnipodCommunicationService communicationService; - OmnipodManager omnipodManager; - - - public OmnipodCommunicationManager(Context context, RFSpy rfspy) { - super(rfspy); - omnipodCommunicationManager = this; - OmnipodUtil.getPumpStatus().previousConnection = SP.getLong( - RileyLinkConst.Prefs.LastGoodDeviceCommunicationTime, 0L); - communicationService = new OmnipodCommunicationService(this); - omnipodManager = new OmnipodManager(communicationService, getPodSessionState()); - } - - - private PodSessionState getPodSessionState() { - - - return null; - } - - - public static OmnipodCommunicationManager getInstance() { - return omnipodCommunicationManager; - } - - - @Override - protected void configurePumpSpecificSettings() { - pumpStatus = OmnipodUtil.getPumpStatus(); - } - - - @Override - public E createResponseMessage(byte[] payload, Class clazz) { - // TODO - - //PumpMessage pumpMessage = new PumpMessage(payload); - //eturn (E) pumpMessage; - return null; - } - - - @Override - public boolean tryToConnectToDevice() { - return false; //isDeviceReachable(true); - } - - - public String getErrorResponse() { - return this.errorMessage; - } - - - @Override - public byte[] createPumpMessageContent(RLMessageType type) { - return new byte[0]; - } - - - private boolean isLogEnabled() { - return L.isEnabled(L.PUMPCOMM); - } - - - // This are just skeleton methods, we need to see what we can get returned and act accordingly - - public PumpEnactResult initPod() { - omnipodManager.pairAndPrime(); - - - return null; - } - - - public PumpEnactResult getPodStatus() { - return null; - } - - - public PumpEnactResult deactivatePod() { - return null; - } - - public PumpEnactResult setBasalProfile(Profile profile) { - return null; - } - - public PumpEnactResult resetPodStatus() { - return null; - } - - public PumpEnactResult setBolus(Double parameter) { - return null; - } - - public PumpEnactResult cancelBolus() { - return null; - } - - public PumpEnactResult setTemporaryBasal(TempBasalPair tbr) { - return null; - } - - public PumpEnactResult cancelTemporaryBasal() { - return null; - } - - @Override - public PumpEnactResult acknowledgeAlerts() { - return null; - } - -} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/comm/OmnipodCommunicationService.java b/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/comm/OmnipodCommunicationService.java index 39b1f397ce..2a93c00f1d 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/comm/OmnipodCommunicationService.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/comm/OmnipodCommunicationService.java @@ -35,33 +35,30 @@ import info.nightscout.androidaps.plugins.pump.omnipod.exception.PodReturnedErro * Created by andy on 6/29/18. */ -public class OmnipodCommunicationService /*extends RileyLinkCommunicationManager*/ { +public class OmnipodCommunicationService extends RileyLinkCommunicationManager { private static final Logger LOG = LoggerFactory.getLogger(OmnipodCommunicationService.class); - //RFSpy rfspy = null; - OmnipodCommunicationManager communicationManager; - public OmnipodCommunicationService(OmnipodCommunicationManager communicationManager) { - //this.rfspy = rfspy; - this.communicationManager = communicationManager; + public OmnipodCommunicationService(RFSpy rfspy) { + super(rfspy); } -// @Override -// protected void configurePumpSpecificSettings() { -// } -// -// @Override -// public boolean tryToConnectToDevice() { -// // TODO -// return false; -// } -// -// @Override -// public byte[] createPumpMessageContent(RLMessageType type) { -// return new byte[0]; -// } + @Override + protected void configurePumpSpecificSettings() { + } - //@Override + @Override + public boolean tryToConnectToDevice() { + // TODO + return false; + } + + @Override + public byte[] createPumpMessageContent(RLMessageType type) { + return new byte[0]; + } + + @Override public E createResponseMessage(byte[] payload, Class clazz) { return (E) new OmnipodPacket(payload); } @@ -199,7 +196,7 @@ public class OmnipodCommunicationService /*extends RileyLinkCommunicationManager OmnipodPacket ack = createAckPacket(podState, packetAddress, messageAddress); boolean quiet = false; while (!quiet) try { - this.communicationManager.sendAndListen(ack, 300, 1, 0, 40, OmnipodPacket.class); + sendAndListen(ack, 300, 1, 0, 40, OmnipodPacket.class); } catch (RileyLinkCommunicationException ex) { if (RileyLinkBLEError.Timeout.equals(ex.getErrorCode())) { quiet = true; @@ -227,7 +224,7 @@ public class OmnipodCommunicationService /*extends RileyLinkCommunicationManager while (System.currentTimeMillis() < timeoutTime) { OmnipodPacket response = null; try { - response = this.communicationManager.sendAndListen(packet, responseTimeoutMilliseconds, repeatCount, 9, preambleExtensionMilliseconds, OmnipodPacket.class); + response = sendAndListen(packet, responseTimeoutMilliseconds, repeatCount, 9, preambleExtensionMilliseconds, OmnipodPacket.class); } catch (Exception ex) { LOG.debug("Ignoring exception in exchangePackets: " + ex.getClass().getSimpleName() + ": " + ex.getMessage()); } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/comm/ui/OmnipodUIComm.java b/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/comm/ui/OmnipodUIComm.java index 2d91deec37..b5f6d4136b 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/comm/ui/OmnipodUIComm.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/comm/ui/OmnipodUIComm.java @@ -4,7 +4,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import info.nightscout.androidaps.logging.L; -import info.nightscout.androidaps.plugins.pump.omnipod.comm.OmnipodCommunicationManager; import info.nightscout.androidaps.plugins.pump.omnipod.defs.OmnipodCommunicationManagerInterface; import info.nightscout.androidaps.plugins.pump.omnipod.defs.OmnipodCommandType; import info.nightscout.androidaps.plugins.pump.omnipod.util.OmnipodUtil; diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/comm/ui/OmnipodUITask.java b/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/comm/ui/OmnipodUITask.java index 6e88f95f67..a14b22e627 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/comm/ui/OmnipodUITask.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/comm/ui/OmnipodUITask.java @@ -8,11 +8,10 @@ import info.nightscout.androidaps.data.PumpEnactResult; import info.nightscout.androidaps.logging.L; import info.nightscout.androidaps.plugins.bus.RxBus; import info.nightscout.androidaps.plugins.pump.common.data.TempBasalPair; +import info.nightscout.androidaps.plugins.pump.omnipod.comm.data.PodCommResponse; import info.nightscout.androidaps.plugins.pump.omnipod.defs.OmnipodCommandType; import info.nightscout.androidaps.plugins.pump.omnipod.defs.OmnipodCommunicationManagerInterface; import info.nightscout.androidaps.plugins.pump.omnipod.defs.PodDeviceState; -import info.nightscout.androidaps.plugins.pump.omnipod.defs.PodInitActionType; -import info.nightscout.androidaps.plugins.pump.omnipod.defs.PodInitReceiver; import info.nightscout.androidaps.plugins.pump.omnipod.defs.PodResponseType; import info.nightscout.androidaps.plugins.pump.omnipod.events.EventOmnipodDeviceStatusChange; import info.nightscout.androidaps.plugins.pump.omnipod.events.EventOmnipodPumpValuesChanged; @@ -57,7 +56,8 @@ public class OmnipodUITask { // break; case InitPod: - returnData = communicationManager.initPod((PodInitActionType) parameters[0], (PodInitReceiver) parameters[1]); + returnData = communicationManager.initPod(); +// TODO returnData = communicationManager.pairAndPrime(); break; case DeactivatePod: @@ -66,6 +66,7 @@ public class OmnipodUITask { case ResetPodStatus: returnData = communicationManager.resetPodStatus(); +// TODO returnData = communicationManager.resetPodState(); break; case SetBasalProfile: @@ -77,6 +78,7 @@ public class OmnipodUITask { if (amount != null) returnData = communicationManager.setBolus(amount); +// TODO returnData = communicationManager.bolus(amount); } break; @@ -130,8 +132,8 @@ public class OmnipodUITask { } - public Object getResult() { - return returnData; + public T getResult() { + return (T)returnData; } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/defs/OmnipodCommunicationManagerInterface.java b/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/defs/OmnipodCommunicationManagerInterface.java index aabaaed6e5..e63f4903c4 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/defs/OmnipodCommunicationManagerInterface.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/defs/OmnipodCommunicationManagerInterface.java @@ -13,9 +13,17 @@ public interface OmnipodCommunicationManagerInterface { */ PumpEnactResult initPod(PodInitActionType podInitActionType, PodInitReceiver podIniReceiver); + // TODO remove + PumpEnactResult pairAndPrime(); + + // TODO remove + PumpEnactResult insertCannula(Profile basalProfile); + + /** * Get Pod Status (is pod running, battery left ?, reservoir, etc) */ + // TODO we should probably return a (wrapped) StatusResponse instead of a PumpEnactResult PumpEnactResult getPodStatus(); /** @@ -26,7 +34,7 @@ public interface OmnipodCommunicationManagerInterface { /** * Set Basal Profile */ - PumpEnactResult setBasalProfile(Profile profile); + PumpEnactResult setBasalProfile(Profile basalProfile); /** * Reset Pod status (if we forget to disconnect Pod and want to init new pod, and want to forget current pod) @@ -48,9 +56,9 @@ public interface OmnipodCommunicationManagerInterface { /** * Set Temporary Basal * - * @param tbr TempBasalPair object containing amount and duration in minutes + * @param tempBasalPair TempBasalPair object containg amount and duration in minutes */ - PumpEnactResult setTemporaryBasal(TempBasalPair tbr); + PumpEnactResult setTemporaryBasal(TempBasalPair tempBasalPair); /** * Cancel Temporary Basal (if TB is already stopped, return acknowledgment) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/defs/schedule/BasalScheduleMapper.java b/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/defs/schedule/BasalScheduleMapper.java index cce2dceb1a..f0a2fa7e9d 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/defs/schedule/BasalScheduleMapper.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/defs/schedule/BasalScheduleMapper.java @@ -8,6 +8,7 @@ import java.util.List; import info.nightscout.androidaps.data.Profile; public class BasalScheduleMapper { + // TODO add tests public static BasalSchedule mapProfileToBasalSchedule(Profile profile) { Profile.ProfileValue[] basalValues = profile.getBasalValues(); List entries = new ArrayList<>(); diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/service/RileyLinkOmnipodService.java b/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/service/RileyLinkOmnipodService.java index 67c280ce3c..584d3bc1f8 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/service/RileyLinkOmnipodService.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/service/RileyLinkOmnipodService.java @@ -6,6 +6,8 @@ import android.content.res.Configuration; import android.os.Binder; import android.os.IBinder; +import com.google.gson.Gson; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -21,8 +23,12 @@ import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.defs.RileyLin import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.defs.RileyLinkTargetDevice; import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.RileyLinkService; import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.RileyLinkServiceData; +import info.nightscout.androidaps.plugins.pump.omnipod.OmnipodManager; import info.nightscout.androidaps.plugins.pump.omnipod.OmnipodPumpPlugin; -import info.nightscout.androidaps.plugins.pump.omnipod.comm.OmnipodCommunicationManager; +import info.nightscout.androidaps.plugins.pump.omnipod.comm.OmnipodCommunicationService; +import info.nightscout.androidaps.plugins.pump.omnipod.defs.OmnipodCommunicationManagerInterface; +import info.nightscout.androidaps.plugins.pump.omnipod.defs.state.PodSessionState; +import info.nightscout.androidaps.plugins.pump.omnipod.util.OmnipodConst; import info.nightscout.androidaps.plugins.pump.omnipod.util.OmnipodUtil; import info.nightscout.androidaps.utils.SP; @@ -36,7 +42,7 @@ public class RileyLinkOmnipodService extends RileyLinkService { private static RileyLinkOmnipodService instance; - OmnipodCommunicationManager omnipodCommunicationManager; + OmnipodCommunicationManagerInterface omnipodCommunicationManager; OmnipodPumpStatus pumpStatus = null; private IBinder mBinder = new LocalBinder(); @@ -101,7 +107,26 @@ public class RileyLinkOmnipodService extends RileyLinkService { RileyLinkUtil.setRileyLinkBLE(rileyLinkBLE); // init rileyLinkCommunicationManager - omnipodCommunicationManager = new OmnipodCommunicationManager(context, rfspy); + initializeErosOmnipodManager(); + // TODO Dash + } + + private void initializeErosOmnipodManager() { + if(OmnipodManager.getInstance() == null) { + PodSessionState podState = null; + if (SP.contains(OmnipodConst.Prefs.PodState)) { + try { + Gson gson = OmnipodUtil.getGsonInstance(); + String storedPodState = SP.getString(OmnipodConst.Prefs.PodState, null); + podState = gson.fromJson(storedPodState, PodSessionState.class); + } catch (Exception ex) { + LOG.error("Could not deserialize Pod state: " + ex.getClass().getSimpleName() + ": " + ex.getMessage()); + } + } + omnipodCommunicationManager = new OmnipodManager(new OmnipodCommunicationService(rfspy), podState); + } else { + omnipodCommunicationManager = OmnipodManager.getInstance(); + } } @@ -112,7 +137,11 @@ public class RileyLinkOmnipodService extends RileyLinkService { @Override public RileyLinkCommunicationManager getDeviceCommunicationManager() { - return this.omnipodCommunicationManager; + if(omnipodCommunicationManager instanceof OmnipodManager) { // Eros + return ((OmnipodManager) omnipodCommunicationManager).getCommunicationService(); + } + // FIXME is this correct for Dash? + return (RileyLinkCommunicationManager)omnipodCommunicationManager; } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/util/OmnipodUtil.java b/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/util/OmnipodUtil.java index 3bd137fb83..ce6f76b0ff 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/util/OmnipodUtil.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/util/OmnipodUtil.java @@ -47,7 +47,7 @@ public class OmnipodUtil extends RileyLinkUtil { private static RileyLinkOmnipodService omnipodService; private static OmnipodPumpStatus omnipodPumpStatus; private static OmnipodCommandType currentCommand; - private static Gson gsonInstance = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create(); + private static Gson gsonInstance = createGson(); private static PodSessionState podSessionState; private static PodDeviceState podDeviceState; private static OmnipodPumpPlugin omnipodPumpPlugin; @@ -102,8 +102,8 @@ public class OmnipodUtil extends RileyLinkUtil { } - public static OmnipodCommunicationManager getOmnipodCommunicationManager() { - return (OmnipodCommunicationManager) RileyLinkUtil.rileyLinkCommunicationManager; + public static OmnipodCommunicationManagerInterface getOmnipodCommunicationManager() { + return (OmnipodCommunicationManagerInterface) RileyLinkUtil.rileyLinkCommunicationManager; } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod_dash/comm/OmnipodDashCommunicationManager.java b/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod_dash/comm/OmnipodDashCommunicationManager.java index 4f58ba38a0..f07aa097bb 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod_dash/comm/OmnipodDashCommunicationManager.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod_dash/comm/OmnipodDashCommunicationManager.java @@ -64,16 +64,6 @@ public class OmnipodDashCommunicationManager implements OmnipodCommunicationMana } - // This are just skeleton methods, we need to see what we can get returned and act accordingly - - public PumpEnactResult initPod() { - //omnipodManager.pairAndPrime(); - - - return null; - } - - @Override public PumpEnactResult initPod(PodInitActionType podInitActionType, PodInitReceiver podInitReceiver) { return null; diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/virtual/VirtualPumpPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/pump/virtual/VirtualPumpPlugin.java index 1c2cf1f954..6b561bc41d 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/virtual/VirtualPumpPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/virtual/VirtualPumpPlugin.java @@ -128,6 +128,7 @@ public class VirtualPumpPlugin extends PluginBase implements PumpInterface { @Override protected void onStop() { MainApp.bus().unregister(this); + super.onStop(); } @Subscribe diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/TreatmentsPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/TreatmentsPlugin.java index a9284dd366..c1a26adcbd 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/TreatmentsPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/TreatmentsPlugin.java @@ -110,6 +110,7 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface @Override protected void onStop() { MainApp.bus().register(this); + super.onStop(); } public TreatmentService getService() { @@ -294,14 +295,19 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface } + /** + * Returns all Treatments after specified timestamp. Also returns invalid entries (required to + * map "Fill Canulla" entries to history (and not to add double bolus for it) + * + * @param fromTimestamp + * @return + */ @Override public List getTreatmentsFromHistoryAfterTimestamp(long fromTimestamp) { List in5minback = new ArrayList<>(); long time = System.currentTimeMillis(); synchronized (treatments) { for (Treatment t : treatments) { - if (!t.isValid) - continue; if (t.date <= time && t.date >= fromTimestamp) in5minback.add(t); } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/dialogs/WizardInfoDialog.java b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/dialogs/WizardInfoDialog.java deleted file mode 100644 index e068e094f1..0000000000 --- a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/dialogs/WizardInfoDialog.java +++ /dev/null @@ -1,86 +0,0 @@ -package info.nightscout.androidaps.plugins.treatments.dialogs; - -import android.os.Bundle; -import androidx.fragment.app.DialogFragment; -import android.view.LayoutInflater; -import android.view.View; -import android.view.View.OnClickListener; -import android.view.ViewGroup; -import android.view.WindowManager; -import android.widget.CheckBox; -import android.widget.TextView; - -import org.json.JSONObject; - -import info.nightscout.androidaps.R; -import info.nightscout.androidaps.utils.DecimalFormatter; -import info.nightscout.androidaps.utils.JsonHelper; - -public class WizardInfoDialog extends DialogFragment implements OnClickListener { - JSONObject json; - - public WizardInfoDialog() { - super(); - } - - public void setData(JSONObject json) { - this.json = json; - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.treatments_wizardinfo_dialog, container, false); - - getDialog().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN); - - view.findViewById(R.id.ok).setOnClickListener(this); - - // BG - ((TextView) view.findViewById(R.id.treatments_wizard_bg)).setText(DecimalFormatter.to1Decimal(JsonHelper.safeGetDouble(json, "bg")) + " ISF: " + DecimalFormatter.to1Decimal(JsonHelper.safeGetDouble(json, "isf"))); - ((TextView) view.findViewById(R.id.treatments_wizard_bginsulin)).setText(DecimalFormatter.to2Decimal(JsonHelper.safeGetDouble(json, "insulinbg")) + "U"); - ((CheckBox) view.findViewById(R.id.treatments_wizard_bgcheckbox)).setChecked(JsonHelper.safeGetBoolean(json, "insulinbgused")); - ((CheckBox) view.findViewById(R.id.treatments_wizard_ttcheckbox)).setChecked(JsonHelper.safeGetBoolean(json, "ttused")); - // Trend - ((TextView) view.findViewById(R.id.treatments_wizard_bgtrend)).setText(JsonHelper.safeGetString(json, "trend")); - ((TextView) view.findViewById(R.id.treatments_wizard_bgtrendinsulin)).setText(DecimalFormatter.to2Decimal(JsonHelper.safeGetDouble(json, "insulintrend")) + "U"); - ((CheckBox) view.findViewById(R.id.treatments_wizard_bgtrendcheckbox)).setChecked(JsonHelper.safeGetBoolean(json, "trendused")); - // COB - ((TextView) view.findViewById(R.id.treatments_wizard_cob)).setText(DecimalFormatter.to0Decimal(JsonHelper.safeGetDouble(json, "cob")) + "g IC: " + DecimalFormatter.to1Decimal(JsonHelper.safeGetDouble(json, "ic"))); - ((TextView) view.findViewById(R.id.treatments_wizard_cobinsulin)).setText(DecimalFormatter.to2Decimal(JsonHelper.safeGetDouble(json, "insulincob")) + "U"); - ((CheckBox) view.findViewById(R.id.treatments_wizard_cobcheckbox)).setChecked(JsonHelper.safeGetBoolean(json, "cobused")); - // Bolus IOB - ((TextView) view.findViewById(R.id.treatments_wizard_bolusiobinsulin)).setText(DecimalFormatter.to2Decimal(JsonHelper.safeGetDouble(json, "bolusiob")) + "U"); - ((CheckBox) view.findViewById(R.id.treatments_wizard_bolusiobcheckbox)).setChecked(JsonHelper.safeGetBoolean(json, "bolusiobused")); - // Basal IOB - ((TextView) view.findViewById(R.id.treatments_wizard_basaliobinsulin)).setText(DecimalFormatter.to2Decimal(JsonHelper.safeGetDouble(json, "basaliob")) + "U"); - ((CheckBox) view.findViewById(R.id.treatments_wizard_basaliobcheckbox)).setChecked(JsonHelper.safeGetBoolean(json, "basaliobused")); - // Superbolus - ((TextView) view.findViewById(R.id.treatments_wizard_sbinsulin)).setText(DecimalFormatter.to2Decimal(JsonHelper.safeGetDouble(json, "insulinsuperbolus")) + "U"); - ((CheckBox) view.findViewById(R.id.treatments_wizard_sbcheckbox)).setChecked(JsonHelper.safeGetBoolean(json, "superbolusused")); - // Carbs - ((TextView) view.findViewById(R.id.treatments_wizard_carbs)).setText(DecimalFormatter.to0Decimal(JsonHelper.safeGetDouble(json, "carbs")) + "g IC: " + DecimalFormatter.to1Decimal(JsonHelper.safeGetDouble(json, "ic"))); - ((TextView) view.findViewById(R.id.treatments_wizard_carbsinsulin)).setText(DecimalFormatter.to2Decimal(JsonHelper.safeGetDouble(json, "insulincarbs")) + "U"); - // Correction - ((TextView) view.findViewById(R.id.treatments_wizard_correctioninsulin)).setText(DecimalFormatter.to2Decimal(JsonHelper.safeGetDouble(json, "othercorrection")) + "U"); - // Profile - ((TextView) view.findViewById(R.id.treatments_wizard_profile)).setText(JsonHelper.safeGetString(json, "profile")); - // Notes - ((TextView) view.findViewById(R.id.treatments_wizard_notes)).setText(JsonHelper.safeGetString(json, "notes")); - // Total - ((TextView) view.findViewById(R.id.treatments_wizard_totalinsulin)).setText(DecimalFormatter.to2Decimal(JsonHelper.safeGetDouble(json, "insulin")) + "U"); - - setCancelable(true); - return view; - } - - @Override - public synchronized void onClick(View view) { - switch (view.getId()) { - case R.id.ok: - dismiss(); - break; - } - } - -} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/dialogs/WizardInfoDialog.kt b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/dialogs/WizardInfoDialog.kt new file mode 100644 index 0000000000..4e77a8f758 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/dialogs/WizardInfoDialog.kt @@ -0,0 +1,70 @@ +package info.nightscout.androidaps.plugins.treatments.dialogs + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.view.WindowManager +import androidx.fragment.app.DialogFragment +import info.nightscout.androidaps.R +import info.nightscout.androidaps.utils.DecimalFormatter +import info.nightscout.androidaps.utils.JsonHelper +import kotlinx.android.synthetic.main.treatments_wizardinfo_dialog.* +import org.json.JSONObject + +class WizardInfoDialog : DialogFragment() { + private var json: JSONObject? = null + + fun setData(json: JSONObject) { + this.json = json + } + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle?): View? { + dialog.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN) + isCancelable = true + return inflater.inflate(R.layout.treatments_wizardinfo_dialog, container, false) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + close.setOnClickListener { dismiss() } + + // BG + treatments_wizard_bg.text = DecimalFormatter.to1Decimal(JsonHelper.safeGetDouble(json, "bg")) + " ISF: " + DecimalFormatter.to1Decimal(JsonHelper.safeGetDouble(json, "isf")) + treatments_wizard_bginsulin.text = DecimalFormatter.to2Decimal(JsonHelper.safeGetDouble(json, "insulinbg")) + "U" + treatments_wizard_bgcheckbox.isChecked = JsonHelper.safeGetBoolean(json, "insulinbgused") + treatments_wizard_ttcheckbox.isChecked = JsonHelper.safeGetBoolean(json, "ttused") + // Trend + treatments_wizard_bgtrend.text = JsonHelper.safeGetString(json, "trend") + treatments_wizard_bgtrendinsulin.text = DecimalFormatter.to2Decimal(JsonHelper.safeGetDouble(json, "insulintrend")) + "U" + treatments_wizard_bgtrendcheckbox.isChecked = JsonHelper.safeGetBoolean(json, "trendused") + // COB + treatments_wizard_cob.text = DecimalFormatter.to0Decimal(JsonHelper.safeGetDouble(json, "cob")) + "g IC: " + DecimalFormatter.to1Decimal(JsonHelper.safeGetDouble(json, "ic")) + treatments_wizard_cobinsulin.text = DecimalFormatter.to2Decimal(JsonHelper.safeGetDouble(json, "insulincob")) + "U" + treatments_wizard_cobcheckbox.isChecked = JsonHelper.safeGetBoolean(json, "cobused") + // Bolus IOB + treatments_wizard_bolusiobinsulin.text = DecimalFormatter.to2Decimal(JsonHelper.safeGetDouble(json, "bolusiob")) + "U" + treatments_wizard_bolusiobcheckbox.isChecked = JsonHelper.safeGetBoolean(json, "bolusiobused") + // Basal IOB + treatments_wizard_basaliobinsulin.text = DecimalFormatter.to2Decimal(JsonHelper.safeGetDouble(json, "basaliob")) + "U" + treatments_wizard_basaliobcheckbox.isChecked = JsonHelper.safeGetBoolean(json, "basaliobused") + // Superbolus + treatments_wizard_sbinsulin.text = DecimalFormatter.to2Decimal(JsonHelper.safeGetDouble(json, "insulinsuperbolus")) + "U" + treatments_wizard_sbcheckbox.isChecked = JsonHelper.safeGetBoolean(json, "superbolusused") + // Carbs + treatments_wizard_carbs.text = DecimalFormatter.to0Decimal(JsonHelper.safeGetDouble(json, "carbs")) + "g IC: " + DecimalFormatter.to1Decimal(JsonHelper.safeGetDouble(json, "ic")) + treatments_wizard_carbsinsulin.text = DecimalFormatter.to2Decimal(JsonHelper.safeGetDouble(json, "insulincarbs")) + "U" + // Correction + treatments_wizard_correctioninsulin.text = DecimalFormatter.to2Decimal(JsonHelper.safeGetDouble(json, "othercorrection")) + "U" + // Profile + treatments_wizard_profile.text = JsonHelper.safeGetString(json, "profile") + // Notes + treatments_wizard_notes.text = JsonHelper.safeGetString(json, "notes") + // Percentage + treatments_wizard_percent_used.text = DecimalFormatter.to0Decimal(JsonHelper.safeGetDouble(json, "percentageCorrection", 100.0)) + "%" + // Total + treatments_wizard_totalinsulin.text = DecimalFormatter.to2Decimal(JsonHelper.safeGetDouble(json, "insulin")) + "U" + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/receivers/ChargingStateReceiver.java b/app/src/main/java/info/nightscout/androidaps/receivers/ChargingStateReceiver.java index c6df43e002..d325ee9506 100644 --- a/app/src/main/java/info/nightscout/androidaps/receivers/ChargingStateReceiver.java +++ b/app/src/main/java/info/nightscout/androidaps/receivers/ChargingStateReceiver.java @@ -36,7 +36,7 @@ public class ChargingStateReceiver extends BroadcastReceiver { } static public boolean isCharging() { - return lastEvent != null && lastEvent.isCharging; + return lastEvent != null && lastEvent.isCharging(); } static public EventChargingState getLastEvent() { diff --git a/app/src/main/java/info/nightscout/androidaps/receivers/DataReceiver.java b/app/src/main/java/info/nightscout/androidaps/receivers/DataReceiver.java index 95fd6bfb09..6c2e7c6920 100644 --- a/app/src/main/java/info/nightscout/androidaps/receivers/DataReceiver.java +++ b/app/src/main/java/info/nightscout/androidaps/receivers/DataReceiver.java @@ -1,9 +1,8 @@ package info.nightscout.androidaps.receivers; -import android.content.BroadcastReceiver; -import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import androidx.legacy.content.WakefulBroadcastReceiver; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -11,16 +10,15 @@ import org.slf4j.LoggerFactory; import info.nightscout.androidaps.logging.L; import info.nightscout.androidaps.services.DataService; -public class DataReceiver extends BroadcastReceiver { +public class DataReceiver extends WakefulBroadcastReceiver { private static Logger log = LoggerFactory.getLogger(L.DATASERVICE); @Override public void onReceive(Context context, Intent intent) { if (L.isEnabled(L.DATASERVICE)) log.debug("onReceive " + intent); - // Explicitly specify that GcmIntentService will handle the intent. - ComponentName comp = new ComponentName(context.getPackageName(), - DataService.class.getName()); - DataService.enqueueWork(context, intent.setComponent(comp)); + startWakefulService(context, new Intent(context, DataService.class) + .setAction(intent.getAction()) + .putExtras(intent)); } } 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 24a7698e9a..6b8ac46f11 100644 --- a/app/src/main/java/info/nightscout/androidaps/services/DataService.java +++ b/app/src/main/java/info/nightscout/androidaps/services/DataService.java @@ -1,13 +1,10 @@ package info.nightscout.androidaps.services; -import android.content.Context; +import android.app.IntentService; import android.content.Intent; import android.os.Bundle; import android.provider.Telephony; -import androidx.annotation.NonNull; -import androidx.core.app.JobIntentService; - import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; @@ -19,16 +16,15 @@ import info.nightscout.androidaps.R; import info.nightscout.androidaps.db.CareportalEvent; import info.nightscout.androidaps.events.EventNsFood; import info.nightscout.androidaps.events.EventNsTreatment; -import info.nightscout.androidaps.logging.BundleLogger; import info.nightscout.androidaps.logging.L; import info.nightscout.androidaps.plugins.general.nsclient.data.NSDeviceStatus; import info.nightscout.androidaps.plugins.general.nsclient.data.NSMbg; import info.nightscout.androidaps.plugins.general.nsclient.data.NSSettingsStatus; import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification; import info.nightscout.androidaps.plugins.general.overview.notifications.Notification; -import info.nightscout.androidaps.plugins.general.smsCommunicator.SmsCommunicatorPlugin; import info.nightscout.androidaps.plugins.profile.ns.NSProfilePlugin; import info.nightscout.androidaps.plugins.pump.danaR.activities.DanaRNSHistorySync; +import info.nightscout.androidaps.plugins.general.smsCommunicator.SmsCommunicatorPlugin; import info.nightscout.androidaps.plugins.source.SourceDexcomPlugin; import info.nightscout.androidaps.plugins.source.SourceEversensePlugin; import info.nightscout.androidaps.plugins.source.SourceGlimpPlugin; @@ -38,30 +34,21 @@ import info.nightscout.androidaps.plugins.source.SourcePoctechPlugin; import info.nightscout.androidaps.plugins.source.SourceTomatoPlugin; import info.nightscout.androidaps.plugins.source.SourceXdripPlugin; import info.nightscout.androidaps.receivers.DataReceiver; +import info.nightscout.androidaps.logging.BundleLogger; import info.nightscout.androidaps.utils.JsonHelper; import info.nightscout.androidaps.utils.SP; -public class DataService extends JobIntentService { +public class DataService extends IntentService { private Logger log = LoggerFactory.getLogger(L.DATASERVICE); - // Service unique ID - static final int SERVICE_JOB_ID = 4378; - - // Enqueuing work in to this service. - public static void enqueueWork(Context context, Intent work) { - enqueueWork(context, DataService.class, SERVICE_JOB_ID, work); + public DataService() { + super("DataService"); + registerBus(); } @Override - public void onDestroy() { - super.onDestroy(); - if (L.isEnabled(L.DATASERVICE)) - log.debug("All work complete"); - } - - @Override - protected void onHandleWork(@NonNull Intent intent) { + protected void onHandleIntent(final Intent intent) { if (L.isEnabled(L.DATASERVICE)) { log.debug("onHandleIntent " + intent); log.debug("onHandleIntent " + BundleLogger.log(intent.getExtras())); @@ -113,7 +100,7 @@ public class DataService extends JobIntentService { Intents.ACTION_REMOVED_TREATMENT.equals(action) || Intents.ACTION_NEW_CAL.equals(action) || Intents.ACTION_NEW_MBG.equals(action)) - ) { + ) { handleNewDataFromNSClient(intent); } else if (Telephony.Sms.Intents.SMS_RECEIVED_ACTION.equals(action)) { SmsCommunicatorPlugin.getPlugin().handleNewData(intent); @@ -121,6 +108,22 @@ public class DataService extends JobIntentService { if (L.isEnabled(L.DATASERVICE)) log.debug("onHandleIntent exit " + intent); + DataReceiver.completeWakefulIntent(intent); + } + + @Override + public void onDestroy() { + super.onDestroy(); + MainApp.bus().unregister(this); + } + + private void registerBus() { + try { + MainApp.bus().unregister(this); + } catch (RuntimeException x) { + // Ignore + } + MainApp.bus().register(this); } private void handleNewDataFromNSClient(Intent intent) { diff --git a/app/src/main/java/info/nightscout/androidaps/services/LocationService.java b/app/src/main/java/info/nightscout/androidaps/services/LocationService.java index feec4dcab8..33f92d770a 100644 --- a/app/src/main/java/info/nightscout/androidaps/services/LocationService.java +++ b/app/src/main/java/info/nightscout/androidaps/services/LocationService.java @@ -11,10 +11,14 @@ import android.os.IBinder; import androidx.core.app.ActivityCompat; +import com.squareup.otto.Subscribe; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.R; +import info.nightscout.androidaps.events.EventAppExit; import info.nightscout.androidaps.events.EventLocationChange; import info.nightscout.androidaps.logging.L; import info.nightscout.androidaps.plugins.bus.RxBus; @@ -80,12 +84,14 @@ public class LocationService extends Service { super.onStartCommand(intent, flags, startId); if (L.isEnabled(L.LOCATION)) log.debug("onStartCommand"); - startForeground(PersistentNotificationPlugin.ONGOING_NOTIFICATION_ID, PersistentNotificationPlugin.getPlugin().updateNotification()); + startForeground(PersistentNotificationPlugin.ONGOING_NOTIFICATION_ID, PersistentNotificationPlugin.getPlugin().getLastNotification()); return START_STICKY; } @Override public void onCreate() { + super.onCreate(); + startForeground(PersistentNotificationPlugin.ONGOING_NOTIFICATION_ID, PersistentNotificationPlugin.getPlugin().getLastNotification()); if (L.isEnabled(L.LOCATION)) log.debug("onCreate"); @@ -119,6 +125,7 @@ public class LocationService extends Service { } catch (IllegalArgumentException ex) { log.error("network provider does not exist, " + ex.getMessage()); } + MainApp.bus().register(this); } @Override @@ -136,6 +143,15 @@ public class LocationService extends Service { log.error("fail to remove location listener, ignore", ex); } } + MainApp.bus().unregister(this); + } + + @Subscribe + public void onStatusEvent(EventAppExit event) { + if (L.isEnabled(L.CORE)) + log.debug("EventAppExit received"); + + stopSelf(); } private void initializeLocationManager() { diff --git a/app/src/main/java/info/nightscout/androidaps/setupwizard/SWDefinition.java b/app/src/main/java/info/nightscout/androidaps/setupwizard/SWDefinition.java index 46f7fcf185..cbc0af6491 100644 --- a/app/src/main/java/info/nightscout/androidaps/setupwizard/SWDefinition.java +++ b/app/src/main/java/info/nightscout/androidaps/setupwizard/SWDefinition.java @@ -202,8 +202,6 @@ public class SWDefinition { private SWScreen screenAge = new SWScreen(R.string.patientage) .skippable(false) - .add(new SWInfotext() - .label(R.string.patientage_summary)) .add(new SWBreak()) .add(new SWRadioButton() .option(R.array.ageArray, R.array.ageValues) diff --git a/app/src/main/java/info/nightscout/androidaps/utils/AndroidPermission.java b/app/src/main/java/info/nightscout/androidaps/utils/AndroidPermission.java index 7963ae0545..021885ca6c 100644 --- a/app/src/main/java/info/nightscout/androidaps/utils/AndroidPermission.java +++ b/app/src/main/java/info/nightscout/androidaps/utils/AndroidPermission.java @@ -3,6 +3,7 @@ package info.nightscout.androidaps.utils; import android.Manifest; import android.annotation.SuppressLint; import android.app.Activity; +import android.content.ActivityNotFoundException; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; @@ -29,6 +30,8 @@ public class AndroidPermission { public static final int CASE_BATTERY = 0x4; public static final int CASE_PHONE_STATE = 0x5; + private static boolean permission_battery_optimization_failed = false; + @SuppressLint("BatteryLife") private static void askForPermission(Activity activity, String[] permission, Integer requestCode) { boolean test = false; @@ -45,10 +48,15 @@ public class AndroidPermission { ActivityCompat.requestPermissions(activity, permission, requestCode); } if (testBattery) { - Intent i = new Intent(); - i.setAction(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS); - i.setData(Uri.parse("package:" + activity.getPackageName())); - activity.startActivityForResult(i, CASE_BATTERY); + try { + Intent i = new Intent(); + i.setAction(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS); + i.setData(Uri.parse("package:" + activity.getPackageName())); + activity.startActivityForResult(i, CASE_BATTERY); + } catch (ActivityNotFoundException e) { + permission_battery_optimization_failed = true; + OKDialog.show(activity, MainApp.gs(R.string.permission), MainApp.gs(R.string.alert_dialog_permission_battery_optimization_failed), activity::recreate); + } } } @@ -60,9 +68,11 @@ public class AndroidPermission { public static boolean permissionNotGranted(Context context, String permission) { boolean selfCheck = ContextCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED; if (permission.equals(Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS)) { - PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); - String packageName = context.getPackageName(); - selfCheck = selfCheck && powerManager.isIgnoringBatteryOptimizations(packageName); + if (!permission_battery_optimization_failed) { + PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); + String packageName = context.getPackageName(); + selfCheck = selfCheck && powerManager.isIgnoringBatteryOptimizations(packageName); + } } return !selfCheck; } @@ -71,7 +81,7 @@ public class AndroidPermission { if (SP.getBoolean(R.string.key_smscommunicator_remotecommandsallowed, false)) { if (permissionNotGranted(activity, Manifest.permission.RECEIVE_SMS)) { NotificationWithAction notification = new NotificationWithAction(Notification.PERMISSION_SMS, MainApp.gs(R.string.smscommunicator_missingsmspermission), Notification.URGENT); - notification.action(MainApp.gs(R.string.request), () -> AndroidPermission.askForPermission(activity, new String[]{Manifest.permission.RECEIVE_SMS, + notification.action(R.string.request, () -> AndroidPermission.askForPermission(activity, new String[]{Manifest.permission.RECEIVE_SMS, Manifest.permission.SEND_SMS, Manifest.permission.RECEIVE_MMS}, AndroidPermission.CASE_SMS)); MainApp.bus().post(new EventNewNotification(notification)); @@ -81,7 +91,7 @@ public class AndroidPermission { if (Build.VERSION.SDK_INT == Build.VERSION_CODES.O) { if (permissionNotGranted(activity, Manifest.permission.READ_PHONE_STATE)) { NotificationWithAction notification = new NotificationWithAction(Notification.PERMISSION_PHONESTATE, MainApp.gs(R.string.smscommunicator_missingphonestatepermission), Notification.URGENT); - notification.action(MainApp.gs(R.string.request), () -> + notification.action(R.string.request, () -> AndroidPermission.askForPermission(activity, new String[]{Manifest.permission.READ_PHONE_STATE}, AndroidPermission.CASE_PHONE_STATE)); MainApp.bus().post(new EventNewNotification(notification)); } else @@ -93,7 +103,7 @@ public class AndroidPermission { public static synchronized void notifyForBatteryOptimizationPermission(Activity activity) { if (permissionNotGranted(activity, Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS)) { NotificationWithAction notification = new NotificationWithAction(Notification.PERMISSION_BATTERY, String.format(MainApp.gs(R.string.needwhitelisting), MainApp.gs(R.string.app_name)), Notification.URGENT); - notification.action(MainApp.gs(R.string.request), () -> AndroidPermission.askForPermission(activity, new String[]{Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS}, AndroidPermission.CASE_BATTERY)); + notification.action(R.string.request, () -> AndroidPermission.askForPermission(activity, new String[]{Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS}, AndroidPermission.CASE_BATTERY)); MainApp.bus().post(new EventNewNotification(notification)); } else MainApp.bus().post(new EventDismissNotification(Notification.PERMISSION_BATTERY)); @@ -102,7 +112,7 @@ public class AndroidPermission { public static synchronized void notifyForStoragePermission(Activity activity) { if (permissionNotGranted(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE)) { NotificationWithAction notification = new NotificationWithAction(Notification.PERMISSION_STORAGE, MainApp.gs(R.string.needstoragepermission), Notification.URGENT); - notification.action(MainApp.gs(R.string.request), () -> AndroidPermission.askForPermission(activity, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, + notification.action(R.string.request, () -> AndroidPermission.askForPermission(activity, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE}, AndroidPermission.CASE_STORAGE)); MainApp.bus().post(new EventNewNotification(notification)); } else @@ -112,7 +122,7 @@ public class AndroidPermission { public static synchronized void notifyForLocationPermissions(Activity activity) { if (permissionNotGranted(activity, Manifest.permission.ACCESS_FINE_LOCATION)) { NotificationWithAction notification = new NotificationWithAction(Notification.PERMISSION_LOCATION, MainApp.gs(R.string.needlocationpermission), Notification.URGENT); - notification.action(MainApp.gs(R.string.request), () -> AndroidPermission.askForPermission(activity, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, AndroidPermission.CASE_LOCATION)); + notification.action(R.string.request, () -> AndroidPermission.askForPermission(activity, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, AndroidPermission.CASE_LOCATION)); MainApp.bus().post(new EventNewNotification(notification)); } else MainApp.bus().post(new EventDismissNotification(Notification.PERMISSION_LOCATION)); diff --git a/app/src/main/java/info/nightscout/androidaps/utils/BolusWizard.kt b/app/src/main/java/info/nightscout/androidaps/utils/BolusWizard.kt index b741e4656c..598616f1bf 100644 --- a/app/src/main/java/info/nightscout/androidaps/utils/BolusWizard.kt +++ b/app/src/main/java/info/nightscout/androidaps/utils/BolusWizard.kt @@ -231,6 +231,7 @@ class BolusWizard @JvmOverloads constructor(val profile: Profile, boluscalcJSON.put("insulintrend", insulinFromTrend) boluscalcJSON.put("trend", trend) boluscalcJSON.put("ttused", useTT) + boluscalcJSON.put("percentageCorrection", percentageCorrection) } catch (e: JSONException) { log.error("Unhandled exception", e) } diff --git a/app/src/main/java/info/nightscout/androidaps/utils/CompositeDisposablePlusAssign.kt b/app/src/main/java/info/nightscout/androidaps/utils/CompositeDisposablePlusAssign.kt new file mode 100644 index 0000000000..1f2fb892e5 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/utils/CompositeDisposablePlusAssign.kt @@ -0,0 +1,9 @@ +package info.nightscout.androidaps.utils + +import io.reactivex.disposables.CompositeDisposable +import io.reactivex.disposables.Disposable + +operator fun CompositeDisposable.plusAssign(disposable: Disposable) { + add(disposable) +} + diff --git a/app/src/main/java/info/nightscout/androidaps/utils/DigitsKeyListenerWithComma.java b/app/src/main/java/info/nightscout/androidaps/utils/DigitsKeyListenerWithComma.java new file mode 100644 index 0000000000..a84ccd61a2 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/utils/DigitsKeyListenerWithComma.java @@ -0,0 +1,199 @@ +package info.nightscout.androidaps.utils; + +import android.text.InputType; +import android.text.SpannableStringBuilder; +import android.text.Spanned; +import android.text.method.NumberKeyListener; +import android.view.KeyEvent; + +class DigitsKeyListenerWithComma extends NumberKeyListener { + + /** + * The characters that are used. + * + * @see KeyEvent#getMatch + * @see #getAcceptedChars + */ + private static final char[][] CHARACTERS = new char[][]{ + new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}, + new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-'}, + new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.', ','}, + new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '.', ','}, + }; + + private char[] mAccepted; + private boolean mSign; + private boolean mDecimal; + + private static final int SIGN = 1; + private static final int DECIMAL = 2; + + private static DigitsKeyListenerWithComma[] sInstance = new DigitsKeyListenerWithComma[4]; + + @Override + protected char[] getAcceptedChars() { + return mAccepted; + } + + /** + * Allocates a DigitsKeyListener that accepts the digits 0 through 9. + */ + public DigitsKeyListenerWithComma() { + this(false, false); + } + + /** + * Allocates a DigitsKeyListener that accepts the digits 0 through 9, + * plus the minus sign (only at the beginning) and/or decimal point + * (only one per field) if specified. + */ + public DigitsKeyListenerWithComma(boolean sign, boolean decimal) { + mSign = sign; + mDecimal = decimal; + + int kind = (sign ? SIGN : 0) | (decimal ? DECIMAL : 0); + mAccepted = CHARACTERS[kind]; + } + + /** + * Returns a DigitsKeyListener that accepts the digits 0 through 9. + */ + public static DigitsKeyListenerWithComma getInstance() { + return getInstance(false, false); + } + + /** + * Returns a DigitsKeyListener that accepts the digits 0 through 9, + * plus the minus sign (only at the beginning) and/or decimal point + * (only one per field) if specified. + */ + public static DigitsKeyListenerWithComma getInstance(boolean sign, boolean decimal) { + int kind = (sign ? SIGN : 0) | (decimal ? DECIMAL : 0); + + if (sInstance[kind] != null) + return sInstance[kind]; + + sInstance[kind] = new DigitsKeyListenerWithComma(sign, decimal); + return sInstance[kind]; + } + + /** + * Returns a DigitsKeyListener that accepts only the characters + * that appear in the specified String. Note that not all characters + * may be available on every keyboard. + */ + public static DigitsKeyListenerWithComma getInstance(String accepted) { + // TODO: do we need a cache of these to avoid allocating? + + DigitsKeyListenerWithComma dim = new DigitsKeyListenerWithComma(); + + dim.mAccepted = new char[accepted.length()]; + accepted.getChars(0, accepted.length(), dim.mAccepted, 0); + + return dim; + } + + public int getInputType() { + int contentType = InputType.TYPE_CLASS_NUMBER; + if (mSign) { + contentType |= InputType.TYPE_NUMBER_FLAG_SIGNED; + } + if (mDecimal) { + contentType |= InputType.TYPE_NUMBER_FLAG_DECIMAL; + } + return contentType; + } + + @Override + public CharSequence filter(CharSequence source, int start, int end, + Spanned dest, int dstart, int dend) { + CharSequence out = super.filter(source, start, end, dest, dstart, dend); + + if (mSign == false && mDecimal == false) { + return out; + } + + if (out != null) { + source = out; + start = 0; + end = out.length(); + } + + int sign = -1; + int decimal = -1; + int dlen = dest.length(); + + /* + * Find out if the existing text has '-' or '.' characters. + */ + + for (int i = 0; i < dstart; i++) { + char c = dest.charAt(i); + + if (c == '-') { + sign = i; + } else if (c == '.' || c == ',') { + decimal = i; + } + } + for (int i = dend; i < dlen; i++) { + char c = dest.charAt(i); + + if (c == '-') { + return ""; // Nothing can be inserted in front of a '-'. + } else if (c == '.' || c == ',') { + decimal = i; + } + } + + /* + * If it does, we must strip them out from the source. + * In addition, '-' must be the very first character, + * and nothing can be inserted before an existing '-'. + * Go in reverse order so the offsets are stable. + */ + + SpannableStringBuilder stripped = null; + + for (int i = end - 1; i >= start; i--) { + char c = source.charAt(i); + boolean strip = false; + + if (c == '-') { + if (i != start || dstart != 0) { + strip = true; + } else if (sign >= 0) { + strip = true; + } else { + sign = i; + } + } else if (c == '.' || c == ',') { + if (decimal >= 0) { + strip = true; + } else { + decimal = i; + } + } + + if (strip) { + if (end == start + 1) { + return ""; // Only one character, and it was stripped. + } + + if (stripped == null) { + stripped = new SpannableStringBuilder(source, start, end); + } + + stripped.delete(i - start, i + 1 - start); + } + } + + if (stripped != null) { + return stripped; + } else if (out != null) { + return out; + } else { + return null; + } + } +} \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/utils/JsonHelper.java b/app/src/main/java/info/nightscout/androidaps/utils/JsonHelper.java index 8f715a0448..5308c62420 100644 --- a/app/src/main/java/info/nightscout/androidaps/utils/JsonHelper.java +++ b/app/src/main/java/info/nightscout/androidaps/utils/JsonHelper.java @@ -72,6 +72,19 @@ public class JsonHelper { return result; } + public static double safeGetDouble(JSONObject json, String fieldName, double defaultValue) { + double result = defaultValue; + + if (json != null && json.has(fieldName)) { + try { + result = json.getDouble(fieldName); + } catch (JSONException ignored) { + } + } + + return result; + } + public static int safeGetInt(JSONObject json, String fieldName) { int result = 0; diff --git a/app/src/main/java/info/nightscout/androidaps/utils/NumberPicker.java b/app/src/main/java/info/nightscout/androidaps/utils/NumberPicker.java index b125d0b2a3..e2a7489fc2 100644 --- a/app/src/main/java/info/nightscout/androidaps/utils/NumberPicker.java +++ b/app/src/main/java/info/nightscout/androidaps/utils/NumberPicker.java @@ -183,7 +183,8 @@ public class NumberPicker extends LinearLayout implements View.OnKeyListener, } setParams(initValue, minValue, maxValue, step, formater, allowZero, okButton); this.textWatcher = textWatcher; - editText.addTextChangedListener(textWatcher); + if (textWatcher != null) + editText.addTextChangedListener(textWatcher); } public void setParams(Double initValue, Double minValue, Double maxValue, Double step, NumberFormat formater, boolean allowZero, Button okButton) { @@ -196,7 +197,7 @@ public class NumberPicker extends LinearLayout implements View.OnKeyListener, callValueChangedListener(); this.okButton = okButton; - editText.setKeyListener(DigitsKeyListener.getInstance(minValue < 0, step != Math.rint(step))); + editText.setKeyListener(DigitsKeyListenerWithComma.getInstance(minValue < 0, step != Math.rint(step))); if (textWatcher != null) editText.removeTextChangedListener(textWatcher); diff --git a/app/src/main/java/info/nightscout/androidaps/utils/TimeListEdit.java b/app/src/main/java/info/nightscout/androidaps/utils/TimeListEdit.java index 6271ee95fa..be8b89dff4 100644 --- a/app/src/main/java/info/nightscout/androidaps/utils/TimeListEdit.java +++ b/app/src/main/java/info/nightscout/androidaps/utils/TimeListEdit.java @@ -1,9 +1,6 @@ package info.nightscout.androidaps.utils; import android.content.Context; -import android.os.Handler; -import androidx.core.content.ContextCompat; -import androidx.core.widget.TextViewCompat; import android.text.Editable; import android.text.TextWatcher; import android.view.Gravity; @@ -15,6 +12,10 @@ import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; +import androidx.annotation.NonNull; +import androidx.core.content.ContextCompat; +import androidx.core.widget.TextViewCompat; + import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; @@ -24,6 +25,7 @@ import org.slf4j.LoggerFactory; import java.text.DecimalFormat; import java.text.NumberFormat; import java.util.ArrayList; +import java.util.List; import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.R; @@ -77,8 +79,8 @@ public class TimeListEdit { } private void buildView() { - layout = (LinearLayout) view.findViewById(resLayoutId); - layout.removeAllViews(); + layout = view.findViewById(resLayoutId); + layout.removeAllViewsInLayout(); textlabel = new TextView(context); textlabel.setText(label); @@ -96,72 +98,63 @@ public class TimeListEdit { } // last "plus" to append new interval + float factor = layout.getContext().getResources().getDisplayMetrics().density; finalAdd = new ImageView(context); finalAdd.setImageResource(R.drawable.add); - LinearLayout.LayoutParams illp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT); + LinearLayout.LayoutParams illp = new LinearLayout.LayoutParams((int) (35d * factor), (int) (35 * factor)); illp.setMargins(0, 25, 0, 25); // llp.setMargins(left, top, right, bottom); illp.gravity = Gravity.CENTER; layout.addView(finalAdd); finalAdd.setLayoutParams(illp); - finalAdd.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - addItem(itemsCount(), itemsCount() > 0 ? secondFromMidnight(itemsCount() - 1) + ONEHOURINSECONDS : 0, 0, 0); - callSave(); - log(); - fillView(); - } + finalAdd.setOnClickListener(view -> { + addItem(itemsCount(), itemsCount() > 0 ? secondFromMidnight(itemsCount() - 1) + ONEHOURINSECONDS : 0, 0, 0); + callSave(); + log(); + fillView(); }); fillView(); } - private void inflateRow(int i) { + private void inflateRow(final int position) { LayoutInflater inflater = LayoutInflater.from(context); - View childview = intervals[i] = inflater.inflate(R.layout.timelistedit_element, layout, false); - spinners[i] = new SpinnerHelper(childview.findViewById(R.id.timelistedit_time)); - numberPickers1[i] = (NumberPicker) childview.findViewById(R.id.timelistedit_edit1); - numberPickers2[i] = (NumberPicker) childview.findViewById(R.id.timelistedit_edit2); - addButtons[i] = (ImageView) childview.findViewById(R.id.timelistedit_add); - removeButtons[i] = (ImageView) childview.findViewById(R.id.timelistedit_remove); + View childView = intervals[position] = inflater.inflate(R.layout.timelistedit_element, layout, false); + spinners[position] = new SpinnerHelper(childView.findViewById(R.id.timelistedit_time)); + numberPickers1[position] = childView.findViewById(R.id.timelistedit_edit1); + numberPickers2[position] = childView.findViewById(R.id.timelistedit_edit2); + addButtons[position] = childView.findViewById(R.id.timelistedit_add); + removeButtons[position] = childView.findViewById(R.id.timelistedit_remove); - final int fixedPos = i; - addButtons[i].setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - int seconds = secondFromMidnight(fixedPos); - addItem(fixedPos, seconds, 0, 0); - // for here for the rest of values - for (int i = fixedPos + 1; i < itemsCount(); i++) { - if (secondFromMidnight(i - 1) >= secondFromMidnight(i)) { - editItem(i, secondFromMidnight(i - 1) + ONEHOURINSECONDS, value1(i), value2(i)); - } + addButtons[position].setOnClickListener(view -> { + int seconds = secondFromMidnight(position); + addItem(position, seconds, 0, 0); + // for here for the rest of values + for (int i = position + 1; i < itemsCount(); i++) { + if (secondFromMidnight(i - 1) >= secondFromMidnight(i)) { + editItem(i, secondFromMidnight(i - 1) + ONEHOURINSECONDS, value1(i), value2(i)); } - while (itemsCount() > 24 || secondFromMidnight(itemsCount() - 1) > 23 * ONEHOURINSECONDS) - removeItem(itemsCount() - 1); - callSave(); - log(); - fillView(); } + while (itemsCount() > 24 || secondFromMidnight(itemsCount() - 1) > 23 * ONEHOURINSECONDS) + removeItem(itemsCount() - 1); + callSave(); + log(); + fillView(); }); - removeButtons[i].setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - removeItem(fixedPos); - callSave(); - log(); - fillView(); - } + removeButtons[position].setOnClickListener(view -> { + removeItem(position); + callSave(); + log(); + fillView(); }); - spinners[i].setOnItemSelectedListener( + spinners[position].setOnItemSelectedListener( new AdapterView.OnItemSelectedListener() { @Override - public void onItemSelected(AdapterView parent, View view, int position, long id) { - int seconds = DateUtil.toSeconds(spinners[fixedPos].getSelectedItem().toString()); - editItem(fixedPos, seconds, value1(fixedPos), value2(fixedPos)); + public void onItemSelected(AdapterView parent, View view, int selected, long id) { + int seconds = ((SpinnerAdapter) spinners[position].getAdapter()).valueForPosition(selected); + editItem(position, seconds, value1(position), value2(position)); log(); callSave(); fillView(); @@ -173,30 +166,10 @@ public class TimeListEdit { } ); - numberPickers1[i].setTextWatcher(new TextWatcher() { - @Override - public void afterTextChanged(Editable s) { - editItem(fixedPos, secondFromMidnight(fixedPos), SafeParse.stringToDouble(numberPickers1[fixedPos].getText()), value2(fixedPos)); - callSave(); - log(); - } - - @Override - public void beforeTextChanged(CharSequence s, int start, - int count, int after) { - } - - @Override - public void onTextChanged(CharSequence s, int start, - int before, int count) { - } - }); - - - numberPickers2[i].setTextWatcher(new TextWatcher() { + numberPickers1[position].setTextWatcher(new TextWatcher() { @Override public void afterTextChanged(Editable s) { - editItem(fixedPos, secondFromMidnight(fixedPos), value1(fixedPos), SafeParse.stringToDouble(numberPickers2[fixedPos].getText())); + editItem(position, secondFromMidnight(position), SafeParse.stringToDouble(numberPickers1[position].getText()), value2(position)); callSave(); log(); } @@ -212,7 +185,27 @@ public class TimeListEdit { } }); - layout.addView(childview); + + numberPickers2[position].setTextWatcher(new TextWatcher() { + @Override + public void afterTextChanged(Editable s) { + editItem(position, secondFromMidnight(position), value1(position), SafeParse.stringToDouble(numberPickers2[position].getText())); + callSave(); + log(); + } + + @Override + public void beforeTextChanged(CharSequence s, int start, + int count, int after) { + } + + @Override + public void onTextChanged(CharSequence s, int start, + int before, int count) { + } + }); + + layout.addView(childView); } private void fillView() { @@ -220,7 +213,7 @@ public class TimeListEdit { if (i < itemsCount()) { intervals[i].setVisibility(View.VISIBLE); buildInterval(i); - } else if (i <= inflatedUntil){ + } else if (i <= inflatedUntil) { intervals[i].setVisibility(View.GONE); } } @@ -232,9 +225,8 @@ public class TimeListEdit { } } - private View buildInterval(int i) { + private void buildInterval(int i) { SpinnerHelper timeSpinner = spinners[i]; - View childview = intervals[i]; final NumberPicker editText1 = numberPickers1[i]; final NumberPicker editText2 = numberPickers2[i]; @@ -244,8 +236,8 @@ public class TimeListEdit { if (i == 0) next = ONEHOURINSECONDS; fillSpinner(timeSpinner, secondFromMidnight(i), previous, next); - editText1.setParams(value1(i), min, max, step, formatter, false, view.findViewById(R.id.localprofile_save)); - editText2.setParams(value2(i), min, max, step, formatter, false, view.findViewById(R.id.localprofile_save)); + editText1.setParams(value1(i), min, max, step, formatter, false,null); + editText2.setParams(value2(i), min, max, step, formatter, false, null); if (data2 == null) { editText2.setVisibility(View.GONE); @@ -263,29 +255,38 @@ public class TimeListEdit { addButtons[i].setVisibility(View.VISIBLE); } - return childview; + } + + class SpinnerAdapter extends ArrayAdapter { + List values; + + SpinnerAdapter(@NonNull Context context, int resource, final @NonNull List objects, final @NonNull List values) { + super(context, resource, objects); + this.values = values; + } + + int valueForPosition(int position) { + return values.get(position); + } } private void fillSpinner(final SpinnerHelper spinner, int secondsFromMidnight, int previous, int next) { int posInList = 0; ArrayList timeList = new ArrayList<>(); + ArrayList timeListValues = new ArrayList<>(); int pos = 0; for (int t = previous + ONEHOURINSECONDS; t < next; t += ONEHOURINSECONDS) { timeList.add(DateUtil.timeStringFromSeconds(t)); + timeListValues.add(t); if (secondsFromMidnight == t) posInList = pos; pos++; } - final ArrayAdapter adapter = new ArrayAdapter<>(context, - R.layout.spinner_centered, timeList); + final SpinnerAdapter adapter = new SpinnerAdapter(context, + R.layout.spinner_centered, timeList, timeListValues); spinner.setAdapter(adapter); - final int finalPosInList = posInList; - new Handler().postDelayed(new Runnable() { - public void run() { - spinner.setSelection(finalPosInList, false); - adapter.notifyDataSetChanged(); - } - }, 100); + spinner.setSelection(posInList, false); + adapter.notifyDataSetChanged(); } private int itemsCount() { @@ -350,7 +351,7 @@ public class TimeListEdit { data1.put(index, newObject1); if (data2 != null) { JSONObject newObject2 = new JSONObject(); - newObject1.put("time", time); + newObject2.put("time", time); newObject2.put("timeAsSeconds", timeAsSeconds); newObject2.put("value", value2); data2.put(index, newObject2); @@ -362,7 +363,7 @@ public class TimeListEdit { } private void addItem(int index, int timeAsSeconds, double value1, double value2) { - if(itemsCount()>inflatedUntil) { + if (itemsCount() > inflatedUntil) { layout.removeView(finalAdd); inflateRow(++inflatedUntil); layout.addView(finalAdd); @@ -389,10 +390,8 @@ public class TimeListEdit { } private void log() { - if (log.isDebugEnabled()) { - for (int i = 0; i < data1.length(); i++) { - log.debug(i + ": @" + DateUtil.timeStringFromSeconds(secondFromMidnight(i)) + " " + value1(i) + (data2 != null ? " " + value2(i) : "")); - } + for (int i = 0; i < data1.length(); i++) { + log.debug(i + ": @" + DateUtil.timeStringFromSeconds(secondFromMidnight(i)) + " " + value1(i) + (data2 != null ? " " + value2(i) : "")); } } @@ -400,9 +399,9 @@ public class TimeListEdit { if (save != null) save.run(); } - public void updateLabel(String txt){ + public void updateLabel(String txt) { this.label = txt; - if(textlabel!=null) + if (textlabel != null) textlabel.setText(txt); } } diff --git a/app/src/main/res/layout/activity_agreement.xml b/app/src/main/res/layout/activity_agreement.xml index 9a17432930..5c98f937ed 100644 --- a/app/src/main/res/layout/activity_agreement.xml +++ b/app/src/main/res/layout/activity_agreement.xml @@ -8,8 +8,7 @@ tools:context="info.nightscout.androidaps.activities.AgreementActivity"> + android:layout_height="fill_parent"> diff --git a/app/src/main/res/layout/activity_setupwizard.xml b/app/src/main/res/layout/activity_setupwizard.xml index 8510abd33f..4bcc5b1221 100644 --- a/app/src/main/res/layout/activity_setupwizard.xml +++ b/app/src/main/res/layout/activity_setupwizard.xml @@ -23,7 +23,6 @@ app:srcCompat="@drawable/ic_exit_to_app" /> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/automation_event_item.xml b/app/src/main/res/layout/automation_event_item.xml index ce377a6aa0..6cbc138278 100644 --- a/app/src/main/res/layout/automation_event_item.xml +++ b/app/src/main/res/layout/automation_event_item.xml @@ -11,6 +11,27 @@ android:background="@color/ribbonDefault" android:padding="8dp"> + + + + + android:layout_below="@id/automation_enabled" + android:orientation="horizontal" /> - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/bgsource_item.xml b/app/src/main/res/layout/bgsource_item.xml index 4cb3be97b8..5d1842b8c6 100644 --- a/app/src/main/res/layout/bgsource_item.xml +++ b/app/src/main/res/layout/bgsource_item.xml @@ -1,7 +1,6 @@ diff --git a/app/src/main/res/layout/combopump_fragment.xml b/app/src/main/res/layout/combopump_fragment.xml index 87650081a5..af76a31a9d 100644 --- a/app/src/main/res/layout/combopump_fragment.xml +++ b/app/src/main/res/layout/combopump_fragment.xml @@ -476,7 +476,6 @@ diff --git a/app/src/main/res/layout/danar_history_item.xml b/app/src/main/res/layout/danar_history_item.xml index b03a26f55a..f2c73ffbf2 100644 --- a/app/src/main/res/layout/danar_history_item.xml +++ b/app/src/main/res/layout/danar_history_item.xml @@ -12,7 +12,6 @@ -