diff --git a/app/build.gradle b/app/build.gradle index 61dae24ba6..2720ef7605 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -247,6 +247,7 @@ dependencies { implementation project(':danar') implementation project(':rileylink') implementation project(':medtronic') + implementation project(':omnipod') implementation fileTree(include: ['*.jar'], dir: 'libs') implementation 'com.google.android.gms:play-services-wearable:17.0.0' @@ -267,6 +268,8 @@ dependencies { implementation "androidx.activity:activity-ktx:${activityVersion}" implementation "androidx.fragment:fragment:${fragmentVersion}" implementation 'androidx.constraintlayout:constraintlayout:1.1.3' + implementation "androidx.navigation:navigation-fragment-ktx:$nav_version" + implementation "androidx.navigation:navigation-ui-ktx:$nav_version" implementation 'com.google.android.material:material:1.1.0' implementation "io.reactivex.rxjava2:rxandroid:${rxandroid_version}" @@ -282,8 +285,6 @@ dependencies { implementation "com.jjoe64:graphview:4.0.1" implementation "com.joanzapata.iconify:android-iconify-fontawesome:2.2.2" implementation 'com.madgag.spongycastle:core:1.58.0.0' - // Omnipod wizard - implementation(name: "com.atech-software.android.library.wizardpager-1.1.4", ext: "aar") implementation("com.google.android:flexbox:0.3.0") { exclude group: "com.android.support" } diff --git a/app/libs/com.atech-software.android.library.wizardpager-1.1.4.aar b/app/libs/com.atech-software.android.library.wizardpager-1.1.4.aar deleted file mode 100644 index af0c6511cf..0000000000 Binary files a/app/libs/com.atech-software.android.library.wizardpager-1.1.4.aar and /dev/null differ diff --git a/app/src/main/java/info/nightscout/androidaps/dependencyInjection/AppComponent.kt b/app/src/main/java/info/nightscout/androidaps/dependencyInjection/AppComponent.kt index 1c0583f042..ef728a2193 100644 --- a/app/src/main/java/info/nightscout/androidaps/dependencyInjection/AppComponent.kt +++ b/app/src/main/java/info/nightscout/androidaps/dependencyInjection/AppComponent.kt @@ -10,6 +10,7 @@ import info.nightscout.androidaps.dana.di.DanaModule import info.nightscout.androidaps.danar.di.DanaRModule import info.nightscout.androidaps.danars.di.DanaRSModule import info.nightscout.androidaps.plugins.pump.common.dagger.RileyLinkModule +import info.nightscout.androidaps.plugins.pump.omnipod.dagger.OmnipodModule import javax.inject.Singleton @Singleton @@ -29,6 +30,7 @@ import javax.inject.Singleton WizardModule::class, RileyLinkModule::class, MedtronicModule::class, + OmnipodModule::class, APSModule::class, PreferencesModule::class, OverviewModule::class, diff --git a/app/src/main/java/info/nightscout/androidaps/dependencyInjection/CommandQueueModule.kt b/app/src/main/java/info/nightscout/androidaps/dependencyInjection/CommandQueueModule.kt index e9339e187b..014a8de8e3 100644 --- a/app/src/main/java/info/nightscout/androidaps/dependencyInjection/CommandQueueModule.kt +++ b/app/src/main/java/info/nightscout/androidaps/dependencyInjection/CommandQueueModule.kt @@ -26,4 +26,5 @@ abstract class CommandQueueModule { @ContributesAndroidInjector abstract fun commandTempBasalAbsoluteInjector(): CommandTempBasalAbsolute @ContributesAndroidInjector abstract fun commandTempBasalPercentInjector(): CommandTempBasalPercent @ContributesAndroidInjector abstract fun commandSetUserSettingsInjector(): CommandSetUserSettings + @ContributesAndroidInjector abstract fun commandCustomCommandInjector(): CommandCustomCommand } \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/dependencyInjection/FragmentsModule.kt b/app/src/main/java/info/nightscout/androidaps/dependencyInjection/FragmentsModule.kt index 0af077c632..42dd3e2972 100644 --- a/app/src/main/java/info/nightscout/androidaps/dependencyInjection/FragmentsModule.kt +++ b/app/src/main/java/info/nightscout/androidaps/dependencyInjection/FragmentsModule.kt @@ -36,6 +36,7 @@ import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.dialog.RileyL import info.nightscout.androidaps.plugins.pump.insight.LocalInsightFragment import info.nightscout.androidaps.plugins.pump.medtronic.MedtronicFragment import info.nightscout.androidaps.plugins.pump.medtronic.dialog.RileyLinkStatusDeviceMedtronic +import info.nightscout.androidaps.plugins.pump.omnipod.ui.OmnipodOverviewFragment import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpFragment import info.nightscout.androidaps.plugins.source.BGSourceFragment import info.nightscout.androidaps.plugins.treatments.TreatmentsFragment @@ -67,6 +68,7 @@ abstract class FragmentsModule { @ContributesAndroidInjector abstract fun contributesLoopFragment(): LoopFragment @ContributesAndroidInjector abstract fun contributesMaintenanceFragment(): MaintenanceFragment @ContributesAndroidInjector abstract fun contributesMedtronicFragment(): MedtronicFragment + @ContributesAndroidInjector abstract fun contributesOmnipodFragment(): OmnipodOverviewFragment @ContributesAndroidInjector abstract fun contributesNSProfileFragment(): NSProfileFragment @ContributesAndroidInjector abstract fun contributesNSClientFragment(): NSClientFragment @ContributesAndroidInjector diff --git a/app/src/main/java/info/nightscout/androidaps/dependencyInjection/ServicesModule.kt b/app/src/main/java/info/nightscout/androidaps/dependencyInjection/ServicesModule.kt index ec71d8a4ad..6ba01130ae 100644 --- a/app/src/main/java/info/nightscout/androidaps/dependencyInjection/ServicesModule.kt +++ b/app/src/main/java/info/nightscout/androidaps/dependencyInjection/ServicesModule.kt @@ -10,6 +10,7 @@ import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.Riley import info.nightscout.androidaps.plugins.pump.insight.InsightAlertService import info.nightscout.androidaps.plugins.pump.insight.connection_service.InsightConnectionService import info.nightscout.androidaps.plugins.pump.medtronic.service.RileyLinkMedtronicService +import info.nightscout.androidaps.plugins.pump.omnipod.rileylink.service.RileyLinkOmnipodService import info.nightscout.androidaps.services.AlarmSoundService import info.nightscout.androidaps.services.DataService import info.nightscout.androidaps.services.LocationService @@ -29,4 +30,5 @@ abstract class ServicesModule { @ContributesAndroidInjector abstract fun contributesInsightConnectionService(): InsightConnectionService @ContributesAndroidInjector abstract fun contributesRileyLinkService(): RileyLinkService @ContributesAndroidInjector abstract fun contributesRileyLinkMedtronicService(): RileyLinkMedtronicService + @ContributesAndroidInjector abstract fun contributesRileyLinkOmnipodService(): RileyLinkOmnipodService } \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/combo/ComboPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/pump/combo/ComboPlugin.java index e443ac4657..82ba382519 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/combo/ComboPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/combo/ComboPlugin.java @@ -29,6 +29,7 @@ import info.nightscout.androidaps.db.CareportalEvent; import info.nightscout.androidaps.db.Source; import info.nightscout.androidaps.db.TDD; import info.nightscout.androidaps.db.TemporaryBasal; +import info.nightscout.androidaps.db.Treatment; import info.nightscout.androidaps.events.EventInitializationChanged; import info.nightscout.androidaps.events.EventRefreshOverview; import info.nightscout.androidaps.interfaces.CommandQueueProvider; @@ -36,6 +37,7 @@ import info.nightscout.androidaps.interfaces.Constraint; import info.nightscout.androidaps.interfaces.ConstraintsInterface; import info.nightscout.androidaps.interfaces.PluginDescription; import info.nightscout.androidaps.interfaces.PluginType; +import info.nightscout.androidaps.interfaces.ProfileFunction; import info.nightscout.androidaps.interfaces.PumpDescription; import info.nightscout.androidaps.interfaces.PumpInterface; import info.nightscout.androidaps.interfaces.PumpPluginBase; @@ -43,9 +45,9 @@ import info.nightscout.androidaps.logging.AAPSLogger; import info.nightscout.androidaps.logging.LTag; import info.nightscout.androidaps.plugins.bus.RxBusWrapper; import info.nightscout.androidaps.plugins.common.ManufacturerType; -import info.nightscout.androidaps.interfaces.ProfileFunction; import info.nightscout.androidaps.plugins.general.actions.defs.CustomAction; import info.nightscout.androidaps.plugins.general.actions.defs.CustomActionType; +import info.nightscout.androidaps.queue.commands.CustomCommand; import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification; import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification; import info.nightscout.androidaps.plugins.general.overview.events.EventOverviewBolusProgress; @@ -64,7 +66,6 @@ import info.nightscout.androidaps.plugins.pump.combo.ruffyscripter.history.PumpH import info.nightscout.androidaps.plugins.pump.combo.ruffyscripter.history.PumpHistoryRequest; import info.nightscout.androidaps.plugins.pump.combo.ruffyscripter.history.Tdd; import info.nightscout.androidaps.plugins.pump.common.defs.PumpType; -import info.nightscout.androidaps.db.Treatment; import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin; import info.nightscout.androidaps.utils.DateUtil; import info.nightscout.androidaps.utils.InstanceId; @@ -1395,7 +1396,10 @@ public class ComboPlugin extends PumpPluginBase implements PumpInterface, Constr @Override public void executeCustomAction(CustomActionType customActionType) { + } + @Nullable @Override public PumpEnactResult executeCustomCommand(CustomCommand customCommand) { + return null; } @Override diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/insight/LocalInsightPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/pump/insight/LocalInsightPlugin.java index 0da2b70209..033a65e38d 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/insight/LocalInsightPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/insight/LocalInsightPlugin.java @@ -12,6 +12,7 @@ import android.os.IBinder; import android.os.Looper; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import org.json.JSONException; import org.json.JSONObject; @@ -56,6 +57,7 @@ import info.nightscout.androidaps.plugins.bus.RxBusWrapper; import info.nightscout.androidaps.plugins.common.ManufacturerType; import info.nightscout.androidaps.plugins.general.actions.defs.CustomAction; import info.nightscout.androidaps.plugins.general.actions.defs.CustomActionType; +import info.nightscout.androidaps.queue.commands.CustomCommand; import info.nightscout.androidaps.plugins.general.nsclient.NSUpload; import info.nightscout.androidaps.plugins.general.nsclient.UploadQueue; import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification; @@ -1171,7 +1173,10 @@ public class LocalInsightPlugin extends PumpPluginBase implements PumpInterface, @Override public void executeCustomAction(CustomActionType customActionType) { + } + @Nullable @Override public PumpEnactResult executeCustomCommand(CustomCommand customCommand) { + return null; } private void readHistory() { diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/mdi/MDIPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/pump/mdi/MDIPlugin.java index dbc8823395..9ce64fc431 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/mdi/MDIPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/mdi/MDIPlugin.java @@ -1,6 +1,7 @@ package info.nightscout.androidaps.plugins.pump.mdi; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import org.json.JSONException; import org.json.JSONObject; @@ -27,6 +28,7 @@ import info.nightscout.androidaps.plugins.bus.RxBusWrapper; import info.nightscout.androidaps.plugins.common.ManufacturerType; import info.nightscout.androidaps.plugins.general.actions.defs.CustomAction; import info.nightscout.androidaps.plugins.general.actions.defs.CustomActionType; +import info.nightscout.androidaps.queue.commands.CustomCommand; import info.nightscout.androidaps.plugins.pump.common.defs.PumpType; import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin; import info.nightscout.androidaps.utils.DateUtil; @@ -281,7 +283,10 @@ public class MDIPlugin extends PumpPluginBase implements PumpInterface { @Override public void executeCustomAction(CustomActionType customActionType) { + } + @Nullable @Override public PumpEnactResult executeCustomCommand(CustomCommand customCommand) { + return null; } @Override diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/virtual/VirtualPumpPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/pump/virtual/VirtualPumpPlugin.kt index 2ef49e95b5..e9ea8c8eab 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/virtual/VirtualPumpPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/virtual/VirtualPumpPlugin.kt @@ -16,9 +16,9 @@ import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.common.ManufacturerType -import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.plugins.general.actions.defs.CustomAction import info.nightscout.androidaps.plugins.general.actions.defs.CustomActionType +import info.nightscout.androidaps.queue.commands.CustomCommand import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification import info.nightscout.androidaps.plugins.general.overview.events.EventOverviewBolusProgress import info.nightscout.androidaps.plugins.general.overview.notifications.Notification @@ -133,6 +133,11 @@ class VirtualPumpPlugin @Inject constructor( } override fun executeCustomAction(customActionType: CustomActionType) {} + + override fun executeCustomCommand(customCommand: CustomCommand?): PumpEnactResult? { + return null + } + override fun isInitialized(): Boolean { return true } diff --git a/app/src/main/java/info/nightscout/androidaps/queue/CommandQueue.kt b/app/src/main/java/info/nightscout/androidaps/queue/CommandQueue.kt index bbc541c7b9..b2d141b0f2 100644 --- a/app/src/main/java/info/nightscout/androidaps/queue/CommandQueue.kt +++ b/app/src/main/java/info/nightscout/androidaps/queue/CommandQueue.kt @@ -20,16 +20,16 @@ import info.nightscout.androidaps.events.EventProfileNeedsUpdate import info.nightscout.androidaps.interfaces.ActivePluginProvider import info.nightscout.androidaps.interfaces.CommandQueueProvider import info.nightscout.androidaps.interfaces.Constraint +import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker -import info.nightscout.androidaps.interfaces.ProfileFunction +import info.nightscout.androidaps.queue.commands.CustomCommand import info.nightscout.androidaps.plugins.general.overview.events.EventDismissBolusProgressIfRunning import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification import info.nightscout.androidaps.plugins.general.overview.notifications.Notification -import info.nightscout.androidaps.queue.commands.Command import info.nightscout.androidaps.queue.commands.* import info.nightscout.androidaps.queue.commands.Command.CommandType import info.nightscout.androidaps.utils.FabricPrivacy @@ -260,7 +260,7 @@ class CommandQueue @Inject constructor( } else { add(CommandBolus(injector, detailedBolusInfo, callback, type)) if (type == CommandType.BOLUS) { // Bring up bolus progress dialog (start here, so the dialog is shown when the bolus is requested, -// not when the Bolus command is starting. The command closes the dialog upon completion). + // not when the Bolus command is starting. The command closes the dialog upon completion). showBolusProgressDialog(detailedBolusInfo.insulin, detailedBolusInfo.context) // Notify Wear about upcoming bolus rxBus.send(EventBolusRequested(detailedBolusInfo.insulin)) @@ -485,6 +485,55 @@ class CommandQueue @Inject constructor( return true } + override fun customCommand(customCommand: CustomCommand, callback: Callback?): Boolean { + if (isCustomCommandInQueue(customCommand.javaClass)) { + callback?.result(executingNowError())?.run() + return false + } + // remove all unfinished + removeAllCustomCommands(customCommand.javaClass) + // add new command to queue + add(CommandCustomCommand(injector, customCommand, callback)) + notifyAboutNewCommand() + return true + } + + @Synchronized + override fun isCustomCommandInQueue(customCommandType: Class): Boolean { + if(isCustomCommandRunning(customCommandType)) { + return true + } + synchronized(queue) { + for (i in queue.indices) { + val command = queue[i] + if (command is CommandCustomCommand && customCommandType.isInstance(command.customCommand)) { + return true + } + } + } + return false + } + + override fun isCustomCommandRunning(customCommandType: Class): Boolean { + val performing = this.performing + if (performing is CommandCustomCommand && customCommandType.isInstance(performing.customCommand)) { + return true + } + return false + } + + @Synchronized + private fun removeAllCustomCommands(targetType: Class) { + synchronized(queue) { + for (i in queue.indices.reversed()) { + val command = queue[i] + if (command is CustomCommand && targetType.isInstance(command.commandType)) { + queue.removeAt(i) + } + } + } + } + override fun spannedStatus(): Spanned { var s = "" var line = 0 diff --git a/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandCustomCommand.kt b/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandCustomCommand.kt new file mode 100644 index 0000000000..f0df2754d3 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandCustomCommand.kt @@ -0,0 +1,26 @@ +package info.nightscout.androidaps.queue.commands + +import dagger.android.HasAndroidInjector +import info.nightscout.androidaps.interfaces.ActivePluginProvider +import info.nightscout.androidaps.logging.LTag +import info.nightscout.androidaps.queue.Callback +import javax.inject.Inject + +class CommandCustomCommand( + injector: HasAndroidInjector, + val customCommand: CustomCommand, + callback: Callback? +) : Command(injector, CommandType.CUSTOM_COMMAND, callback) { + + @Inject lateinit var activePlugin: ActivePluginProvider + + override fun execute() { + val result = activePlugin.activePump.executeCustomCommand(customCommand) + aapsLogger.debug(LTag.PUMPQUEUE, "Result success: ${result?.success} enacted: ${result?.enacted}") + callback?.result(result)?.run() + } + + override fun status(): String { + return customCommand.statusDescription + } +} \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandStartPump.kt b/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandStartPump.kt index 57e94e8d31..da911775bf 100644 --- a/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandStartPump.kt +++ b/app/src/main/java/info/nightscout/androidaps/queue/commands/CommandStartPump.kt @@ -2,8 +2,6 @@ package info.nightscout.androidaps.queue.commands import dagger.android.HasAndroidInjector import info.nightscout.androidaps.interfaces.ActivePluginProvider -import info.nightscout.androidaps.interfaces.ProfileFunction -import info.nightscout.androidaps.plugins.pump.common.defs.PumpType import info.nightscout.androidaps.plugins.pump.insight.LocalInsightPlugin import info.nightscout.androidaps.queue.Callback import javax.inject.Inject @@ -14,17 +12,12 @@ class CommandStartPump( ) : Command(injector, CommandType.START_PUMP, callback) { @Inject lateinit var activePlugin: ActivePluginProvider - @Inject lateinit var profileFunction: ProfileFunction override fun execute() { val pump = activePlugin.activePump if (pump is LocalInsightPlugin) { val result = pump.startPump() callback?.result(result)?.run() - } else if (pump.pumpDescription.pumpType == PumpType.Insulet_Omnipod) { - // When using CommandQueue.setProfile, it refuses to set the profile is the same as the current profile - // However we need to set the current profile to resume delivery in case the Pod is suspended - pump.setNewBasalProfile(profileFunction.getProfile()) } } diff --git a/app/src/main/java/info/nightscout/androidaps/setupwizard/SWDefinition.kt b/app/src/main/java/info/nightscout/androidaps/setupwizard/SWDefinition.kt index c5d7164d5a..1d7c37929f 100644 --- a/app/src/main/java/info/nightscout/androidaps/setupwizard/SWDefinition.kt +++ b/app/src/main/java/info/nightscout/androidaps/setupwizard/SWDefinition.kt @@ -16,10 +16,10 @@ import info.nightscout.androidaps.interfaces.ActivePluginProvider import info.nightscout.androidaps.interfaces.CommandQueueProvider import info.nightscout.androidaps.interfaces.PluginBase import info.nightscout.androidaps.interfaces.PluginType +import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin -import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.plugins.constraints.objectives.ObjectivesFragment import info.nightscout.androidaps.plugins.constraints.objectives.ObjectivesPlugin import info.nightscout.androidaps.plugins.general.maintenance.ImportExportPrefs @@ -30,12 +30,13 @@ import info.nightscout.androidaps.plugins.profile.local.LocalProfileFragment import info.nightscout.androidaps.plugins.profile.local.LocalProfilePlugin import info.nightscout.androidaps.plugins.profile.ns.NSProfileFragment import info.nightscout.androidaps.plugins.profile.ns.NSProfilePlugin +import info.nightscout.androidaps.plugins.pump.omnipod.OmnipodPumpPlugin import info.nightscout.androidaps.setupwizard.elements.* import info.nightscout.androidaps.setupwizard.events.EventSWUpdate import info.nightscout.androidaps.utils.AndroidPermission import info.nightscout.androidaps.utils.CryptoUtil -import info.nightscout.androidaps.utils.locale.LocaleHelper.update import info.nightscout.androidaps.utils.extensions.isRunningTest +import info.nightscout.androidaps.utils.locale.LocaleHelper.update import info.nightscout.androidaps.utils.protection.ProtectionCheck import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.sharedPreferences.SP @@ -313,11 +314,37 @@ class SWDefinition @Inject constructor( }, null) }) .visibility(SWValidator { (activePlugin.activePump as PluginBase).preferencesId > 0 })) + .add(SWInfotext(injector) + .label(R.string.setupwizard_pump_pump_not_initialized) + .visibility(SWValidator { !isPumpInitialized() })) + .add( // Omnipod only + SWInfotext(injector) + .label(R.string.setupwizard_pump_waiting_for_riley_link_connection) + .visibility(SWValidator { + val activePump = activePlugin.activePump + activePump is OmnipodPumpPlugin && !activePump.isRileyLinkReady + })) .add(SWButton(injector) .text(R.string.readstatus) - .action(Runnable { commandQueue.readStatus("Clicked connect to pump", null) })) + .action(Runnable { commandQueue.readStatus("Clicked connect to pump", null) }) + .visibility(SWValidator { + // Hide for Omnipod, because as we don't require a Pod to be paired in the setup wizard, + // Getting the status might not be possible + activePlugin.activePump !is OmnipodPumpPlugin + })) .add(SWEventListener(injector, EventPumpStatusChanged::class.java)) - .validator(SWValidator { activePlugin.activePump.isInitialized }) + .validator(SWValidator { + isPumpInitialized() + }) + + private fun isPumpInitialized(): Boolean { + val activePump = activePlugin.activePump + + // For Omnipod, consider the pump initialized when a RL has been configured successfully + // Users will be prompted to activate a Pod after completing the setup wizard. + return activePump.isInitialized || (activePump is OmnipodPumpPlugin && activePump.isRileyLinkReady) + } + private val screenAps = SWScreen(injector, R.string.configbuilder_aps) .skippable(false) .add(SWInfotext(injector) diff --git a/app/src/main/java/info/nightscout/androidaps/setupwizard/SetupWizardActivity.kt b/app/src/main/java/info/nightscout/androidaps/setupwizard/SetupWizardActivity.kt index 44af0e1312..782e07f069 100644 --- a/app/src/main/java/info/nightscout/androidaps/setupwizard/SetupWizardActivity.kt +++ b/app/src/main/java/info/nightscout/androidaps/setupwizard/SetupWizardActivity.kt @@ -16,13 +16,14 @@ import info.nightscout.androidaps.events.EventPumpStatusChanged import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientStatus import info.nightscout.androidaps.plugins.profile.local.LocalProfilePlugin +import info.nightscout.androidaps.plugins.pump.common.events.EventRileyLinkDeviceStatusChange import info.nightscout.androidaps.setupwizard.elements.SWItem import info.nightscout.androidaps.setupwizard.events.EventSWUpdate import info.nightscout.androidaps.utils.AndroidPermission import info.nightscout.androidaps.utils.FabricPrivacy -import info.nightscout.androidaps.utils.locale.LocaleHelper.update import info.nightscout.androidaps.utils.alertDialogs.OKDialog.show import info.nightscout.androidaps.utils.alertDialogs.OKDialog.showConfirmation +import info.nightscout.androidaps.utils.locale.LocaleHelper.update import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.sharedPreferences.SP import io.reactivex.android.schedulers.AndroidSchedulers @@ -81,6 +82,11 @@ class SetupWizardActivity : NoSplashAppCompatActivity() { .observeOn(AndroidSchedulers.mainThread()) .subscribe({ updateButtons() }) { fabricPrivacy.logException(it) } ) + disposable.add(rxBus + .toObservable(EventRileyLinkDeviceStatusChange::class.java) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe({ updateButtons() }) { fabricPrivacy.logException(it) } + ) disposable.add(rxBus .toObservable(EventNSClientStatus::class.java) .observeOn(AndroidSchedulers.mainThread()) @@ -104,6 +110,7 @@ class SetupWizardActivity : NoSplashAppCompatActivity() { updateButtons() }) { fabricPrivacy.logException(it) } ) + updateButtons() } private fun generateLayout() { @@ -172,7 +179,7 @@ class SetupWizardActivity : NoSplashAppCompatActivity() { finish() } - @Suppress("UNUSED_PARAMETER","SameParameterValue") + @Suppress("UNUSED_PARAMETER", "SameParameterValue") private fun nextPage(view: View?): Int { var page = currentWizardPage + 1 while (page < screens.size) { @@ -182,7 +189,7 @@ class SetupWizardActivity : NoSplashAppCompatActivity() { return min(currentWizardPage, screens.size - 1) } - @Suppress("UNUSED_PARAMETER","SameParameterValue") + @Suppress("UNUSED_PARAMETER", "SameParameterValue") private fun previousPage(view: View?): Int { var page = currentWizardPage - 1 while (page >= 0) { diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 69d711c5bc..7ce5ed2790 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -951,6 +951,8 @@ Configure BG source Please select source of profile. If patient is a child you should use NS profile. If there is nobody following you on Nightscout you will probably prefer Local profile. Please remember that you are only selecting the profile source. To use it you must activate it by executing \"Profile switch\" Select one from availables algorithms. They are sorted from oldest to newest. Newer algorithm is usually more powerful and more aggressive. Thus if you are new looper you may probably start with AMA and not with latest one. Do not forget to read the OpenAPS documentation and configure it before use. + Waiting for RileyLink connection…\n + Note: You can continue setup once the pump has been initialized.\n Start your first objective Permission Ask for permission diff --git a/app/src/test/java/info/nightscout/androidaps/queue/CommandQueueTest.kt b/app/src/test/java/info/nightscout/androidaps/queue/CommandQueueTest.kt index b375602bfb..505a823937 100644 --- a/app/src/test/java/info/nightscout/androidaps/queue/CommandQueueTest.kt +++ b/app/src/test/java/info/nightscout/androidaps/queue/CommandQueueTest.kt @@ -11,6 +11,7 @@ import info.nightscout.androidaps.interfaces.ActivePluginProvider import info.nightscout.androidaps.interfaces.Constraint import info.nightscout.androidaps.interfaces.PumpDescription import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker +import info.nightscout.androidaps.queue.commands.CustomCommand import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin import info.nightscout.androidaps.queue.commands.Command @@ -192,4 +193,92 @@ class CommandQueueTest : TestBaseWithProfile() { Assert.assertFalse(queued) Assert.assertEquals(commandQueue.size(), 0) } + + @Test + fun isCustomCommandRunning() { + // given + Assert.assertEquals(0, commandQueue.size()) + + // when + val queued1 = commandQueue.customCommand(CustomCommand1(), null) + val queued2 = commandQueue.customCommand(CustomCommand2(), null) + commandQueue.pickup() + + // then + Assert.assertTrue(queued1) + Assert.assertTrue(queued2) + Assert.assertTrue(commandQueue.isCustomCommandInQueue(CustomCommand1::class.java)) + Assert.assertTrue(commandQueue.isCustomCommandInQueue(CustomCommand2::class.java)) + Assert.assertFalse(commandQueue.isCustomCommandInQueue(CustomCommand3::class.java)) + + Assert.assertTrue(commandQueue.isCustomCommandRunning(CustomCommand1::class.java)) + Assert.assertFalse(commandQueue.isCustomCommandRunning(CustomCommand2::class.java)) + Assert.assertFalse(commandQueue.isCustomCommandRunning(CustomCommand3::class.java)) + + + Assert.assertEquals(1, commandQueue.size()) + } + + @Test + fun isCustomCommandInQueue() { + // given + Assert.assertEquals(0, commandQueue.size()) + + // when + val queued1 = commandQueue.customCommand(CustomCommand1(), null) + val queued2 = commandQueue.customCommand(CustomCommand2(), null) + + // then + Assert.assertTrue(queued1) + Assert.assertTrue(queued2) + Assert.assertTrue(commandQueue.isCustomCommandInQueue(CustomCommand1::class.java)) + Assert.assertTrue(commandQueue.isCustomCommandInQueue(CustomCommand2::class.java)) + Assert.assertFalse(commandQueue.isCustomCommandInQueue(CustomCommand3::class.java)) + Assert.assertEquals(2, commandQueue.size()) + } + + @Test + fun differentCustomCommandsAllowed() { + // given + Assert.assertEquals(0, commandQueue.size()) + + // when + val queued1 = commandQueue.customCommand(CustomCommand1(), null) + val queued2 = commandQueue.customCommand(CustomCommand2(), null) + + // then + Assert.assertTrue(queued1) + Assert.assertTrue(queued2) + Assert.assertEquals(2, commandQueue.size()) + } + + @Test + fun sameCustomCommandNotAllowed() { + // given + Assert.assertEquals(0, commandQueue.size()) + + // when + val queued1 = commandQueue.customCommand(CustomCommand1(), null) + val queued2 = commandQueue.customCommand(CustomCommand1(), null) + + // then + Assert.assertTrue(queued1) + Assert.assertFalse(queued2) + Assert.assertEquals(1, commandQueue.size()) + } + + private class CustomCommand1 : CustomCommand { + override val statusDescription: String + get() = "CUSTOM COMMAND 1" + } + + private class CustomCommand2 : CustomCommand { + override val statusDescription: String + get() = "CUSTOM COMMAND 2" + } + + private class CustomCommand3 : CustomCommand { + override val statusDescription: String + get() = "CUSTOM COMMAND 3" + } } \ No newline at end of file diff --git a/build.gradle b/build.gradle index aeeb75768d..185f3010ee 100644 --- a/build.gradle +++ b/build.gradle @@ -13,7 +13,8 @@ buildscript { coroutinesVersion = '1.3.7' activityVersion = '1.2.0-alpha06' fragmentVersion = '1.3.0-alpha07' - ormLiteVersion = "4.46" + ormLiteVersion = '4.46' + nav_version = '2.3.0' } repositories { google() diff --git a/core/src/main/java/info/nightscout/androidaps/interfaces/CommandQueueProvider.kt b/core/src/main/java/info/nightscout/androidaps/interfaces/CommandQueueProvider.kt index a5f9bf21df..877dac9809 100644 --- a/core/src/main/java/info/nightscout/androidaps/interfaces/CommandQueueProvider.kt +++ b/core/src/main/java/info/nightscout/androidaps/interfaces/CommandQueueProvider.kt @@ -3,6 +3,7 @@ package info.nightscout.androidaps.interfaces import android.text.Spanned import info.nightscout.androidaps.data.DetailedBolusInfo import info.nightscout.androidaps.data.Profile +import info.nightscout.androidaps.queue.commands.CustomCommand import info.nightscout.androidaps.queue.Callback import info.nightscout.androidaps.queue.commands.Command @@ -33,6 +34,9 @@ interface CommandQueueProvider { fun setUserOptions(callback: Callback?): Boolean fun loadTDDs(callback: Callback?): Boolean fun loadEvents(callback: Callback?): Boolean + fun customCommand(customCommand: CustomCommand, callback: Callback?): Boolean + fun isCustomCommandRunning(customCommandType: Class): Boolean + fun isCustomCommandInQueue(customCommandType: Class): Boolean fun spannedStatus(): Spanned fun isThisProfileSet(profile: Profile): Boolean } \ No newline at end of file diff --git a/core/src/main/java/info/nightscout/androidaps/interfaces/PumpInterface.java b/core/src/main/java/info/nightscout/androidaps/interfaces/PumpInterface.java index 8308cc34e2..6d895506f7 100644 --- a/core/src/main/java/info/nightscout/androidaps/interfaces/PumpInterface.java +++ b/core/src/main/java/info/nightscout/androidaps/interfaces/PumpInterface.java @@ -1,5 +1,7 @@ package info.nightscout.androidaps.interfaces; +import androidx.annotation.Nullable; + import org.jetbrains.annotations.NotNull; import org.json.JSONObject; @@ -11,7 +13,9 @@ import info.nightscout.androidaps.data.PumpEnactResult; import info.nightscout.androidaps.plugins.common.ManufacturerType; import info.nightscout.androidaps.plugins.general.actions.defs.CustomAction; import info.nightscout.androidaps.plugins.general.actions.defs.CustomActionType; +import info.nightscout.androidaps.queue.commands.CustomCommand; import info.nightscout.androidaps.plugins.pump.common.defs.PumpType; +import info.nightscout.androidaps.queue.Callback; import info.nightscout.androidaps.utils.TimeChangeType; /** @@ -105,10 +109,32 @@ public interface PumpInterface { boolean canHandleDST(); + /** + * Provides a list of custom actions to be displayed in the Actions tab. + * Plese note that these actions will not be queued upon execution + * + * @return list of custom actions + */ + @Nullable List getCustomActions(); + /** + * Executes a custom action. Please note that these actions will not be queued + * + * @param customActionType action to be executed + */ void executeCustomAction(CustomActionType customActionType); + /** + * Executes a custom queued command + * See {@link CommandQueueProvider#customCommand(CustomCommand, Callback)} for queuing a custom command. + * + * @param customCommand the custom command to be executed + * @return PumpEnactResult that represents the command execution result + */ + @Nullable + PumpEnactResult executeCustomCommand(CustomCommand customCommand); + /** * This method will be called when time or Timezone changes, and pump driver can then do a specific action (for * example update clock on pump). diff --git a/core/src/main/java/info/nightscout/androidaps/queue/commands/Command.kt b/core/src/main/java/info/nightscout/androidaps/queue/commands/Command.kt index ea6a8b9196..149810ea35 100644 --- a/core/src/main/java/info/nightscout/androidaps/queue/commands/Command.kt +++ b/core/src/main/java/info/nightscout/androidaps/queue/commands/Command.kt @@ -31,7 +31,8 @@ abstract class Command( SET_USER_SETTINGS, // so far only Dana specific, START_PUMP, STOP_PUMP, - INSIGHT_SET_TBR_OVER_ALARM // insight only + INSIGHT_SET_TBR_OVER_ALARM, // insight only + CUSTOM_COMMAND } init { diff --git a/core/src/main/java/info/nightscout/androidaps/queue/commands/CustomCommand.kt b/core/src/main/java/info/nightscout/androidaps/queue/commands/CustomCommand.kt new file mode 100644 index 0000000000..d0c5c26d51 --- /dev/null +++ b/core/src/main/java/info/nightscout/androidaps/queue/commands/CustomCommand.kt @@ -0,0 +1,16 @@ +package info.nightscout.androidaps.queue.commands + +import java.io.Serializable + +/** + * Implement this interface for every custom pump command that you want to be able to queue + * See [info.nightscout.androidaps.interfaces.CommandQueueProvider.customCommand] for queuing a custom command. + */ +interface CustomCommand : Serializable { + + /** + * @return short description of this command to be used in [info.nightscout.androidaps.queue.commands.Command.status] + * The description is typically all caps. + */ + val statusDescription: String +} \ No newline at end of file diff --git a/core/src/main/java/info/nightscout/androidaps/utils/HtmlHelper.kt b/core/src/main/java/info/nightscout/androidaps/utils/HtmlHelper.kt index dd0da3b72f..873c751e2e 100644 --- a/core/src/main/java/info/nightscout/androidaps/utils/HtmlHelper.kt +++ b/core/src/main/java/info/nightscout/androidaps/utils/HtmlHelper.kt @@ -1,11 +1,10 @@ package info.nightscout.androidaps.utils -import android.os.Build import android.text.Html import android.text.Spanned object HtmlHelper { fun fromHtml(source: String): Spanned { - return Html.fromHtml(source, Html.FROM_HTML_MODE_LEGACY) + return Html.fromHtml(source, Html.FROM_HTML_MODE_LEGACY) } } \ No newline at end of file diff --git a/danar/src/main/java/info/nightscout/androidaps/danar/AbstractDanaRPlugin.java b/danar/src/main/java/info/nightscout/androidaps/danar/AbstractDanaRPlugin.java index f048c101ff..6650d1c913 100644 --- a/danar/src/main/java/info/nightscout/androidaps/danar/AbstractDanaRPlugin.java +++ b/danar/src/main/java/info/nightscout/androidaps/danar/AbstractDanaRPlugin.java @@ -1,6 +1,7 @@ package info.nightscout.androidaps.danar; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import org.json.JSONException; import org.json.JSONObject; @@ -9,9 +10,9 @@ import java.util.Date; import java.util.List; import dagger.android.HasAndroidInjector; -import info.nightscout.androidaps.dana.DanaPumpInterface; import info.nightscout.androidaps.dana.DanaFragment; import info.nightscout.androidaps.dana.DanaPump; +import info.nightscout.androidaps.dana.DanaPumpInterface; import info.nightscout.androidaps.dana.comm.RecordTypes; import info.nightscout.androidaps.danar.services.AbstractDanaRExecutionService; import info.nightscout.androidaps.data.Profile; @@ -37,6 +38,7 @@ import info.nightscout.androidaps.plugins.common.ManufacturerType; import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker; import info.nightscout.androidaps.plugins.general.actions.defs.CustomAction; import info.nightscout.androidaps.plugins.general.actions.defs.CustomActionType; +import info.nightscout.androidaps.queue.commands.CustomCommand; import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification; import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification; import info.nightscout.androidaps.plugins.general.overview.notifications.Notification; @@ -511,7 +513,10 @@ public abstract class AbstractDanaRPlugin extends PumpPluginBase implements Pump @Override public void executeCustomAction(CustomActionType customActionType) { + } + @Nullable @Override public PumpEnactResult executeCustomCommand(CustomCommand customCommand) { + return null; } @Override diff --git a/danars/src/main/java/info/nightscout/androidaps/danars/DanaRSPlugin.kt b/danars/src/main/java/info/nightscout/androidaps/danars/DanaRSPlugin.kt index 291f2d3b9b..2979ab605a 100644 --- a/danars/src/main/java/info/nightscout/androidaps/danars/DanaRSPlugin.kt +++ b/danars/src/main/java/info/nightscout/androidaps/danars/DanaRSPlugin.kt @@ -26,6 +26,7 @@ import info.nightscout.androidaps.plugins.common.ManufacturerType import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker import info.nightscout.androidaps.plugins.general.actions.defs.CustomAction import info.nightscout.androidaps.plugins.general.actions.defs.CustomActionType +import info.nightscout.androidaps.queue.commands.CustomCommand import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification import info.nightscout.androidaps.plugins.general.overview.notifications.Notification @@ -658,6 +659,7 @@ class DanaRSPlugin @Inject constructor( override fun loadTDDs(): PumpEnactResult = loadHistory(info.nightscout.androidaps.dana.comm.RecordTypes.RECORD_TYPE_DAILY) override fun getCustomActions(): List? = null override fun executeCustomAction(customActionType: CustomActionType) {} + override fun executeCustomCommand(customCommand: CustomCommand?): PumpEnactResult? = null override fun canHandleDST(): Boolean = false override fun timezoneOrDSTChanged(timeChangeType: TimeChangeType?) {} override fun clearPairing() { diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/MedtronicPumpPlugin.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/MedtronicPumpPlugin.java index ee58a61b6b..2f9b88d5c9 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/MedtronicPumpPlugin.java +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/MedtronicPumpPlugin.java @@ -48,6 +48,7 @@ import info.nightscout.androidaps.plugins.bus.RxBusWrapper; import info.nightscout.androidaps.plugins.common.ManufacturerType; import info.nightscout.androidaps.plugins.general.actions.defs.CustomAction; import info.nightscout.androidaps.plugins.general.actions.defs.CustomActionType; +import info.nightscout.androidaps.queue.commands.CustomCommand; import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification; import info.nightscout.androidaps.plugins.general.overview.notifications.Notification; import info.nightscout.androidaps.plugins.pump.common.PumpPluginAbstract; @@ -1583,6 +1584,10 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter } + @Nullable @Override public PumpEnactResult executeCustomCommand(CustomCommand customCommand) { + return null; + } + @Override public void timezoneOrDSTChanged(TimeChangeType changeType) { diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/MedtronicCommunicationManager.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/MedtronicCommunicationManager.java index 3c1c4b35e1..2fc2313440 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/MedtronicCommunicationManager.java +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/MedtronicCommunicationManager.java @@ -13,13 +13,11 @@ import javax.inject.Inject; import javax.inject.Singleton; import info.nightscout.androidaps.logging.LTag; -import info.nightscout.androidaps.plugins.pump.common.data.PumpStatus; import info.nightscout.androidaps.plugins.pump.common.defs.PumpDeviceState; 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.RileyLinkCommunicationException; import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.ble.data.RFSpyResponse; -import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.ble.data.RLMessage; import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.ble.data.RadioPacket; import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.ble.data.RadioResponse; import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.ble.defs.RLMessageType; @@ -56,7 +54,7 @@ import info.nightscout.androidaps.plugins.pump.medtronic.util.MedtronicUtil; * functionality added. */ @Singleton -public class MedtronicCommunicationManager extends RileyLinkCommunicationManager { +public class MedtronicCommunicationManager extends RileyLinkCommunicationManager { @Inject MedtronicPumpStatus medtronicPumpStatus; @Inject MedtronicPumpPlugin medtronicPumpPlugin; @@ -75,7 +73,8 @@ public class MedtronicCommunicationManager extends RileyLinkCommunicationManager // This empty constructor must be kept, otherwise dagger injection might break! @Inject - public MedtronicCommunicationManager() {} + public MedtronicCommunicationManager() { + } @Inject public void onInit() { @@ -85,9 +84,8 @@ public class MedtronicCommunicationManager extends RileyLinkCommunicationManager } @Override - public RLMessage createResponseMessage(byte[] payload) { - PumpMessage pumpMessage = new PumpMessage(aapsLogger, payload); - return pumpMessage; + public PumpMessage createResponseMessage(byte[] payload) { + return new PumpMessage(aapsLogger, payload); } @Override @@ -170,7 +168,7 @@ public class MedtronicCommunicationManager extends RileyLinkCommunicationManager if (radioResponse.isValid()) { - PumpMessage pumpResponse = (PumpMessage) createResponseMessage(radioResponse.getPayload()); + PumpMessage pumpResponse = createResponseMessage(radioResponse.getPayload()); if (!pumpResponse.isValid()) { aapsLogger.warn(LTag.PUMPCOMM, "Response is invalid ! [interrupted={}, timeout={}]", rfSpyResponse.wasInterrupted(), @@ -545,14 +543,15 @@ public class MedtronicCommunicationManager extends RileyLinkCommunicationManager } - private PumpMessage sendAndListen(RLMessage msg) throws RileyLinkCommunicationException { + private PumpMessage sendAndListen(PumpMessage msg) throws RileyLinkCommunicationException { return sendAndListen(msg, 4000); // 2000 } // All pump communications go through this function. - protected PumpMessage sendAndListen(RLMessage msg, int timeout_ms) throws RileyLinkCommunicationException { - return (PumpMessage) super.sendAndListen(msg, timeout_ms); + @Override + protected PumpMessage sendAndListen(PumpMessage msg, int timeout_ms) throws RileyLinkCommunicationException { + return super.sendAndListen(msg, timeout_ms); } diff --git a/omnipod/build.gradle b/omnipod/build.gradle index c3b3a84f35..e520dc6323 100644 --- a/omnipod/build.gradle +++ b/omnipod/build.gradle @@ -75,6 +75,8 @@ dependencies { implementation 'androidx.core:core-ktx:1.2.0' implementation "androidx.preference:preference-ktx:1.1.1" implementation "androidx.activity:activity-ktx:${activityVersion}" + implementation "androidx.fragment:fragment:${fragmentVersion}" + implementation 'androidx.constraintlayout:constraintlayout:2.0.1' implementation 'com.google.android.material:material:1.1.0' implementation 'com.google.firebase:firebase-analytics-ktx:17.4.3' @@ -86,12 +88,9 @@ dependencies { implementation "com.joanzapata.iconify:android-iconify-fontawesome:2.2.2" - // Omnipod - start implementation 'org.apache.commons:commons-lang3:3.10' implementation 'net.danlew:android.joda:2.10.6' implementation "com.google.code.gson:gson:2.8.6" - implementation(name: "com.atech-software.android.library.wizardpager-1.1.4", ext: "aar") - // Omnipod - end implementation "com.google.dagger:dagger-android:$dagger_version" implementation "com.google.dagger:dagger-android-support:$dagger_version" @@ -100,6 +99,12 @@ dependencies { kapt "com.google.dagger:dagger-android-processor:$dagger_version" kapt "com.google.dagger:dagger-compiler:$dagger_version" + // Navigation + implementation "androidx.navigation:navigation-fragment-ktx:$nav_version" + implementation "androidx.navigation:navigation-ui-ktx:$nav_version" + + implementation 'com.google.android.material:material:1.1.0' + testImplementation 'junit:junit:4.13' testImplementation "org.mockito:mockito-core:2.8.47" testImplementation "org.powermock:powermock-api-mockito2:$powermockVersion" diff --git a/omnipod/libs/com.atech-software.android.library.wizardpager-1.1.4.aar b/omnipod/libs/com.atech-software.android.library.wizardpager-1.1.4.aar deleted file mode 100644 index af0c6511cf..0000000000 Binary files a/omnipod/libs/com.atech-software.android.library.wizardpager-1.1.4.aar and /dev/null differ diff --git a/omnipod/src/main/AndroidManifest.xml b/omnipod/src/main/AndroidManifest.xml index ebf23405da..4c8d3b5305 100644 --- a/omnipod/src/main/AndroidManifest.xml +++ b/omnipod/src/main/AndroidManifest.xml @@ -9,8 +9,7 @@ - + + \ No newline at end of file diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/OmnipodPumpPlugin.java b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/OmnipodPumpPlugin.java index ffdc74eb19..6e1c85314b 100644 --- a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/OmnipodPumpPlugin.java +++ b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/OmnipodPumpPlugin.java @@ -12,15 +12,13 @@ import android.os.SystemClock; import androidx.annotation.NonNull; -import org.jetbrains.annotations.NotNull; import org.joda.time.DateTime; import org.joda.time.Duration; import org.json.JSONException; import org.json.JSONObject; -import java.util.ArrayList; +import java.util.Collections; import java.util.Date; -import java.util.Iterator; import java.util.List; import java.util.Objects; import java.util.Optional; @@ -44,6 +42,7 @@ import info.nightscout.androidaps.interfaces.ActivePluginProvider; import info.nightscout.androidaps.interfaces.CommandQueueProvider; import info.nightscout.androidaps.interfaces.PluginDescription; import info.nightscout.androidaps.interfaces.PluginType; +import info.nightscout.androidaps.interfaces.ProfileFunction; import info.nightscout.androidaps.interfaces.PumpDescription; import info.nightscout.androidaps.interfaces.PumpInterface; import info.nightscout.androidaps.interfaces.PumpPluginBase; @@ -53,7 +52,6 @@ import info.nightscout.androidaps.plugins.bus.RxBusWrapper; import info.nightscout.androidaps.plugins.common.ManufacturerType; import info.nightscout.androidaps.plugins.general.actions.defs.CustomAction; import info.nightscout.androidaps.plugins.general.actions.defs.CustomActionType; -import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification; import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification; import info.nightscout.androidaps.plugins.general.overview.notifications.Notification; import info.nightscout.androidaps.plugins.pump.common.data.TempBasalPair; @@ -71,7 +69,6 @@ import info.nightscout.androidaps.plugins.pump.omnipod.data.ActiveBolus; import info.nightscout.androidaps.plugins.pump.omnipod.data.RLHistoryItemOmnipod; import info.nightscout.androidaps.plugins.pump.omnipod.definition.OmnipodCommandType; import info.nightscout.androidaps.plugins.pump.omnipod.definition.OmnipodCustomActionType; -import info.nightscout.androidaps.plugins.pump.omnipod.definition.OmnipodStatusRequestType; import info.nightscout.androidaps.plugins.pump.omnipod.definition.OmnipodStorageKeys; import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.action.service.ExpirationReminderBuilder; import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.response.podinfo.PodInfoRecentPulseLog; @@ -81,10 +78,15 @@ import info.nightscout.androidaps.plugins.pump.omnipod.driver.manager.PodStateMa import info.nightscout.androidaps.plugins.pump.omnipod.event.EventOmnipodPumpValuesChanged; import info.nightscout.androidaps.plugins.pump.omnipod.event.EventOmnipodTbrChanged; import info.nightscout.androidaps.plugins.pump.omnipod.manager.AapsOmnipodManager; +import info.nightscout.androidaps.plugins.pump.omnipod.queue.command.CommandHandleTimeChange; +import info.nightscout.androidaps.plugins.pump.omnipod.queue.command.CommandUpdateAlertConfiguration; +import info.nightscout.androidaps.plugins.pump.omnipod.queue.command.OmnipodCustomCommand; +import info.nightscout.androidaps.plugins.pump.omnipod.queue.command.OmnipodCustomCommandType; import info.nightscout.androidaps.plugins.pump.omnipod.rileylink.service.RileyLinkOmnipodService; -import info.nightscout.androidaps.plugins.pump.omnipod.ui.OmnipodFragment; +import info.nightscout.androidaps.plugins.pump.omnipod.ui.OmnipodOverviewFragment; import info.nightscout.androidaps.plugins.pump.omnipod.util.AapsOmnipodUtil; import info.nightscout.androidaps.plugins.pump.omnipod.util.OmnipodAlertUtil; +import info.nightscout.androidaps.queue.commands.CustomCommand; import info.nightscout.androidaps.utils.DateUtil; import info.nightscout.androidaps.utils.DecimalFormatter; import info.nightscout.androidaps.utils.FabricPrivacy; @@ -104,6 +106,7 @@ import io.reactivex.schedulers.Schedulers; public class OmnipodPumpPlugin extends PumpPluginBase implements PumpInterface, RileyLinkPumpDevice { private static final long RILEY_LINK_CONNECT_TIMEOUT_MILLIS = 3 * 60 * 1000L; // 3 minutes private static final long STATUS_CHECK_INTERVAL_MILLIS = 60 * 1000L; // 1 minute + public static final int STARTUP_STATUS_REQUEST_TRIES = 2; private final PodStateManager podStateManager; private final RileyLinkServiceData rileyLinkServiceData; @@ -112,6 +115,7 @@ public class OmnipodPumpPlugin extends PumpPluginBase implements PumpInterface, private final AapsOmnipodUtil aapsOmnipodUtil; private final RileyLinkUtil rileyLinkUtil; private final OmnipodAlertUtil omnipodAlertUtil; + private final ProfileFunction profileFunction; private final AAPSLogger aapsLogger; private final RxBusWrapper rxBus; private final ActivePluginProvider activePlugin; @@ -124,8 +128,8 @@ public class OmnipodPumpPlugin extends PumpPluginBase implements PumpInterface, private final ServiceConnection serviceConnection; private final PumpType pumpType = PumpType.Insulet_Omnipod; - private final List customActions = new ArrayList<>(); - private final List statusRequestList = new ArrayList<>(); + private final List customActions = Collections.singletonList(new CustomAction( + R.string.omnipod_custom_action_reset_rileylink, OmnipodCustomActionType.RESET_RILEY_LINK_CONFIGURATION, true)); private final CompositeDisposable disposables = new CompositeDisposable(); // variables for handling statuses and history @@ -136,12 +140,11 @@ public class OmnipodPumpPlugin extends PumpPluginBase implements PumpInterface, private boolean busy = false; private int timeChangeRetries; private long nextPodCheck; - private boolean sentIdToFirebase; private long lastConnectionTimeMillis; private final Handler loopHandler = new Handler(Looper.getMainLooper()); private final Runnable statusChecker; - private OmnipodCommandType currentCommand; + private boolean isCancelTempBasalRunning; @Inject public OmnipodPumpPlugin( @@ -161,15 +164,16 @@ public class OmnipodPumpPlugin extends PumpPluginBase implements PumpInterface, DateUtil dateUtil, AapsOmnipodUtil aapsOmnipodUtil, RileyLinkUtil rileyLinkUtil, - OmnipodAlertUtil omnipodAlertUtil + OmnipodAlertUtil omnipodAlertUtil, + ProfileFunction profileFunction ) { super(new PluginDescription() // .mainType(PluginType.PUMP) // - .fragmentClass(OmnipodFragment.class.getName()) // + .fragmentClass(OmnipodOverviewFragment.class.getName()) // .pluginName(R.string.omnipod_name) // .shortName(R.string.omnipod_name_short) // .preferencesId(R.xml.pref_omnipod) // - .description(R.string.description_pump_omnipod), // + .description(R.string.omnipod_pump_description), // injector, aapsLogger, resourceHelper, commandQueue); this.aapsLogger = aapsLogger; this.rxBus = rxBus; @@ -186,12 +190,10 @@ public class OmnipodPumpPlugin extends PumpPluginBase implements PumpInterface, this.aapsOmnipodUtil = aapsOmnipodUtil; this.rileyLinkUtil = rileyLinkUtil; this.omnipodAlertUtil = omnipodAlertUtil; + this.profileFunction = profileFunction; pumpDescription = new PumpDescription(pumpType); - customActions.add(new CustomAction( - R.string.omnipod_custom_action_reset_rileylink, OmnipodCustomActionType.RESET_RILEY_LINK_CONFIGURATION, true)); - this.serviceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { @@ -228,14 +230,11 @@ public class OmnipodPumpPlugin extends PumpPluginBase implements PumpInterface, aapsOmnipodManager.createSuspendedFakeTbrIfNotExists(); } - if (!getCommandQueue().statusInQueue()) { - if (!OmnipodPumpPlugin.this.statusRequestList.isEmpty()) { - getCommandQueue().readStatus("Status Refresh Requested", null); - } else if (OmnipodPumpPlugin.this.hasTimeDateOrTimeZoneChanged) { - getCommandQueue().readStatus("Date or Time Zone Changed", null); - } else if (!OmnipodPumpPlugin.this.verifyPodAlertConfiguration()) { - getCommandQueue().readStatus("Expiration Alerts Changed", null); - } + if (OmnipodPumpPlugin.this.hasTimeDateOrTimeZoneChanged) { + getCommandQueue().customCommand(new CommandHandleTimeChange(false), null); + } + if (!OmnipodPumpPlugin.this.verifyPodAlertConfiguration()) { + getCommandQueue().customCommand(new CommandUpdateAlertConfiguration(), null); } doPodCheck(); @@ -288,7 +287,7 @@ public class OmnipodPumpPlugin extends PumpPluginBase implements PumpInterface, event.isChanged(getResourceHelper(), R.string.key_omnipod_low_reservoir_alert_enabled) || event.isChanged(getResourceHelper(), R.string.key_omnipod_low_reservoir_alert_units)) { if (!verifyPodAlertConfiguration() && !getCommandQueue().statusInQueue()) { - getCommandQueue().readStatus("Expiration Alerts Changed", null); + getCommandQueue().customCommand(new CommandUpdateAlertConfiguration(), null); } } }, fabricPrivacy::logException) @@ -316,13 +315,17 @@ public class OmnipodPumpPlugin extends PumpPluginBase implements PumpInterface, ); } + public boolean isRileyLinkReady() { + return rileyLinkServiceData.rileyLinkServiceState.isReady(); + } + private void updateAapsTbr() { // As per the characteristics of the Omnipod, we only know whether or not a TBR is currently active // But it doesn't tell us the duration or amount, so we can only update TBR status in AAPS if // The pod is not running a TBR, while AAPS thinks it is if (!podStateManager.isTempBasalRunning()) { // Only report TBR cancellations if they haven't been explicitly requested - if (currentCommand != OmnipodCommandType.CANCEL_TEMPORARY_BASAL) { + if (!isCancelTempBasalRunning) { if (activePlugin.getActiveTreatments().isTempBasalInProgress() && !aapsOmnipodManager.hasSuspendedFakeTbr()) { aapsOmnipodManager.reportCancelledTbr(); } @@ -348,13 +351,9 @@ public class OmnipodPumpPlugin extends PumpPluginBase implements PumpInterface, Notification notification = new Notification(Notification.OMNIPOD_POD_NOT_ATTACHED, resourceHelper.gs(R.string.omnipod_error_pod_not_attached), Notification.NORMAL); rxBus.send(new EventNewNotification(notification)); } else { - rxBus.send(new EventDismissNotification(Notification.OMNIPOD_POD_NOT_ATTACHED)); - if (podStateManager.isSuspended()) { - Notification notification = new Notification(Notification.OMNIPOD_POD_SUSPENDED, resourceHelper.gs(R.string.omnipod_error_pod_suspended), Notification.NORMAL); + Notification notification = new Notification(Notification.OMNIPOD_POD_SUSPENDED, resourceHelper.gs(R.string.omnipod_confirmation_pod_suspended), Notification.NORMAL); rxBus.send(new EventNewNotification(notification)); - } else { - rxBus.send(new EventDismissNotification(Notification.OMNIPOD_POD_SUSPENDED)); } } @@ -362,7 +361,6 @@ public class OmnipodPumpPlugin extends PumpPluginBase implements PumpInterface, } } - // TODO is this correct? @Override public boolean isInitialized() { return isConnected() && podStateManager.isPodActivationCompleted(); @@ -442,109 +440,23 @@ public class OmnipodPumpPlugin extends PumpPluginBase implements PumpInterface, lastConnectionTimeMillis = System.currentTimeMillis(); } - // We abuse getPumpStatus to squeeze commands in the queue - // The only actual status requests we send to the Pod are on startup (in initializeAfterRileyLinkConnection) - // And when the user explicitly requested it by clicking the Refresh button on the Omnipod tab - // We don't do periodical status requests because that can drain the Pod's battery - // However that should be fine because we get a StatusResponse from all insulin commands sent to the Pod + /** + * The only actual status requests we send to the Pod here are on startup (in {@link #initializeAfterRileyLinkConnection() initializeAfterRileyLinkConnection()}) + * And when the user explicitly requested it by clicking the Refresh button on the Omnipod tab (which is executed through {@link #executeCustomCommand(CustomCommand)}) + * We don't do periodical status requests because that could drain the Pod's battery + */ @Override public void getPumpStatus() { if (firstRun) { initializeAfterRileyLinkConnection(); - } else if (!statusRequestList.isEmpty()) { - Iterator iterator = statusRequestList.iterator(); - - while (iterator.hasNext()) { - OmnipodStatusRequestType statusRequest = iterator.next(); - switch (statusRequest) { - case GET_PULSE_LOG: - try { - PodInfoRecentPulseLog result = executeCommand(OmnipodCommandType.GET_POD_PULSE_LOG, aapsOmnipodManager::readPulseLog); - Intent i = new Intent(context, ErrorHelperActivity.class); - i.putExtra("soundid", 0); - i.putExtra("status", "Pulse Log (copied to clipboard):\n" + result.toString()); - i.putExtra("title", resourceHelper.gs(R.string.omnipod_warning)); - i.putExtra("clipboardContent", result.toString()); - i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - context.startActivity(i); - } catch (Exception ex) { - aapsLogger.warn(LTag.PUMP, "Failed to retrieve pulse log", ex); - Intent i = new Intent(context, ErrorHelperActivity.class); - i.putExtra("soundid", 0); - i.putExtra("status", "Failed to retrieve pulse log"); - i.putExtra("title", resourceHelper.gs(R.string.omnipod_warning)); - i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - context.startActivity(i); - } - break; - case ACKNOWLEDGE_ALERTS: - executeCommand(OmnipodCommandType.ACKNOWLEDGE_ALERTS, aapsOmnipodManager::acknowledgeAlerts); - break; - case GET_POD_STATE: - executeCommand(OmnipodCommandType.GET_POD_STATUS, aapsOmnipodManager::getPodStatus); - break; - case SUSPEND_DELIVERY: - executeCommand(OmnipodCommandType.SUSPEND_DELIVERY, aapsOmnipodManager::suspendDelivery); - break; - default: - aapsLogger.error(LTag.PUMP, "Unknown status request: " + statusRequest.name()); - } - iterator.remove(); - } - } else if (this.hasTimeDateOrTimeZoneChanged) { - PumpEnactResult result = executeCommand(OmnipodCommandType.SET_TIME, aapsOmnipodManager::setTime); - - if (result.success) { - this.hasTimeDateOrTimeZoneChanged = false; - timeChangeRetries = 0; - - Notification notification = new Notification( - Notification.TIME_OR_TIMEZONE_CHANGE, - resourceHelper.gs(R.string.omnipod_time_or_timezone_change), - Notification.INFO, 60); - rxBus.send(new EventNewNotification(notification)); - - } else { - timeChangeRetries++; - - if (timeChangeRetries > 3) { - this.hasTimeDateOrTimeZoneChanged = false; - timeChangeRetries = 0; - } - } - } else if (!verifyPodAlertConfiguration()) { - Duration expirationReminderTimeBeforeShutdown = omnipodAlertUtil.getExpirationReminderTimeBeforeShutdown(); - Integer lowReservoirAlertUnits = omnipodAlertUtil.getLowReservoirAlertUnits(); - - List alertConfigurations = new ExpirationReminderBuilder(podStateManager) // - .expirationAdvisory(expirationReminderTimeBeforeShutdown != null, - Optional.ofNullable(expirationReminderTimeBeforeShutdown).orElse(Duration.ZERO)) // - .lowReservoir(lowReservoirAlertUnits != null, Optional.ofNullable(lowReservoirAlertUnits).orElse(0)) // - .build(); - - PumpEnactResult result = executeCommand(OmnipodCommandType.CONFIGURE_ALERTS, () -> aapsOmnipodManager.configureAlerts(alertConfigurations)); - - if (result.success) { - aapsLogger.info(LTag.PUMP, "Successfully configured alerts in Pod"); - - podStateManager.setExpirationAlertTimeBeforeShutdown(expirationReminderTimeBeforeShutdown); - podStateManager.setLowReservoirAlertUnits(lowReservoirAlertUnits); - - Notification notification = new Notification( - Notification.OMNIPOD_POD_ALERTS_UPDATED, - resourceHelper.gs(R.string.omnipod_expiration_alerts_updated), - Notification.INFO, 60); - rxBus.send(new EventNewNotification(notification)); - } else { - aapsLogger.warn(LTag.PUMP, "Failed to configure alerts in Pod"); - } + firstRun = false; } } - @NotNull + @NonNull @Override public PumpEnactResult setNewBasalProfile(Profile profile) { - PumpEnactResult result = executeCommand(OmnipodCommandType.SET_BASAL_PROFILE, () -> aapsOmnipodManager.setBasalProfile(profile)); + PumpEnactResult result = executeCommand(OmnipodCommandType.SET_BASAL_PROFILE, () -> aapsOmnipodManager.setBasalProfile(profile, true)); aapsLogger.info(LTag.PUMP, "Basal Profile was set: " + result.success); @@ -563,7 +475,7 @@ public class OmnipodPumpPlugin extends PumpPluginBase implements PumpInterface, @Override public long lastDataTime() { - return podStateManager.isPodActivationCompleted() ? podStateManager.getLastSuccessfulCommunication().getMillis() : 0; + return podStateManager.isPodInitialized() ? podStateManager.getLastSuccessfulCommunication().getMillis() : 0; } @Override @@ -618,7 +530,7 @@ public class OmnipodPumpPlugin extends PumpPluginBase implements PumpInterface, executeCommand(OmnipodCommandType.CANCEL_BOLUS, aapsOmnipodManager::cancelBolus); } - // if enforceNew===true current temp basal is cancelled and new TBR set (duration is prolonged), + // if enforceNew is true, current temp basal is cancelled and new TBR set (duration is prolonged), // if false and the same rate is requested enacted=false and success=true is returned and TBR is not changed @Override public PumpEnactResult setTempBasalAbsolute(Double absoluteRate, Integer @@ -660,7 +572,12 @@ public class OmnipodPumpPlugin extends PumpPluginBase implements PumpInterface, return new PumpEnactResult(getInjector()).success(true).enacted(false); } - return executeCommand(OmnipodCommandType.CANCEL_TEMPORARY_BASAL, aapsOmnipodManager::cancelTemporaryBasal); + isCancelTempBasalRunning = true; + try { + return executeCommand(OmnipodCommandType.CANCEL_TEMPORARY_BASAL, aapsOmnipodManager::cancelTemporaryBasal); + } finally { + isCancelTempBasalRunning = false; + } } // TODO improve (i8n and more) @@ -719,12 +636,12 @@ public class OmnipodPumpPlugin extends PumpPluginBase implements PumpInterface, return pumpType.getManufacturer(); } - @Override @NotNull + @Override @NonNull public PumpType model() { return pumpType; } - @NotNull + @NonNull @Override public String serialNumber() { return podStateManager.isPodInitialized() ? String.valueOf(podStateManager.getAddress()) : "-"; @@ -779,18 +696,145 @@ public class OmnipodPumpPlugin extends PumpPluginBase implements PumpInterface, break; default: - aapsLogger.warn(LTag.PUMP, "Unknown custom action: {}" + mcat); + aapsLogger.warn(LTag.PUMP, "Unknown custom action: " + mcat); break; } } + @Override + public PumpEnactResult executeCustomCommand(CustomCommand command) { + if (!(command instanceof OmnipodCustomCommand)) { + aapsLogger.warn(LTag.PUMP, "Unknown custom command: " + command.getClass().getName()); + return new PumpEnactResult(getInjector()).success(false).enacted(false).comment(resourceHelper.gs(R.string.omnipod_error_unknown_custom_command, command.getClass().getName())); + } + + OmnipodCustomCommandType commandType = ((OmnipodCustomCommand) command).getType(); + + aapsLogger.debug(LTag.PUMP, "Executing custom command: " + commandType); + + switch (commandType) { + case ACKNOWLEDGE_ALERTS: + return executeCommand(OmnipodCommandType.ACKNOWLEDGE_ALERTS, aapsOmnipodManager::acknowledgeAlerts); + case GET_POD_STATUS: + return executeCommand(OmnipodCommandType.GET_POD_STATUS, aapsOmnipodManager::getPodStatus); + case READ_PULSE_LOG: + return retrievePulseLog(); + case SUSPEND_DELIVERY: + return executeCommand(OmnipodCommandType.SUSPEND_DELIVERY, aapsOmnipodManager::suspendDelivery); + case RESUME_DELIVERY: + return executeCommand(OmnipodCommandType.RESUME_DELIVERY, () -> aapsOmnipodManager.setBasalProfile(profileFunction.getProfile(), false)); + case DEACTIVATE_POD: + return executeCommand(OmnipodCommandType.DEACTIVATE_POD, aapsOmnipodManager::deactivatePod); + case HANDLE_TIME_CHANGE: + return handleTimeChange(((CommandHandleTimeChange) command).isRequestedByUser()); + case UPDATE_ALERT_CONFIGURATION: + return updateAlertConfiguration(); + default: + aapsLogger.warn(LTag.PUMP, "Unknown custom command: " + commandType); + return new PumpEnactResult(getInjector()).success(false).enacted(false).comment(resourceHelper.gs(R.string.omnipod_error_unknown_custom_command, commandType)); + } + } + + private PumpEnactResult retrievePulseLog() { + PodInfoRecentPulseLog result; + try { + result = executeCommand(OmnipodCommandType.READ_POD_PULSE_LOG, aapsOmnipodManager::readPulseLog); + } catch (Exception ex) { + return new PumpEnactResult(getInjector()).success(false).enacted(false).comment(aapsOmnipodManager.translateException(ex)); + } + + Intent i = new Intent(context, ErrorHelperActivity.class); + i.putExtra("soundid", 0); + i.putExtra("status", resourceHelper.gs(R.string.omnipod_pulse_log_value) + ":\n" + result.toString()); + i.putExtra("title", resourceHelper.gs(R.string.omnipod_pulse_log)); + i.putExtra("clipboardContent", result.toString()); + i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + context.startActivity(i); + return new PumpEnactResult(getInjector()).success(true).enacted(false); + } + + @NonNull private PumpEnactResult updateAlertConfiguration() { + Duration expirationReminderTimeBeforeShutdown = omnipodAlertUtil.getExpirationReminderTimeBeforeShutdown(); + Integer lowReservoirAlertUnits = omnipodAlertUtil.getLowReservoirAlertUnits(); + + List alertConfigurations = new ExpirationReminderBuilder(podStateManager) // + .expirationAdvisory(expirationReminderTimeBeforeShutdown != null, + Optional.ofNullable(expirationReminderTimeBeforeShutdown).orElse(Duration.ZERO)) // + .lowReservoir(lowReservoirAlertUnits != null, Optional.ofNullable(lowReservoirAlertUnits).orElse(0)) // + .build(); + + PumpEnactResult result = executeCommand(OmnipodCommandType.CONFIGURE_ALERTS, () -> aapsOmnipodManager.configureAlerts(alertConfigurations)); + + if (result.success) { + aapsLogger.info(LTag.PUMP, "Successfully configured alerts in Pod"); + + podStateManager.setExpirationAlertTimeBeforeShutdown(expirationReminderTimeBeforeShutdown); + podStateManager.setLowReservoirAlertUnits(lowReservoirAlertUnits); + + Notification notification = new Notification( + Notification.OMNIPOD_POD_ALERTS_UPDATED, + resourceHelper.gs(R.string.omnipod_confirmation_expiration_alerts_updated), + Notification.INFO, 60); + rxBus.send(new EventNewNotification(notification)); + } else { + aapsLogger.warn(LTag.PUMP, "Failed to configure alerts in Pod"); + } + + return result; + } + + @NonNull private PumpEnactResult handleTimeChange(boolean requestedByUser) { + aapsLogger.debug(LTag.PUMP, "Setting time, requestedByUser={}", requestedByUser); + + PumpEnactResult result; + if (requestedByUser || aapsOmnipodManager.isTimeChangeEventEnabled()) { + result = executeCommand(OmnipodCommandType.SET_TIME, () -> aapsOmnipodManager.setTime(!requestedByUser)); + } else { + // Even if automatically changing the time is disabled, we still want to at least do a GetStatus request, + // in order to update the Pod's activation time, which we need for calculating the time on the Pod + result = executeCommand(OmnipodCommandType.GET_POD_STATUS, aapsOmnipodManager::getPodStatus); + } + + if (result.success) { + this.hasTimeDateOrTimeZoneChanged = false; + timeChangeRetries = 0; + + if (!requestedByUser && aapsOmnipodManager.isTimeChangeEventEnabled()) { + Notification notification = new Notification( + Notification.TIME_OR_TIMEZONE_CHANGE, + resourceHelper.gs(R.string.omnipod_confirmation_time_on_pod_updated), + Notification.INFO, 60); + rxBus.send(new EventNewNotification(notification)); + } + + } else { + if (!requestedByUser) { + timeChangeRetries++; + + if (timeChangeRetries > 3) { + if (aapsOmnipodManager.isTimeChangeEventEnabled()) { + Notification notification = new Notification( + Notification.TIME_OR_TIMEZONE_CHANGE, + resourceHelper.gs(R.string.omnipod_error_automatic_time_or_timezone_change_failed), + Notification.INFO, 60); + rxBus.send(new EventNewNotification(notification)); + } + this.hasTimeDateOrTimeZoneChanged = false; + timeChangeRetries = 0; + } + } + } + + return result; + } + @Override public void timezoneOrDSTChanged(TimeChangeType timeChangeType) { aapsLogger.warn(LTag.PUMP, "Time, Date and/or TimeZone changed. [changeType=" + timeChangeType.name() + ", eventHandlingEnabled=" + aapsOmnipodManager.isTimeChangeEventEnabled() + "]"); - if (aapsOmnipodManager.isTimeChangeEventEnabled() && podStateManager.isPodRunning()) { + if (podStateManager.isPodRunning()) { aapsLogger.info(LTag.PUMP, "Time, Date and/or TimeZone changed event received and will be consumed by driver."); - this.hasTimeDateOrTimeZoneChanged = true; + hasTimeDateOrTimeZoneChanged = true; } } @@ -819,10 +863,6 @@ public class OmnipodPumpPlugin extends PumpPluginBase implements PumpInterface, return false; } - public void addPodStatusRequest(OmnipodStatusRequestType pumpStatusRequest) { - statusRequestList.add(pumpStatusRequest); - } - @Override public boolean isFakingTempsByExtendedBoluses() { return false; @@ -853,50 +893,47 @@ public class OmnipodPumpPlugin extends PumpPluginBase implements PumpInterface, aapsLogger.debug(LTag.PUMP, "stopConnecting [PumpPluginAbstract] - default (empty) implementation."); } - @NotNull @Override public PumpEnactResult setTempBasalPercent(Integer percent, Integer + @NonNull @Override public PumpEnactResult setTempBasalPercent(Integer percent, Integer durationInMinutes, Profile profile, boolean enforceNew) { aapsLogger.debug(LTag.PUMP, "setTempBasalPercent [OmnipodPumpPlugin] - Not implemented."); return getOperationNotSupportedWithCustomText(info.nightscout.androidaps.core.R.string.pump_operation_not_supported_by_pump_driver); } - @NotNull @Override public PumpEnactResult setExtendedBolus(Double insulin, Integer + @NonNull @Override public PumpEnactResult setExtendedBolus(Double insulin, Integer durationInMinutes) { aapsLogger.debug(LTag.PUMP, "setExtendedBolus [OmnipodPumpPlugin] - Not implemented."); return getOperationNotSupportedWithCustomText(info.nightscout.androidaps.core.R.string.pump_operation_not_supported_by_pump_driver); } - @NotNull @Override public PumpEnactResult cancelExtendedBolus() { + @NonNull @Override public PumpEnactResult cancelExtendedBolus() { aapsLogger.debug(LTag.PUMP, "cancelExtendedBolus [OmnipodPumpPlugin] - Not implemented."); return getOperationNotSupportedWithCustomText(info.nightscout.androidaps.core.R.string.pump_operation_not_supported_by_pump_driver); } - @NotNull @Override public PumpEnactResult loadTDDs() { + @NonNull @Override public PumpEnactResult loadTDDs() { aapsLogger.debug(LTag.PUMP, "loadTDDs [OmnipodPumpPlugin] - Not implemented."); return getOperationNotSupportedWithCustomText(info.nightscout.androidaps.core.R.string.pump_operation_not_supported_by_pump_driver); } private void initializeAfterRileyLinkConnection() { if (podStateManager.isPodInitialized() && podStateManager.getPodProgressStatus().isAtLeast(PodProgressStatus.PAIRING_COMPLETED)) { - PumpEnactResult result = executeCommand(OmnipodCommandType.GET_POD_STATUS, aapsOmnipodManager::getPodStatus); - if (result.success) { - aapsLogger.debug(LTag.PUMP, "Successfully retrieved Pod status on startup"); - } else { - aapsLogger.warn(LTag.PUMP, "Failed to retrieve Pod status on startup"); + for (int i = 0; STARTUP_STATUS_REQUEST_TRIES > i; i++) { + PumpEnactResult result = executeCommand(OmnipodCommandType.GET_POD_STATUS, aapsOmnipodManager::getPodStatus); + if (result.success) { + aapsLogger.debug(LTag.PUMP, "Successfully retrieved Pod status on startup"); + break; + } else { + aapsLogger.warn(LTag.PUMP, "Failed to retrieve Pod status on startup"); + } } } else { aapsLogger.debug(LTag.PUMP, "Not retrieving Pod status on startup: no Pod running"); } - if (!sentIdToFirebase) { - Bundle params = new Bundle(); - params.putString("version", BuildConfig.VERSION); + Bundle params = new Bundle(); + params.putString("version", BuildConfig.VERSION); - fabricPrivacy.getFirebaseAnalytics().logEvent("OmnipodPumpInit", params); - - sentIdToFirebase = true; - } - - this.firstRun = false; + fabricPrivacy.getFirebaseAnalytics().logEvent("OmnipodPumpInit", params); } @NonNull private PumpEnactResult deliverBolus(final DetailedBolusInfo detailedBolusInfo) { @@ -914,19 +951,14 @@ public class OmnipodPumpPlugin extends PumpPluginBase implements PumpInterface, private T executeCommand(OmnipodCommandType commandType, Supplier supplier) { try { - currentCommand = commandType; aapsLogger.debug(LTag.PUMP, "Executing command: {}", commandType); rileyLinkUtil.getRileyLinkHistory().add(new RLHistoryItemOmnipod(getInjector(), commandType)); - T pumpEnactResult = supplier.get(); - + return supplier.get(); + } finally { rxBus.send(new EventRefreshOverview("Omnipod command: " + commandType.name(), false)); rxBus.send(new EventOmnipodPumpValuesChanged()); - - return pumpEnactResult; - } finally { - currentCommand = null; } } @@ -946,7 +978,7 @@ public class OmnipodPumpPlugin extends PumpPluginBase implements PumpInterface, return true; } - private void incrementStatistics(String statsKey) { + private void incrementStatistics(int statsKey) { long currentCount = sp.getLong(statsKey, 0L); currentCount++; sp.putLong(statsKey, currentCount); diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dagger/OmnipodInjectHelpers.kt b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dagger/OmnipodInjectHelpers.kt new file mode 100644 index 0000000000..cd932bad82 --- /dev/null +++ b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dagger/OmnipodInjectHelpers.kt @@ -0,0 +1,38 @@ +package info.nightscout.androidaps.plugins.pump.omnipod.dagger + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider +import dagger.MapKey +import javax.inject.Inject +import javax.inject.Provider +import javax.inject.Qualifier +import javax.inject.Scope +import kotlin.reflect.KClass + +@Qualifier +annotation class OmnipodPluginQualifier + +@Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER) +@kotlin.annotation.Retention(AnnotationRetention.RUNTIME) +@MapKey +internal annotation class ViewModelKey(val value: KClass) + +// TODO: These annotations and Factories could be used globally -> move to core or app + +@Suppress("UNCHECKED_CAST") +class ViewModelFactory @Inject constructor( + private val viewModels: MutableMap, @JvmSuppressWildcards Provider> +) : ViewModelProvider.Factory { + + override fun create(modelClass: Class): T = viewModels[modelClass]?.get() as T +} + +@MustBeDocumented +@Scope +@Retention(AnnotationRetention.RUNTIME) +annotation class ActivityScope + +@MustBeDocumented +@Scope +@Retention(AnnotationRetention.RUNTIME) +annotation class FragmentScope diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dagger/OmnipodModule.kt b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dagger/OmnipodModule.kt index 225b1bb5ca..fd2b49ae1c 100644 --- a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dagger/OmnipodModule.kt +++ b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dagger/OmnipodModule.kt @@ -9,11 +9,8 @@ import info.nightscout.androidaps.plugins.pump.omnipod.manager.AapsPodStateManag import info.nightscout.androidaps.plugins.pump.omnipod.rileylink.manager.OmnipodRileyLinkCommunicationManager import info.nightscout.androidaps.plugins.pump.omnipod.ui.PodHistoryActivity import info.nightscout.androidaps.plugins.pump.omnipod.ui.PodManagementActivity -import info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.initpod.InitActionFragment -import info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.initpod.InitPodTask -import info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.pages.InitPodRefreshAction -import info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.pages.PodInfoFragment -import info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.removepod.RemoveActionFragment +import info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.activation.PodActivationWizardActivity +import info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.deactivation.PodDeactivationWizardActivity @Module @Suppress("unused") @@ -24,21 +21,23 @@ abstract class OmnipodModule { abstract fun contributesPodManagementActivity(): PodManagementActivity @ContributesAndroidInjector abstract fun contributesPodHistoryActivity(): PodHistoryActivity - // Fragments - @ContributesAndroidInjector abstract fun initActionFragment(): InitActionFragment - @ContributesAndroidInjector abstract fun removeActionFragment(): RemoveActionFragment - @ContributesAndroidInjector abstract fun podInfoFragment(): PodInfoFragment + @ActivityScope + @ContributesAndroidInjector(modules = [OmnipodWizardModule::class]) + abstract fun contributesActivationWizardActivity(): PodActivationWizardActivity + + @ActivityScope + @ContributesAndroidInjector(modules = [OmnipodWizardModule::class]) + abstract fun contributesDeactivationWizardActivity(): PodDeactivationWizardActivity // Service @ContributesAndroidInjector abstract fun omnipodCommunicationManagerProvider(): OmnipodRileyLinkCommunicationManager // Data - @ContributesAndroidInjector abstract fun initPodRefreshAction(): InitPodRefreshAction - @ContributesAndroidInjector abstract fun initPodTask(): InitPodTask @ContributesAndroidInjector abstract fun rlHistoryItemOmnipod(): RLHistoryItemOmnipod companion object { + @Provides fun podStateManagerProvider(aapsPodStateManager: AapsPodStateManager): PodStateManager = aapsPodStateManager } diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dagger/OmnipodWizardModule.kt b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dagger/OmnipodWizardModule.kt new file mode 100644 index 0000000000..4421900b15 --- /dev/null +++ b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dagger/OmnipodWizardModule.kt @@ -0,0 +1,92 @@ +package info.nightscout.androidaps.plugins.pump.omnipod.dagger + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider +import dagger.Binds +import dagger.Module +import dagger.Provides +import dagger.android.ContributesAndroidInjector +import dagger.multibindings.IntoMap +import info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.activation.fragment.AttachPodInfoFragment +import info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.activation.fragment.FillPodInfoFragment +import info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.activation.fragment.InitializePodActionFragment +import info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.activation.fragment.InsertCannulaActionFragment +import info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.activation.fragment.PodActivatedInfoFragment +import info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.activation.viewmodel.InitializePodActionViewModel +import info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.activation.viewmodel.InsertCannulaActionViewModel +import info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.deactivation.fragment.DeactivatePodActionFragment +import info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.deactivation.fragment.DeactivatePodInfoFragment +import info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.deactivation.fragment.PodDeactivatedInfoFragment +import info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.deactivation.fragment.PodDiscardedInfoFragment +import info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.deactivation.viewmodel.DeactivatePodActionViewModel +import javax.inject.Provider + +@Module +abstract class OmnipodWizardModule { + + companion object { + @Provides + @OmnipodPluginQualifier + fun providesViewModelFactory(@OmnipodPluginQualifier viewModels: MutableMap, @JvmSuppressWildcards Provider>): ViewModelProvider.Factory { + return ViewModelFactory(viewModels) + } + } + + // #### VIEW MODELS ############################################################################ + @Binds + @IntoMap + @OmnipodPluginQualifier + @ViewModelKey(InitializePodActionViewModel::class) + internal abstract fun initializePodActionViewModel(viewModel: InitializePodActionViewModel): ViewModel + + @Binds + @IntoMap + @OmnipodPluginQualifier + @ViewModelKey(InsertCannulaActionViewModel::class) + internal abstract fun insertCannulaActionViewModel(viewModel: InsertCannulaActionViewModel): ViewModel + + @Binds + @IntoMap + @OmnipodPluginQualifier + @ViewModelKey(DeactivatePodActionViewModel::class) + internal abstract fun deactivatePodActionViewModel(viewModel: DeactivatePodActionViewModel): ViewModel + + // #### FRAGMENTS ############################################################################## + @FragmentScope + @ContributesAndroidInjector + internal abstract fun contributesDeactivatePodActionFragment(): DeactivatePodActionFragment + + @FragmentScope + @ContributesAndroidInjector + internal abstract fun contributesInsertCannulaActionFragment(): InsertCannulaActionFragment + + @FragmentScope + @ContributesAndroidInjector + internal abstract fun contributesInitializePodActionFragment(): InitializePodActionFragment + + @FragmentScope + @ContributesAndroidInjector + internal abstract fun contributesAttachPodInfoFragment(): AttachPodInfoFragment + + @FragmentScope + @ContributesAndroidInjector + internal abstract fun contributesDeactivatePodInfoFragment(): DeactivatePodInfoFragment + + @FragmentScope + @ContributesAndroidInjector + internal abstract fun contributesFillPodInfoFragment(): FillPodInfoFragment + + @FragmentScope + @ContributesAndroidInjector + internal abstract fun contributesPodDeactivatedInfoFragment(): PodDeactivatedInfoFragment + + @FragmentScope + @ContributesAndroidInjector + internal abstract fun contributesPodDiscardedInfoFragment(): PodDiscardedInfoFragment + + @FragmentScope + @ContributesAndroidInjector + internal abstract fun contributesPodActivatedInfoFragment(): PodActivatedInfoFragment +} + + diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/definition/OmnipodCommandType.java b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/definition/OmnipodCommandType.java index b7be57c864..8d9b250ac4 100644 --- a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/definition/OmnipodCommandType.java +++ b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/definition/OmnipodCommandType.java @@ -6,8 +6,8 @@ import info.nightscout.androidaps.plugins.pump.omnipod.R; * Created by andy on 4.8.2019 */ public enum OmnipodCommandType { - PAIR_AND_PRIME_POD(R.string.omnipod_cmd_pair_and_prime), // First step of Pod activation - FILL_CANNULA_AND_SET_BASAL_PROFILE(R.string.omnipod_cmd_fill_cannula_set_basal_profile), // Second step of Pod activation + INITIALIZE_POD(R.string.omnipod_cmd_initialize_pod), // First step of Pod activation + INSERT_CANNULA(R.string.omnipod_cmd_insert_cannula), // Second step of Pod activation DEACTIVATE_POD(R.string.omnipod_cmd_deactivate_pod), // SET_BASAL_PROFILE(R.string.omnipod_cmd_set_basal_schedule), // SET_BOLUS(R.string.omnipod_cmd_set_bolus), // @@ -19,8 +19,9 @@ public enum OmnipodCommandType { SET_TIME(R.string.omnipod_cmd_set_time), // CONFIGURE_ALERTS(R.string.omnipod_cmd_configure_alerts), // ACKNOWLEDGE_ALERTS(R.string.omnipod_cmd_acknowledge_alerts), // - GET_POD_PULSE_LOG(R.string.omnipod_cmd_get_pulse_log), // - SUSPEND_DELIVERY(R.string.omnipod_cmd_suspend_delivery); + READ_POD_PULSE_LOG(R.string.omnipod_cmd_read_pulse_log), // + SUSPEND_DELIVERY(R.string.omnipod_cmd_suspend_delivery), + RESUME_DELIVERY(R.string.omnipod_cmd_resume_delivery); private int resourceId; diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/definition/OmnipodStatusRequestType.java b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/definition/OmnipodStatusRequestType.java deleted file mode 100644 index c657f6fc6e..0000000000 --- a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/definition/OmnipodStatusRequestType.java +++ /dev/null @@ -1,8 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.omnipod.definition; - -public enum OmnipodStatusRequestType { - ACKNOWLEDGE_ALERTS, - GET_POD_STATE, - GET_PULSE_LOG, - SUSPEND_DELIVERY -} diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/definition/OmnipodStorageKeys.java b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/definition/OmnipodStorageKeys.java index 9dae97c900..557e8352db 100644 --- a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/definition/OmnipodStorageKeys.java +++ b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/definition/OmnipodStorageKeys.java @@ -3,11 +3,9 @@ package info.nightscout.androidaps.plugins.pump.omnipod.definition; import info.nightscout.androidaps.plugins.pump.omnipod.R; public class OmnipodStorageKeys { - private static final String PREFIX = "AAPS.Omnipod."; - public static class Preferences { - public static final String POD_STATE = PREFIX + "pod_state"; - public static final String ACTIVE_BOLUS = PREFIX + "current_bolus"; + public static final int POD_STATE = R.string.key_omnipod_pod_state; + public static final int ACTIVE_BOLUS = R.string.key_omnipod_current_bolus; public static final int BASAL_BEEPS_ENABLED = R.string.key_omnipod_basal_beeps_enabled; public static final int BOLUS_BEEPS_ENABLED = R.string.key_omnipod_bolus_beeps_enabled; public static final int SMB_BEEPS_ENABLED = R.string.key_omnipod_smb_beeps_enabled; @@ -22,8 +20,8 @@ public class OmnipodStorageKeys { } public static class Statistics { - public static final String TBRS_SET = PREFIX + "tbrs_set"; - public static final String STANDARD_BOLUSES_DELIVERED = PREFIX + "std_boluses_delivered"; - public static final String SMB_BOLUSES_DELIVERED = PREFIX + "smb_boluses_delivered"; + public static final int TBRS_SET = R.string.key_omnipod_tbrs_set; + public static final int STANDARD_BOLUSES_DELIVERED = R.string.key_omnipod_std_boluses_delivered; + public static final int SMB_BOLUSES_DELIVERED = R.string.key_omnipod_smb_boluses_delivered; } } diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/definition/PodHistoryEntryType.java b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/definition/PodHistoryEntryType.java index cd15bac1a4..89560786e0 100644 --- a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/definition/PodHistoryEntryType.java +++ b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/definition/PodHistoryEntryType.java @@ -13,10 +13,10 @@ import info.nightscout.androidaps.plugins.pump.omnipod.R; */ public enum PodHistoryEntryType { - PAIR_AND_PRIME(1, R.string.omnipod_init_pod_wizard_step2_title, PumpHistoryEntryGroup.Prime), - FILL_CANNULA_SET_BASAL_PROFILE(2, R.string.omnipod_init_pod_wizard_step4_title, PumpHistoryEntryGroup.Prime), + INITIALIZE_POD(1, R.string.omnipod_cmd_initialize_pod, PumpHistoryEntryGroup.Prime), + INSERT_CANNULA(2, R.string.omnipod_cmd_insert_cannula, PumpHistoryEntryGroup.Prime), DEACTIVATE_POD(3, R.string.omnipod_cmd_deactivate_pod, PumpHistoryEntryGroup.Prime), - RESET_POD_STATE(4, R.string.omnipod_cmd_discard_pod, PumpHistoryEntryGroup.Prime), + DISCARD_POD(4, R.string.omnipod_cmd_discard_pod, PumpHistoryEntryGroup.Prime), SET_TEMPORARY_BASAL(10, R.string.omnipod_cmd_set_tbr, PumpHistoryEntryGroup.Basal), CANCEL_TEMPORARY_BASAL_BY_DRIVER(11, R.string.omnipod_cmd_cancel_tbr_by_driver, PumpHistoryEntryGroup.Basal), diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/definition/PodInitActionType.java b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/definition/PodInitActionType.java deleted file mode 100644 index 1424712010..0000000000 --- a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/definition/PodInitActionType.java +++ /dev/null @@ -1,54 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.omnipod.definition; - -import java.util.ArrayList; -import java.util.List; - -import info.nightscout.androidaps.plugins.pump.omnipod.R; - -public enum PodInitActionType { - - PAIR_AND_PRIME_WIZARD_STEP(), // - PAIR_POD(R.string.omnipod_init_pod_pair_pod, PAIR_AND_PRIME_WIZARD_STEP), // - PRIME_POD(R.string.omnipod_init_pod_prime_pod, PAIR_AND_PRIME_WIZARD_STEP), // - - FILL_CANNULA_SET_BASAL_PROFILE_WIZARD_STEP(), // - FILL_CANNULA(R.string.omnipod_init_pod_fill_cannula, FILL_CANNULA_SET_BASAL_PROFILE_WIZARD_STEP), // - SET_BASAL_PROFILE(R.string.omnipod_init_pod_set_basal_profile, FILL_CANNULA_SET_BASAL_PROFILE_WIZARD_STEP), // - - DEACTIVATE_POD_WIZARD_STEP(), // - CANCEL_DELIVERY(R.string.omnipod_deactivate_pod_cancel_delivery, DEACTIVATE_POD_WIZARD_STEP), // - DEACTIVATE_POD(R.string.omnipod_deactivate_pod_deactivate_pod, DEACTIVATE_POD_WIZARD_STEP); - - private int resourceId; - private PodInitActionType parent; - - PodInitActionType(int resourceId, PodInitActionType parent) { - this.resourceId = resourceId; - this.parent = parent; - } - - PodInitActionType() { - } - - public boolean isParent() { - return this.parent == null; - } - - public List getChildren() { - - List outList = new ArrayList<>(); - - for (PodInitActionType value : values()) { - if (value.parent == this) { - outList.add(value); - } - } - - return outList; - } - - public int getResourceId() { - return resourceId; - } - -} diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/definition/PodInitReceiver.java b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/definition/PodInitReceiver.java deleted file mode 100644 index 35f9f41229..0000000000 --- a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/definition/PodInitReceiver.java +++ /dev/null @@ -1,7 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.omnipod.definition; - -public interface PodInitReceiver { - - void returnInitTaskStatus(PodInitActionType podInitActionType, boolean isSuccess, String errorMessage); - -} diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/communication/action/AcknowledgeAlertsAction.java b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/communication/action/AcknowledgeAlertsAction.java index 6ae13b159c..5b6da7d781 100644 --- a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/communication/action/AcknowledgeAlertsAction.java +++ b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/communication/action/AcknowledgeAlertsAction.java @@ -6,7 +6,6 @@ import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.mess import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.response.StatusResponse; import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.AlertSet; import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.AlertSlot; -import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.ActionInitializationException; import info.nightscout.androidaps.plugins.pump.omnipod.driver.manager.PodStateManager; import info.nightscout.androidaps.plugins.pump.omnipod.rileylink.manager.OmnipodRileyLinkCommunicationManager; @@ -16,12 +15,12 @@ public class AcknowledgeAlertsAction implements OmnipodAction { public AcknowledgeAlertsAction(PodStateManager podStateManager, AlertSet alerts) { if (podStateManager == null) { - throw new ActionInitializationException("Pod state manager cannot be null"); + throw new IllegalArgumentException("Pod state manager cannot be null"); } if (alerts == null) { - throw new ActionInitializationException("Alert set can not be null"); + throw new IllegalArgumentException("Alert set can not be null"); } else if (alerts.size() == 0) { - throw new ActionInitializationException("Alert set can not be empty"); + throw new IllegalArgumentException("Alert set can not be empty"); } this.podStateManager = podStateManager; this.alerts = alerts; diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/communication/action/BolusAction.java b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/communication/action/BolusAction.java index c87ccdb497..b58935eeb5 100644 --- a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/communication/action/BolusAction.java +++ b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/communication/action/BolusAction.java @@ -9,7 +9,6 @@ import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.mess import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.command.SetInsulinScheduleCommand; import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.response.StatusResponse; import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.schedule.BolusDeliverySchedule; -import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.ActionInitializationException; import info.nightscout.androidaps.plugins.pump.omnipod.driver.manager.PodStateManager; import info.nightscout.androidaps.plugins.pump.omnipod.rileylink.manager.OmnipodRileyLinkCommunicationManager; @@ -23,10 +22,10 @@ public class BolusAction implements OmnipodAction { public BolusAction(PodStateManager podStateManager, double units, Duration timeBetweenPulses, boolean acknowledgementBeep, boolean completionBeep) { if (podStateManager == null) { - throw new ActionInitializationException("Pod state manager cannot be null"); + throw new IllegalArgumentException("Pod state manager cannot be null"); } if (timeBetweenPulses == null) { - throw new ActionInitializationException("Time between pulses cannot be null"); + throw new IllegalArgumentException("Time between pulses cannot be null"); } this.podStateManager = podStateManager; this.units = units; diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/communication/action/CancelDeliveryAction.java b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/communication/action/CancelDeliveryAction.java index 7b83b3ee96..b0b4c0ad18 100644 --- a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/communication/action/CancelDeliveryAction.java +++ b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/communication/action/CancelDeliveryAction.java @@ -10,7 +10,6 @@ import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.mess import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.response.StatusResponse; import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.BeepType; import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.DeliveryType; -import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.ActionInitializationException; import info.nightscout.androidaps.plugins.pump.omnipod.driver.manager.PodStateManager; import info.nightscout.androidaps.plugins.pump.omnipod.rileylink.manager.OmnipodRileyLinkCommunicationManager; @@ -22,10 +21,10 @@ public class CancelDeliveryAction implements OmnipodAction { public CancelDeliveryAction(PodStateManager podStateManager, EnumSet deliveryTypes, boolean acknowledgementBeep) { if (podStateManager == null) { - throw new ActionInitializationException("Pod state manager cannot be null"); + throw new IllegalArgumentException("Pod state manager cannot be null"); } if (deliveryTypes == null) { - throw new ActionInitializationException("Delivery types cannot be null"); + throw new IllegalArgumentException("Delivery types cannot be null"); } this.podStateManager = podStateManager; this.deliveryTypes = deliveryTypes; diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/communication/action/ConfigureAlertsAction.java b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/communication/action/ConfigureAlertsAction.java index bc4235c2e0..345127e91e 100644 --- a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/communication/action/ConfigureAlertsAction.java +++ b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/communication/action/ConfigureAlertsAction.java @@ -5,7 +5,6 @@ import java.util.List; import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.command.ConfigureAlertsCommand; import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.response.StatusResponse; import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.AlertConfiguration; -import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.ActionInitializationException; import info.nightscout.androidaps.plugins.pump.omnipod.driver.manager.PodStateManager; import info.nightscout.androidaps.plugins.pump.omnipod.rileylink.manager.OmnipodRileyLinkCommunicationManager; @@ -15,10 +14,10 @@ public class ConfigureAlertsAction implements OmnipodAction { public ConfigureAlertsAction(PodStateManager podStateManager, List alertConfigurations) { if (podStateManager == null) { - throw new ActionInitializationException("Pod state manager cannot be null"); + throw new IllegalArgumentException("Pod state manager cannot be null"); } if (alertConfigurations == null) { - throw new ActionInitializationException("Alert configurations cannot be null"); + throw new IllegalArgumentException("Alert configurations cannot be null"); } this.podStateManager = podStateManager; this.alertConfigurations = alertConfigurations; diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/communication/action/DeactivatePodAction.java b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/communication/action/DeactivatePodAction.java index efe855b82f..266396d6e4 100644 --- a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/communication/action/DeactivatePodAction.java +++ b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/communication/action/DeactivatePodAction.java @@ -5,7 +5,6 @@ import java.util.EnumSet; import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.command.DeactivatePodCommand; import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.response.StatusResponse; import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.DeliveryType; -import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.ActionInitializationException; import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.PodFaultException; import info.nightscout.androidaps.plugins.pump.omnipod.driver.manager.PodStateManager; import info.nightscout.androidaps.plugins.pump.omnipod.rileylink.manager.OmnipodRileyLinkCommunicationManager; @@ -16,7 +15,7 @@ public class DeactivatePodAction implements OmnipodAction { public DeactivatePodAction(PodStateManager podStateManager, boolean acknowledgementBeep) { if (podStateManager == null) { - throw new ActionInitializationException("Pod state manager cannot be null"); + throw new IllegalArgumentException("Pod state manager cannot be null"); } this.podStateManager = podStateManager; this.acknowledgementBeep = acknowledgementBeep; diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/communication/action/GetPodInfoAction.java b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/communication/action/GetPodInfoAction.java index cc925c6e4c..217c768a78 100644 --- a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/communication/action/GetPodInfoAction.java +++ b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/communication/action/GetPodInfoAction.java @@ -3,7 +3,6 @@ package info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.act import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.command.GetStatusCommand; import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.response.podinfo.PodInfoResponse; import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.PodInfoType; -import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.ActionInitializationException; import info.nightscout.androidaps.plugins.pump.omnipod.driver.manager.PodStateManager; import info.nightscout.androidaps.plugins.pump.omnipod.rileylink.manager.OmnipodRileyLinkCommunicationManager; @@ -13,10 +12,10 @@ public class GetPodInfoAction implements OmnipodAction { public GetPodInfoAction(PodStateManager podStateManager, PodInfoType podInfoType) { if (podStateManager == null) { - throw new ActionInitializationException("Pod state manager cannot be null"); + throw new IllegalArgumentException("Pod state manager cannot be null"); } if (podInfoType == null) { - throw new ActionInitializationException("Pod info type cannot be null"); + throw new IllegalArgumentException("Pod info type cannot be null"); } this.podStateManager = podStateManager; this.podInfoType = podInfoType; diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/communication/action/GetStatusAction.java b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/communication/action/GetStatusAction.java index aac7b55d6c..27d1f3a129 100644 --- a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/communication/action/GetStatusAction.java +++ b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/communication/action/GetStatusAction.java @@ -3,7 +3,6 @@ package info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.act import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.command.GetStatusCommand; import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.response.StatusResponse; import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.PodInfoType; -import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.ActionInitializationException; import info.nightscout.androidaps.plugins.pump.omnipod.driver.manager.PodStateManager; import info.nightscout.androidaps.plugins.pump.omnipod.rileylink.manager.OmnipodRileyLinkCommunicationManager; @@ -12,7 +11,7 @@ public class GetStatusAction implements OmnipodAction { public GetStatusAction(PodStateManager podState) { if (podState == null) { - throw new ActionInitializationException("Pod state manager cannot be null"); + throw new IllegalArgumentException("Pod state manager cannot be null"); } this.podStateManager = podState; } diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/communication/action/InsertCannulaAction.java b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/communication/action/InsertCannulaAction.java index b364aa8c81..7dae20fea9 100644 --- a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/communication/action/InsertCannulaAction.java +++ b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/communication/action/InsertCannulaAction.java @@ -11,7 +11,6 @@ import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.AlertCo import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.OmnipodConstants; import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.PodProgressStatus; import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.schedule.BasalSchedule; -import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.ActionInitializationException; import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.IllegalPodProgressException; import info.nightscout.androidaps.plugins.pump.omnipod.driver.manager.PodStateManager; import info.nightscout.androidaps.plugins.pump.omnipod.rileylink.manager.OmnipodRileyLinkCommunicationManager; @@ -26,10 +25,10 @@ public class InsertCannulaAction implements OmnipodAction { public InsertCannulaAction(PodStateManager podStateManager, BasalSchedule initialBasalSchedule, Duration expirationReminderTimeBeforeShutdown, Integer lowReservoirAlertUnits) { if (podStateManager == null) { - throw new ActionInitializationException("Pod state manager cannot be null"); + throw new IllegalArgumentException("Pod state manager cannot be null"); } if (initialBasalSchedule == null) { - throw new ActionInitializationException("Initial basal schedule cannot be null"); + throw new IllegalArgumentException("Initial basal schedule cannot be null"); } this.podStateManager = podStateManager; this.initialBasalSchedule = initialBasalSchedule; diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/communication/action/PrimeAction.java b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/communication/action/PrimeAction.java index 115ad1c6b1..44c50e1a38 100644 --- a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/communication/action/PrimeAction.java +++ b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/communication/action/PrimeAction.java @@ -3,7 +3,6 @@ package info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.act import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.action.service.PrimeService; import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.response.StatusResponse; import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.PodProgressStatus; -import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.ActionInitializationException; import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.IllegalPodProgressException; import info.nightscout.androidaps.plugins.pump.omnipod.driver.manager.PodStateManager; import info.nightscout.androidaps.plugins.pump.omnipod.rileylink.manager.OmnipodRileyLinkCommunicationManager; @@ -15,10 +14,10 @@ public class PrimeAction implements OmnipodAction { public PrimeAction(PrimeService primeService, PodStateManager podStateManager) { if (primeService == null) { - throw new ActionInitializationException("Prime service cannot be null"); + throw new IllegalArgumentException("Prime service cannot be null"); } if (podStateManager == null) { - throw new ActionInitializationException("Pod state manager cannot be null"); + throw new IllegalArgumentException("Pod state manager cannot be null"); } this.service = primeService; this.podStateManager = podStateManager; diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/communication/action/SetBasalScheduleAction.java b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/communication/action/SetBasalScheduleAction.java index a64766c5d3..4b35bb781c 100644 --- a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/communication/action/SetBasalScheduleAction.java +++ b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/communication/action/SetBasalScheduleAction.java @@ -9,7 +9,6 @@ import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.mess import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.command.SetInsulinScheduleCommand; import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.response.StatusResponse; import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.schedule.BasalSchedule; -import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.ActionInitializationException; import info.nightscout.androidaps.plugins.pump.omnipod.driver.manager.PodStateManager; import info.nightscout.androidaps.plugins.pump.omnipod.rileylink.manager.OmnipodRileyLinkCommunicationManager; @@ -23,13 +22,13 @@ public class SetBasalScheduleAction implements OmnipodAction { public SetBasalScheduleAction(PodStateManager podStateManager, BasalSchedule basalSchedule, boolean confidenceReminder, Duration scheduleOffset, boolean acknowledgementBeep) { if (podStateManager == null) { - throw new ActionInitializationException("Pod state manager cannot be null"); + throw new IllegalArgumentException("Pod state manager cannot be null"); } if (basalSchedule == null) { - throw new ActionInitializationException("Basal schedule cannot be null"); + throw new IllegalArgumentException("Basal schedule cannot be null"); } if (scheduleOffset == null) { - throw new ActionInitializationException("Schedule offset cannot be null"); + throw new IllegalArgumentException("Schedule offset cannot be null"); } this.podStateManager = podStateManager; this.basalSchedule = basalSchedule; diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/communication/action/SetTempBasalAction.java b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/communication/action/SetTempBasalAction.java index cadb602f68..e33de1f8c5 100644 --- a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/communication/action/SetTempBasalAction.java +++ b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/communication/action/SetTempBasalAction.java @@ -10,7 +10,6 @@ import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.mess import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.command.SetInsulinScheduleCommand; import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.command.TempBasalExtraCommand; import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.response.StatusResponse; -import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.ActionInitializationException; import info.nightscout.androidaps.plugins.pump.omnipod.driver.manager.PodStateManager; import info.nightscout.androidaps.plugins.pump.omnipod.rileylink.manager.OmnipodRileyLinkCommunicationManager; @@ -24,10 +23,10 @@ public class SetTempBasalAction implements OmnipodAction { public SetTempBasalAction(PodStateManager podStateManager, double rate, Duration duration, boolean acknowledgementBeep, boolean completionBeep) { if (podStateManager == null) { - throw new ActionInitializationException("Pod state manager cannot be null"); + throw new IllegalArgumentException("Pod state manager cannot be null"); } if (duration == null) { - throw new ActionInitializationException("Duration cannot be null"); + throw new IllegalArgumentException("Duration cannot be null"); } this.podStateManager = podStateManager; this.rate = rate; diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/communication/action/service/ExpirationReminderBuilder.java b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/communication/action/service/ExpirationReminderBuilder.java index 990bed5de6..0c39fefd99 100644 --- a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/communication/action/service/ExpirationReminderBuilder.java +++ b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/communication/action/service/ExpirationReminderBuilder.java @@ -17,11 +17,9 @@ import info.nightscout.androidaps.plugins.pump.omnipod.driver.util.AlertConfigur public final class ExpirationReminderBuilder { private final Map alerts = new HashMap<>(); private final DateTime endOfServiceTime; - private final PodStateManager podStateManager; public ExpirationReminderBuilder(PodStateManager podStateManager) { this.endOfServiceTime = podStateManager.getActivatedAt().plus(OmnipodConstants.SERVICE_DURATION); - this.podStateManager = podStateManager; } public ExpirationReminderBuilder defaults() { @@ -45,21 +43,17 @@ public final class ExpirationReminderBuilder { public ExpirationReminderBuilder expirationAdvisory(boolean active, Duration timeBeforeShutdown) { DateTime expirationAdvisoryAlarmTime = endOfServiceTime.minus(timeBeforeShutdown); - if (DateTime.now().isBefore(expirationAdvisoryAlarmTime)) { - Duration timeUntilExpirationAdvisoryAlarm = new Duration(DateTime.now(), - expirationAdvisoryAlarmTime); - AlertConfiguration expirationAdvisoryAlertConfiguration = AlertConfigurationUtil.createExpirationAdvisoryAlertConfiguration(active, - timeUntilExpirationAdvisoryAlarm, timeBeforeShutdown); - alerts.put(expirationAdvisoryAlertConfiguration.getAlertSlot(), expirationAdvisoryAlertConfiguration); - } + Duration timeUntilExpirationAdvisoryAlarm = DateTime.now().isBefore(expirationAdvisoryAlarmTime) ? new Duration(DateTime.now(), + expirationAdvisoryAlarmTime) : Duration.ZERO; + AlertConfiguration expirationAdvisoryAlertConfiguration = AlertConfigurationUtil.createExpirationAdvisoryAlertConfiguration(active, + timeUntilExpirationAdvisoryAlarm, timeBeforeShutdown); + alerts.put(expirationAdvisoryAlertConfiguration.getAlertSlot(), expirationAdvisoryAlertConfiguration); return this; } public ExpirationReminderBuilder lowReservoir(boolean active, int units) { - if (podStateManager.getReservoirLevel() == null || podStateManager.getReservoirLevel().intValue() > units) { - AlertConfiguration lowReservoirAlertConfiguration = AlertConfigurationUtil.createLowReservoirAlertConfiguration(active, (double) units); - alerts.put(lowReservoirAlertConfiguration.getAlertSlot(), lowReservoirAlertConfiguration); - } + AlertConfiguration lowReservoirAlertConfiguration = AlertConfigurationUtil.createLowReservoirAlertConfiguration(active, (double) units); + alerts.put(lowReservoirAlertConfiguration.getAlertSlot(), lowReservoirAlertConfiguration); return this; } diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/communication/message/OmnipodMessage.java b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/communication/message/OmnipodMessage.java index 995121c1c3..7531631b12 100644 --- a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/communication/message/OmnipodMessage.java +++ b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/communication/message/OmnipodMessage.java @@ -3,10 +3,13 @@ package info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.mes import java.util.ArrayList; import java.util.List; +import info.nightscout.androidaps.logging.AAPSLogger; +import info.nightscout.androidaps.logging.LTag; import info.nightscout.androidaps.plugins.pump.common.utils.ByteUtil; import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.command.GetStatusCommand; import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.MessageBlockType; import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.OmnipodCrc; +import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.PacketType; import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.PodInfoType; import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.CrcMismatchException; import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.MessageDecodingException; @@ -91,8 +94,11 @@ public class OmnipodMessage { return encodedData; } - public void padWithGetStatusCommands(int packetSize) { - while (getEncoded().length < packetSize) { + public void padWithGetStatusCommands(int packetSize, AAPSLogger aapsLogger) { + while (getEncoded().length <= packetSize) { + if (getEncoded().length == PacketType.PDM.getMaxBodyLength()) { + aapsLogger.debug(LTag.PUMPBTCOMM, "Message length equals max body length: {}", this); + } messageBlocks.add(new GetStatusCommand(PodInfoType.NORMAL)); } } diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/communication/message/command/BolusExtraCommand.java b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/communication/message/command/BolusExtraCommand.java index 465d1dee13..6ec315aa16 100644 --- a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/communication/message/command/BolusExtraCommand.java +++ b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/communication/message/command/BolusExtraCommand.java @@ -6,7 +6,6 @@ import info.nightscout.androidaps.plugins.pump.common.utils.ByteUtil; import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.MessageBlock; import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.MessageBlockType; import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.OmnipodConstants; -import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.CommandInitializationException; public class BolusExtraCommand extends MessageBlock { private final boolean acknowledgementBeep; @@ -29,9 +28,9 @@ public class BolusExtraCommand extends MessageBlock { boolean acknowledgementBeep, boolean completionBeep, Duration programReminderInterval, Duration timeBetweenPulses) { if (units <= 0D) { - throw new CommandInitializationException("Units should be > 0"); + throw new IllegalArgumentException("Units should be > 0"); } else if (units > OmnipodConstants.MAX_BOLUS) { - throw new CommandInitializationException("Units exceeds max bolus"); + throw new IllegalArgumentException("Units exceeds max bolus"); } this.units = units; this.squareWaveUnits = squareWaveUnits; diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/communication/message/command/SetInsulinScheduleCommand.java b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/communication/message/command/SetInsulinScheduleCommand.java index 88ad5d206d..c9089559cb 100644 --- a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/communication/message/command/SetInsulinScheduleCommand.java +++ b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/communication/message/command/SetInsulinScheduleCommand.java @@ -12,7 +12,6 @@ import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.schedul import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.schedule.BolusDeliverySchedule; import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.schedule.DeliverySchedule; import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.schedule.TempBasalDeliverySchedule; -import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.CommandInitializationException; public class SetInsulinScheduleCommand extends NonceResyncableMessageBlock { @@ -51,12 +50,12 @@ public class SetInsulinScheduleCommand extends NonceResyncableMessageBlock { // Temp basal public SetInsulinScheduleCommand(int nonce, double tempBasalRate, Duration duration) { if (tempBasalRate < 0D) { - throw new CommandInitializationException("Rate should be >= 0"); + throw new IllegalArgumentException("Rate should be >= 0"); } else if (tempBasalRate > OmnipodConstants.MAX_BASAL_RATE) { - throw new CommandInitializationException("Rate exceeds max basal rate"); + throw new IllegalArgumentException("Rate exceeds max basal rate"); } if (duration.isLongerThan(OmnipodConstants.MAX_TEMP_BASAL_DURATION)) { - throw new CommandInitializationException("Duration exceeds max temp basal duration"); + throw new IllegalArgumentException("Duration exceeds max temp basal duration"); } int pulsesPerHour = (int) Math.round(tempBasalRate / OmnipodConstants.POD_PULSE_SIZE); int pulsesPerSegment = pulsesPerHour / 2; diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/communication/message/command/TempBasalExtraCommand.java b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/communication/message/command/TempBasalExtraCommand.java index 031b36af71..baac0f9305 100644 --- a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/communication/message/command/TempBasalExtraCommand.java +++ b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/communication/message/command/TempBasalExtraCommand.java @@ -10,7 +10,6 @@ import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.mess import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.MessageBlockType; import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.OmnipodConstants; import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.schedule.RateEntry; -import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.CommandInitializationException; public class TempBasalExtraCommand extends MessageBlock { private final boolean acknowledgementBeep; @@ -24,12 +23,12 @@ public class TempBasalExtraCommand extends MessageBlock { public TempBasalExtraCommand(double rate, Duration duration, boolean acknowledgementBeep, boolean completionBeep, Duration programReminderInterval) { if (rate < 0D) { - throw new CommandInitializationException("Rate should be >= 0"); + throw new IllegalArgumentException("Rate should be >= 0"); } else if (rate > OmnipodConstants.MAX_BASAL_RATE) { - throw new CommandInitializationException("Rate exceeds max basal rate"); + throw new IllegalArgumentException("Rate exceeds max basal rate"); } if (duration.isLongerThan(OmnipodConstants.MAX_TEMP_BASAL_DURATION)) { - throw new CommandInitializationException("Duration exceeds max temp basal duration"); + throw new IllegalArgumentException("Duration exceeds max temp basal duration"); } this.acknowledgementBeep = acknowledgementBeep; diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/communication/message/response/podinfo/PodInfoFaultEvent.java b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/communication/message/response/podinfo/PodInfoFaultEvent.java index d099894ab6..13a782fdf7 100644 --- a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/communication/message/response/podinfo/PodInfoFaultEvent.java +++ b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/communication/message/response/podinfo/PodInfoFaultEvent.java @@ -69,7 +69,9 @@ public class PodInfoFaultEvent extends PodInfo implements StatusUpdatableRespons unacknowledgedAlerts = new AlertSet(encodedData[15]); faultAccessingTables = encodedData[16] == 0x02; - logEventErrorType = LogEventErrorCode.fromByte((byte) (encodedData[17] >>> 4)); + int i = ByteUtil.convertUnsignedByteToInt(encodedData[17]); + byte value = (byte) (i >>> 4); + logEventErrorType = LogEventErrorCode.fromByte(value); logEventErrorPodProgressStatus = PodProgressStatus.fromByte((byte) (encodedData[17] & 0x0f)); receiverLowGain = (byte) (ByteUtil.convertUnsignedByteToInt(encodedData[18]) >>> 6); radioRSSI = (byte) (encodedData[18] & 0x3f); diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/definition/OmnipodConstants.java b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/definition/OmnipodConstants.java index b36dc765c7..b5b65f0f58 100644 --- a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/definition/OmnipodConstants.java +++ b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/definition/OmnipodConstants.java @@ -21,10 +21,8 @@ public class OmnipodConstants { public static final Duration AVERAGE_TEMP_BASAL_COMMAND_COMMUNICATION_DURATION = Duration.millis(1500); public static final Duration SERVICE_DURATION = Duration.standardHours(80); - public static final Duration EXPIRATION_ADVISORY_WINDOW = Duration.standardHours(9); public static final Duration END_OF_SERVICE_IMMINENT_WINDOW = Duration.standardHours(1); public static final Duration NOMINAL_POD_LIFE = Duration.standardHours(72); - public static final double LOW_RESERVOIR_ALERT = 20.0; public static final double POD_PRIME_BOLUS_UNITS = 2.6; public static final double POD_CANNULA_INSERTION_BOLUS_UNITS = 0.5; diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/exception/ActionInitializationException.java b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/exception/ActionInitializationException.java deleted file mode 100644 index 1de5bf13dc..0000000000 --- a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/exception/ActionInitializationException.java +++ /dev/null @@ -1,7 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.omnipod.driver.exception; - -public class ActionInitializationException extends OmnipodException { - public ActionInitializationException(String message) { - super(message, true); - } -} diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/exception/CommandInitializationException.java b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/exception/CommandInitializationException.java deleted file mode 100644 index 57bd2c0189..0000000000 --- a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/exception/CommandInitializationException.java +++ /dev/null @@ -1,11 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.omnipod.driver.exception; - -public class CommandInitializationException extends OmnipodException { - public CommandInitializationException(String message) { - super(message, true); - } - - public CommandInitializationException(String message, Throwable cause) { - super(message, cause, true); - } -} diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/exception/CommunicationException.java b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/exception/CommunicationException.java deleted file mode 100644 index e9a7eb3bd0..0000000000 --- a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/exception/CommunicationException.java +++ /dev/null @@ -1,34 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.omnipod.driver.exception; - -public class CommunicationException extends OmnipodException { - private final Type type; - - public CommunicationException(Type type) { - super(type.getDescription(), false); - this.type = type; - } - - public CommunicationException(Type type, Throwable cause) { - super(type.getDescription() + ": " + cause, cause, false); - this.type = type; - } - - public Type getType() { - return type; - } - - public enum Type { - TIMEOUT("Communication timeout"), - UNEXPECTED_EXCEPTION("Caught an unexpected Exception"); - - private final String description; - - Type(String description) { - this.description = description; - } - - public String getDescription() { - return description; - } - } -} diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/exception/PodProgressStatusVerificationFailedException.java b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/exception/PodProgressStatusVerificationFailedException.java new file mode 100644 index 0000000000..d429e6a900 --- /dev/null +++ b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/exception/PodProgressStatusVerificationFailedException.java @@ -0,0 +1,16 @@ +package info.nightscout.androidaps.plugins.pump.omnipod.driver.exception; + +import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.PodProgressStatus; + +public class PodProgressStatusVerificationFailedException extends OmnipodException { + private final PodProgressStatus expectedStatus; + + public PodProgressStatusVerificationFailedException(PodProgressStatus expectedStatus, Throwable cause) { + super("Failed to verify Pod progress status (expected=" + expectedStatus + ")", cause, false); + this.expectedStatus = expectedStatus; + } + + public PodProgressStatus getExpectedStatus() { + return expectedStatus; + } +} diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/exception/RileyLinkInterruptedException.java b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/exception/RileyLinkInterruptedException.java new file mode 100644 index 0000000000..3cb5f18267 --- /dev/null +++ b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/exception/RileyLinkInterruptedException.java @@ -0,0 +1,7 @@ +package info.nightscout.androidaps.plugins.pump.omnipod.driver.exception; + +public class RileyLinkInterruptedException extends OmnipodException { + public RileyLinkInterruptedException() { + super("RileyLink interrupted", false); + } +} diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/exception/RileyLinkTimeoutException.java b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/exception/RileyLinkTimeoutException.java new file mode 100644 index 0000000000..7e4b48a226 --- /dev/null +++ b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/exception/RileyLinkTimeoutException.java @@ -0,0 +1,8 @@ +package info.nightscout.androidaps.plugins.pump.omnipod.driver.exception; + +// Response indicating that there was a timeout in communication between the RileyLink and the Pod +public class RileyLinkTimeoutException extends OmnipodException { + public RileyLinkTimeoutException() { + super("Timeout in communication between RileyLink and Pod", false); + } +} diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/exception/RileyLinkUnexpectedException.java b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/exception/RileyLinkUnexpectedException.java new file mode 100644 index 0000000000..e844eca158 --- /dev/null +++ b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/exception/RileyLinkUnexpectedException.java @@ -0,0 +1,7 @@ +package info.nightscout.androidaps.plugins.pump.omnipod.driver.exception; + +public class RileyLinkUnexpectedException extends OmnipodException { + public RileyLinkUnexpectedException(Throwable cause) { + super("Unexpected Exception during RileyLink communication", cause, false); + } +} diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/exception/RileyLinkUnreachableException.java b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/exception/RileyLinkUnreachableException.java new file mode 100644 index 0000000000..05320c051d --- /dev/null +++ b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/exception/RileyLinkUnreachableException.java @@ -0,0 +1,8 @@ +package info.nightscout.androidaps.plugins.pump.omnipod.driver.exception; + +// Indicates that we didn't get any response from the RL +public class RileyLinkUnreachableException extends OmnipodException { + public RileyLinkUnreachableException() { + super("Timeout in communication between phone and RileyLink", false); + } +} diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/manager/OmnipodManager.java b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/manager/OmnipodManager.java index 9da707a26b..e642fd1f71 100644 --- a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/manager/OmnipodManager.java +++ b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/manager/OmnipodManager.java @@ -41,7 +41,6 @@ import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.PodInfo import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.PodProgressStatus; import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.schedule.BasalSchedule; import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.CommandFailedAfterChangingDeliveryStatusException; -import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.CommunicationException; import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.DeliveryStatusVerificationFailedException; import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.IllegalDeliveryStatusException; import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.IllegalPacketTypeException; @@ -49,6 +48,7 @@ import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.IllegalP import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.NonceOutOfSyncException; import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.OmnipodException; import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.PodFaultException; +import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.PodProgressStatusVerificationFailedException; import info.nightscout.androidaps.plugins.pump.omnipod.rileylink.manager.OmnipodRileyLinkCommunicationManager; import info.nightscout.androidaps.utils.sharedPreferences.SP; import io.reactivex.Completable; @@ -59,7 +59,7 @@ import io.reactivex.schedulers.Schedulers; import io.reactivex.subjects.SingleSubject; public class OmnipodManager { - private static final int ACTION_VERIFICATION_TRIES = 3; + private static final int ACTION_VERIFICATION_TRIES = 2; private final OmnipodRileyLinkCommunicationManager communicationService; private PodStateManager podStateManager; @@ -87,7 +87,7 @@ public class OmnipodManager { this.podStateManager = podStateManager; } - public synchronized Single pairAndPrime() { + public synchronized Single pairAndPrime() { logStartingCommandExecution("pairAndPrime"); try { @@ -126,14 +126,14 @@ public class OmnipodManager { logCommandExecutionFinished("pairAndPrime"); } - long delayInSeconds = calculateBolusDuration(OmnipodConstants.POD_PRIME_BOLUS_UNITS, OmnipodConstants.POD_PRIMING_DELIVERY_RATE).getStandardSeconds(); + long delayInMillis = calculateEstimatedBolusDuration(DateTime.now().minus(OmnipodConstants.AVERAGE_BOLUS_COMMAND_COMMUNICATION_DURATION), OmnipodConstants.POD_PRIME_BOLUS_UNITS, OmnipodConstants.POD_PRIMING_DELIVERY_RATE).getMillis(); - return Single.timer(delayInSeconds, TimeUnit.SECONDS) // - .map(o -> verifySetupAction(PodProgressStatus.PRIMING_COMPLETED)) // - .observeOn(Schedulers.io()); + return Single.timer(delayInMillis, TimeUnit.MILLISECONDS) // + .map(o -> verifyPodProgressStatus(PodProgressStatus.PRIMING_COMPLETED)) // + .subscribeOn(Schedulers.io()); } - public synchronized Single insertCannula( + public synchronized Single insertCannula( BasalSchedule basalSchedule, Duration expirationReminderTimeBeforeShutdown, Integer lowReservoirAlertUnits) { if (!podStateManager.isPodInitialized() || podStateManager.getPodProgressStatus().isBefore(PodProgressStatus.PRIMING_COMPLETED)) { throw new IllegalPodProgressException(PodProgressStatus.PRIMING_COMPLETED, !podStateManager.isPodInitialized() ? null : podStateManager.getPodProgressStatus()); @@ -154,11 +154,11 @@ public class OmnipodManager { logCommandExecutionFinished("insertCannula"); } - long delayInSeconds = calculateBolusDuration(OmnipodConstants.POD_CANNULA_INSERTION_BOLUS_UNITS, OmnipodConstants.POD_CANNULA_INSERTION_DELIVERY_RATE).getStandardSeconds(); + long delayInMillis = calculateEstimatedBolusDuration(DateTime.now().minus(OmnipodConstants.AVERAGE_BOLUS_COMMAND_COMMUNICATION_DURATION), OmnipodConstants.POD_CANNULA_INSERTION_BOLUS_UNITS, OmnipodConstants.POD_CANNULA_INSERTION_DELIVERY_RATE).getMillis(); - return Single.timer(delayInSeconds, TimeUnit.SECONDS) // - .map(o -> verifySetupAction(PodProgressStatus.ABOVE_FIFTY_UNITS)) // - .observeOn(Schedulers.io()); + return Single.timer(delayInMillis, TimeUnit.MILLISECONDS) // + .map(o -> verifyPodProgressStatus(PodProgressStatus.ABOVE_FIFTY_UNITS)) // + .subscribeOn(Schedulers.io()); } public synchronized StatusResponse getPodStatus() { @@ -224,13 +224,10 @@ public class OmnipodManager { suspendDelivery(acknowledgementBeep); } - // Store the new Basal schedule after successfully suspending delivery, so that if setting the Basal schedule fails, - // And we later try to resume delivery, the new schedule is used - podStateManager.setBasalSchedule(schedule); - try { executeAndVerify(() -> communicationService.executeAction(new SetBasalScheduleAction(podStateManager, schedule, false, podStateManager.getScheduleOffset(), acknowledgementBeep))); + podStateManager.setBasalSchedule(schedule); } catch (OmnipodException ex) { if (ex.isCertainFailure()) { if (!wasSuspended) { @@ -240,7 +237,9 @@ public class OmnipodManager { } // verifyDeliveryStatus will throw an exception if verification fails - if (!verifyDeliveryStatus(DeliveryStatus.NORMAL, ex)) { + if (verifyDeliveryStatus(DeliveryStatus.NORMAL, ex)) { + podStateManager.setBasalSchedule(schedule); + } else { if (!wasSuspended) { throw new CommandFailedAfterChangingDeliveryStatusException("Suspending delivery succeeded but setting the new basal schedule did not", ex); } @@ -248,6 +247,8 @@ public class OmnipodManager { throw ex; } } + + } finally { logCommandExecutionFinished("setBasalSchedule"); } @@ -270,10 +271,14 @@ public class OmnipodManager { throw ex; } - // verifyDeliveryStatus will throw an exception if verification fails - if (!verifyDeliveryStatus(DeliveryStatus.NORMAL, ex)) { - ex.setCertainFailure(true); - throw ex; + try { + if (!verifyDeliveryStatus(DeliveryStatus.NORMAL, ex)) { + ex.setCertainFailure(true); + throw ex; + } + } catch (DeliveryStatusVerificationFailedException ex2) { + podStateManager.setTempBasalCertain(false); + throw ex2; } } } @@ -321,7 +326,23 @@ public class OmnipodManager { } public synchronized void cancelTemporaryBasal(boolean acknowledgementBeep) { - cancelDelivery(EnumSet.of(DeliveryType.TEMP_BASAL), acknowledgementBeep); + try { + cancelDelivery(EnumSet.of(DeliveryType.TEMP_BASAL), acknowledgementBeep); + } catch (OmnipodException ex) { + if (ex.isCertainFailure()) { + throw ex; + } + + try { + if (!verifyDeliveryStatus(DeliveryStatus.NORMAL, ex)) { + ex.setCertainFailure(true); + throw ex; + } + } catch (DeliveryStatusVerificationFailedException ex2) { + podStateManager.setTempBasalCertain(false); + throw ex2; + } + } } private synchronized StatusResponse cancelDelivery(EnumSet deliveryTypes, boolean acknowledgementBeep) { @@ -367,7 +388,7 @@ public class OmnipodManager { } DateTime estimatedBolusStartDate = DateTime.now().minus(OmnipodConstants.AVERAGE_BOLUS_COMMAND_COMMUNICATION_DURATION); - Duration estimatedBolusDuration = calculateBolusDuration(units, OmnipodConstants.POD_BOLUS_DELIVERY_RATE); + Duration estimatedBolusDuration = calculateEstimatedBolusDuration(estimatedBolusStartDate, units, OmnipodConstants.POD_BOLUS_DELIVERY_RATE); Duration estimatedRemainingBolusDuration = estimatedBolusDuration.minus(OmnipodConstants.AVERAGE_BOLUS_COMMAND_COMMUNICATION_DURATION); podStateManager.setLastBolus(estimatedBolusStartDate, units, estimatedBolusDuration, commandDeliveryStatus == CommandDeliveryStatus.SUCCESS); @@ -376,11 +397,11 @@ public class OmnipodManager { if (progressIndicationConsumer != null) { - int numberOfProgressReports = Math.max(20, Math.min(100, (int) Math.ceil(units) * 10)); + long numberOfProgressReports = Math.max(10, Math.min(100, estimatedRemainingBolusDuration.getStandardSeconds())); long progressReportInterval = estimatedRemainingBolusDuration.getMillis() / numberOfProgressReports; disposables.add(Flowable.intervalRange(0, numberOfProgressReports + 1, 0, progressReportInterval, TimeUnit.MILLISECONDS) // - .observeOn(Schedulers.io()) // + .subscribeOn(Schedulers.io()) // .subscribe(count -> { int percentage = (int) ((double) count / numberOfProgressReports * 100); double estimatedUnitsDelivered = activeBolusData == null ? 0 : activeBolusData.estimateUnitsDelivered(); @@ -400,8 +421,8 @@ public class OmnipodManager { bolusCommandExecutionSubject = null; disposables.add(Completable.complete() // - .delay(estimatedRemainingBolusDuration.getMillis() + 250, TimeUnit.MILLISECONDS) // - .observeOn(Schedulers.io()) // + .delay(estimatedRemainingBolusDuration.getMillis(), TimeUnit.MILLISECONDS) // + .subscribeOn(Schedulers.io()) // .doOnComplete(() -> { synchronized (bolusDataMutex) { double bolusNotDelivered = 0.0d; @@ -412,9 +433,8 @@ public class OmnipodManager { StatusResponse statusResponse = getPodStatus(); if (statusResponse.getDeliveryStatus().isBolusing()) { throw new IllegalDeliveryStatusException(DeliveryStatus.NORMAL, statusResponse.getDeliveryStatus()); - } else { - break; } + break; } catch (PodFaultException ex) { // Subtract units not delivered in case of a Pod failure bolusNotDelivered = ex.getFaultEvent().getBolusNotDelivered(); @@ -513,6 +533,8 @@ public class OmnipodManager { podStateManager.setTimeZone(oldTimeZone); throw ex; } + + podStateManager.updateActivatedAt(); } finally { logCommandExecutionFinished("setTime"); } @@ -529,9 +551,9 @@ public class OmnipodManager { try { PodInfoResponse podInfoResponse = communicationService.executeAction(new GetPodInfoAction(podStateManager, PodInfoType.RECENT_PULSE_LOG)); PodInfoRecentPulseLog pulseLogInfo = (PodInfoRecentPulseLog) podInfoResponse.getPodInfo(); - aapsLogger.info(LTag.PUMPCOMM, "Retrieved pulse log from the pod: {}", pulseLogInfo.toString()); + aapsLogger.info(LTag.PUMPCOMM, "Read pulse log from the pod: {}", pulseLogInfo.toString()); } catch (Exception ex) { - aapsLogger.warn(LTag.PUMPCOMM, "Failed to retrieve pulse log from the pod", ex); + aapsLogger.warn(LTag.PUMPCOMM, "Failed to read pulse log", ex); } try { @@ -573,7 +595,7 @@ public class OmnipodManager { logStartingCommandExecution("verifyCommand"); try { return supplier.get(); - } catch (Exception originalException) { + } catch (OmnipodException originalException) { if (isCertainFailure(originalException)) { throw originalException; } else { @@ -586,18 +608,11 @@ public class OmnipodManager { return statusResponse; } catch (NonceOutOfSyncException verificationException) { - aapsLogger.error(LTag.PUMPCOMM, "Command resolved to FAILURE (CERTAIN_FAILURE)", verificationException); - - if (originalException instanceof OmnipodException) { - ((OmnipodException) originalException).setCertainFailure(true); - throw originalException; - } else { - OmnipodException newException = new CommunicationException(CommunicationException.Type.UNEXPECTED_EXCEPTION, originalException); - newException.setCertainFailure(true); - throw newException; - } + aapsLogger.info(LTag.PUMPCOMM, "Command resolved to FAILURE (CERTAIN_FAILURE)", verificationException); + originalException.setCertainFailure(true); + throw originalException; } catch (Exception verificationException) { - aapsLogger.error(LTag.PUMPCOMM, "Command unresolved (UNCERTAIN_FAILURE)", verificationException); + aapsLogger.warn(LTag.PUMPCOMM, "Command unresolved (UNCERTAIN_FAILURE)", verificationException); throw originalException; } } @@ -612,26 +627,36 @@ public class OmnipodManager { } } - private SetupActionResult verifySetupAction(PodProgressStatus expectedPodProgressStatus) { - SetupActionResult result = null; + /** + * @param expectedPodProgressStatus expected Pod progress status + * @return true if the Pod's progress status matches the expected status, otherwise false + * @throws PodProgressStatusVerificationFailedException in case reading the Pod status fails + */ + private boolean verifyPodProgressStatus(PodProgressStatus expectedPodProgressStatus) { + Boolean result = null; + Throwable lastException = null; + for (int i = 0; ACTION_VERIFICATION_TRIES > i; i++) { try { StatusResponse statusResponse = getPodStatus(); if (statusResponse.getPodProgressStatus().equals(expectedPodProgressStatus)) { - result = new SetupActionResult(SetupActionResult.ResultType.SUCCESS); - break; + return true; } else { - result = new SetupActionResult(SetupActionResult.ResultType.FAILURE) // - .podProgressStatus(statusResponse.getPodProgressStatus()); - break; + result = false; } } catch (Exception ex) { - result = new SetupActionResult(SetupActionResult.ResultType.VERIFICATION_FAILURE) // - .exception(ex); + lastException = ex; } } - return result; + + if (result != null) { + return result; + } + + final Throwable ex = lastException; + + throw new PodProgressStatusVerificationFailedException(expectedPodProgressStatus, ex); } /** @@ -664,14 +689,27 @@ public class OmnipodManager { aapsLogger.debug(LTag.PUMPCOMM, "Command execution finished for action: " + action); } - private static Duration calculateBolusDuration(double units, double deliveryRate) { - // TODO take current (temp) basal into account - // Be aware that the Pod possibly doesn't have a Basal Schedule yet - return Duration.standardSeconds((long) Math.ceil(units / deliveryRate)); - } + private Duration calculateEstimatedBolusDuration(DateTime startTime, double units, double deliveryRateInUnitsPerSecond) { + if (!podStateManager.isPodActivationCompleted()) { + // No basal or temp basal is active yet + return Duration.standardSeconds((long) Math.ceil(units / deliveryRateInUnitsPerSecond)); + } - public static Duration calculateBolusDuration(double units) { - return calculateBolusDuration(units, OmnipodConstants.POD_BOLUS_DELIVERY_RATE); + double pulseIntervalInSeconds = OmnipodConstants.POD_PULSE_SIZE / deliveryRateInUnitsPerSecond; + long numberOfPulses = Math.round(units / OmnipodConstants.POD_PULSE_SIZE); + double totalEstimatedDurationInSeconds = 0D; + + for (int i = 0; numberOfPulses > i; i++) { + DateTime estimatedTimeAtPulse = startTime.plusMillis((int) (totalEstimatedDurationInSeconds * 1000)); + double effectiveBasalRateAtPulse = podStateManager.getEffectiveBasalRateAt(estimatedTimeAtPulse); + double effectivePulsesPerHourAtPulse = effectiveBasalRateAtPulse / OmnipodConstants.POD_PULSE_SIZE; + double effectiveBasalPulsesPerSecondAtPulse = effectivePulsesPerHourAtPulse / 3600; + double effectiveBasalPulsesPerBolusPulse = pulseIntervalInSeconds * effectiveBasalPulsesPerSecondAtPulse; + + totalEstimatedDurationInSeconds += pulseIntervalInSeconds * (1 + effectiveBasalPulsesPerBolusPulse); + } + + return Duration.millis(Math.round(totalEstimatedDurationInSeconds * 1000)); } public static boolean isCertainFailure(Exception ex) { diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/manager/PodStateManager.java b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/manager/PodStateManager.java index 4aed1057f6..f7fa1ee694 100644 --- a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/manager/PodStateManager.java +++ b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/manager/PodStateManager.java @@ -84,6 +84,7 @@ public abstract class PodStateManager { /** * @return true if we have a Pod state and the Pod is running, meaning the activation process has completed and the Pod is not deactivated or in a fault state + * This does not mean the Pod is actually delivering insulin, combine with {@link #isSuspended() isSuspended()} for that */ public final boolean isPodRunning() { return isPodInitialized() && getPodProgressStatus().isRunning(); @@ -295,8 +296,21 @@ public abstract class PodStateManager { } public final DateTime getTime() { - DateTime now = DateTime.now(); - return now.withZone(getSafe(() -> podState.getTimeZone())); + DateTimeZone timeZone = getSafe(() -> podState.getTimeZone()); + if (timeZone == null) { + return DateTime.now(); + } + Duration timeActive = getSafe(() -> podState.getTimeActive()); + DateTime activatedAt = getSafe(() -> podState.getActivatedAt()); + DateTime lastUpdatedFromResponse = getSafe(() -> podState.getLastUpdatedFromResponse()); + if (timeActive == null || activatedAt == null) { + return DateTime.now().withZone(timeZone); + } + return activatedAt.plus(timeActive).plus(new Duration(lastUpdatedFromResponse, DateTime.now())); + } + + public final boolean timeDeviatesMoreThan(Duration duration) { + return new Duration(getTime(), DateTime.now().withZoneRetainFields(getSafe(() -> podState.getTimeZone()))).abs().isLongerThan(duration); } public final DateTime getActivatedAt() { @@ -304,22 +318,23 @@ public abstract class PodStateManager { return activatedAt == null ? null : activatedAt.withZone(getSafe(() -> podState.getTimeZone())); } + public final void updateActivatedAt() { + setAndStore(() -> podState.setActivatedAt(DateTime.now().withZone(getSafe(() -> podState.getTimeZone())).minus(getSafe(this::getTimeActive)))); + } + + public final Duration getTimeActive() { + return getSafe(() -> podState.getTimeActive()); + } + public final DateTime getExpiresAt() { - DateTime expiresAt = getSafe(() -> podState.getExpiresAt()); - return expiresAt == null ? null : expiresAt.withZone(getSafe(() -> podState.getTimeZone())); + DateTime activatedAt = getSafe(() -> podState.getActivatedAt()); + return activatedAt == null ? null : activatedAt.withZone(getSafe(() -> podState.getTimeZone())).plus(OmnipodConstants.NOMINAL_POD_LIFE); } public final PodProgressStatus getPodProgressStatus() { return getSafe(() -> podState.getPodProgressStatus()); } - public final void setPodProgressStatus(PodProgressStatus podProgressStatus) { - if (podProgressStatus == null) { - throw new IllegalArgumentException("Pod progress status can not be null"); - } - setAndStore(() -> podState.setPodProgressStatus(podProgressStatus)); - } - public final boolean isSuspended() { return getSafe(() -> podState.isSuspended()); } @@ -392,6 +407,10 @@ public abstract class PodStateManager { return certain == null || certain; } + public final void setTempBasalCertain(boolean certain) { + setSafe(() -> podState.setTempBasalCertain(certain)); + } + public final void setTempBasal(DateTime startTime, Double amount, Duration duration, boolean certain) { setTempBasal(startTime, amount, duration, certain, true); } @@ -427,16 +446,50 @@ public abstract class PodStateManager { } /** - * @return true when a Temp Basal is stored in the Pod Stated and this temp basal is currently running (based on start time and duration) + * @return true when a Temp Basal is stored in the Pod State and this temp basal is currently running (based on start time and duration) */ public final boolean isTempBasalRunning() { + return isTempBasalRunningAt(DateTime.now()); + } + + /** + * @return true when a Temp Basal is stored in the Pod State and this temp basal is running at the given time (based on start time and duration) + */ + public final boolean isTempBasalRunningAt(DateTime time) { if (hasTempBasal()) { - DateTime tempBasalEndTime = getTempBasalStartTime().plus(getTempBasalDuration()); - return DateTime.now().isBefore(tempBasalEndTime); + DateTime tempBasalStartTime = getTempBasalStartTime(); + DateTime tempBasalEndTime = tempBasalStartTime.plus(getTempBasalDuration()); + return (time.isAfter(tempBasalStartTime) || time.isEqual(tempBasalStartTime)) && time.isBefore(tempBasalEndTime); } return false; } + /** + * @return the current effective basal rate (taking Pod suspension, TBR, and basal profile into account) + */ + public final double getEffectiveBasalRate() { + if (isSuspended()) { + return 0d; + } + return getEffectiveBasalRateAt(DateTime.now()); + } + + /** + * @return the effective basal rate at the given time (taking TBR, and basal profile into account) + * Suspension is not taken into account as we don't keep historic data of that + */ + public final double getEffectiveBasalRateAt(DateTime time) { + BasalSchedule basalSchedule = getSafe(() -> podState.getBasalSchedule()); + if (basalSchedule == null) { + return 0d; + } + if (isTempBasalRunningAt(time)) { + return getTempBasalAmount(); + } + Duration offset = new Duration(time.withTimeAtStartOfDay(), time); + return basalSchedule.rateAt(offset); + } + public final DeliveryStatus getLastDeliveryStatus() { return getSafe(() -> podState.getLastDeliveryStatus()); } @@ -463,21 +516,16 @@ public abstract class PodStateManager { public final void updateFromResponse(StatusUpdatableResponse statusResponse) { setSafe(() -> { if (podState.getActivatedAt() == null) { - DateTime activatedAtCalculated = getTime().minus(statusResponse.getTimeActive()); + DateTime activatedAtCalculated = DateTime.now().withZone(podState.getTimeZone()).minus(statusResponse.getTimeActive()); podState.setActivatedAt(activatedAtCalculated); } - DateTime expiresAt = podState.getExpiresAt(); - DateTime expiresAtCalculated = podState.getActivatedAt().plus(OmnipodConstants.NOMINAL_POD_LIFE); - if (expiresAt == null || expiresAtCalculated.isBefore(expiresAt) || expiresAtCalculated.isAfter(expiresAt.plusMinutes(1))) { - podState.setExpiresAt(expiresAtCalculated); - } - podState.setSuspended(statusResponse.getDeliveryStatus() == DeliveryStatus.SUSPENDED); podState.setActiveAlerts(statusResponse.getUnacknowledgedAlerts()); podState.setLastDeliveryStatus(statusResponse.getDeliveryStatus()); podState.setReservoirLevel(statusResponse.getReservoirLevel()); podState.setTotalTicksDelivered(statusResponse.getTicksDelivered()); podState.setPodProgressStatus(statusResponse.getPodProgressStatus()); + podState.setTimeActive(statusResponse.getTimeActive()); if (statusResponse.getDeliveryStatus().isTbrRunning()) { if (!isTempBasalCertain() && isTempBasalRunning()) { podState.setTempBasalCertain(true); @@ -577,7 +625,7 @@ public abstract class PodStateManager { private DateTime lastUpdatedFromResponse; private DateTimeZone timeZone; private DateTime activatedAt; - private DateTime expiresAt; + private Duration timeActive; private PodInfoFaultEvent faultEvent; private Double reservoirLevel; private Integer totalTicksDelivered; @@ -695,12 +743,12 @@ public abstract class PodStateManager { this.activatedAt = activatedAt; } - DateTime getExpiresAt() { - return expiresAt; + public Duration getTimeActive() { + return timeActive; } - void setExpiresAt(DateTime expiresAt) { - this.expiresAt = expiresAt; + public void setTimeActive(Duration timeActive) { + this.timeActive = timeActive; } PodInfoFaultEvent getFaultEvent() { @@ -881,7 +929,7 @@ public abstract class PodStateManager { ", lastUpdatedFromResponse=" + lastUpdatedFromResponse + ", timeZone=" + timeZone + ", activatedAt=" + activatedAt + - ", expiresAt=" + expiresAt + + ", timeActive=" + timeActive + ", faultEvent=" + faultEvent + ", reservoirLevel=" + reservoirLevel + ", totalTicksDelivered=" + totalTicksDelivered + @@ -899,7 +947,7 @@ public abstract class PodStateManager { ", tempBasalStartTime=" + tempBasalStartTime + ", tempBasalDuration=" + tempBasalDuration + ", tempBasalCertain=" + tempBasalCertain + - ", expirationAlertHoursBeforeShutdown=" + expirationAlertTimeBeforeShutdown + + ", expirationAlertTimeBeforeShutdown=" + expirationAlertTimeBeforeShutdown + ", lowReservoirAlertUnits=" + lowReservoirAlertUnits + ", configuredAlerts=" + configuredAlerts + '}'; diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/manager/SetupActionResult.java b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/manager/SetupActionResult.java deleted file mode 100644 index 867c56aa9f..0000000000 --- a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/manager/SetupActionResult.java +++ /dev/null @@ -1,61 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.omnipod.driver.manager; - -import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.PodProgressStatus; - -public class SetupActionResult { - private final ResultType resultType; - private String message; - private Exception exception; - private PodProgressStatus podProgressStatus; - - public SetupActionResult(ResultType resultType) { - this.resultType = resultType; - } - - public SetupActionResult message(String message) { - this.message = message; - return this; - } - - public SetupActionResult exception(Exception ex) { - exception = ex; - return this; - } - - public SetupActionResult podProgressStatus(PodProgressStatus podProgressStatus) { - this.podProgressStatus = podProgressStatus; - return this; - } - - public ResultType getResultType() { - return resultType; - } - - public String getMessage() { - return message; - } - - public Exception getException() { - return exception; - } - - public PodProgressStatus getPodProgressStatus() { - return podProgressStatus; - } - - public enum ResultType { - SUCCESS(true), - VERIFICATION_FAILURE(false), - FAILURE(false); - - private final boolean success; - - ResultType(boolean success) { - this.success = success; - } - - public boolean isSuccess() { - return success; - } - } -} diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/util/AlertConfigurationUtil.java b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/util/AlertConfigurationUtil.java index 0d223458d6..92e2d2d74d 100644 --- a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/util/AlertConfigurationUtil.java +++ b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/driver/util/AlertConfigurationUtil.java @@ -18,12 +18,12 @@ public class AlertConfigurationUtil { public static AlertConfiguration createExpirationAdvisoryAlertConfiguration(boolean active, Duration timeUntilAlert, Duration duration) { return new AlertConfiguration(AlertType.EXPIRATION_ADVISORY_ALERT, AlertSlot.SLOT7, active, false, duration, - new TimerAlertTrigger(timeUntilAlert), BeepType.BIP_BEEP_BIP_BEEP_BIP_BEEP_BIP_BEEP, BeepRepeat.EVERY_15_MINUTES); + new TimerAlertTrigger(timeUntilAlert), BeepType.BIP_BEEP_BIP_BEEP_BIP_BEEP_BIP_BEEP, BeepRepeat.EVERY_MINUTE_FOR_3_MINUTES_REPEAT_EVERY_15_MINUTES); } public static AlertConfiguration createShutdownImminentAlertConfiguration(Duration timeUntilAlert) { return new AlertConfiguration(AlertType.SHUTDOWN_IMMINENT_ALARM, AlertSlot.SLOT2, true, false, Duration.ZERO, - new TimerAlertTrigger(timeUntilAlert), BeepType.BIP_BEEP_BIP_BEEP_BIP_BEEP_BIP_BEEP, BeepRepeat.EVERY_MINUTE_FOR_3_MINUTES_REPEAT_EVERY_15_MINUTES); + new TimerAlertTrigger(timeUntilAlert), BeepType.BIP_BEEP_BIP_BEEP_BIP_BEEP_BIP_BEEP, BeepRepeat.EVERY_15_MINUTES); } public static AlertConfiguration createAutoOffAlertConfiguration(boolean active, Duration countdownDuration) { diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/manager/AapsOmnipodManager.java b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/manager/AapsOmnipodManager.java index 97a2123d76..cddf3b2692 100644 --- a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/manager/AapsOmnipodManager.java +++ b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/manager/AapsOmnipodManager.java @@ -2,10 +2,13 @@ package info.nightscout.androidaps.plugins.pump.omnipod.manager; import org.joda.time.DateTime; import org.joda.time.Duration; +import org.json.JSONException; +import org.json.JSONObject; import java.util.ArrayList; import java.util.Date; import java.util.List; +import java.util.function.Supplier; import javax.inject.Inject; import javax.inject.Singleton; @@ -14,15 +17,19 @@ import dagger.android.HasAndroidInjector; import info.nightscout.androidaps.data.DetailedBolusInfo; import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.data.PumpEnactResult; +import info.nightscout.androidaps.db.CareportalEvent; import info.nightscout.androidaps.db.OmnipodHistoryRecord; import info.nightscout.androidaps.db.Source; import info.nightscout.androidaps.db.TemporaryBasal; import info.nightscout.androidaps.events.Event; +import info.nightscout.androidaps.events.EventRefreshOverview; import info.nightscout.androidaps.interfaces.ActivePluginProvider; import info.nightscout.androidaps.interfaces.DatabaseHelperInterface; +import info.nightscout.androidaps.interfaces.ProfileFunction; import info.nightscout.androidaps.logging.AAPSLogger; import info.nightscout.androidaps.logging.LTag; import info.nightscout.androidaps.plugins.bus.RxBusWrapper; +import info.nightscout.androidaps.plugins.general.nsclient.NSUpload; import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification; import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification; import info.nightscout.androidaps.plugins.general.overview.events.EventOverviewBolusProgress; @@ -32,10 +39,9 @@ import info.nightscout.androidaps.plugins.pump.common.defs.PumpType; import info.nightscout.androidaps.plugins.pump.common.utils.ByteUtil; import info.nightscout.androidaps.plugins.pump.omnipod.R; import info.nightscout.androidaps.plugins.pump.omnipod.data.ActiveBolus; +import info.nightscout.androidaps.plugins.pump.omnipod.definition.OmnipodCommandType; import info.nightscout.androidaps.plugins.pump.omnipod.definition.OmnipodStorageKeys; import info.nightscout.androidaps.plugins.pump.omnipod.definition.PodHistoryEntryType; -import info.nightscout.androidaps.plugins.pump.omnipod.definition.PodInitActionType; -import info.nightscout.androidaps.plugins.pump.omnipod.definition.PodInitReceiver; import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.response.StatusResponse; import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.response.podinfo.PodInfoRecentPulseLog; import info.nightscout.androidaps.plugins.pump.omnipod.driver.communication.message.response.podinfo.PodInfoResponse; @@ -44,12 +50,10 @@ import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.Deliver import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.FaultEventCode; import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.OmnipodConstants; import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.PodInfoType; +import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.PodProgressStatus; import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.schedule.BasalSchedule; import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.schedule.BasalScheduleEntry; -import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.ActionInitializationException; import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.CommandFailedAfterChangingDeliveryStatusException; -import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.CommandInitializationException; -import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.CommunicationException; import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.CrcMismatchException; import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.DeliveryStatusVerificationFailedException; import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.IllegalDeliveryStatusException; @@ -66,16 +70,19 @@ import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.NotEnoug import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.OmnipodException; import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.PodFaultException; import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.PodReturnedErrorResponseException; +import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.RileyLinkInterruptedException; +import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.RileyLinkTimeoutException; +import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.RileyLinkUnexpectedException; +import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.RileyLinkUnreachableException; import info.nightscout.androidaps.plugins.pump.omnipod.driver.manager.OmnipodManager; import info.nightscout.androidaps.plugins.pump.omnipod.driver.manager.PodStateManager; -import info.nightscout.androidaps.plugins.pump.omnipod.driver.manager.SetupActionResult; import info.nightscout.androidaps.plugins.pump.omnipod.event.EventOmnipodPumpValuesChanged; import info.nightscout.androidaps.plugins.pump.omnipod.rileylink.manager.OmnipodRileyLinkCommunicationManager; import info.nightscout.androidaps.plugins.pump.omnipod.util.AapsOmnipodUtil; import info.nightscout.androidaps.plugins.pump.omnipod.util.OmnipodAlertUtil; +import info.nightscout.androidaps.utils.DateUtil; import info.nightscout.androidaps.utils.resources.ResourceHelper; import info.nightscout.androidaps.utils.sharedPreferences.SP; -import io.reactivex.disposables.Disposable; import io.reactivex.subjects.SingleSubject; @Singleton @@ -92,6 +99,8 @@ public class AapsOmnipodManager { private final OmnipodManager delegate; private final DatabaseHelperInterface databaseHelper; private final OmnipodAlertUtil omnipodAlertUtil; + private final NSUpload nsUpload; + private final ProfileFunction profileFunction; private boolean basalBeepsEnabled; private boolean bolusBeepsEnabled; @@ -112,20 +121,22 @@ public class AapsOmnipodManager { HasAndroidInjector injector, ActivePluginProvider activePlugin, DatabaseHelperInterface databaseHelper, - OmnipodAlertUtil omnipodAlertUtil) { - if (podStateManager == null) { - throw new IllegalArgumentException("Pod state manager can not be null"); - } + OmnipodAlertUtil omnipodAlertUtil, + NSUpload nsUpload, + ProfileFunction profileFunction + ) { this.podStateManager = podStateManager; this.aapsOmnipodUtil = aapsOmnipodUtil; this.aapsLogger = aapsLogger; this.rxBus = rxBus; + this.sp = sp; this.resourceHelper = resourceHelper; this.injector = injector; this.activePlugin = activePlugin; this.databaseHelper = databaseHelper; - this.sp = sp; this.omnipodAlertUtil = omnipodAlertUtil; + this.nsUpload = nsUpload; + this.profileFunction = profileFunction; delegate = new OmnipodManager(aapsLogger, sp, communicationService, podStateManager); @@ -142,141 +153,159 @@ public class AapsOmnipodManager { timeChangeEventEnabled = sp.getBoolean(OmnipodStorageKeys.Preferences.TIME_CHANGE_EVENT_ENABLED, true); } - public PumpEnactResult pairAndPrime(PodInitActionType podInitActionType, PodInitReceiver podInitReceiver) { - if (podInitActionType != PodInitActionType.PAIR_AND_PRIME_WIZARD_STEP) { - return new PumpEnactResult(injector).success(false).enacted(false).comment(getStringResource(R.string.omnipod_error_illegal_init_action_type, podInitActionType.name())); - } - + public PumpEnactResult initializePod() { + PumpEnactResult result = new PumpEnactResult(injector); try { - Disposable disposable = delegate.pairAndPrime().subscribe(res -> // - handleSetupActionResult(podInitActionType, podInitReceiver, res, System.currentTimeMillis(), null)); + Boolean res = executeCommand(delegate::pairAndPrime) + .blockingGet(); - return new PumpEnactResult(injector).success(true).enacted(true); + result.success(res).enacted(res); + + if (!res) { + result.comment(R.string.omnipod_error_failed_to_initialize_pod); + } } catch (Exception ex) { - String comment = handleAndTranslateException(ex); - podInitReceiver.returnInitTaskStatus(podInitActionType, false, comment); - addFailureToHistory(System.currentTimeMillis(), PodHistoryEntryType.PAIR_AND_PRIME, comment); - return new PumpEnactResult(injector).success(false).enacted(false).comment(comment); + result.success(false).enacted(false).comment(translateException(ex)); } + + addToHistory(System.currentTimeMillis(), PodHistoryEntryType.INITIALIZE_POD, result.comment, result.success); + + return result; } - public PumpEnactResult setInitialBasalScheduleAndInsertCannula(PodInitActionType podInitActionType, PodInitReceiver podInitReceiver, Profile profile) { - if (podInitActionType != PodInitActionType.FILL_CANNULA_SET_BASAL_PROFILE_WIZARD_STEP) { - return new PumpEnactResult(injector).success(false).enacted(false).comment(getStringResource(R.string.omnipod_error_illegal_init_action_type, podInitActionType.name())); - } - - try { - BasalSchedule basalSchedule; - try { - basalSchedule = mapProfileToBasalSchedule(profile); - } catch (Exception ex) { - throw new CommandInitializationException("Basal profile mapping failed", ex); - } - - Disposable disposable = delegate.insertCannula(basalSchedule, omnipodAlertUtil.getExpirationReminderTimeBeforeShutdown(), omnipodAlertUtil.getLowReservoirAlertUnits()).subscribe(res -> // - handleSetupActionResult(podInitActionType, podInitReceiver, res, System.currentTimeMillis(), profile)); - - rxBus.send(new EventDismissNotification(Notification.OMNIPOD_POD_NOT_ATTACHED)); - - cancelSuspendedFakeTbrIfExists(); - - return new PumpEnactResult(injector).success(true).enacted(true); - } catch (Exception ex) { - String comment = handleAndTranslateException(ex); - podInitReceiver.returnInitTaskStatus(podInitActionType, false, comment); - addFailureToHistory(PodHistoryEntryType.FILL_CANNULA_SET_BASAL_PROFILE, comment); + public PumpEnactResult insertCannula(Profile profile) { + if (profile == null) { + String comment = getStringResource(R.string.omnipod_error_set_initial_basal_schedule_no_profile); return new PumpEnactResult(injector).success(false).enacted(false).comment(comment); } + + PumpEnactResult result = new PumpEnactResult(injector); + + try { + BasalSchedule basalSchedule = mapProfileToBasalSchedule(profile); + + Boolean res = executeCommand(() -> delegate.insertCannula(basalSchedule, omnipodAlertUtil.getExpirationReminderTimeBeforeShutdown(), omnipodAlertUtil.getLowReservoirAlertUnits())) // + .blockingGet(); + + result.success(res).enacted(res); + if (!res) { + result.comment(R.string.omnipod_error_failed_to_insert_cannula); + } + } catch (Exception ex) { + result.success(false).enacted(false).comment(translateException(ex)); + } + + addToHistory(System.currentTimeMillis(), PodHistoryEntryType.INSERT_CANNULA, result.comment, result.success); + + if (result.success) { + uploadCareportalEvent(System.currentTimeMillis() - 2000, CareportalEvent.PUMPBATTERYCHANGE); + uploadCareportalEvent(System.currentTimeMillis() - 1000, CareportalEvent.INSULINCHANGE); + uploadCareportalEvent(System.currentTimeMillis(), CareportalEvent.SITECHANGE); + + sendEvent(new EventDismissNotification(Notification.OMNIPOD_POD_NOT_ATTACHED)); + + cancelSuspendedFakeTbrIfExists(); + } + + return result; } public PumpEnactResult configureAlerts(List alertConfigurations) { try { - StatusResponse statusResponse = delegate.configureAlerts(alertConfigurations); - addSuccessToHistory(PodHistoryEntryType.CONFIGURE_ALERTS, alertConfigurations); - return new PumpEnactResult(injector).success(true).enacted(false); + executeCommand(() -> delegate.configureAlerts(alertConfigurations)); } catch (Exception ex) { - String comment = handleAndTranslateException(ex); - addFailureToHistory(PodHistoryEntryType.CONFIGURE_ALERTS, comment); - return new PumpEnactResult(injector).success(false).enacted(false).comment(comment); + String errorMessage = translateException(ex); + addFailureToHistory(PodHistoryEntryType.CONFIGURE_ALERTS, errorMessage); + return new PumpEnactResult(injector).success(false).enacted(false).comment(errorMessage); } + + addSuccessToHistory(PodHistoryEntryType.CONFIGURE_ALERTS, alertConfigurations); + return new PumpEnactResult(injector).success(true).enacted(false); } public PumpEnactResult getPodStatus() { + StatusResponse statusResponse; + try { - StatusResponse statusResponse = delegate.getPodStatus(); - addSuccessToHistory(PodHistoryEntryType.GET_POD_STATUS, statusResponse); - return new PumpEnactResult(injector).success(true).enacted(false); + statusResponse = executeCommand(delegate::getPodStatus); } catch (Exception ex) { - String comment = handleAndTranslateException(ex); - addFailureToHistory(PodHistoryEntryType.GET_POD_STATUS, comment); - return new PumpEnactResult(injector).success(false).enacted(false).comment(comment); + String errorMessage = translateException(ex); + addFailureToHistory(PodHistoryEntryType.GET_POD_STATUS, errorMessage); + return new PumpEnactResult(injector).success(false).enacted(false).comment(errorMessage); } + + addSuccessToHistory(PodHistoryEntryType.GET_POD_STATUS, statusResponse); + return new PumpEnactResult(injector).success(true).enacted(false); } - public PumpEnactResult deactivatePod(PodInitReceiver podInitReceiver) { + public PumpEnactResult deactivatePod() { try { - delegate.deactivatePod(); + executeCommand(delegate::deactivatePod); } catch (Exception ex) { - String comment = handleAndTranslateException(ex); - podInitReceiver.returnInitTaskStatus(PodInitActionType.DEACTIVATE_POD_WIZARD_STEP, false, comment); - addFailureToHistory(PodHistoryEntryType.DEACTIVATE_POD, comment); - return new PumpEnactResult(injector).success(false).enacted(false).comment(comment); + String errorMessage = translateException(ex); + addFailureToHistory(PodHistoryEntryType.DEACTIVATE_POD, errorMessage); + return new PumpEnactResult(injector).success(false).enacted(false).comment(errorMessage); } addSuccessToHistory(PodHistoryEntryType.DEACTIVATE_POD, null); - createSuspendedFakeTbrIfNotExists(); - podInitReceiver.returnInitTaskStatus(PodInitActionType.DEACTIVATE_POD_WIZARD_STEP, true, null); - return new PumpEnactResult(injector).success(true).enacted(true); } - public PumpEnactResult setBasalProfile(Profile profile) { + public PumpEnactResult setBasalProfile(Profile profile, boolean showNotifications) { + if (profile == null) { + String note = getStringResource(R.string.omnipod_error_failed_to_set_profile_empty_profile); + showNotification(Notification.FAILED_UDPATE_PROFILE, note, Notification.URGENT, R.raw.boluserror); + return new PumpEnactResult(injector).success(false).enacted(false).comment(note); + } + PodHistoryEntryType historyEntryType = podStateManager.isSuspended() ? PodHistoryEntryType.RESUME_DELIVERY : PodHistoryEntryType.SET_BASAL_SCHEDULE; try { - BasalSchedule basalSchedule; - try { - basalSchedule = mapProfileToBasalSchedule(profile); - } catch (Exception ex) { - throw new CommandInitializationException("Basal profile mapping failed", ex); - } - delegate.setBasalSchedule(basalSchedule, isBasalBeepsEnabled()); - - if (historyEntryType == PodHistoryEntryType.RESUME_DELIVERY) { - cancelSuspendedFakeTbrIfExists(); - } - addSuccessToHistory(historyEntryType, profile.getBasalValues()); + BasalSchedule basalSchedule = mapProfileToBasalSchedule(profile); + executeCommand(() -> delegate.setBasalSchedule(basalSchedule, isBasalBeepsEnabled())); } catch (CommandFailedAfterChangingDeliveryStatusException ex) { createSuspendedFakeTbrIfNotExists(); - String comment = getStringResource(R.string.omnipod_error_set_basal_failed_delivery_suspended); - showNotification(Notification.FAILED_UDPATE_PROFILE, comment, Notification.URGENT, R.raw.boluserror); - addFailureToHistory(historyEntryType, comment); - return new PumpEnactResult(injector).success(false).enacted(false).comment(comment); - } catch (DeliveryStatusVerificationFailedException ex) { - String comment; - if (ex.getExpectedStatus() == DeliveryStatus.SUSPENDED) { - // Happened when suspending delivery before setting the new profile - comment = getStringResource(R.string.omnipod_error_set_basal_failed_delivery_might_be_suspended); - } else { - // Happened when setting the new profile (after suspending delivery) - comment = getStringResource(R.string.omnipod_error_set_basal_might_have_failed_delivery_might_be_suspended); + if (showNotifications) { + showNotification(Notification.FAILED_UDPATE_PROFILE, getStringResource(R.string.omnipod_error_set_basal_failed_delivery_suspended), Notification.URGENT, R.raw.boluserror); } - showNotification(Notification.FAILED_UDPATE_PROFILE, comment, Notification.URGENT, R.raw.boluserror); - addFailureToHistory(historyEntryType, comment); - return new PumpEnactResult(injector).success(false).enacted(false).comment(comment); + String errorMessage = translateException(ex.getCause()); + addFailureToHistory(historyEntryType, errorMessage); + return new PumpEnactResult(injector).success(false).enacted(false).comment(errorMessage); + } catch (DeliveryStatusVerificationFailedException ex) { + if (showNotifications) { + String note; + if (ex.getExpectedStatus() == DeliveryStatus.SUSPENDED) { + // Happened when suspending delivery before setting the new profile + note = getStringResource(R.string.omnipod_error_set_basal_failed_delivery_might_be_suspended); + } else { + // Happened when setting the new profile (after suspending delivery) + note = getStringResource(R.string.omnipod_error_set_basal_might_have_failed_delivery_might_be_suspended); + } + showNotification(Notification.FAILED_UDPATE_PROFILE, note, Notification.URGENT, R.raw.boluserror); + } + String errorMessage = translateException(ex.getCause()); + addFailureToHistory(historyEntryType, errorMessage); + return new PumpEnactResult(injector).success(false).enacted(false).comment(errorMessage); } catch (Exception ex) { - String comment = handleAndTranslateException(ex); - showNotification(Notification.FAILED_UDPATE_PROFILE, comment, Notification.URGENT, R.raw.boluserror); - addFailureToHistory(historyEntryType, comment); - return new PumpEnactResult(injector).success(false).enacted(false).comment(comment); + if (showNotifications) { + showNotification(Notification.FAILED_UDPATE_PROFILE, getStringResource(R.string.omnipod_error_set_basal_failed), Notification.URGENT, R.raw.boluserror); + } + String errorMessage = translateException(ex); + addFailureToHistory(historyEntryType, errorMessage); + return new PumpEnactResult(injector).success(false).enacted(false).comment(errorMessage); } - rxBus.send(new EventDismissNotification(Notification.OMNIPOD_POD_SUSPENDED)); - showNotification(Notification.PROFILE_SET_OK, - resourceHelper.gs(R.string.profile_set_ok), - Notification.INFO, null); + if (historyEntryType == PodHistoryEntryType.RESUME_DELIVERY) { + cancelSuspendedFakeTbrIfExists(); + sendEvent(new EventDismissNotification(Notification.OMNIPOD_POD_SUSPENDED)); + } + addSuccessToHistory(historyEntryType, profile.getBasalValues()); + + if (showNotifications) { + showNotification(Notification.PROFILE_SET_OK, resourceHelper.gs(R.string.profile_set_ok), Notification.INFO, null); + } return new PumpEnactResult(injector).success(true).enacted(true); } @@ -284,10 +313,13 @@ public class AapsOmnipodManager { public PumpEnactResult discardPodState() { podStateManager.discardState(); - addSuccessToHistory(System.currentTimeMillis(), PodHistoryEntryType.RESET_POD_STATE, null); + addSuccessToHistory(System.currentTimeMillis(), PodHistoryEntryType.DISCARD_POD, null); createSuspendedFakeTbrIfNotExists(); + sendEvent(new EventOmnipodPumpValuesChanged()); + rxBus.send(new EventRefreshOverview("Omnipod command: " + OmnipodCommandType.DISCARD_POD, false)); + return new PumpEnactResult(injector).success(true).enacted(true); } @@ -298,27 +330,27 @@ public class AapsOmnipodManager { Date bolusStarted; try { - bolusCommandResult = delegate.bolus(PumpType.Insulet_Omnipod.determineCorrectBolusSize(detailedBolusInfo.insulin), beepsEnabled, beepsEnabled, detailedBolusInfo.isSMB ? null : + bolusCommandResult = executeCommand(() -> delegate.bolus(PumpType.Insulet_Omnipod.determineCorrectBolusSize(detailedBolusInfo.insulin), beepsEnabled, beepsEnabled, detailedBolusInfo.isSMB ? null : (estimatedUnitsDelivered, percentage) -> { EventOverviewBolusProgress progressUpdateEvent = EventOverviewBolusProgress.INSTANCE; progressUpdateEvent.setStatus(getStringResource(R.string.bolusdelivering, detailedBolusInfo.insulin)); progressUpdateEvent.setPercent(percentage); sendEvent(progressUpdateEvent); - }); + })); bolusStarted = new Date(); } catch (Exception ex) { - String comment = handleAndTranslateException(ex); - addFailureToHistory(System.currentTimeMillis(), PodHistoryEntryType.SET_BOLUS, comment); - return new PumpEnactResult(injector).success(false).enacted(false).comment(comment); + String errorMessage = translateException(ex); + addFailureToHistory(System.currentTimeMillis(), PodHistoryEntryType.SET_BOLUS, errorMessage); + return new PumpEnactResult(injector).success(false).enacted(false).comment(errorMessage); } if (OmnipodManager.CommandDeliveryStatus.UNCERTAIN_FAILURE.equals(bolusCommandResult.getCommandDeliveryStatus())) { // For safety reasons, we treat this as a bolus that has successfully been delivered, in order to prevent insulin overdose if (detailedBolusInfo.isSMB) { - showNotification(getStringResource(R.string.omnipod_bolus_failed_uncertain_smb, detailedBolusInfo.insulin), Notification.URGENT, R.raw.boluserror); + showNotification(getStringResource(R.string.omnipod_error_bolus_failed_uncertain_smb, detailedBolusInfo.insulin), Notification.URGENT, R.raw.boluserror); } else { - showNotification(getStringResource(R.string.omnipod_bolus_failed_uncertain), Notification.URGENT, R.raw.boluserror); + showNotification(getStringResource(R.string.omnipod_error_bolus_failed_uncertain), Notification.URGENT, R.raw.boluserror); } } @@ -378,7 +410,7 @@ public class AapsOmnipodManager { aapsLogger.debug(LTag.PUMP, "Bolus command successfully executed. Proceeding bolus cancellation"); } else { aapsLogger.debug(LTag.PUMP, "Not cancelling bolus: bolus command failed"); - String comment = getStringResource(R.string.omnipod_bolus_did_not_succeed); + String comment = getStringResource(R.string.omnipod_error_bolus_did_not_succeed); addFailureToHistory(System.currentTimeMillis(), PodHistoryEntryType.CANCEL_BOLUS, comment); return new PumpEnactResult(injector).success(true).enacted(false).comment(comment); } @@ -387,19 +419,19 @@ public class AapsOmnipodManager { String comment = null; for (int i = 1; delegate.hasActiveBolus(); i++) { aapsLogger.debug(LTag.PUMP, "Attempting to cancel bolus (#{})", i); + try { - delegate.cancelBolus(isBolusBeepsEnabled()); + executeCommand(() -> delegate.cancelBolus(isBolusBeepsEnabled())); aapsLogger.debug(LTag.PUMP, "Successfully cancelled bolus", i); addSuccessToHistory(System.currentTimeMillis(), PodHistoryEntryType.CANCEL_BOLUS, null); return new PumpEnactResult(injector).success(true).enacted(true); } catch (PodFaultException ex) { aapsLogger.debug(LTag.PUMP, "Successfully cancelled bolus (implicitly because of a Pod Fault)"); - showPodFaultNotification(ex.getFaultEvent().getFaultEventCode()); addSuccessToHistory(System.currentTimeMillis(), PodHistoryEntryType.CANCEL_BOLUS, null); return new PumpEnactResult(injector).success(true).enacted(true); } catch (Exception ex) { aapsLogger.debug(LTag.PUMP, "Failed to cancel bolus", ex); - comment = handleAndTranslateException(ex); + comment = translateException(ex); } } @@ -410,19 +442,18 @@ public class AapsOmnipodManager { public PumpEnactResult setTemporaryBasal(TempBasalPair tempBasalPair) { boolean beepsEnabled = isTbrBeepsEnabled(); try { - delegate.setTemporaryBasal(PumpType.Insulet_Omnipod.determineCorrectBasalSize(tempBasalPair.getInsulinRate()), Duration.standardMinutes(tempBasalPair.getDurationMinutes()), beepsEnabled, beepsEnabled); + executeCommand(() -> delegate.setTemporaryBasal(PumpType.Insulet_Omnipod.determineCorrectBasalSize(tempBasalPair.getInsulinRate()), Duration.standardMinutes(tempBasalPair.getDurationMinutes()), beepsEnabled, beepsEnabled)); } catch (CommandFailedAfterChangingDeliveryStatusException ex) { - String comment = getStringResource(R.string.omnipod_cancelled_old_tbr_failed_to_set_new); - addFailureToHistory(PodHistoryEntryType.SET_TEMPORARY_BASAL, comment); - showNotification(comment, Notification.NORMAL, null); - return new PumpEnactResult(injector).success(false).enacted(false).comment(comment); + String errorMessage = translateException(ex.getCause()); + addFailureToHistory(PodHistoryEntryType.SET_TEMPORARY_BASAL, errorMessage); + return new PumpEnactResult(injector).success(false).enacted(false).comment(errorMessage); } catch (DeliveryStatusVerificationFailedException ex) { - String comment; + String errorMessage = translateException(ex.getCause()); + + String note; if (ex.getExpectedStatus() == DeliveryStatus.TEMP_BASAL_RUNNING) { // Happened after cancelling the old TBR, when attempting to set new TBR - - comment = getStringResource(R.string.omnipod_error_set_temp_basal_failed_old_tbr_cancelled_new_might_have_failed); - long pumpId = addFailureToHistory(PodHistoryEntryType.SET_TEMPORARY_BASAL, comment); + note = getStringResource(R.string.omnipod_error_set_temp_basal_failed_old_tbr_cancelled_new_might_have_failed); // Assume that setting the temp basal succeeded here, because in case it didn't succeed, // The next StatusResponse that we receive will allow us to recover from the wrong state @@ -430,19 +461,20 @@ public class AapsOmnipodManager { // If we would assume that the TBR didn't succeed, we couldn't properly recover upon the next StatusResponse, // as we could only see that the Pod is running a TBR, but we don't know the rate and duration as // the Pod doesn't provide this information + long pumpId = addFailureToHistory(PodHistoryEntryType.SET_TEMPORARY_BASAL, errorMessage); addTempBasalTreatment(System.currentTimeMillis(), pumpId, tempBasalPair); } else { // Happened when attempting to cancel the old TBR - comment = getStringResource(R.string.omnipod_error_set_temp_basal_failed_old_tbr_might_be_cancelled); - addFailureToHistory(PodHistoryEntryType.SET_TEMPORARY_BASAL, comment); + note = getStringResource(R.string.omnipod_error_set_temp_basal_failed_old_tbr_might_be_cancelled); + addFailureToHistory(PodHistoryEntryType.SET_TEMPORARY_BASAL, errorMessage); } + showNotification(note, Notification.URGENT, R.raw.boluserror); - showNotification(comment, Notification.URGENT, R.raw.boluserror); - return new PumpEnactResult(injector).success(false).enacted(false).comment(comment); + return new PumpEnactResult(injector).success(false).enacted(false).comment(errorMessage); } catch (Exception ex) { - String comment = handleAndTranslateException(ex); - addFailureToHistory(PodHistoryEntryType.SET_TEMPORARY_BASAL, comment); - return new PumpEnactResult(injector).success(false).enacted(false).comment(comment); + String errorMessage = translateException(ex); + addFailureToHistory(PodHistoryEntryType.SET_TEMPORARY_BASAL, errorMessage); + return new PumpEnactResult(injector).success(false).enacted(false).comment(errorMessage); } long pumpId = addSuccessToHistory(PodHistoryEntryType.SET_TEMPORARY_BASAL, tempBasalPair); @@ -454,11 +486,14 @@ public class AapsOmnipodManager { public PumpEnactResult cancelTemporaryBasal() { try { - delegate.cancelTemporaryBasal(isTbrBeepsEnabled()); + executeCommand(() -> delegate.cancelTemporaryBasal(isTbrBeepsEnabled())); } catch (Exception ex) { - String comment = handleAndTranslateException(ex); - addFailureToHistory(PodHistoryEntryType.CANCEL_TEMPORARY_BASAL, comment); - return new PumpEnactResult(injector).success(false).enacted(false).comment(comment); + if (ex instanceof OmnipodException && !((OmnipodException) ex).isCertainFailure()) { + showNotification(getStringResource(R.string.omnipod_error_cancel_temp_basal_failed_uncertain), Notification.URGENT, R.raw.boluserror); + } + String errorMessage = translateException(ex); + addFailureToHistory(PodHistoryEntryType.CANCEL_TEMPORARY_BASAL, errorMessage); + return new PumpEnactResult(injector).success(false).enacted(false).comment(errorMessage); } long pumpId = addSuccessToHistory(PodHistoryEntryType.CANCEL_TEMPORARY_BASAL, null); @@ -476,59 +511,63 @@ public class AapsOmnipodManager { public PumpEnactResult acknowledgeAlerts() { try { - delegate.acknowledgeAlerts(); - addSuccessToHistory(PodHistoryEntryType.ACKNOWLEDGE_ALERTS, null); + executeCommand(delegate::acknowledgeAlerts); } catch (Exception ex) { - String comment = handleAndTranslateException(ex); - addFailureToHistory(PodHistoryEntryType.ACKNOWLEDGE_ALERTS, comment); - return new PumpEnactResult(injector).success(false).enacted(false).comment(comment); + String errorMessage = translateException(ex); + addFailureToHistory(PodHistoryEntryType.ACKNOWLEDGE_ALERTS, errorMessage); + return new PumpEnactResult(injector).success(false).enacted(false).comment(errorMessage); } + + addSuccessToHistory(PodHistoryEntryType.ACKNOWLEDGE_ALERTS, null); return new PumpEnactResult(injector).success(true).enacted(true); } public PumpEnactResult suspendDelivery() { try { - delegate.suspendDelivery(isBasalBeepsEnabled()); + executeCommand(() -> delegate.suspendDelivery(isBasalBeepsEnabled())); } catch (Exception ex) { - String comment = handleAndTranslateException(ex); - addFailureToHistory(PodHistoryEntryType.SUSPEND_DELIVERY, comment); - return new PumpEnactResult(injector).success(false).enacted(false).comment(comment); + String errorMessage = translateException(ex); + addFailureToHistory(PodHistoryEntryType.SUSPEND_DELIVERY, errorMessage); + return new PumpEnactResult(injector).success(false).enacted(false).comment(errorMessage); } addSuccessToHistory(PodHistoryEntryType.SUSPEND_DELIVERY, null); - createSuspendedFakeTbrIfNotExists(); return new PumpEnactResult(injector).success(true).enacted(true); } // Updates the pods current time based on the device timezone and the pod's time zone - public PumpEnactResult setTime() { + public PumpEnactResult setTime(boolean showNotifications) { try { - delegate.setTime(isBasalBeepsEnabled()); - addSuccessToHistory(PodHistoryEntryType.SET_TIME, null); + executeCommand(() -> delegate.setTime(isBasalBeepsEnabled())); } catch (CommandFailedAfterChangingDeliveryStatusException ex) { createSuspendedFakeTbrIfNotExists(); - String comment = getStringResource(R.string.omnipod_error_set_time_failed_delivery_suspended); - showNotification(comment, Notification.URGENT, R.raw.boluserror); - addFailureToHistory(PodHistoryEntryType.SET_TIME, comment); - return new PumpEnactResult(injector).success(false).enacted(false).comment(comment); + if (showNotifications) { + showNotification(getStringResource(R.string.omnipod_error_set_time_failed_delivery_suspended), Notification.URGENT, R.raw.boluserror); + } + String errorMessage = translateException(ex.getCause()); + addFailureToHistory(PodHistoryEntryType.SET_TIME, errorMessage); + return new PumpEnactResult(injector).success(false).enacted(false).comment(errorMessage); } catch (DeliveryStatusVerificationFailedException ex) { - String comment = getStringResource(R.string.omnipod_error_set_time_failed_delivery_might_be_suspended); - showNotification(comment, Notification.URGENT, R.raw.boluserror); - addFailureToHistory(PodHistoryEntryType.SET_TIME, comment); - return new PumpEnactResult(injector).success(false).enacted(false).comment(comment); + if (showNotifications) { + showNotification(getStringResource(R.string.omnipod_error_set_time_failed_delivery_might_be_suspended), Notification.URGENT, R.raw.boluserror); + } + String errorMessage = translateException(ex.getCause()); + addFailureToHistory(PodHistoryEntryType.SET_TIME, errorMessage); + return new PumpEnactResult(injector).success(false).enacted(false).comment(errorMessage); } catch (Exception ex) { - String comment = handleAndTranslateException(ex); - addFailureToHistory(PodHistoryEntryType.SET_TIME, comment); - return new PumpEnactResult(injector).success(false).enacted(false).comment(comment); + String errorMessage = translateException(ex); + addFailureToHistory(PodHistoryEntryType.SET_TIME, errorMessage); + return new PumpEnactResult(injector).success(false).enacted(false).comment(errorMessage); } + addSuccessToHistory(PodHistoryEntryType.SET_TIME, null); return new PumpEnactResult(injector).success(true).enacted(true); } public PodInfoRecentPulseLog readPulseLog() { - PodInfoResponse response = delegate.getPodInfo(PodInfoType.RECENT_PULSE_LOG); + PodInfoResponse response = executeCommand(() -> delegate.getPodInfo(PodInfoType.RECENT_PULSE_LOG)); return (PodInfoRecentPulseLog) response.getPodInfo(); } @@ -660,7 +699,8 @@ public class AapsOmnipodManager { return addSuccessToHistory(System.currentTimeMillis(), entryType, data); } - private long addSuccessToHistory(long requestTime, PodHistoryEntryType entryType, Object data) { + private long addSuccessToHistory(long requestTime, PodHistoryEntryType entryType, Object + data) { return addToHistory(requestTime, entryType, data, true); } @@ -668,11 +708,13 @@ public class AapsOmnipodManager { return addFailureToHistory(System.currentTimeMillis(), entryType, data); } - private long addFailureToHistory(long requestTime, PodHistoryEntryType entryType, Object data) { + private long addFailureToHistory(long requestTime, PodHistoryEntryType entryType, Object + data) { return addToHistory(requestTime, entryType, data, false); } - private long addToHistory(long requestTime, PodHistoryEntryType entryType, Object data, boolean success) { + private long addToHistory(long requestTime, PodHistoryEntryType entryType, Object data, + boolean success) { OmnipodHistoryRecord omnipodHistoryRecord = new OmnipodHistoryRecord(requestTime, entryType.getCode()); if (data != null) { @@ -691,88 +733,91 @@ public class AapsOmnipodManager { return omnipodHistoryRecord.getPumpId(); } - private void handleSetupActionResult(PodInitActionType podInitActionType, PodInitReceiver podInitReceiver, SetupActionResult res, long time, Profile profile) { - String comment = null; - switch (res.getResultType()) { - case FAILURE: { - aapsLogger.error(LTag.PUMP, "Setup action failed: illegal setup progress: {}", res.getPodProgressStatus()); - comment = getStringResource(R.string.omnipod_driver_error_invalid_progress_state, res.getPodProgressStatus()); - } - break; - case VERIFICATION_FAILURE: { - aapsLogger.error(LTag.PUMP, "Setup action verification failed: caught exception", res.getException()); - comment = getStringResource(R.string.omnipod_driver_error_setup_action_verification_failed); - } - break; + private void executeCommand(Runnable runnable) { + try { + runnable.run(); + } catch (Exception ex) { + handleException(ex); + throw ex; } - - if (podInitActionType == PodInitActionType.PAIR_AND_PRIME_WIZARD_STEP) { - addToHistory(time, PodHistoryEntryType.PAIR_AND_PRIME, comment, res.getResultType().isSuccess()); - } else { - addToHistory(time, PodHistoryEntryType.FILL_CANNULA_SET_BASAL_PROFILE, res.getResultType().isSuccess() ? profile.getBasalValues() : comment, res.getResultType().isSuccess()); - } - - podInitReceiver.returnInitTaskStatus(podInitActionType, res.getResultType().isSuccess(), comment); } - private String handleAndTranslateException(Exception ex) { + private T executeCommand(Supplier supplier) { + try { + return supplier.get(); + } catch (Exception ex) { + handleException(ex); + throw ex; + } + } + + private void handleException(Exception ex) { + if (ex instanceof OmnipodException) { + aapsLogger.error(LTag.PUMP, String.format("Caught OmnipodException[certainFailure=%s] from OmnipodManager", ((OmnipodException) ex).isCertainFailure()), ex); + if (ex instanceof PodFaultException) { + FaultEventCode faultEventCode = ((PodFaultException) ex).getFaultEvent().getFaultEventCode(); + if (!(faultEventCode == FaultEventCode.NO_FAULTS && podStateManager.isPodInitialized() && podStateManager.getPodProgressStatus() == PodProgressStatus.ACTIVATION_TIME_EXCEEDED)) { + showPodFaultNotification(faultEventCode); + } + } + } else { + aapsLogger.error(LTag.PUMP, "Caught an unexpected non-OmnipodException from OmnipodManager", ex); + } + } + + public String translateException(Throwable ex) { String comment; - if (ex instanceof OmnipodException) { - if (ex instanceof ActionInitializationException || ex instanceof CommandInitializationException) { - comment = getStringResource(R.string.omnipod_driver_error_invalid_parameters); - } else if (ex instanceof CommunicationException) { - if (((CommunicationException) ex).getType() == CommunicationException.Type.TIMEOUT) { - comment = getStringResource(R.string.omnipod_driver_error_communication_failed_timeout); - } else { - comment = getStringResource(R.string.omnipod_driver_error_communication_failed_unexpected_exception); - } - } else if (ex instanceof CrcMismatchException) { - comment = getStringResource(R.string.omnipod_driver_error_crc_mismatch); - } else if (ex instanceof IllegalPacketTypeException) { - comment = getStringResource(R.string.omnipod_driver_error_invalid_packet_type); - } else if (ex instanceof IllegalPodProgressException || ex instanceof IllegalDeliveryStatusException) { - comment = getStringResource(R.string.omnipod_driver_error_invalid_progress_state); - } else if (ex instanceof IllegalVersionResponseTypeException) { - comment = getStringResource(R.string.omnipod_driver_error_invalid_response); - } else if (ex instanceof IllegalResponseException) { - comment = getStringResource(R.string.omnipod_driver_error_invalid_response); - } else if (ex instanceof IllegalMessageSequenceNumberException) { - comment = getStringResource(R.string.omnipod_driver_error_invalid_message_sequence_number); - } else if (ex instanceof IllegalMessageAddressException) { - comment = getStringResource(R.string.omnipod_driver_error_invalid_message_address); - } else if (ex instanceof MessageDecodingException) { - comment = getStringResource(R.string.omnipod_driver_error_message_decoding_failed); - } else if (ex instanceof NonceOutOfSyncException) { - comment = getStringResource(R.string.omnipod_driver_error_nonce_out_of_sync); - } else if (ex instanceof NonceResyncException) { - comment = getStringResource(R.string.omnipod_driver_error_nonce_resync_failed); - } else if (ex instanceof NotEnoughDataException) { - comment = getStringResource(R.string.omnipod_driver_error_not_enough_data); - } else if (ex instanceof PodFaultException) { - FaultEventCode faultEventCode = ((PodFaultException) ex).getFaultEvent().getFaultEventCode(); - showPodFaultNotification(faultEventCode); - comment = createPodFaultErrorMessage(faultEventCode); - } else if (ex instanceof PodReturnedErrorResponseException) { - comment = getStringResource(R.string.omnipod_driver_error_pod_returned_error_response); - } else { - // Shouldn't be reachable - comment = getStringResource(R.string.omnipod_driver_error_unexpected_exception_type, ex.getClass().getName()); - } - aapsLogger.error(LTag.PUMP, String.format("Caught OmnipodException[certainFailure=%s] from OmnipodManager (user-friendly error message: %s)", ((OmnipodException) ex).isCertainFailure(), comment), ex); + if (ex instanceof CrcMismatchException) { + comment = getStringResource(R.string.omnipod_error_crc_mismatch); + } else if (ex instanceof IllegalPacketTypeException) { + comment = getStringResource(R.string.omnipod_error_invalid_packet_type); + } else if (ex instanceof IllegalPodProgressException || ex instanceof IllegalDeliveryStatusException) { + comment = getStringResource(R.string.omnipod_error_invalid_progress_state); + } else if (ex instanceof IllegalVersionResponseTypeException) { + comment = getStringResource(R.string.omnipod_error_invalid_response); + } else if (ex instanceof IllegalResponseException) { + comment = getStringResource(R.string.omnipod_error_invalid_response); + } else if (ex instanceof IllegalMessageSequenceNumberException) { + comment = getStringResource(R.string.omnipod_error_invalid_message_sequence_number); + } else if (ex instanceof IllegalMessageAddressException) { + comment = getStringResource(R.string.omnipod_error_invalid_message_address); + } else if (ex instanceof MessageDecodingException) { + comment = getStringResource(R.string.omnipod_error_message_decoding_failed); + } else if (ex instanceof NonceOutOfSyncException) { + comment = getStringResource(R.string.omnipod_error_nonce_out_of_sync); + } else if (ex instanceof NonceResyncException) { + comment = getStringResource(R.string.omnipod_error_nonce_resync_failed); + } else if (ex instanceof NotEnoughDataException) { + comment = getStringResource(R.string.omnipod_error_not_enough_data); + } else if (ex instanceof PodFaultException) { + FaultEventCode faultEventCode = ((PodFaultException) ex).getFaultEvent().getFaultEventCode(); + comment = createPodFaultErrorMessage(faultEventCode); + } else if (ex instanceof PodReturnedErrorResponseException) { + comment = getStringResource(R.string.omnipod_error_pod_returned_error_response); + } else if (ex instanceof RileyLinkUnreachableException) { + comment = getStringResource(R.string.omnipod_error_communication_failed_no_response_from_riley_link); + } else if (ex instanceof RileyLinkInterruptedException) { + comment = getStringResource(R.string.omnipod_error_communication_failed_riley_link_interrupted); + } else if (ex instanceof RileyLinkTimeoutException) { + comment = getStringResource(R.string.omnipod_error_communication_failed_no_response_from_pod); + } else if (ex instanceof RileyLinkUnexpectedException) { + Throwable cause = ex.getCause(); + comment = getStringResource(R.string.omnipod_error_unexpected_exception, cause.getClass().getName(), cause.getMessage()); } else { - comment = getStringResource(R.string.omnipod_driver_error_unexpected_exception_type, ex.getClass().getName()); - aapsLogger.error(LTag.PUMP, String.format("Caught unexpected exception type[certainFailure=false] from OmnipodManager (user-friendly error message: %s)", comment), ex); + // Shouldn't be reachable + comment = getStringResource(R.string.omnipod_error_unexpected_exception, ex.getClass().getName(), ex.getMessage()); } return comment; } private String createPodFaultErrorMessage(FaultEventCode faultEventCode) { - String comment; - comment = getStringResource(R.string.omnipod_driver_error_pod_fault, + if (faultEventCode == FaultEventCode.NO_FAULTS && podStateManager.getPodProgressStatus() == PodProgressStatus.ACTIVATION_TIME_EXCEEDED) { + return getStringResource(R.string.omnipod_error_pod_fault_activation_time_exceeded); + } + return getStringResource(R.string.omnipod_error_pod_fault, ByteUtil.convertUnsignedByteToInt(faultEventCode.getValue()), faultEventCode.name()); - return comment; } private void sendEvent(Event event) { @@ -822,4 +867,29 @@ public class AapsOmnipodManager { return new BasalSchedule(entries); } + + private void uploadCareportalEvent(long date, String event) { + if (databaseHelper.getCareportalEventFromTimestamp(date) != null) + return; + try { + JSONObject data = new JSONObject(); + String enteredBy = sp.getString("careportal_enteredby", ""); + if (enteredBy.isEmpty()) { + data.put("enteredBy", enteredBy); + } + data.put("created_at", DateUtil.toISOString(date)); + data.put("mills", date); + data.put("eventType", event); + data.put("units", profileFunction.getUnits()); + CareportalEvent careportalEvent = new CareportalEvent(injector); + careportalEvent.date = date; + careportalEvent.source = Source.USER; + careportalEvent.eventType = event; + careportalEvent.json = data.toString(); + databaseHelper.createOrUpdate(careportalEvent); + nsUpload.uploadCareportalEntryToNS(data); + } catch (JSONException e) { + aapsLogger.error(LTag.PUMPCOMM, "Unhandled exception when uploading SiteChange event.", e); + } + } } diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/queue/command/CommandAcknowledgeAlerts.java b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/queue/command/CommandAcknowledgeAlerts.java new file mode 100644 index 0000000000..649623e05e --- /dev/null +++ b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/queue/command/CommandAcknowledgeAlerts.java @@ -0,0 +1,7 @@ +package info.nightscout.androidaps.plugins.pump.omnipod.queue.command; + +public final class CommandAcknowledgeAlerts extends OmnipodCustomCommand { + public CommandAcknowledgeAlerts() { + super(OmnipodCustomCommandType.ACKNOWLEDGE_ALERTS); + } +} diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/queue/command/CommandDeactivatePod.java b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/queue/command/CommandDeactivatePod.java new file mode 100644 index 0000000000..3921ec19d7 --- /dev/null +++ b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/queue/command/CommandDeactivatePod.java @@ -0,0 +1,7 @@ +package info.nightscout.androidaps.plugins.pump.omnipod.queue.command; + +public final class CommandDeactivatePod extends OmnipodCustomCommand { + public CommandDeactivatePod() { + super(OmnipodCustomCommandType.DEACTIVATE_POD); + } +} diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/queue/command/CommandGetPodStatus.java b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/queue/command/CommandGetPodStatus.java new file mode 100644 index 0000000000..0dfe7880f8 --- /dev/null +++ b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/queue/command/CommandGetPodStatus.java @@ -0,0 +1,7 @@ +package info.nightscout.androidaps.plugins.pump.omnipod.queue.command; + +public final class CommandGetPodStatus extends OmnipodCustomCommand { + public CommandGetPodStatus() { + super(OmnipodCustomCommandType.GET_POD_STATUS); + } +} diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/queue/command/CommandHandleTimeChange.java b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/queue/command/CommandHandleTimeChange.java new file mode 100644 index 0000000000..c760b401b5 --- /dev/null +++ b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/queue/command/CommandHandleTimeChange.java @@ -0,0 +1,14 @@ +package info.nightscout.androidaps.plugins.pump.omnipod.queue.command; + +public final class CommandHandleTimeChange extends OmnipodCustomCommand { + private final boolean requestedByUser; + + public CommandHandleTimeChange(boolean requestedByUser) { + super(OmnipodCustomCommandType.HANDLE_TIME_CHANGE); + this.requestedByUser = requestedByUser; + } + + public boolean isRequestedByUser() { + return requestedByUser; + } +} diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/queue/command/CommandReadPulseLog.java b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/queue/command/CommandReadPulseLog.java new file mode 100644 index 0000000000..5eb910c6db --- /dev/null +++ b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/queue/command/CommandReadPulseLog.java @@ -0,0 +1,7 @@ +package info.nightscout.androidaps.plugins.pump.omnipod.queue.command; + +public final class CommandReadPulseLog extends OmnipodCustomCommand { + public CommandReadPulseLog() { + super(OmnipodCustomCommandType.READ_PULSE_LOG); + } +} diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/queue/command/CommandResumeDelivery.java b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/queue/command/CommandResumeDelivery.java new file mode 100644 index 0000000000..fe3b07de9f --- /dev/null +++ b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/queue/command/CommandResumeDelivery.java @@ -0,0 +1,7 @@ +package info.nightscout.androidaps.plugins.pump.omnipod.queue.command; + +public final class CommandResumeDelivery extends OmnipodCustomCommand { + public CommandResumeDelivery() { + super(OmnipodCustomCommandType.RESUME_DELIVERY); + } +} diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/queue/command/CommandSuspendDelivery.java b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/queue/command/CommandSuspendDelivery.java new file mode 100644 index 0000000000..12dc8e8d42 --- /dev/null +++ b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/queue/command/CommandSuspendDelivery.java @@ -0,0 +1,7 @@ +package info.nightscout.androidaps.plugins.pump.omnipod.queue.command; + +public final class CommandSuspendDelivery extends OmnipodCustomCommand { + public CommandSuspendDelivery() { + super(OmnipodCustomCommandType.SUSPEND_DELIVERY); + } +} diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/queue/command/CommandUpdateAlertConfiguration.java b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/queue/command/CommandUpdateAlertConfiguration.java new file mode 100644 index 0000000000..4edc243845 --- /dev/null +++ b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/queue/command/CommandUpdateAlertConfiguration.java @@ -0,0 +1,7 @@ +package info.nightscout.androidaps.plugins.pump.omnipod.queue.command; + +public final class CommandUpdateAlertConfiguration extends OmnipodCustomCommand { + public CommandUpdateAlertConfiguration() { + super(OmnipodCustomCommandType.UPDATE_ALERT_CONFIGURATION); + } +} diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/queue/command/OmnipodCustomCommand.java b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/queue/command/OmnipodCustomCommand.java new file mode 100644 index 0000000000..06b2e2a051 --- /dev/null +++ b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/queue/command/OmnipodCustomCommand.java @@ -0,0 +1,21 @@ +package info.nightscout.androidaps.plugins.pump.omnipod.queue.command; + +import androidx.annotation.NonNull; + +import info.nightscout.androidaps.queue.commands.CustomCommand; + +public abstract class OmnipodCustomCommand implements CustomCommand { + private final OmnipodCustomCommandType type; + + OmnipodCustomCommand(@NonNull OmnipodCustomCommandType type) { + this.type = type; + } + + public final OmnipodCustomCommandType getType() { + return type; + } + + @Override public final String getStatusDescription() { + return type.getDescription(); + } +} diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/queue/command/OmnipodCustomCommandType.java b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/queue/command/OmnipodCustomCommandType.java new file mode 100644 index 0000000000..e6df62c47b --- /dev/null +++ b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/queue/command/OmnipodCustomCommandType.java @@ -0,0 +1,22 @@ +package info.nightscout.androidaps.plugins.pump.omnipod.queue.command; + +public enum OmnipodCustomCommandType { + ACKNOWLEDGE_ALERTS("ACKNOWLEDGE ALERTS"), + GET_POD_STATUS("GET POD STATUS"), + READ_PULSE_LOG("READ PULSE LOG"), + SUSPEND_DELIVERY("SUSPEND DELIVERY"), + RESUME_DELIVERY("RESUME DELIVERY"), + DEACTIVATE_POD("DEACTIVATE POD"), + HANDLE_TIME_CHANGE("HANDLE TIME CHANGE"), + UPDATE_ALERT_CONFIGURATION("UPDATE ALERT CONFIGURATION"); + + private final String description; + + OmnipodCustomCommandType(String description) { + this.description = description; + } + + String getDescription() { + return description; + } +} diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/rileylink/manager/OmnipodRileyLinkCommunicationManager.java b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/rileylink/manager/OmnipodRileyLinkCommunicationManager.java index 19b6b6a4a0..adb9e97e69 100644 --- a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/rileylink/manager/OmnipodRileyLinkCommunicationManager.java +++ b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/rileylink/manager/OmnipodRileyLinkCommunicationManager.java @@ -12,7 +12,6 @@ import info.nightscout.androidaps.logging.LTag; import info.nightscout.androidaps.plugins.pump.common.defs.PumpDeviceState; import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.RileyLinkCommunicationManager; import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.ble.RileyLinkCommunicationException; -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.common.hw.rileylink.ble.defs.RileyLinkBLEError; import info.nightscout.androidaps.plugins.pump.common.utils.ByteUtil; @@ -30,7 +29,6 @@ import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.Message import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.OmnipodConstants; import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.PacketType; import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.PodInfoType; -import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.CommunicationException; import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.IllegalMessageAddressException; import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.IllegalMessageSequenceNumberException; import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.IllegalPacketTypeException; @@ -41,13 +39,16 @@ import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.NotEnoug import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.OmnipodException; import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.PodFaultException; import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.PodReturnedErrorResponseException; +import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.RileyLinkTimeoutException; +import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.RileyLinkUnexpectedException; +import info.nightscout.androidaps.plugins.pump.omnipod.driver.exception.RileyLinkUnreachableException; import info.nightscout.androidaps.plugins.pump.omnipod.driver.manager.PodStateManager; /** * Created by andy on 6/29/18. */ @Singleton -public class OmnipodRileyLinkCommunicationManager extends RileyLinkCommunicationManager { +public class OmnipodRileyLinkCommunicationManager extends RileyLinkCommunicationManager { // This empty constructor must be kept, otherwise dagger injection might break! @Inject public OmnipodRileyLinkCommunicationManager() { @@ -69,7 +70,7 @@ public class OmnipodRileyLinkCommunicationManager extends RileyLinkCommunication } @Override - public RLMessage createResponseMessage(byte[] payload) { + public OmnipodPacket createResponseMessage(byte[] payload) { return new OmnipodPacket(payload); } @@ -137,7 +138,7 @@ public class OmnipodRileyLinkCommunicationManager extends RileyLinkCommunication if (responseClass.isInstance(responseMessageBlock)) { podStateManager.setLastSuccessfulCommunication(DateTime.now()); - return (T) responseMessageBlock; + return responseClass.cast(responseMessageBlock); } else { if (responseMessageBlock.getType() == MessageBlockType.ERROR_RESPONSE) { ErrorResponse error = (ErrorResponse) responseMessageBlock; @@ -194,13 +195,13 @@ public class OmnipodRileyLinkCommunicationManager extends RileyLinkCommunication // receive an ACK instead of a normal response, or a partial response and a communication timeout if (message.isNonceResyncable() && !message.containsBlock(DeactivatePodCommand.class)) { OmnipodMessage paddedMessage = new OmnipodMessage(message); - // If messages are nonce resyncable, we want do distinguish between certain and uncertain failures for verification purposes + // If messages are nonce resyncable, we want to distinguish between certain and uncertain failures for verification purposes // However, some commands (e.g. cancel delivery) are single packet command by nature. When we get a timeout with a single packet, // we are unsure whether or not the command was received by the pod // However, if we send > 1 packet, we know that the command wasn't received if we never send the subsequent packets, // because the last packet contains the CRC. // So we pad the message with get status commands to make it > packet - paddedMessage.padWithGetStatusCommands(PacketType.PDM.getMaxBodyLength()); // First packet is of type PDM + paddedMessage.padWithGetStatusCommands(PacketType.PDM.getMaxBodyLength(), aapsLogger); // First packet is of type PDM encodedMessage = paddedMessage.getEncoded(); } else { encodedMessage = message.getEncoded(); @@ -219,23 +220,16 @@ public class OmnipodRileyLinkCommunicationManager extends RileyLinkCommunication try { // We actually ignore previous (ack) responses if it was not last packet to send response = exchangePackets(podStateManager, packet); - } catch (Exception ex) { - OmnipodException newException; - if (ex instanceof OmnipodException) { - newException = (OmnipodException) ex; - } else { - newException = new CommunicationException(CommunicationException.Type.UNEXPECTED_EXCEPTION, ex); - } - + } catch (OmnipodException ex) { boolean lastPacket = encodedMessage.length == 0; // If this is not the last packet, the message wasn't fully sent, // so it's impossible for the pod to have received the message - newException.setCertainFailure(!lastPacket); + ex.setCertainFailure(!lastPacket); - aapsLogger.debug(LTag.PUMPBTCOMM, "Caught exception in transportMessages. Set certainFailure to {} because encodedMessage.length={}", newException.isCertainFailure(), encodedMessage.length); + aapsLogger.debug(LTag.PUMPBTCOMM, "Caught OmnipodException in transportMessages. Set certainFailure to {} because encodedMessage.length={}", ex.isCertainFailure(), encodedMessage.length); - throw newException; + throw ex; } } @@ -247,6 +241,7 @@ public class OmnipodRileyLinkCommunicationManager extends RileyLinkCommunication byte[] receivedMessageData = response.getEncodedMessage(); while (receivedMessage == null) { try { + aapsLogger.debug(LTag.PUMPBTCOMM, "Attempting to decode message: {}", ByteUtil.shortHexStringWithoutSpaces(receivedMessageData)); receivedMessage = OmnipodMessage.decodeMessage(receivedMessageData); if (receivedMessage.getAddress() != message.getAddress()) { throw new IllegalMessageAddressException(message.getAddress(), receivedMessage.getAddress()); @@ -261,18 +256,11 @@ public class OmnipodRileyLinkCommunicationManager extends RileyLinkCommunication OmnipodPacket ackForCon = createAckPacket(podStateManager, packetAddress, ackAddressOverride); - try { - OmnipodPacket conPacket = exchangePackets(podStateManager, ackForCon, 3, 40); - if (conPacket.getPacketType() != PacketType.CON) { - throw new IllegalPacketTypeException(PacketType.CON, conPacket.getPacketType()); - } - receivedMessageData = ByteUtil.concat(receivedMessageData, conPacket.getEncodedMessage()); - } catch (OmnipodException ex2) { - throw ex2; - } catch (Exception ex2) { - throw new CommunicationException(CommunicationException.Type.UNEXPECTED_EXCEPTION, ex2); + OmnipodPacket conPacket = exchangePackets(podStateManager, ackForCon, 3, 40); + if (conPacket.getPacketType() != PacketType.CON) { + throw new IllegalPacketTypeException(PacketType.CON, conPacket.getPacketType()); } - + receivedMessageData = ByteUtil.concat(receivedMessageData, conPacket.getEncodedMessage()); } } @@ -317,8 +305,6 @@ public class OmnipodRileyLinkCommunicationManager extends RileyLinkCommunication } } catch (OmnipodException ex) { aapsLogger.debug(LTag.PUMPBTCOMM, "Ignoring exception in ackUntilQuiet", ex); - } catch (Exception ex) { - throw new CommunicationException(CommunicationException.Type.UNEXPECTED_EXCEPTION, ex); } podStateManager.increasePacketNumber(); @@ -337,24 +323,32 @@ public class OmnipodRileyLinkCommunicationManager extends RileyLinkCommunication podStateManager.increasePacketNumber(); + boolean gotResponseFromRileyLink = false; + while (System.currentTimeMillis() < timeoutTime) { OmnipodPacket response; try { - response = (OmnipodPacket) sendAndListen(packet, responseTimeoutMilliseconds, repeatCount, 9, preambleExtensionMilliseconds); - } catch (RileyLinkCommunicationException | OmnipodException ex) { + response = sendAndListen(packet, responseTimeoutMilliseconds, repeatCount, 9, preambleExtensionMilliseconds); + gotResponseFromRileyLink = true; + } catch (RileyLinkCommunicationException ex) { + if (ex.getErrorCode() != RileyLinkBLEError.NoResponse) { + gotResponseFromRileyLink = true; + } + aapsLogger.debug(LTag.PUMPBTCOMM, "Ignoring exception in exchangePackets: " + ex.getClass().getSimpleName() + ": " + ex.getMessage()); + continue; + } catch (OmnipodException ex) { + gotResponseFromRileyLink = true; aapsLogger.debug(LTag.PUMPBTCOMM, "Ignoring exception in exchangePackets: " + ex.getClass().getSimpleName() + ": " + ex.getMessage()); continue; } catch (Exception ex) { - throw new CommunicationException(CommunicationException.Type.UNEXPECTED_EXCEPTION, ex); + throw new RileyLinkUnexpectedException(ex); } - if (response == null) { - aapsLogger.debug(LTag.PUMPBTCOMM, "exchangePackets response is null"); - continue; - } else if (!response.isValid()) { + if (!response.isValid()) { aapsLogger.debug(LTag.PUMPBTCOMM, "exchangePackets response is invalid: " + response); continue; } + if (response.getAddress() != packet.getAddress() && response.getAddress() != OmnipodConstants.DEFAULT_ADDRESS) { // In some (strange) cases, the Pod remains a packet address of 0xffffffff during it's lifetime aapsLogger.debug(LTag.PUMPBTCOMM, "Packet address " + response.getAddress() + " doesn't match " + packet.getAddress()); @@ -371,7 +365,12 @@ public class OmnipodRileyLinkCommunicationManager extends RileyLinkCommunication return response; } - throw new CommunicationException(CommunicationException.Type.TIMEOUT); + + if (gotResponseFromRileyLink) { + throw new RileyLinkTimeoutException(); + } + + throw new RileyLinkUnreachableException(); } } diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/OmnipodFragment.kt b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/OmnipodOverviewFragment.kt similarity index 55% rename from omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/OmnipodFragment.kt rename to omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/OmnipodOverviewFragment.kt index ca7382149e..055e7550d2 100644 --- a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/OmnipodFragment.kt +++ b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/OmnipodOverviewFragment.kt @@ -11,6 +11,7 @@ import android.view.View import android.view.ViewGroup import dagger.android.support.DaggerFragment import info.nightscout.androidaps.Constants +import info.nightscout.androidaps.activities.ErrorHelperActivity import info.nightscout.androidaps.events.EventPreferenceChange import info.nightscout.androidaps.interfaces.ActivePluginProvider import info.nightscout.androidaps.interfaces.CommandQueueProvider @@ -22,14 +23,14 @@ import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.dialog.RileyL import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.RileyLinkServiceData import info.nightscout.androidaps.plugins.pump.omnipod.OmnipodPumpPlugin import info.nightscout.androidaps.plugins.pump.omnipod.R -import info.nightscout.androidaps.plugins.pump.omnipod.definition.OmnipodStatusRequestType import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.OmnipodConstants import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.PodProgressStatus import info.nightscout.androidaps.plugins.pump.omnipod.driver.manager.PodStateManager import info.nightscout.androidaps.plugins.pump.omnipod.event.EventOmnipodPumpValuesChanged import info.nightscout.androidaps.plugins.pump.omnipod.manager.AapsOmnipodManager +import info.nightscout.androidaps.plugins.pump.omnipod.queue.command.* import info.nightscout.androidaps.plugins.pump.omnipod.util.AapsOmnipodUtil -import info.nightscout.androidaps.queue.commands.Command +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 @@ -42,17 +43,18 @@ import info.nightscout.androidaps.utils.sharedPreferences.SP import info.nightscout.androidaps.utils.ui.UIRunnable import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.disposables.CompositeDisposable -import io.reactivex.schedulers.Schedulers -import kotlinx.android.synthetic.main.omnipod_fragment.* +import kotlinx.android.synthetic.main.omnipod_overview.* import org.apache.commons.lang3.StringUtils import org.joda.time.DateTime import org.joda.time.Duration +import java.util.* import javax.inject.Inject +import kotlin.collections.ArrayList -class OmnipodFragment : DaggerFragment() { +class OmnipodOverviewFragment : DaggerFragment() { companion object { - private val REFRESH_INTERVAL_MILLIS = 15 * 1000L; // 15 seconds - private val PLACEHOLDER = "-"; // 15 seconds + private val REFRESH_INTERVAL_MILLIS = 15 * 1000L // 15 seconds + private val PLACEHOLDER = "-" // 15 seconds } @Inject lateinit var fabricPrivacy: FabricPrivacy @@ -83,18 +85,13 @@ class OmnipodFragment : DaggerFragment() { } override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { - return inflater.inflate(R.layout.omnipod_fragment, container, false) + return inflater.inflate(R.layout.omnipod_overview, container, false) } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - omnipod_button_resume_delivery.setOnClickListener { - disablePodActionButtons() - commandQueue.startPump(null) - } - - omnipod_button_pod_mgmt.setOnClickListener { + omnipod_overview_button_pod_management.setOnClickListener { if (omnipodPumpPlugin.rileyLinkService?.verifyConfiguration() == true) { activity?.let { activity -> protectionCheck.queryProtection( @@ -107,13 +104,19 @@ class OmnipodFragment : DaggerFragment() { } } - omnipod_button_refresh_status.setOnClickListener { + omnipod_overview_button_resume_delivery.setOnClickListener { disablePodActionButtons() - omnipodPumpPlugin.addPodStatusRequest(OmnipodStatusRequestType.GET_POD_STATE); - commandQueue.readStatus("Clicked Refresh", null) + commandQueue.customCommand(CommandResumeDelivery(), + DisplayResultDialogCallback(resourceHelper.gs(R.string.omnipod_error_failed_to_resume_delivery), true).messageOnSuccess(resourceHelper.gs(R.string.omnipod_confirmation_delivery_resumed))) } - omnipod_button_rileylink_stats.setOnClickListener { + omnipod_overview_button_refresh_status.setOnClickListener { + disablePodActionButtons() + commandQueue.customCommand(CommandGetPodStatus(), + DisplayResultDialogCallback(resourceHelper.gs(R.string.omnipod_error_failed_to_refresh_status), false)) + } + + omnipod_overview_button_rileylink_stats.setOnClickListener { if (omnipodPumpPlugin.rileyLinkService?.verifyConfiguration() == true) { startActivity(Intent(context, RileyLinkStatusActivity::class.java)) } else { @@ -121,22 +124,31 @@ class OmnipodFragment : DaggerFragment() { } } - omnipod_button_acknowledge_active_alerts.setOnClickListener { + omnipod_overview_button_acknowledge_active_alerts.setOnClickListener { disablePodActionButtons() - omnipodPumpPlugin.addPodStatusRequest(OmnipodStatusRequestType.ACKNOWLEDGE_ALERTS); - commandQueue.readStatus("Clicked Acknowledge Alert", null) + commandQueue.customCommand(CommandAcknowledgeAlerts(), + DisplayResultDialogCallback(resourceHelper.gs(R.string.omnipod_error_failed_to_acknowledge_alerts), false) + .messageOnSuccess(resourceHelper.gs(R.string.omnipod_confirmation_acknowledged_alerts))) } - omnipod_button_suspend_delivery.setOnClickListener { + omnipod_overview_button_suspend_delivery.setOnClickListener { disablePodActionButtons() - omnipodPumpPlugin.addPodStatusRequest(OmnipodStatusRequestType.SUSPEND_DELIVERY); - commandQueue.readStatus("Clicked Suspend Delivery", null) + commandQueue.customCommand(CommandSuspendDelivery(), + DisplayResultDialogCallback(resourceHelper.gs(R.string.omnipod_error_failed_to_suspend_delivery), true) + .messageOnSuccess(resourceHelper.gs(R.string.omnipod_confirmation_suspended_delivery))) } - omnipod_button_pulse_log.setOnClickListener { + omnipod_overview_button_set_time.setOnClickListener { disablePodActionButtons() - omnipodPumpPlugin.addPodStatusRequest(OmnipodStatusRequestType.GET_PULSE_LOG); - commandQueue.readStatus("Clicked Pulse Log", null) + commandQueue.customCommand(CommandHandleTimeChange(true), + DisplayResultDialogCallback(resourceHelper.gs(R.string.omnipod_error_failed_to_set_time), true) + .messageOnSuccess(resourceHelper.gs(R.string.omnipod_confirmation_time_on_pod_updated))) + } + + omnipod_overview_button_pulse_log.setOnClickListener { + disablePodActionButtons() + commandQueue.customCommand(CommandReadPulseLog(), + DisplayResultDialogCallback(resourceHelper.gs(R.string.omnipod_error_failed_to_read_pulse_log), false)) } } @@ -166,9 +178,9 @@ class OmnipodFragment : DaggerFragment() { }, { fabricPrivacy.logException(it) }) disposables += rxBus .toObservable(EventPreferenceChange::class.java) - .observeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) .subscribe({ - updatePulseLogButton() + updatePodActionButtons() }, { fabricPrivacy.logException(it) }) updateUi() } @@ -193,7 +205,7 @@ class OmnipodFragment : DaggerFragment() { val resourceId = rileyLinkServiceState.getResourceId() val rileyLinkError = rileyLinkServiceData.rileyLinkError - omnipod_rl_status.text = + omnipod_overview_riley_link_status.text = when { rileyLinkServiceState == RileyLinkServiceState.NotStarted -> resourceHelper.gs(resourceId) rileyLinkServiceState.isConnecting -> "{fa-bluetooth-b spin} " + resourceHelper.gs(resourceId) @@ -201,7 +213,7 @@ class OmnipodFragment : DaggerFragment() { rileyLinkServiceState.isError && rileyLinkError != null -> "{fa-bluetooth-b} " + resourceHelper.gs(rileyLinkError.getResourceId(RileyLinkTargetDevice.Omnipod)) else -> "{fa-bluetooth-b} " + resourceHelper.gs(resourceId) } - omnipod_rl_status.setTextColor(if (rileyLinkServiceState.isError || rileyLinkError != null) Color.RED else Color.WHITE) + omnipod_overview_riley_link_status.setTextColor(if (rileyLinkServiceState.isError || rileyLinkError != null) Color.RED else Color.WHITE) } private fun updateOmnipodStatus() { @@ -210,7 +222,7 @@ class OmnipodFragment : DaggerFragment() { updateTempBasal() updatePodStatus() - val errors = ArrayList(); + val errors = ArrayList() if (omnipodPumpPlugin.rileyLinkService != null) { val rileyLinkErrorDescription = omnipodPumpPlugin.rileyLinkService.errorDescription if (StringUtils.isNotEmpty(rileyLinkErrorDescription)) { @@ -219,32 +231,41 @@ class OmnipodFragment : DaggerFragment() { } if (!podStateManager.hasPodState() || !podStateManager.isPodInitialized) { - omnipod_pod_address.text = if (podStateManager.hasPodState()) { + omnipod_overview_pod_address.text = if (podStateManager.hasPodState()) { podStateManager.address.toString() } else { PLACEHOLDER } - omnipod_pod_lot.text = PLACEHOLDER - omnipod_pod_tid.text = PLACEHOLDER - omnipod_pod_firmware_version.text = PLACEHOLDER - omnipod_pod_expiry.text = PLACEHOLDER - omnipod_pod_expiry.setTextColor(Color.WHITE) - omnipod_base_basal_rate.text = PLACEHOLDER - omnipod_total_delivered.text = PLACEHOLDER - omnipod_reservoir.text = PLACEHOLDER - omnipod_pod_active_alerts.text = PLACEHOLDER + omnipod_overview_pod_lot.text = PLACEHOLDER + omnipod_overview_pod_tid.text = PLACEHOLDER + omnipod_overview_firmware_version.text = PLACEHOLDER + omnipod_overview_time_on_pod.text = PLACEHOLDER + omnipod_overview_pod_expiry_date.text = PLACEHOLDER + omnipod_overview_pod_expiry_date.setTextColor(Color.WHITE) + omnipod_overview_base_basal_rate.text = PLACEHOLDER + omnipod_overview_total_delivered.text = PLACEHOLDER + omnipod_overview_reservoir.text = PLACEHOLDER + omnipod_overview_reservoir.setTextColor(Color.WHITE) + omnipod_overview_pod_active_alerts.text = PLACEHOLDER } else { - omnipod_pod_address.text = podStateManager.address.toString() - omnipod_pod_lot.text = podStateManager.lot.toString() - omnipod_pod_tid.text = podStateManager.tid.toString() - omnipod_pod_firmware_version.text = resourceHelper.gs(R.string.omnipod_pod_firmware_version_value, podStateManager.pmVersion.toString(), podStateManager.piVersion.toString()) + omnipod_overview_pod_address.text = podStateManager.address.toString() + omnipod_overview_pod_lot.text = podStateManager.lot.toString() + omnipod_overview_pod_tid.text = podStateManager.tid.toString() + omnipod_overview_firmware_version.text = resourceHelper.gs(R.string.omnipod_firmware_version_value, podStateManager.pmVersion.toString(), podStateManager.piVersion.toString()) + + omnipod_overview_time_on_pod.text = readableZonedTime(podStateManager.time) + omnipod_overview_time_on_pod.setTextColor(if (podStateManager.timeDeviatesMoreThan(Duration.standardMinutes(5))) { + Color.RED + } else { + Color.WHITE + }) val expiresAt = podStateManager.expiresAt if (expiresAt == null) { - omnipod_pod_expiry.text = PLACEHOLDER - omnipod_pod_expiry.setTextColor(Color.WHITE) + omnipod_overview_pod_expiry_date.text = PLACEHOLDER + omnipod_overview_pod_expiry_date.setTextColor(Color.WHITE) } else { - omnipod_pod_expiry.text = dateUtil.dateAndTimeString(expiresAt.toDate()) - omnipod_pod_expiry.setTextColor(if (DateTime.now().isAfter(expiresAt)) { + omnipod_overview_pod_expiry_date.text = readableZonedTime(expiresAt) + omnipod_overview_pod_expiry_date.setTextColor(if (DateTime.now().isAfter(expiresAt)) { Color.RED } else { Color.WHITE @@ -259,29 +280,29 @@ class OmnipodFragment : DaggerFragment() { val now = DateTime.now() // base basal rate - omnipod_base_basal_rate.text = if (podStateManager.isPodActivationCompleted) { + omnipod_overview_base_basal_rate.text = if (podStateManager.isPodActivationCompleted) { resourceHelper.gs(R.string.pump_basebasalrate, omnipodPumpPlugin.model().determineCorrectBasalSize(podStateManager.basalSchedule.rateAt(Duration(now.withTimeAtStartOfDay(), now)))) } else { PLACEHOLDER } // total delivered - omnipod_total_delivered.text = if (podStateManager.isPodActivationCompleted && podStateManager.totalInsulinDelivered != null) { - resourceHelper.gs(R.string.omnipod_total_delivered, podStateManager.totalInsulinDelivered - OmnipodConstants.POD_SETUP_UNITS); + omnipod_overview_total_delivered.text = if (podStateManager.isPodActivationCompleted && podStateManager.totalInsulinDelivered != null) { + resourceHelper.gs(R.string.omnipod_overview_total_delivered_value, podStateManager.totalInsulinDelivered - OmnipodConstants.POD_SETUP_UNITS) } else { PLACEHOLDER } // reservoir if (podStateManager.reservoirLevel == null) { - omnipod_reservoir.text = resourceHelper.gs(R.string.omnipod_reservoir_over50) - omnipod_reservoir.setTextColor(Color.WHITE) + omnipod_overview_reservoir.text = resourceHelper.gs(R.string.omnipod_overview_reservoir_value_over50) + omnipod_overview_reservoir.setTextColor(Color.WHITE) } else { - omnipod_reservoir.text = resourceHelper.gs(R.string.omnipod_reservoir_left, podStateManager.reservoirLevel) - warnColors.setColorInverse(omnipod_reservoir, podStateManager.reservoirLevel, 50.0, 20.0) + omnipod_overview_reservoir.text = resourceHelper.gs(R.string.omnipod_overview_reservoir_value, podStateManager.reservoirLevel) + warnColors.setColorInverse(omnipod_overview_reservoir, podStateManager.reservoirLevel, 50.0, 20.0) } - omnipod_pod_active_alerts.text = if (podStateManager.hasActiveAlerts()) { + omnipod_overview_pod_active_alerts.text = if (podStateManager.hasActiveAlerts()) { TextUtils.join(System.lineSeparator(), omnipodUtil.getTranslatedActiveAlerts(podStateManager)) } else { PLACEHOLDER @@ -289,27 +310,27 @@ class OmnipodFragment : DaggerFragment() { } if (errors.size == 0) { - omnipod_errors.text = PLACEHOLDER - omnipod_errors.setTextColor(Color.WHITE) + omnipod_overview_errors.text = PLACEHOLDER + omnipod_overview_errors.setTextColor(Color.WHITE) } else { - omnipod_errors.text = StringUtils.join(errors, System.lineSeparator()) - omnipod_errors.setTextColor(Color.RED) + omnipod_overview_errors.text = StringUtils.join(errors, System.lineSeparator()) + omnipod_overview_errors.setTextColor(Color.RED) } } private fun updateLastConnection() { if (podStateManager.isPodInitialized && podStateManager.lastSuccessfulCommunication != null) { - omnipod_last_connection.text = readableDuration(podStateManager.lastSuccessfulCommunication) + omnipod_overview_last_connection.text = readableDuration(podStateManager.lastSuccessfulCommunication) val lastConnectionColor = if (omnipodPumpPlugin.isUnreachableAlertTimeoutExceeded(getPumpUnreachableTimeout().millis)) { Color.RED } else { Color.WHITE } - omnipod_last_connection.setTextColor(lastConnectionColor) + omnipod_overview_last_connection.setTextColor(lastConnectionColor) } else { - omnipod_last_connection.setTextColor(Color.WHITE) - omnipod_last_connection.text = if (podStateManager.hasPodState() && podStateManager.lastSuccessfulCommunication != null) { + omnipod_overview_last_connection.setTextColor(Color.WHITE) + omnipod_overview_last_connection.text = if (podStateManager.hasPodState() && podStateManager.lastSuccessfulCommunication != null) { readableDuration(podStateManager.lastSuccessfulCommunication) } else { PLACEHOLDER @@ -318,16 +339,16 @@ class OmnipodFragment : DaggerFragment() { } private fun updatePodStatus() { - omnipod_pod_status.text = if (!podStateManager.hasPodState()) { + omnipod_overview_pod_status.text = if (!podStateManager.hasPodState()) { resourceHelper.gs(R.string.omnipod_pod_status_no_active_pod) } else if (!podStateManager.isPodActivationCompleted) { if (!podStateManager.isPodInitialized) { - resourceHelper.gs(R.string.omnipod_pod_status_waiting_for_pair_and_prime) + resourceHelper.gs(R.string.omnipod_pod_status_waiting_for_activation) } else { if (PodProgressStatus.ACTIVATION_TIME_EXCEEDED == podStateManager.podProgressStatus) { resourceHelper.gs(R.string.omnipod_pod_status_activation_time_exceeded) } else if (podStateManager.podProgressStatus.isBefore(PodProgressStatus.PRIMING_COMPLETED)) { - resourceHelper.gs(R.string.omnipod_pod_status_waiting_for_pair_and_prime) + resourceHelper.gs(R.string.omnipod_pod_status_waiting_for_activation) } else { resourceHelper.gs(R.string.omnipod_pod_status_waiting_for_cannula_insertion) } @@ -353,12 +374,12 @@ class OmnipodFragment : DaggerFragment() { } else { Color.WHITE } - omnipod_pod_status.setTextColor(podStatusColor) + omnipod_overview_pod_status.setTextColor(podStatusColor) } private fun updateLastBolus() { if (podStateManager.isPodActivationCompleted && podStateManager.hasLastBolus()) { - var text = resourceHelper.gs(R.string.omnipod_last_bolus, omnipodPumpPlugin.model().determineCorrectBolusSize(podStateManager.lastBolusAmount), resourceHelper.gs(R.string.insulin_unit_shortname), readableDuration(podStateManager.lastBolusStartTime)) + var text = resourceHelper.gs(R.string.omnipod_overview_last_bolus_value, omnipodPumpPlugin.model().determineCorrectBolusSize(podStateManager.lastBolusAmount), resourceHelper.gs(R.string.insulin_unit_shortname), readableDuration(podStateManager.lastBolusStartTime)) val textColor: Int if (podStateManager.isLastBolusCertain) { @@ -368,12 +389,12 @@ class OmnipodFragment : DaggerFragment() { text += " (" + resourceHelper.gs(R.string.omnipod_uncertain) + ")" } - omnipod_last_bolus.text = text; - omnipod_last_bolus.setTextColor(textColor) + omnipod_overview_last_bolus.text = text + omnipod_overview_last_bolus.setTextColor(textColor) } else { - omnipod_last_bolus.text = PLACEHOLDER - omnipod_last_bolus.setTextColor(Color.WHITE) + omnipod_overview_last_bolus.text = PLACEHOLDER + omnipod_overview_last_bolus.setTextColor(Color.WHITE) } } @@ -381,15 +402,15 @@ class OmnipodFragment : DaggerFragment() { if (podStateManager.isPodActivationCompleted && podStateManager.isTempBasalRunning) { val now = DateTime.now() - val startTime = podStateManager.tempBasalStartTime; + val startTime = podStateManager.tempBasalStartTime val amount = podStateManager.tempBasalAmount - val duration = podStateManager.tempBasalDuration; + val duration = podStateManager.tempBasalDuration val minutesRunning = Duration(startTime, now).standardMinutes var text: String val textColor: Int - text = resourceHelper.gs(R.string.omnipod_temp_basal, amount, dateUtil.timeString(startTime.millis), minutesRunning, duration.standardMinutes) + text = resourceHelper.gs(R.string.omnipod_overview_temp_basal_value, amount, dateUtil.timeString(startTime.millis), minutesRunning, duration.standardMinutes) if (podStateManager.isTempBasalCertain) { textColor = Color.WHITE } else { @@ -397,20 +418,20 @@ class OmnipodFragment : DaggerFragment() { text += " (" + resourceHelper.gs(R.string.omnipod_uncertain) + ")" } - omnipod_temp_basal.text = text; - omnipod_temp_basal.setTextColor(textColor) + omnipod_overview_temp_basal.text = text + omnipod_overview_temp_basal.setTextColor(textColor) } else { - omnipod_temp_basal.text = PLACEHOLDER - omnipod_temp_basal.setTextColor(Color.WHITE) + omnipod_overview_temp_basal.text = PLACEHOLDER + omnipod_overview_temp_basal.setTextColor(Color.WHITE) } } private fun updateQueueStatus() { if (isQueueEmpty()) { - omnipod_queue.visibility = View.GONE + omnipod_overview_queue.visibility = View.GONE } else { - omnipod_queue.visibility = View.VISIBLE - omnipod_queue.text = commandQueue.spannedStatus().toString() + omnipod_overview_queue.visibility = View.VISIBLE + omnipod_overview_queue.text = commandQueue.spannedStatus().toString() } } @@ -419,62 +440,111 @@ class OmnipodFragment : DaggerFragment() { updateResumeDeliveryButton() updateAcknowledgeAlertsButton() updateSuspendDeliveryButton() + updateSetTimeButton() updatePulseLogButton() } private fun disablePodActionButtons() { - omnipod_button_acknowledge_active_alerts.isEnabled = false - omnipod_button_resume_delivery.isEnabled = false - omnipod_button_refresh_status.isEnabled = false - omnipod_button_pulse_log.isEnabled = false + omnipod_overview_button_acknowledge_active_alerts.isEnabled = false + omnipod_overview_button_resume_delivery.isEnabled = false + omnipod_overview_button_suspend_delivery.isEnabled = false + omnipod_overview_button_set_time.isEnabled = false + omnipod_overview_button_refresh_status.isEnabled = false + omnipod_overview_button_pulse_log.isEnabled = false } private fun updateRefreshStatusButton() { - omnipod_button_refresh_status.isEnabled = podStateManager.isPodInitialized && podStateManager.podProgressStatus.isAtLeast(PodProgressStatus.PAIRING_COMPLETED) + omnipod_overview_button_refresh_status.isEnabled = podStateManager.isPodInitialized && podStateManager.podProgressStatus.isAtLeast(PodProgressStatus.PAIRING_COMPLETED) && rileyLinkServiceData.rileyLinkServiceState.isReady && isQueueEmpty() } private fun updateResumeDeliveryButton() { - val queueEmptyOrStartingPump = isQueueEmpty() || commandQueue.isRunning(Command.CommandType.START_PUMP) - if (podStateManager.isPodActivationCompleted && podStateManager.isSuspended && queueEmptyOrStartingPump) { - omnipod_button_resume_delivery.visibility = View.VISIBLE - omnipod_button_resume_delivery.isEnabled = rileyLinkServiceData.rileyLinkServiceState.isReady && isQueueEmpty() + if (podStateManager.isPodRunning && (podStateManager.isSuspended || commandQueue.isCustomCommandInQueue(CommandResumeDelivery::class.java))) { + omnipod_overview_button_resume_delivery.visibility = View.VISIBLE + omnipod_overview_button_resume_delivery.isEnabled = rileyLinkServiceData.rileyLinkServiceState.isReady && isQueueEmpty() } else { - omnipod_button_resume_delivery.visibility = View.GONE + omnipod_overview_button_resume_delivery.visibility = View.GONE } } private fun updateAcknowledgeAlertsButton() { - omnipod_button_acknowledge_active_alerts.isEnabled = podStateManager.isPodActivationCompleted && podStateManager.hasActiveAlerts() - && !podStateManager.isPodDead && rileyLinkServiceData.rileyLinkServiceState.isReady && isQueueEmpty() + if (podStateManager.isPodRunning && (podStateManager.hasActiveAlerts() || commandQueue.isCustomCommandInQueue(CommandAcknowledgeAlerts::class.java))) { + omnipod_overview_button_acknowledge_active_alerts.visibility = View.VISIBLE + omnipod_overview_button_acknowledge_active_alerts.isEnabled = rileyLinkServiceData.rileyLinkServiceState.isReady && isQueueEmpty() + } else { + omnipod_overview_button_acknowledge_active_alerts.visibility = View.GONE + } } private fun updateSuspendDeliveryButton() { // If the Pod is currently suspended, we show the Resume delivery button instead. - if (omnipodManager.isSuspendDeliveryButtonEnabled && !(podStateManager.isPodRunning && podStateManager.isSuspended)) { - omnipod_button_suspend_delivery.visibility = View.VISIBLE - omnipod_button_suspend_delivery.isEnabled = podStateManager.isPodRunning && !podStateManager.isSuspended && rileyLinkServiceData.rileyLinkServiceState.isReady && isQueueEmpty() + if (omnipodManager.isSuspendDeliveryButtonEnabled && podStateManager.isPodRunning && (!podStateManager.isSuspended || commandQueue.isCustomCommandInQueue(CommandSuspendDelivery::class.java))) { + omnipod_overview_button_suspend_delivery.visibility = View.VISIBLE + omnipod_overview_button_suspend_delivery.isEnabled = podStateManager.isPodRunning && !podStateManager.isSuspended && rileyLinkServiceData.rileyLinkServiceState.isReady && isQueueEmpty() } else { - omnipod_button_suspend_delivery.visibility = View.GONE + omnipod_overview_button_suspend_delivery.visibility = View.GONE + } + } + + private fun updateSetTimeButton() { + if (podStateManager.isPodRunning && (podStateManager.timeDeviatesMoreThan(Duration.standardMinutes(5)) || commandQueue.isCustomCommandInQueue(CommandHandleTimeChange::class.java))) { + omnipod_overview_button_set_time.visibility = View.VISIBLE + omnipod_overview_button_set_time.isEnabled = !podStateManager.isSuspended && rileyLinkServiceData.rileyLinkServiceState.isReady && isQueueEmpty() + } else { + omnipod_overview_button_set_time.visibility = View.GONE } } private fun updatePulseLogButton() { if (omnipodManager.isPulseLogButtonEnabled) { - omnipod_button_pulse_log.visibility = View.VISIBLE - omnipod_button_pulse_log.isEnabled = podStateManager.isPodActivationCompleted && rileyLinkServiceData.rileyLinkServiceState.isReady && isQueueEmpty() + omnipod_overview_button_pulse_log.visibility = View.VISIBLE + omnipod_overview_button_pulse_log.isEnabled = podStateManager.isPodActivationCompleted && rileyLinkServiceData.rileyLinkServiceState.isReady && isQueueEmpty() } else { - omnipod_button_pulse_log.visibility = View.GONE + omnipod_overview_button_pulse_log.visibility = View.GONE } } private fun displayNotConfiguredDialog() { context?.let { - OKDialog.show(it, resourceHelper.gs(R.string.omnipod_warning), - resourceHelper.gs(R.string.omnipod_error_operation_not_possible_no_configuration), null) + UIRunnable(Runnable { + OKDialog.show(it, resourceHelper.gs(R.string.omnipod_warning), + resourceHelper.gs(R.string.omnipod_error_operation_not_possible_no_configuration), null) + }).run() } } + private fun displayErrorDialog(title: String, message: String, withSound: Boolean) { + context?.let { + val i = Intent(it, ErrorHelperActivity::class.java) + i.putExtra("soundid", if (withSound) R.raw.boluserror else 0) + i.putExtra("status", message) + i.putExtra("title", title) + i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + it.startActivity(i) + } + } + + private fun displayOkDialog(title: String, message: String) { + context?.let { + UIRunnable(Runnable { + OKDialog.show(it, title, message, null) + }).run() + } + } + + private fun readableZonedTime(time: DateTime): String { + val timeAsJavaData = time.toLocalDateTime().toDate() + val timeZone = podStateManager.timeZone.toTimeZone() + if (timeZone == TimeZone.getDefault()) { + return dateUtil.dateAndTimeString(timeAsJavaData) + } + + val isDaylightTime = timeZone.inDaylightTime(timeAsJavaData) + val locale = resources.configuration.locales.get(0) + val timeZoneDisplayName = timeZone.getDisplayName(isDaylightTime, TimeZone.SHORT, locale) + " " + timeZone.getDisplayName(isDaylightTime, TimeZone.LONG, locale) + return resourceHelper.gs(R.string.omnipod_time_with_timezone, dateUtil.dateAndTimeString(timeAsJavaData), timeZoneDisplayName) + } + private fun readableDuration(dateTime: DateTime): String { val duration = Duration(dateTime, DateTime.now()) val hours = duration.standardHours.toInt() @@ -521,4 +591,24 @@ class OmnipodFragment : DaggerFragment() { return Duration.standardMinutes(sp.getInt(resourceHelper.gs(R.string.key_pump_unreachable_threshold_minutes), Constants.DEFAULT_PUMP_UNREACHABLE_THRESHOLD_MINUTES).toLong()) } + inner class DisplayResultDialogCallback(private val errorMessagePrefix: String, private val withSoundOnError: Boolean) : Callback() { + private var messageOnSuccess: String? = null + + override fun run() { + if (result.success) { + val messageOnSuccess = this.messageOnSuccess + if (messageOnSuccess != null) { + displayOkDialog(resourceHelper.gs(R.string.omnipod_confirmation), messageOnSuccess) + } + } else { + displayErrorDialog(resourceHelper.gs(R.string.omnipod_warning), resourceHelper.gs(R.string.omnipod_two_strings_concatenated_by_colon, errorMessagePrefix, result.comment), withSoundOnError) + } + } + + fun messageOnSuccess(message: String): DisplayResultDialogCallback { + messageOnSuccess = message + return this + } + } + } diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/PodHistoryActivity.java b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/PodHistoryActivity.java index 4913bb6614..ff8319a557 100644 --- a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/PodHistoryActivity.java +++ b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/PodHistoryActivity.java @@ -250,11 +250,11 @@ public class PodHistoryActivity extends NoSplashAppCompatActivity { case SET_TEMPORARY_BASAL: { TempBasalPair tempBasalPair = aapsOmnipodUtil.getGsonInstance().fromJson(historyEntry.getData(), TempBasalPair.class); - valueView.setText(resourceHelper.gs(R.string.omnipod_cmd_tbr_value, tempBasalPair.getInsulinRate(), tempBasalPair.getDurationMinutes())); + valueView.setText(resourceHelper.gs(R.string.omnipod_history_tbr_value, tempBasalPair.getInsulinRate(), tempBasalPair.getDurationMinutes())); } break; - case FILL_CANNULA_SET_BASAL_PROFILE: + case INSERT_CANNULA: case SET_BASAL_SCHEDULE: { if (historyEntry.getData() != null) { setProfileValue(historyEntry.getData(), valueView); @@ -265,9 +265,9 @@ public class PodHistoryActivity extends NoSplashAppCompatActivity { case SET_BOLUS: { if (historyEntry.getData().contains(";")) { String[] splitVal = historyEntry.getData().split(";"); - valueView.setText(resourceHelper.gs(R.string.omnipod_cmd_bolus_value_with_carbs, Double.valueOf(splitVal[0]), Double.valueOf(splitVal[1]))); + valueView.setText(resourceHelper.gs(R.string.omnipod_history_bolus_value_with_carbs, Double.valueOf(splitVal[0]), Double.valueOf(splitVal[1]))); } else { - valueView.setText(resourceHelper.gs(R.string.omnipod_cmd_bolus_value, Double.valueOf(historyEntry.getData()))); + valueView.setText(resourceHelper.gs(R.string.omnipod_history_bolus_value, Double.valueOf(historyEntry.getData()))); } } break; @@ -275,13 +275,13 @@ public class PodHistoryActivity extends NoSplashAppCompatActivity { case GET_POD_STATUS: case GET_POD_INFO: case SET_TIME: - case PAIR_AND_PRIME: + case INITIALIZE_POD: case CANCEL_TEMPORARY_BASAL_BY_DRIVER: case CANCEL_TEMPORARY_BASAL: case CONFIGURE_ALERTS: case CANCEL_BOLUS: case DEACTIVATE_POD: - case RESET_POD_STATE: + case DISCARD_POD: case ACKNOWLEDGE_ALERTS: case SUSPEND_DELIVERY: case RESUME_DELIVERY: diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/PodManagementActivity.kt b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/PodManagementActivity.kt index 43f4046a5e..03ee8035ae 100644 --- a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/PodManagementActivity.kt +++ b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/PodManagementActivity.kt @@ -2,13 +2,6 @@ package info.nightscout.androidaps.plugins.pump.omnipod.ui import android.content.Intent import android.os.Bundle -import android.view.View -import android.widget.LinearLayout -import androidx.fragment.app.FragmentStatePagerAdapter -import com.atech.android.library.wizardpager.WizardPagerActivity -import com.atech.android.library.wizardpager.WizardPagerContext -import com.atech.android.library.wizardpager.data.WizardPagerSettings -import com.atech.android.library.wizardpager.defs.WizardStepsWayType import dagger.android.HasAndroidInjector import info.nightscout.androidaps.activities.NoSplashAppCompatActivity import info.nightscout.androidaps.interfaces.CommandQueueProvider @@ -16,22 +9,19 @@ import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.pump.common.events.EventRileyLinkDeviceStatusChange import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.RileyLinkServiceData import info.nightscout.androidaps.plugins.pump.omnipod.R -import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.PodProgressStatus import info.nightscout.androidaps.plugins.pump.omnipod.driver.manager.PodStateManager import info.nightscout.androidaps.plugins.pump.omnipod.event.EventOmnipodPumpValuesChanged import info.nightscout.androidaps.plugins.pump.omnipod.manager.AapsOmnipodManager -import info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.defs.PodActionType -import info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.model.FullInitPodWizardModel -import info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.model.RemovePodWizardModel -import info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.model.ShortInitPodWizardModel -import info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.pages.InitPodRefreshAction +import info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.activation.PodActivationWizardActivity +import info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.deactivation.PodDeactivationWizardActivity import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.alertDialogs.OKDialog import info.nightscout.androidaps.utils.extensions.plusAssign +import info.nightscout.androidaps.utils.extensions.toVisibility import info.nightscout.androidaps.utils.resources.ResourceHelper import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.disposables.CompositeDisposable -import kotlinx.android.synthetic.main.omnipod_pod_mgmt.* +import kotlinx.android.synthetic.main.omnipod_pod_management.* import javax.inject.Inject /** @@ -52,22 +42,25 @@ class PodManagementActivity : NoSplashAppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setContentView(R.layout.omnipod_pod_mgmt) + setContentView(R.layout.omnipod_pod_management) - initpod_init_pod.setOnClickListener { - initPodAction() + omnipod_pod_management_button_activate_pod.setOnClickListener { + startActivity(Intent(this, PodActivationWizardActivity::class.java)) } - initpod_remove_pod.setOnClickListener { - deactivatePodAction() + omnipod_pod_management_button_deactivate_pod.setOnClickListener { + startActivity(Intent(this, PodDeactivationWizardActivity::class.java)) } - initpod_reset_pod.setOnClickListener { - discardPodAction() + omnipod_pod_management_button_discard_pod.setOnClickListener { + OKDialog.showConfirmation(this, + resourceHelper.gs(R.string.omnipod_pod_management_discard_pod_state_confirmation), Thread { + aapsOmnipodManager.discardPodState() + }) } - initpod_pod_history.setOnClickListener { - showPodHistory() + omnipod_pod_management_button_pod_history.setOnClickListener { + startActivity(Intent(this, PodHistoryActivity::class.java)) } } @@ -90,86 +83,27 @@ class PodManagementActivity : NoSplashAppCompatActivity() { disposables.clear() } - private fun initPodAction() { - - val pagerSettings = WizardPagerSettings() - var refreshAction = InitPodRefreshAction(injector, PodActionType.INIT_POD) - - pagerSettings.setWizardStepsWayType(WizardStepsWayType.CancelNext) - pagerSettings.setFinishStringResourceId(R.string.close) - pagerSettings.setFinishButtonBackground(R.drawable.finish_background) - pagerSettings.setNextButtonBackground(R.drawable.selectable_item_background) - pagerSettings.setBackStringResourceId(R.string.cancel) - pagerSettings.cancelAction = refreshAction - pagerSettings.finishAction = refreshAction - pagerSettings.pagerAdapterBehavior = FragmentStatePagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT - - val wizardPagerContext = WizardPagerContext.getInstance() - - wizardPagerContext.clearContext() - wizardPagerContext.pagerSettings = pagerSettings - val isFullInit = !podStateManager.isPodInitialized || podStateManager.podProgressStatus.isBefore(PodProgressStatus.PRIMING_COMPLETED) - if (isFullInit) { - wizardPagerContext.wizardModel = FullInitPodWizardModel(applicationContext) - } else { - wizardPagerContext.wizardModel = ShortInitPodWizardModel(applicationContext) - } - - val myIntent = Intent(this@PodManagementActivity, WizardPagerActivity::class.java) - this@PodManagementActivity.startActivity(myIntent) - } - - private fun deactivatePodAction() { - val pagerSettings = WizardPagerSettings() - var refreshAction = InitPodRefreshAction(injector, PodActionType.DEACTIVATE_POD) - - pagerSettings.setWizardStepsWayType(WizardStepsWayType.CancelNext) - pagerSettings.setFinishStringResourceId(R.string.close) - pagerSettings.setFinishButtonBackground(R.drawable.finish_background) - pagerSettings.setNextButtonBackground(R.drawable.selectable_item_background) - pagerSettings.setBackStringResourceId(R.string.cancel) - pagerSettings.cancelAction = refreshAction - pagerSettings.finishAction = refreshAction - pagerSettings.pagerAdapterBehavior = FragmentStatePagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT - - val wizardPagerContext = WizardPagerContext.getInstance(); - - wizardPagerContext.clearContext() - wizardPagerContext.pagerSettings = pagerSettings - wizardPagerContext.wizardModel = RemovePodWizardModel(applicationContext) - - val myIntent = Intent(this@PodManagementActivity, WizardPagerActivity::class.java) - this@PodManagementActivity.startActivity(myIntent) - - } - - private fun discardPodAction() { - OKDialog.showConfirmation(this, - resourceHelper.gs(R.string.omnipod_cmd_discard_pod_desc), Thread { - aapsOmnipodManager.discardPodState() - rxBus.send(EventOmnipodPumpValuesChanged()) - }) - } - - private fun showPodHistory() { - startActivity(Intent(applicationContext, PodHistoryActivity::class.java)) - } - private fun refreshButtons() { - initpod_init_pod.isEnabled = !podStateManager.isPodActivationCompleted - initpod_remove_pod.isEnabled = podStateManager.isPodInitialized - initpod_reset_pod.isEnabled = podStateManager.hasPodState() - - val waitingForRlView = findViewById(R.id.initpod_waiting_for_rl_layout) + // Only show the discard button to reset a cached Pod address before the Pod has actually been initialized + // Otherwise, users should use the Deactivate Pod Wizard. In case proper deactivation fails, + // they will get an option to discard the Pod state there + // TODO maybe rename this button and the confirmation dialog text (see onCreate) + val discardButtonEnabled = podStateManager.hasPodState() && !podStateManager.isPodInitialized + omnipod_pod_management_button_discard_pod.visibility = discardButtonEnabled.toVisibility() + omnipod_pod_management_waiting_for_rl_layout.visibility = (!rileyLinkServiceData.rileyLinkServiceState.isReady).toVisibility() if (rileyLinkServiceData.rileyLinkServiceState.isReady) { - waitingForRlView.visibility = View.GONE + omnipod_pod_management_button_activate_pod.isEnabled = !podStateManager.isPodActivationCompleted + omnipod_pod_management_button_deactivate_pod.isEnabled = podStateManager.isPodInitialized + if (discardButtonEnabled) { + omnipod_pod_management_button_discard_pod.isEnabled = true + } } else { - // if rileylink is not running we disable all operations that require a RL connection - waitingForRlView.visibility = View.VISIBLE - initpod_init_pod.isEnabled = false - initpod_remove_pod.isEnabled = false - initpod_reset_pod.isEnabled = false + omnipod_pod_management_button_activate_pod.isEnabled = false + omnipod_pod_management_button_deactivate_pod.isEnabled = false + if (discardButtonEnabled) { + omnipod_pod_management_button_discard_pod.isEnabled = false + } } } diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/activation/PodActivationWizardActivity.kt b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/activation/PodActivationWizardActivity.kt new file mode 100644 index 0000000000..183c3c239c --- /dev/null +++ b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/activation/PodActivationWizardActivity.kt @@ -0,0 +1,60 @@ +package info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.activation + +import android.os.Bundle +import androidx.annotation.IdRes +import info.nightscout.androidaps.plugins.pump.omnipod.R +import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.PodProgressStatus +import info.nightscout.androidaps.plugins.pump.omnipod.driver.manager.PodStateManager +import info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.common.activity.OmnipodWizardActivityBase +import javax.inject.Inject + +class PodActivationWizardActivity : OmnipodWizardActivityBase() { + companion object { + const val KEY_START_DESTINATION = "startDestination" + } + + @Inject + lateinit var podStateManager: PodStateManager + + @IdRes + private var startDestination: Int = R.id.fillPodInfoFragment + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + setContentView(R.layout.omnipod_pod_activation_wizard_activity) + + startDestination = savedInstanceState?.getInt(KEY_START_DESTINATION, R.id.fillPodInfoFragment) + ?: if (!podStateManager.isPodInitialized || podStateManager.podProgressStatus.isBefore(PodProgressStatus.PRIMING_COMPLETED)) { + R.id.fillPodInfoFragment + } else { + R.id.attachPodInfoFragment + } + + setStartDestination(startDestination) + } + + private fun setStartDestination(@IdRes startDestination: Int) { + this.startDestination = startDestination + val navController = getNavController() + val navInflater = navController.navInflater + val graph = navInflater.inflate(R.navigation.omnipod_pod_activation_wizard_navigation_graph) + graph.startDestination = startDestination + navController.graph = graph + } + + override fun onSaveInstanceState(outState: Bundle) { + super.onSaveInstanceState(outState) + outState.putInt(KEY_START_DESTINATION, startDestination) + } + + override fun getTotalDefinedNumberOfSteps(): Int = 5 + + override fun getActualNumberOfSteps(): Int { + if (startDestination == R.id.attachPodInfoFragment) { + return 3 + } + return 5 + } + +} \ No newline at end of file diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/activation/fragment/AttachPodInfoFragment.kt b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/activation/fragment/AttachPodInfoFragment.kt new file mode 100644 index 0000000000..5642750a20 --- /dev/null +++ b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/activation/fragment/AttachPodInfoFragment.kt @@ -0,0 +1,38 @@ +package info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.activation.fragment + +import android.app.AlertDialog +import android.os.Bundle +import android.view.View +import androidx.annotation.IdRes +import androidx.annotation.StringRes +import androidx.navigation.fragment.findNavController +import info.nightscout.androidaps.plugins.pump.omnipod.R +import info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.common.fragment.InfoFragmentBase +import kotlinx.android.synthetic.main.omnipod_wizard_nav_buttons.* + +class AttachPodInfoFragment : InfoFragmentBase() { + @StringRes + override fun getTitleId(): Int = R.string.omnipod_pod_activation_wizard_attach_pod_title + + @StringRes + override fun getTextId(): Int = R.string.omnipod_pod_activation_wizard_attach_pod_text + + @IdRes + override fun getNextPageActionId(): Int = R.id.action_attachPodInfoFragment_to_insertCannulaActionFragment + + override fun getIndex(): Int = 3 + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + omnipod_wizard_button_next.setOnClickListener { + AlertDialog.Builder(context) + .setIcon(android.R.drawable.ic_dialog_alert) + .setTitle(getString(getTitleId())) + .setMessage(getString(R.string.omnipod_pod_activation_wizard_attach_pod_confirm_insert_cannula_text)) + .setPositiveButton(getString(R.string.omnipod_ok)) { _, _ -> findNavController().navigate(getNextPageActionId()) } + .setNegativeButton(getString(R.string.omnipod_cancel), null) + .show() + } + } +} \ No newline at end of file diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/activation/fragment/FillPodInfoFragment.kt b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/activation/fragment/FillPodInfoFragment.kt new file mode 100644 index 0000000000..425ff1e7ea --- /dev/null +++ b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/activation/fragment/FillPodInfoFragment.kt @@ -0,0 +1,19 @@ +package info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.activation.fragment + +import androidx.annotation.IdRes +import androidx.annotation.StringRes +import info.nightscout.androidaps.plugins.pump.omnipod.R +import info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.common.fragment.InfoFragmentBase + +class FillPodInfoFragment : InfoFragmentBase() { + @StringRes + override fun getTitleId(): Int = R.string.omnipod_pod_activation_wizard_fill_pod_title + + @StringRes + override fun getTextId(): Int = R.string.omnipod_pod_activation_wizard_fill_pod_text + + @IdRes + override fun getNextPageActionId(): Int = R.id.action_fillPodInfoFragment_to_initializePodActionFragment + + override fun getIndex(): Int = 1 +} \ No newline at end of file diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/activation/fragment/InitializePodActionFragment.kt b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/activation/fragment/InitializePodActionFragment.kt new file mode 100644 index 0000000000..bc10c3daf1 --- /dev/null +++ b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/activation/fragment/InitializePodActionFragment.kt @@ -0,0 +1,35 @@ +package info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.activation.fragment + +import android.os.Bundle +import androidx.annotation.IdRes +import androidx.annotation.StringRes +import androidx.fragment.app.viewModels +import androidx.lifecycle.ViewModelProvider +import info.nightscout.androidaps.plugins.pump.omnipod.R +import info.nightscout.androidaps.plugins.pump.omnipod.dagger.OmnipodPluginQualifier +import info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.activation.viewmodel.InitializePodActionViewModel +import javax.inject.Inject + +class InitializePodActionFragment : PodActivationActionFragmentBase() { + @Inject + @OmnipodPluginQualifier + lateinit var viewModelFactory: ViewModelProvider.Factory + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + val vm: InitializePodActionViewModel by viewModels { viewModelFactory } + this.viewModel = vm + } + + @StringRes + override fun getTitleId(): Int = R.string.omnipod_pod_activation_wizard_initialize_pod_title + + @StringRes + override fun getTextId(): Int = R.string.omnipod_pod_activation_wizard_initialize_pod_text + + @IdRes + override fun getNextPageActionId(): Int = R.id.action_initializePodActionFragment_to_attachPodInfoFragment + + override fun getIndex(): Int = 2 +} \ No newline at end of file diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/activation/fragment/InsertCannulaActionFragment.kt b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/activation/fragment/InsertCannulaActionFragment.kt new file mode 100644 index 0000000000..009318c60d --- /dev/null +++ b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/activation/fragment/InsertCannulaActionFragment.kt @@ -0,0 +1,35 @@ +package info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.activation.fragment + +import android.os.Bundle +import androidx.annotation.IdRes +import androidx.annotation.StringRes +import androidx.fragment.app.viewModels +import androidx.lifecycle.ViewModelProvider +import info.nightscout.androidaps.plugins.pump.omnipod.R +import info.nightscout.androidaps.plugins.pump.omnipod.dagger.OmnipodPluginQualifier +import info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.activation.viewmodel.InsertCannulaActionViewModel +import javax.inject.Inject + +class InsertCannulaActionFragment : PodActivationActionFragmentBase() { + @Inject + @OmnipodPluginQualifier + lateinit var viewModelFactory: ViewModelProvider.Factory + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + val vm: InsertCannulaActionViewModel by viewModels { viewModelFactory } + this.viewModel = vm + } + + @StringRes + override fun getTitleId(): Int = R.string.omnipod_pod_activation_wizard_insert_cannula_title + + @StringRes + override fun getTextId(): Int = R.string.omnipod_pod_activation_wizard_insert_cannula_text + + @IdRes + override fun getNextPageActionId(): Int = R.id.action_insertCannulaActionFragment_to_PodActivatedInfoFragment + + override fun getIndex(): Int = 4 +} \ No newline at end of file diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/activation/fragment/PodActivatedInfoFragment.kt b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/activation/fragment/PodActivatedInfoFragment.kt new file mode 100644 index 0000000000..455a8063a3 --- /dev/null +++ b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/activation/fragment/PodActivatedInfoFragment.kt @@ -0,0 +1,19 @@ +package info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.activation.fragment + +import androidx.annotation.IdRes +import androidx.annotation.StringRes +import info.nightscout.androidaps.plugins.pump.omnipod.R +import info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.common.fragment.InfoFragmentBase + +class PodActivatedInfoFragment : InfoFragmentBase() { + @StringRes + override fun getTitleId(): Int = R.string.omnipod_pod_activation_wizard_pod_activated_title + + @StringRes + override fun getTextId(): Int = R.string.omnipod_pod_activation_wizard_pod_activated_text + + @IdRes + override fun getNextPageActionId(): Int? = null + + override fun getIndex(): Int = 5 +} \ No newline at end of file diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/activation/fragment/PodActivationActionFragmentBase.kt b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/activation/fragment/PodActivationActionFragmentBase.kt new file mode 100644 index 0000000000..2055d895e0 --- /dev/null +++ b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/activation/fragment/PodActivationActionFragmentBase.kt @@ -0,0 +1,36 @@ +package info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.activation.fragment + +import android.content.Intent +import android.os.Bundle +import android.view.View +import info.nightscout.androidaps.plugins.pump.omnipod.R +import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.PodProgressStatus +import info.nightscout.androidaps.plugins.pump.omnipod.driver.manager.PodStateManager +import info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.common.fragment.ActionFragmentBase +import info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.deactivation.PodDeactivationWizardActivity +import kotlinx.android.synthetic.main.omnipod_wizard_action_page_fragment.* +import javax.inject.Inject + +abstract class PodActivationActionFragmentBase : ActionFragmentBase() { + @Inject + protected lateinit var podStateManager: PodStateManager + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + omnipod_wizard_button_deactivate_pod.setOnClickListener { + activity?.let { + startActivity(Intent(it, PodDeactivationWizardActivity::class.java)) + it.finish() + } + } + } + + override fun onActionFailure() { + if (podStateManager.isPodInitialized && podStateManager.podProgressStatus == PodProgressStatus.ACTIVATION_TIME_EXCEEDED) { + omnipod_wizard_action_error.setText(R.string.omnipod_error_pod_fault_activation_time_exceeded) + omnipod_wizard_button_retry.visibility = View.GONE + omnipod_wizard_button_deactivate_pod.visibility = View.VISIBLE + } + } +} \ No newline at end of file diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/activation/viewmodel/InitializePodActionViewModel.kt b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/activation/viewmodel/InitializePodActionViewModel.kt new file mode 100644 index 0000000000..429b1170d2 --- /dev/null +++ b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/activation/viewmodel/InitializePodActionViewModel.kt @@ -0,0 +1,10 @@ +package info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.activation.viewmodel + +import info.nightscout.androidaps.data.PumpEnactResult +import info.nightscout.androidaps.plugins.pump.omnipod.manager.AapsOmnipodManager +import info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.common.viewmodel.ActionViewModelBase +import javax.inject.Inject + +class InitializePodActionViewModel @Inject constructor(private val aapsOmnipodManager: AapsOmnipodManager) : ActionViewModelBase() { + override fun doExecuteAction(): PumpEnactResult = aapsOmnipodManager.initializePod() +} \ No newline at end of file diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/activation/viewmodel/InsertCannulaActionViewModel.kt b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/activation/viewmodel/InsertCannulaActionViewModel.kt new file mode 100644 index 0000000000..fe042a4a03 --- /dev/null +++ b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/activation/viewmodel/InsertCannulaActionViewModel.kt @@ -0,0 +1,11 @@ +package info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.activation.viewmodel + +import info.nightscout.androidaps.data.PumpEnactResult +import info.nightscout.androidaps.interfaces.ProfileFunction +import info.nightscout.androidaps.plugins.pump.omnipod.manager.AapsOmnipodManager +import info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.common.viewmodel.ActionViewModelBase +import javax.inject.Inject + +class InsertCannulaActionViewModel @Inject constructor(private val aapsOmnipodManager: AapsOmnipodManager, private val profileFunction: ProfileFunction) : ActionViewModelBase() { + override fun doExecuteAction(): PumpEnactResult = aapsOmnipodManager.insertCannula(profileFunction.getProfile()) +} \ No newline at end of file diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/common/activity/OmnipodWizardActivityBase.kt b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/common/activity/OmnipodWizardActivityBase.kt new file mode 100644 index 0000000000..b15e1a8012 --- /dev/null +++ b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/common/activity/OmnipodWizardActivityBase.kt @@ -0,0 +1,34 @@ +package info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.common.activity + +import android.app.AlertDialog +import androidx.navigation.NavController +import androidx.navigation.fragment.NavHostFragment +import info.nightscout.androidaps.activities.NoSplashAppCompatActivity +import info.nightscout.androidaps.plugins.pump.omnipod.R + +abstract class OmnipodWizardActivityBase : NoSplashAppCompatActivity() { + override fun onBackPressed() { + exitActivityAfterConfirmation() + } + + fun exitActivityAfterConfirmation() { + if (getNavController().previousBackStackEntry == null) { + finish() + } else { + AlertDialog.Builder(this) + .setIcon(android.R.drawable.ic_dialog_alert) + .setTitle(getString(R.string.omnipod_wizard_exit_confirmation_title)) + .setMessage(getString(R.string.omnipod_wizard_exit_confirmation_text)) + .setPositiveButton(getString(R.string.omnipod_yes)) { _, _ -> finish() } + .setNegativeButton(getString(R.string.omnipod_no), null) + .show() + } + } + + protected fun getNavController(): NavController = + (supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment).navController + + abstract fun getTotalDefinedNumberOfSteps(): Int + + abstract fun getActualNumberOfSteps(): Int +} \ No newline at end of file diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/common/fragment/ActionFragmentBase.kt b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/common/fragment/ActionFragmentBase.kt new file mode 100644 index 0000000000..1b0d8e41f6 --- /dev/null +++ b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/common/fragment/ActionFragmentBase.kt @@ -0,0 +1,79 @@ +package info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.common.fragment + +import android.os.Bundle +import android.view.View +import androidx.annotation.LayoutRes +import androidx.annotation.StringRes +import androidx.lifecycle.Observer +import info.nightscout.androidaps.plugins.pump.omnipod.R +import info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.common.viewmodel.ActionViewModelBase +import info.nightscout.androidaps.utils.extensions.toVisibility +import kotlinx.android.synthetic.main.omnipod_wizard_action_page_fragment.* +import kotlinx.android.synthetic.main.omnipod_wizard_nav_buttons.* + +abstract class ActionFragmentBase : WizardFragmentBase() { + protected lateinit var viewModel: ActionViewModelBase + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + omnipod_wizard_button_next.isEnabled = false + omnipod_wizard_action_page_text.setText(getTextId()) + + omnipod_wizard_button_retry.setOnClickListener { viewModel.executeAction() } + + viewModel.isActionExecutingLiveData.observe(viewLifecycleOwner, Observer { isExecuting -> + if (isExecuting) { + omnipod_wizard_action_error.visibility = View.GONE + omnipod_wizard_button_deactivate_pod.visibility = View.GONE + omnipod_wizard_button_discard_pod.visibility = View.GONE + omnipod_wizard_button_retry.visibility = View.GONE + } + omnipod_wizard_action_progress_indication.visibility = isExecuting.toVisibility() + omnipod_wizard_button_cancel.isEnabled = !isExecuting + }) + + viewModel.actionResultLiveData.observe(viewLifecycleOwner, Observer { result -> + result?.let { + val isExecuting = isActionExecuting() + + omnipod_wizard_button_next.isEnabled = result.success + omnipod_wizard_action_success.visibility = result.success.toVisibility() + omnipod_wizard_action_error.visibility = (!isExecuting && !result.success).toVisibility() + omnipod_wizard_button_retry.visibility = (!isExecuting && !result.success).toVisibility() + + if (result.success) { + onActionSuccess() + } else { + omnipod_wizard_action_error.text = result.comment + onActionFailure() + } + } + }) + + if (savedInstanceState == null && !isActionExecuting()) { + viewModel.executeAction() + } + + } + + protected fun isActionExecuting() = viewModel.isActionExecutingLiveData.value!! + + override fun onDestroyView() { + super.onDestroyView() + viewModel.isActionExecutingLiveData.removeObservers(viewLifecycleOwner) + viewModel.actionResultLiveData.removeObservers(viewLifecycleOwner) + } + + fun onActionSuccess() {} + + open fun onActionFailure() {} + + @StringRes + abstract fun getTextId(): Int + + @LayoutRes + override fun getLayoutId(): Int { + return R.layout.omnipod_wizard_action_page_fragment + } +} \ No newline at end of file diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/common/fragment/InfoFragmentBase.kt b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/common/fragment/InfoFragmentBase.kt new file mode 100644 index 0000000000..d1008a1bea --- /dev/null +++ b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/common/fragment/InfoFragmentBase.kt @@ -0,0 +1,26 @@ +package info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.common.fragment + +import android.os.Bundle +import android.view.View +import androidx.annotation.LayoutRes +import androidx.annotation.StringRes +import info.nightscout.androidaps.plugins.pump.omnipod.R +import kotlinx.android.synthetic.main.omnipod_wizard_info_page_fragment.* + +abstract class InfoFragmentBase : WizardFragmentBase() { + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + omnipod_wizard_info_page_text.setText(getTextId()) + } + + @StringRes + abstract fun getTextId(): Int + + @LayoutRes + override fun getLayoutId(): Int { + return R.layout.omnipod_wizard_info_page_fragment + } + +} \ No newline at end of file diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/common/fragment/WizardFragmentBase.kt b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/common/fragment/WizardFragmentBase.kt new file mode 100644 index 0000000000..cd6f135f08 --- /dev/null +++ b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/common/fragment/WizardFragmentBase.kt @@ -0,0 +1,84 @@ +package info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.common.fragment + +import android.content.res.ColorStateList +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.view.ViewStub +import androidx.annotation.IdRes +import androidx.annotation.LayoutRes +import androidx.annotation.StringRes +import androidx.navigation.fragment.findNavController +import dagger.android.support.DaggerFragment +import info.nightscout.androidaps.plugins.pump.omnipod.R +import info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.common.activity.OmnipodWizardActivityBase +import kotlinx.android.synthetic.main.omnipod_wizard_base_fragment.* +import kotlinx.android.synthetic.main.omnipod_wizard_nav_buttons.* +import kotlinx.android.synthetic.main.omnipod_wizard_progress_indication.* +import kotlin.math.roundToInt + +abstract class WizardFragmentBase : DaggerFragment() { + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + val baseView = inflater.inflate(R.layout.omnipod_wizard_base_fragment, container, false) + val contentView = baseView.findViewById(R.id.omnipod_wizard_base_fragment_content) + contentView?.let { + it.layoutResource = getLayoutId() + it.inflate() + } + return baseView + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + omnipod_wizard_base_fragment_title.setText(getTitleId()) + + val nextPage = getNextPageActionId() + + if (nextPage == null) { + omnipod_wizard_button_next.text = getString(R.string.omnipod_wizard_button_finish) + omnipod_wizard_button_next.backgroundTintList = ColorStateList.valueOf(resources.getColor(R.color.review_green, context?.theme)) + } + + updateProgressIndication() + + omnipod_wizard_button_next.setOnClickListener { + if (nextPage == null) { + activity?.finish() + } else { + findNavController().navigate(nextPage) + } + } + + omnipod_wizard_button_cancel.setOnClickListener { + (activity as? OmnipodWizardActivityBase)?.exitActivityAfterConfirmation() + } + } + + private fun updateProgressIndication() { + (activity as? OmnipodWizardActivityBase)?.let { + val numberOfSteps = it.getActualNumberOfSteps() + + val currentFragment = getIndex() - (it.getTotalDefinedNumberOfSteps() - numberOfSteps) + val progressPercentage = (currentFragment / numberOfSteps.toDouble() * 100).roundToInt() + + omnipod_wizard_progress_indication.progress = progressPercentage + } + } + + @LayoutRes + protected abstract fun getLayoutId(): Int + + @IdRes + protected abstract fun getNextPageActionId(): Int? + + @StringRes + protected abstract fun getTitleId(): Int + + protected abstract fun getIndex(): Int +} \ No newline at end of file diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/common/viewmodel/ActionViewModelBase.kt b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/common/viewmodel/ActionViewModelBase.kt new file mode 100644 index 0000000000..1590f752e2 --- /dev/null +++ b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/common/viewmodel/ActionViewModelBase.kt @@ -0,0 +1,30 @@ +package info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.common.viewmodel + +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import info.nightscout.androidaps.data.PumpEnactResult +import io.reactivex.schedulers.Schedulers +import io.reactivex.subjects.SingleSubject + +abstract class ActionViewModelBase : ViewModel() { + + private val _isActionExecutingLiveData = MutableLiveData(false) + val isActionExecutingLiveData: LiveData = _isActionExecutingLiveData + + private val _actionResultLiveData = MutableLiveData(null) + val actionResultLiveData: LiveData = _actionResultLiveData + + fun executeAction() { + _isActionExecutingLiveData.postValue(true) + val disposable = SingleSubject.fromCallable(this::doExecuteAction) + .subscribeOn(Schedulers.io()) + .doOnSuccess { result -> + _isActionExecutingLiveData.postValue(false) + _actionResultLiveData.postValue(result) + } + .subscribe() + } + + protected abstract fun doExecuteAction(): PumpEnactResult +} diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/deactivation/PodDeactivationWizardActivity.kt b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/deactivation/PodDeactivationWizardActivity.kt new file mode 100644 index 0000000000..892d85a97e --- /dev/null +++ b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/deactivation/PodDeactivationWizardActivity.kt @@ -0,0 +1,18 @@ +package info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.deactivation + +import android.os.Bundle +import info.nightscout.androidaps.plugins.pump.omnipod.R +import info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.common.activity.OmnipodWizardActivityBase + +class PodDeactivationWizardActivity : OmnipodWizardActivityBase() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + setContentView(R.layout.omnipod_pod_deactivation_wizard_activity) + } + + override fun getTotalDefinedNumberOfSteps(): Int = 3 + + override fun getActualNumberOfSteps(): Int = 3 + +} \ No newline at end of file diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/deactivation/fragment/DeactivatePodActionFragment.kt b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/deactivation/fragment/DeactivatePodActionFragment.kt new file mode 100644 index 0000000000..a88b5866be --- /dev/null +++ b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/deactivation/fragment/DeactivatePodActionFragment.kt @@ -0,0 +1,65 @@ +package info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.deactivation.fragment + +import android.app.AlertDialog +import android.os.Bundle +import android.view.View +import androidx.annotation.IdRes +import androidx.annotation.StringRes +import androidx.fragment.app.viewModels +import androidx.lifecycle.ViewModelProvider +import androidx.navigation.fragment.findNavController +import info.nightscout.androidaps.plugins.pump.omnipod.R +import info.nightscout.androidaps.plugins.pump.omnipod.dagger.OmnipodPluginQualifier +import info.nightscout.androidaps.plugins.pump.omnipod.manager.AapsOmnipodManager +import info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.common.fragment.ActionFragmentBase +import info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.deactivation.viewmodel.DeactivatePodActionViewModel +import info.nightscout.androidaps.utils.extensions.toVisibility +import kotlinx.android.synthetic.main.omnipod_wizard_action_page_fragment.* +import javax.inject.Inject + +class DeactivatePodActionFragment : ActionFragmentBase() { + @Inject + @OmnipodPluginQualifier + lateinit var viewModelFactory: ViewModelProvider.Factory + + @Inject + lateinit var aapsOmnipodManager: AapsOmnipodManager + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + val vm: DeactivatePodActionViewModel by viewModels { viewModelFactory } + this.viewModel = vm + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + omnipod_wizard_button_discard_pod.setOnClickListener { + AlertDialog.Builder(context) + .setIcon(android.R.drawable.ic_dialog_alert) + .setTitle(getString(R.string.omnipod_pod_deactivation_wizard_discard_pod)) + .setMessage(getString(R.string.omnipod_pod_deactivation_wizard_discard_pod_confirmation)) + .setPositiveButton(getString(R.string.omnipod_yes)) { _, _ -> + aapsOmnipodManager.discardPodState() + findNavController().navigate(R.id.action_deactivatePodActionFragment_to_podDiscardedInfoFragment) + } + .setNegativeButton(getString(R.string.omnipod_no), null) + .show() + } + } + + override fun onActionFailure() { + omnipod_wizard_button_discard_pod.visibility = (!isActionExecuting()).toVisibility() + } + + @StringRes + override fun getTitleId(): Int = R.string.omnipod_pod_deactivation_wizard_deactivating_pod_title + + @StringRes + override fun getTextId(): Int = R.string.omnipod_pod_deactivation_wizard_deactivating_pod_text + + @IdRes + override fun getNextPageActionId(): Int = R.id.action_deactivatePodActionFragment_to_podDeactivatedInfoFragment + + override fun getIndex(): Int = 2 +} \ No newline at end of file diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/deactivation/fragment/DeactivatePodInfoFragment.kt b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/deactivation/fragment/DeactivatePodInfoFragment.kt new file mode 100644 index 0000000000..5fefcfc549 --- /dev/null +++ b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/deactivation/fragment/DeactivatePodInfoFragment.kt @@ -0,0 +1,19 @@ +package info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.deactivation.fragment + +import androidx.annotation.IdRes +import androidx.annotation.StringRes +import info.nightscout.androidaps.plugins.pump.omnipod.R +import info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.common.fragment.InfoFragmentBase + +class DeactivatePodInfoFragment : InfoFragmentBase() { + @StringRes + override fun getTitleId(): Int = R.string.omnipod_pod_deactivation_wizard_deactivate_pod_title + + @StringRes + override fun getTextId(): Int = R.string.omnipod_pod_deactivation_wizard_deactivate_pod_text + + @IdRes + override fun getNextPageActionId(): Int = R.id.action_deactivatePodInfoFragment_to_deactivatePodActionFragment + + override fun getIndex(): Int = 1 +} \ No newline at end of file diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/deactivation/fragment/PodDeactivatedInfoFragment.kt b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/deactivation/fragment/PodDeactivatedInfoFragment.kt new file mode 100644 index 0000000000..3b1c80cbb1 --- /dev/null +++ b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/deactivation/fragment/PodDeactivatedInfoFragment.kt @@ -0,0 +1,19 @@ +package info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.deactivation.fragment + +import androidx.annotation.IdRes +import androidx.annotation.StringRes +import info.nightscout.androidaps.plugins.pump.omnipod.R +import info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.common.fragment.InfoFragmentBase + +class PodDeactivatedInfoFragment : InfoFragmentBase() { + @StringRes + override fun getTitleId(): Int = R.string.omnipod_pod_deactivation_wizard_pod_deactivated_title + + @StringRes + override fun getTextId(): Int = R.string.omnipod_pod_deactivation_wizard_pod_deactivated_text + + @IdRes + override fun getNextPageActionId(): Int? = null + + override fun getIndex(): Int = 3 +} \ No newline at end of file diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/deactivation/fragment/PodDiscardedInfoFragment.kt b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/deactivation/fragment/PodDiscardedInfoFragment.kt new file mode 100644 index 0000000000..7b53f4abc4 --- /dev/null +++ b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/deactivation/fragment/PodDiscardedInfoFragment.kt @@ -0,0 +1,19 @@ +package info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.deactivation.fragment + +import androidx.annotation.IdRes +import androidx.annotation.StringRes +import info.nightscout.androidaps.plugins.pump.omnipod.R +import info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.common.fragment.InfoFragmentBase + +class PodDiscardedInfoFragment : InfoFragmentBase() { + @StringRes + override fun getTitleId(): Int = R.string.omnipod_pod_deactivation_wizard_pod_discarded_title + + @StringRes + override fun getTextId(): Int = R.string.omnipod_pod_deactivation_wizard_pod_discarded_text + + @IdRes + override fun getNextPageActionId(): Int? = null + + override fun getIndex(): Int = 3 +} \ No newline at end of file diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/deactivation/viewmodel/DeactivatePodActionViewModel.kt b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/deactivation/viewmodel/DeactivatePodActionViewModel.kt new file mode 100644 index 0000000000..80296603f2 --- /dev/null +++ b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/deactivation/viewmodel/DeactivatePodActionViewModel.kt @@ -0,0 +1,22 @@ +package info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.deactivation.viewmodel + +import info.nightscout.androidaps.data.PumpEnactResult +import info.nightscout.androidaps.interfaces.CommandQueueProvider +import info.nightscout.androidaps.plugins.pump.omnipod.manager.AapsOmnipodManager +import info.nightscout.androidaps.plugins.pump.omnipod.queue.command.CommandDeactivatePod +import info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.common.viewmodel.ActionViewModelBase +import info.nightscout.androidaps.queue.Callback +import io.reactivex.subjects.SingleSubject +import javax.inject.Inject + +class DeactivatePodActionViewModel @Inject constructor(private val aapsOmnipodManager: AapsOmnipodManager, private val commandQueueProvider: CommandQueueProvider) : ActionViewModelBase() { + override fun doExecuteAction(): PumpEnactResult { + val singleSubject = SingleSubject.create() + commandQueueProvider.customCommand(CommandDeactivatePod(), object : Callback() { + override fun run() { + singleSubject.onSuccess(result) + } + }) + return singleSubject.blockingGet() + } +} \ No newline at end of file diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/defs/PodActionType.java b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/defs/PodActionType.java deleted file mode 100644 index 48380638c2..0000000000 --- a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/defs/PodActionType.java +++ /dev/null @@ -1,7 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.defs; - -public enum PodActionType { - INIT_POD, - DEACTIVATE_POD, - DISCARD_POD -} diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/initpod/InitActionFragment.java b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/initpod/InitActionFragment.java deleted file mode 100644 index e05c86ec5b..0000000000 --- a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/initpod/InitActionFragment.java +++ /dev/null @@ -1,223 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.initpod; - -import android.annotation.SuppressLint; -import android.content.Context; -import android.content.pm.ActivityInfo; -import android.graphics.Color; -import android.os.AsyncTask; -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.Button; -import android.widget.CheckBox; -import android.widget.LinearLayout; -import android.widget.ProgressBar; -import android.widget.TextView; - -import androidx.fragment.app.FragmentActivity; - -import com.atech.android.library.wizardpager.util.WizardPagesUtil; -import com.tech.freak.wizardpager.model.Page; -import com.tech.freak.wizardpager.ui.PageFragmentCallbacks; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.UUID; - -import javax.inject.Inject; - -import dagger.android.HasAndroidInjector; -import dagger.android.support.DaggerFragment; -import info.nightscout.androidaps.data.PumpEnactResult; -import info.nightscout.androidaps.plugins.pump.omnipod.R; -import info.nightscout.androidaps.plugins.pump.omnipod.definition.PodInitActionType; -import info.nightscout.androidaps.plugins.pump.omnipod.definition.PodInitReceiver; - -/** - * Created by andy on 12/11/2019 - */ -public class InitActionFragment extends DaggerFragment implements PodInitReceiver { - protected static final String ARG_KEY = "key"; - protected static final String ARG_POD_INIT_ACTION_TYPE = "podInitActionType"; - - private static boolean isFirstView; - - private PageFragmentCallbacks mCallbacks; - private String mKey; - protected InitActionPage mPage; - - protected ProgressBar progressBar; - protected TextView errorView; - protected Button retryButton; - - PodInitActionType podInitActionType; - private List children; - protected Map mapCheckBoxes; - - protected PumpEnactResult callResult; - - @Inject HasAndroidInjector injector; - - public static InitActionFragment create(String key, PodInitActionType podInitActionType) { - Bundle args = new Bundle(); - args.putString(ARG_KEY, key); - args.putSerializable(ARG_POD_INIT_ACTION_TYPE, podInitActionType); - - InitActionFragment fragment = new InitActionFragment(); - fragment.setArguments(args); - return fragment; - } - - @SuppressLint("SourceLockedOrientationActivity") - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - if (savedInstanceState == null) { - isFirstView = true; - } - - getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); - - Bundle args = getArguments(); - mKey = args.getString(ARG_KEY); - podInitActionType = (PodInitActionType) args.getSerializable(ARG_POD_INIT_ACTION_TYPE); - mPage = (InitActionPage) mCallbacks.onGetPage(mKey); - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - super.onCreateView(inflater, container, savedInstanceState); - - View rootView = inflater.inflate(R.layout.omnipod_initpod_init_action, container, false); - WizardPagesUtil.setTitle(mPage, rootView); - - this.progressBar = rootView.findViewById(R.id.initAction_progressBar); - this.errorView = rootView.findViewById(R.id.initAction_textErrorMessage); - - TextView headerView = rootView.findViewById(R.id.initAction_header); - - LinearLayout linearLayout = rootView.findViewById(R.id.initAction_ItemsHolder); - - children = podInitActionType.getChildren(); - mapCheckBoxes = new HashMap<>(); - - for (PodInitActionType child : children) { - CheckBox checkBox1 = new CheckBox(getContext()); - checkBox1.setText(child.getResourceId()); - checkBox1.setClickable(false); - checkBox1.setTextAppearance(R.style.WizardPagePodListItem); - checkBox1.setHeight(120); - checkBox1.setTextSize(15); - checkBox1.setTextColor(headerView.getTextColors().getDefaultColor()); - - linearLayout.addView(checkBox1); - - mapCheckBoxes.put(child, checkBox1); - } - - if (podInitActionType == PodInitActionType.FILL_CANNULA_SET_BASAL_PROFILE_WIZARD_STEP) { - headerView.setText(R.string.omnipod_init_pod_wizard_step4_action_header); - } else if (podInitActionType == PodInitActionType.DEACTIVATE_POD_WIZARD_STEP) { - headerView.setText(R.string.omnipod_remove_pod_wizard_step2_action_header); - } - - this.retryButton = rootView.findViewById(R.id.initAction_RetryButton); - - this.retryButton.setOnClickListener(view -> { - - getActivity().runOnUiThread(() -> { - for (PodInitActionType actionType : mapCheckBoxes.keySet()) { - mapCheckBoxes.get(actionType).setChecked(false); - mapCheckBoxes.get(actionType).setTextColor(headerView.getTextColors().getDefaultColor()); - } - }); - - new InitPodTask(injector, this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - }); - - return rootView; - } - - @Override - public void onAttach(Context context) { - super.onAttach(context); - - FragmentActivity activity = getActivity(); - - if (!(activity instanceof PageFragmentCallbacks)) { - throw new ClassCastException("Activity must implement PageFragmentCallbacks"); - } - - mCallbacks = (PageFragmentCallbacks) activity; - } - - @Override - public void onDetach() { - super.onDetach(); - mCallbacks = null; - } - - @Override - public void onResume() { - super.onResume(); - if (isFirstView) { - isFirstView = false; - new InitPodTask(injector, this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - } - } - - public void actionOnReceiveResponse(String result) { - } - - @Override - public void returnInitTaskStatus(PodInitActionType podInitActionType, boolean isSuccess, String errorMessage) { - if (podInitActionType.isParent()) { - for (PodInitActionType actionType : mapCheckBoxes.keySet()) { - setCheckBox(actionType, isSuccess); - } - - // special handling for init - processOnFinishedActions(isSuccess, errorMessage); - - } else { - setCheckBox(podInitActionType, isSuccess); - } - } - - private void processOnFinishedActions(boolean isOk, String errorMessage) { - FragmentActivity activity = getActivity(); - if (activity != null) { - activity.runOnUiThread(() -> { - progressBar.setVisibility(View.GONE); - - if (!isOk) { - errorView.setVisibility(View.VISIBLE); - errorView.setText(errorMessage); - - retryButton.setVisibility(View.VISIBLE); - } - - mPage.setActionCompleted(isOk); - - mPage.getData().putString(Page.SIMPLE_DATA_KEY, UUID.randomUUID().toString()); - mPage.notifyDataChanged(); - - }); - } - } - - protected void setCheckBox(PodInitActionType podInitActionType, boolean isSuccess) { - FragmentActivity activity = getActivity(); - if (activity != null) { - activity.runOnUiThread(() -> { - mapCheckBoxes.get(podInitActionType).setChecked(isSuccess); - mapCheckBoxes.get(podInitActionType).setTextColor(isSuccess ? Color.rgb(34, 135, 91) : - Color.rgb(168, 36, 15)); - }); - } - } - -} diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/initpod/InitActionPage.java b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/initpod/InitActionPage.java deleted file mode 100644 index 8c086ffe6e..0000000000 --- a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/initpod/InitActionPage.java +++ /dev/null @@ -1,73 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.initpod; - -import androidx.annotation.StringRes; -import androidx.fragment.app.Fragment; - -import com.tech.freak.wizardpager.model.ModelCallbacks; -import com.tech.freak.wizardpager.model.Page; -import com.tech.freak.wizardpager.model.ReviewItem; - -import java.util.ArrayList; - -import info.nightscout.androidaps.plugins.pump.omnipod.definition.PodInitActionType; - - -/** - * Created by andy on 12/11/2019 - *

- * This page is for InitPod and RemovePod, but Fragments called for this 2 actions are different - */ -public class InitActionPage extends Page { - - protected PodInitActionType podInitActionType; - - private boolean actionCompleted = false; - private boolean actionSuccess = false; - - protected InitActionPage(ModelCallbacks callbacks, String title) { - super(callbacks, title); - } - - public InitActionPage(ModelCallbacks callbacks, @StringRes int titleId, PodInitActionType podInitActionType) { - super(callbacks, titleId); - this.podInitActionType = podInitActionType; - } - - @Override - public Fragment createFragment() { - return InitActionFragment.create(getKey(), this.podInitActionType); - } - - @Override - public void getReviewItems(ArrayList dest) { - } - - @Override - public boolean isCompleted() { - return actionCompleted; - } - - public void setActionCompleted(boolean success) { - this.actionCompleted = success; - this.actionSuccess = success; - } - - /** - * This is used just if we want to override default behavior (for example when we enter Page we want prevent any action, until something happens. - * - * @return - */ - @Override public boolean isBackActionPossible() { - return actionCompleted; - } - - /** - * This is used just if we want to override default behavior (for example when we enter Page we want prevent any action, until something happens. - * - * @return - */ - @Override public boolean isNextActionPossible() { - return actionSuccess; - } - -} diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/initpod/InitPodTask.java b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/initpod/InitPodTask.java deleted file mode 100644 index 12742ff108..0000000000 --- a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/initpod/InitPodTask.java +++ /dev/null @@ -1,67 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.initpod; - -import android.os.AsyncTask; -import android.view.View; - -import javax.inject.Inject; - -import dagger.android.HasAndroidInjector; -import info.nightscout.androidaps.interfaces.ProfileFunction; -import info.nightscout.androidaps.plugins.bus.RxBusWrapper; -import info.nightscout.androidaps.plugins.pump.omnipod.definition.PodInitActionType; -import info.nightscout.androidaps.plugins.pump.omnipod.event.EventOmnipodPumpValuesChanged; -import info.nightscout.androidaps.plugins.pump.omnipod.manager.AapsOmnipodManager; - -/** - * Created by andy on 11/12/2019 - */ -public class InitPodTask extends AsyncTask { - - @Inject ProfileFunction profileFunction; - @Inject AapsOmnipodManager aapsOmnipodManager; - @Inject RxBusWrapper rxBus; - private final InitActionFragment initActionFragment; - - public InitPodTask(HasAndroidInjector injector, InitActionFragment initActionFragment) { - injector.androidInjector().inject(this); - this.initActionFragment = initActionFragment; - } - - @Override - protected void onPreExecute() { - super.onPreExecute(); - initActionFragment.progressBar.setVisibility(View.VISIBLE); - initActionFragment.errorView.setVisibility(View.GONE); - initActionFragment.retryButton.setVisibility(View.GONE); - } - - @Override - protected String doInBackground(Void... params) { - if (initActionFragment.podInitActionType == PodInitActionType.PAIR_AND_PRIME_WIZARD_STEP) { - initActionFragment.callResult = aapsOmnipodManager.pairAndPrime( - initActionFragment.podInitActionType, - initActionFragment - ); - } else if (initActionFragment.podInitActionType == PodInitActionType.FILL_CANNULA_SET_BASAL_PROFILE_WIZARD_STEP) { - initActionFragment.callResult = aapsOmnipodManager.setInitialBasalScheduleAndInsertCannula( - initActionFragment.podInitActionType, - initActionFragment, - profileFunction.getProfile() - ); - } else if (initActionFragment.podInitActionType == PodInitActionType.DEACTIVATE_POD_WIZARD_STEP) { - initActionFragment.callResult = aapsOmnipodManager.deactivatePod(initActionFragment); - } - - rxBus.send(new EventOmnipodPumpValuesChanged()); - - return "OK"; - } - - @Override - protected void onPostExecute(String result) { - super.onPostExecute(result); - - initActionFragment.actionOnReceiveResponse(result); - } - -} diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/model/FullInitPodWizardModel.java b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/model/FullInitPodWizardModel.java deleted file mode 100644 index af364324ae..0000000000 --- a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/model/FullInitPodWizardModel.java +++ /dev/null @@ -1,48 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.model; - -import android.content.Context; - -import com.atech.android.library.wizardpager.model.DisplayTextPage; -import com.tech.freak.wizardpager.model.PageList; - -import info.nightscout.androidaps.plugins.pump.omnipod.R; -import info.nightscout.androidaps.plugins.pump.omnipod.definition.PodInitActionType; -import info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.initpod.InitActionPage; - -/** - * Created by andy on 12/11/2019 - */ -// Full init pod wizard model -// Cannot be merged with ShortInitPodWizardModel, because we can't set any instance variables -// before the onNewRootPageList method is called (which happens in the super constructor) -public class FullInitPodWizardModel extends InitPodWizardModel { - - public FullInitPodWizardModel(Context context) { - super(context); - } - - @Override - protected PageList onNewRootPageList() { - return new PageList( - new DisplayTextPage(this, - R.string.omnipod_init_pod_wizard_step1_title, - R.string.omnipod_init_pod_wizard_step1_desc, - R.style.WizardPagePodContent).setRequired(true).setCancelReason("None"), - - new InitActionPage(this, - R.string.omnipod_init_pod_wizard_step2_title, - PodInitActionType.PAIR_AND_PRIME_WIZARD_STEP - ).setRequired(true).setCancelReason("Cancel"), - - new DisplayTextPage(this, - R.string.omnipod_init_pod_wizard_step3_title, - R.string.omnipod_init_pod_wizard_step3_desc, - R.style.WizardPagePodContent).setRequired(true).setCancelReason("Cancel"), - - new InitActionPage(this, - R.string.omnipod_init_pod_wizard_step4_title, - PodInitActionType.FILL_CANNULA_SET_BASAL_PROFILE_WIZARD_STEP - ).setRequired(true).setCancelReason("Cancel") - ); - } -} diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/model/InitPodWizardModel.java b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/model/InitPodWizardModel.java deleted file mode 100644 index e3c4e9c1fe..0000000000 --- a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/model/InitPodWizardModel.java +++ /dev/null @@ -1,20 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.model; - -import android.content.Context; - -import androidx.fragment.app.Fragment; - -import com.tech.freak.wizardpager.model.AbstractWizardModel; - -import info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.pages.PodInfoFragment; - -abstract class InitPodWizardModel extends AbstractWizardModel { - InitPodWizardModel(Context context) { - super(context); - } - - @Override - public Fragment getReviewFragment() { - return PodInfoFragment.create(true); - } -} diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/model/RemovePodWizardModel.java b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/model/RemovePodWizardModel.java deleted file mode 100644 index 381dcb1950..0000000000 --- a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/model/RemovePodWizardModel.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2012 Roman Nurik - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.model; - -import android.content.Context; - -import androidx.fragment.app.Fragment; - -import com.atech.android.library.wizardpager.model.DisplayTextPage; -import com.tech.freak.wizardpager.model.AbstractWizardModel; -import com.tech.freak.wizardpager.model.PageList; - -import info.nightscout.androidaps.plugins.pump.omnipod.R; -import info.nightscout.androidaps.plugins.pump.omnipod.definition.PodInitActionType; -import info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.pages.PodInfoFragment; -import info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.removepod.RemovePodActionPage; - -/** - * Created by andy on 12/11/2019 - */ -public class RemovePodWizardModel extends AbstractWizardModel { - - public RemovePodWizardModel(Context context) { - super(context); - } - - @Override - protected PageList onNewRootPageList() { - return new PageList( - new DisplayTextPage(this, - R.string.omnipod_remove_pod_wizard_step1_title, - R.string.omnipod_remove_pod_wizard_step1_desc, - R.style.WizardPagePodContent).setRequired(true).setCancelReason("None"), - - new RemovePodActionPage(this, - R.string.omnipod_remove_pod_wizard_step2_title, - PodInitActionType.DEACTIVATE_POD_WIZARD_STEP - ).setRequired(true).setCancelReason("Cancel") - - ); - } - - @Override public Fragment getReviewFragment() { - return PodInfoFragment.create(false); - } - -} diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/model/ShortInitPodWizardModel.java b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/model/ShortInitPodWizardModel.java deleted file mode 100644 index 3813520e80..0000000000 --- a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/model/ShortInitPodWizardModel.java +++ /dev/null @@ -1,39 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.model; - -import android.content.Context; - -import com.atech.android.library.wizardpager.model.DisplayTextPage; -import com.tech.freak.wizardpager.model.PageList; - -import info.nightscout.androidaps.plugins.pump.omnipod.R; -import info.nightscout.androidaps.plugins.pump.omnipod.definition.PodInitActionType; -import info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.initpod.InitActionPage; - -/** - * Created by andy on 12/11/2019 - */ -// Init pod wizard model without the pair and prime step -// Cannot be merged with FullInitPodWizardModel, because we can't set any instance variables -// before the onNewRootPageList method is called (which happens in the super constructor) -public class ShortInitPodWizardModel extends InitPodWizardModel { - - public ShortInitPodWizardModel(Context context) { - super(context); - } - - @Override - protected PageList onNewRootPageList() { - return new PageList( - new DisplayTextPage(this, - R.string.omnipod_init_pod_wizard_step3_title, - R.string.omnipod_init_pod_wizard_step3_desc, - R.style.WizardPagePodContent).setRequired(true).setCancelReason("Cancel"), - - new InitActionPage(this, - R.string.omnipod_init_pod_wizard_step4_title, - PodInitActionType.FILL_CANNULA_SET_BASAL_PROFILE_WIZARD_STEP - ).setRequired(true).setCancelReason("Cancel") - ); - - } -} diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/pages/InitPodRefreshAction.java b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/pages/InitPodRefreshAction.java deleted file mode 100644 index 9f7c47be2b..0000000000 --- a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/pages/InitPodRefreshAction.java +++ /dev/null @@ -1,93 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.pages; - -import com.atech.android.library.wizardpager.defs.action.AbstractCancelAction; -import com.atech.android.library.wizardpager.defs.action.FinishActionInterface; - -import org.json.JSONException; -import org.json.JSONObject; - -import javax.inject.Inject; - -import dagger.android.HasAndroidInjector; -import info.nightscout.androidaps.db.CareportalEvent; -import info.nightscout.androidaps.db.Source; -import info.nightscout.androidaps.interfaces.DatabaseHelperInterface; -import info.nightscout.androidaps.interfaces.ProfileFunction; -import info.nightscout.androidaps.logging.AAPSLogger; -import info.nightscout.androidaps.logging.LTag; -import info.nightscout.androidaps.plugins.general.nsclient.NSUpload; -import info.nightscout.androidaps.plugins.pump.omnipod.driver.manager.PodStateManager; -import info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.defs.PodActionType; -import info.nightscout.androidaps.utils.DateUtil; -import info.nightscout.androidaps.utils.sharedPreferences.SP; - - -/** - * Created by andy on 12/11/2019 - */ -public class InitPodRefreshAction extends AbstractCancelAction implements FinishActionInterface { - - private final PodActionType actionType; - private final HasAndroidInjector injector; - - @Inject PodStateManager podStateManager; - @Inject AAPSLogger aapsLogger; - @Inject SP sp; - @Inject NSUpload nsUpload; - @Inject DatabaseHelperInterface databaseHelper; - @Inject ProfileFunction profileFunction; - - public InitPodRefreshAction(HasAndroidInjector injector, PodActionType actionType) { - this.injector = injector; - injector.androidInjector().inject(this); - this.actionType = actionType; - } - - @Override - public void execute(String cancelReason) { - if (cancelReason != null && cancelReason.trim().length() > 0) { - this.cancelActionText = cancelReason; - } - } - - @Override - public void execute() { - if (actionType == PodActionType.INIT_POD) { - if (podStateManager.isPodRunning()) { - uploadCareportalEvent(System.currentTimeMillis() - 2000, CareportalEvent.PUMPBATTERYCHANGE); - uploadCareportalEvent(System.currentTimeMillis() - 1000, CareportalEvent.INSULINCHANGE); - uploadCareportalEvent(System.currentTimeMillis(), CareportalEvent.SITECHANGE); - } - } - } - - private void uploadCareportalEvent(long date, String event) { - if (databaseHelper.getCareportalEventFromTimestamp(date) != null) - return; - try { - JSONObject data = new JSONObject(); - String enteredBy = sp.getString("careportal_enteredby", ""); - if (enteredBy.isEmpty()) { - data.put("enteredBy", enteredBy); - } - data.put("created_at", DateUtil.toISOString(date)); - data.put("mills", date); - data.put("eventType", event); - data.put("units", profileFunction.getUnits()); - CareportalEvent careportalEvent = new CareportalEvent(injector); - careportalEvent.date = date; - careportalEvent.source = Source.USER; - careportalEvent.eventType = event; - careportalEvent.json = data.toString(); - databaseHelper.createOrUpdate(careportalEvent); - nsUpload.uploadCareportalEntryToNS(data); - } catch (JSONException e) { - aapsLogger.error(LTag.PUMPCOMM, "Unhandled exception when uploading SiteChange event.", e); - } - } - - @Override - public String getFinishActionText() { - return "Finish_OK"; - } -} diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/pages/PodInfoFragment.java b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/pages/PodInfoFragment.java deleted file mode 100644 index 83dbeb0125..0000000000 --- a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/pages/PodInfoFragment.java +++ /dev/null @@ -1,164 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.pages; - -import android.annotation.SuppressLint; -import android.content.Context; -import android.content.pm.ActivityInfo; -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ArrayAdapter; -import android.widget.ListView; -import android.widget.TextView; - -import androidx.fragment.app.FragmentActivity; - -import com.tech.freak.wizardpager.model.ReviewItem; -import com.tech.freak.wizardpager.ui.PageFragmentCallbacks; - -import java.util.ArrayList; - -import javax.inject.Inject; - -import dagger.android.support.DaggerFragment; -import info.nightscout.androidaps.plugins.pump.omnipod.R; -import info.nightscout.androidaps.plugins.pump.omnipod.driver.manager.PodStateManager; -import info.nightscout.androidaps.plugins.pump.omnipod.util.AapsOmnipodUtil; - - -/** - * Created by andy on 12/11/2019 - */ -public class PodInfoFragment extends DaggerFragment { - private static final String ARG_INIT_POD = "initPod"; - - @Inject AapsOmnipodUtil aapsOmnipodUtil; - @Inject PodStateManager podStateManager; - - private boolean isInitPod; - private ArrayList mCurrentReviewItems; - - public static PodInfoFragment create(boolean initPod) { - Bundle args = new Bundle(); - args.putBoolean(ARG_INIT_POD, initPod); - - PodInfoFragment fragment = new PodInfoFragment(); - fragment.setArguments(args); - return fragment; - } - - @SuppressLint("SourceLockedOrientationActivity") @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); - - Bundle args = getArguments(); - isInitPod = args.getBoolean(ARG_INIT_POD); - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - View rootView = inflater.inflate(R.layout.omnipod_initpod_pod_info, container, false); - - TextView titleView = rootView.findViewById(R.id.podInfoTitle); - titleView.setText(R.string.omnipod_init_pod_wizard_pod_info_title); - titleView.setTextColor(getResources().getColor(com.tech.freak.wizardpager.R.color.review_green)); - - TextView headerText = rootView.findViewById(R.id.podInfoText); - headerText.setText(isInitPod ? // - R.string.omnipod_init_pod_wizard_pod_info_init_pod_description : // - R.string.omnipod_init_pod_wizard_pod_info_remove_pod_description); - - if (isInitPod) { - if (createDataOfPod()) { - - ListView listView = (ListView) rootView.findViewById(R.id.podInfoList); - listView.setAdapter(new PodInfoAdapter(mCurrentReviewItems, getContext())); - listView.setChoiceMode(ListView.CHOICE_MODE_NONE); - } - } - - return rootView; - } - - private boolean createDataOfPod() { - if (podStateManager == null) - return false; - - mCurrentReviewItems = new ArrayList<>(); - mCurrentReviewItems.add(new ReviewItem("Pod Address", "" + podStateManager.getAddress(), "33")); - mCurrentReviewItems.add(new ReviewItem("Activated At", podStateManager.getActivatedAt() == null ? "Not activated yet" : podStateManager.getActivatedAt().toString("dd.MM.yyyy HH:mm:ss"), "34")); - if (podStateManager.getLot() != null) { - mCurrentReviewItems.add(new ReviewItem("LOT", "" + podStateManager.getLot(), "35")); - } - if (podStateManager.getTid() != null) { - mCurrentReviewItems.add(new ReviewItem("TID", "" + podStateManager.getLot(), "36")); - } - if (podStateManager.getPiVersion() != null) { - mCurrentReviewItems.add(new ReviewItem("Pi Version", podStateManager.getPiVersion().toString(), "37")); - } - if (podStateManager.getPmVersion() != null) { - mCurrentReviewItems.add(new ReviewItem("Pm Version", podStateManager.getPmVersion().toString(), "38")); - } - - return true; - } - - @Override - public void onAttach(Context context) { - super.onAttach(context); - - FragmentActivity activity = getActivity(); - - if (!(activity instanceof PageFragmentCallbacks)) { - throw new ClassCastException("Activity must implement PageFragmentCallbacks"); - } - } - - @Override - public void onDetach() { - super.onDetach(); - } - - private static class PodInfoAdapter extends ArrayAdapter { - PodInfoAdapter(ArrayList data, Context context) { - super(context, com.tech.freak.wizardpager.R.layout.list_item_review, data); - } - - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - // Get the data item for this position - ReviewItem dataModel = getItem(position); - // Check if an existing view is being reused, otherwise inflate the view - ViewHolder viewHolder; // view lookup cache stored in tag - - if (convertView == null) { - - viewHolder = new ViewHolder(); - LayoutInflater inflater = LayoutInflater.from(getContext()); - convertView = inflater.inflate(R.layout.omnipod_initpod_pod_info_item, parent, false); - viewHolder.txtName = (TextView) convertView.findViewById(android.R.id.text1); - viewHolder.txtType = (TextView) convertView.findViewById(android.R.id.text2); - - convertView.setTag(viewHolder); - } else { - viewHolder = (ViewHolder) convertView.getTag(); - } - - viewHolder.txtName.setText(dataModel.getTitle()); - viewHolder.txtType.setText(dataModel.getDisplayValue()); - - // Return the completed view to render on screen - return convertView; - } - } - - private static class ViewHolder { - TextView txtName; - TextView txtType; - } - -} diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/removepod/RemoveActionFragment.java b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/removepod/RemoveActionFragment.java deleted file mode 100644 index 2ca5a1d198..0000000000 --- a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/removepod/RemoveActionFragment.java +++ /dev/null @@ -1,60 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.removepod; - -import android.os.Bundle; -import android.view.View; - -import com.tech.freak.wizardpager.model.Page; - -import java.util.UUID; - -import info.nightscout.androidaps.plugins.pump.omnipod.definition.PodInitActionType; -import info.nightscout.androidaps.plugins.pump.omnipod.definition.PodInitReceiver; -import info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.initpod.InitActionFragment; - -/** - * Created by andy on 29/11/2019 - */ -public class RemoveActionFragment extends InitActionFragment implements PodInitReceiver { - public static RemoveActionFragment create(String key, PodInitActionType podInitActionType) { - Bundle args = new Bundle(); - args.putString(ARG_KEY, key); - args.putSerializable(ARG_POD_INIT_ACTION_TYPE, podInitActionType); - - RemoveActionFragment fragment = new RemoveActionFragment(); - fragment.setArguments(args); - return fragment; - } - - @Override - public void actionOnReceiveResponse(String result) { - System.out.println("ACTION: actionOnReceiveResponse: " + result); - - boolean isOk = callResult.success; - - progressBar.setVisibility(View.GONE); - - if (!isOk) { - errorView.setVisibility(View.VISIBLE); - errorView.setText(callResult.comment); - - retryButton.setVisibility(View.VISIBLE); - } - - mPage.setActionCompleted(isOk); - - mPage.getData().putString(Page.SIMPLE_DATA_KEY, UUID.randomUUID().toString()); - mPage.notifyDataChanged(); - } - - - @Override - public void returnInitTaskStatus(PodInitActionType podInitActionType, boolean isSuccess, String errorMessage) { - if (podInitActionType.isParent()) { - for (PodInitActionType actionType : mapCheckBoxes.keySet()) { - setCheckBox(actionType, isSuccess); - } - } else { - setCheckBox(podInitActionType, isSuccess); - } - } -} diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/removepod/RemovePodActionPage.java b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/removepod/RemovePodActionPage.java deleted file mode 100644 index 7d1b319d8c..0000000000 --- a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/wizard/removepod/RemovePodActionPage.java +++ /dev/null @@ -1,30 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.removepod; - -import androidx.annotation.StringRes; -import androidx.fragment.app.Fragment; - -import com.tech.freak.wizardpager.model.ModelCallbacks; - -import info.nightscout.androidaps.plugins.pump.omnipod.definition.PodInitActionType; -import info.nightscout.androidaps.plugins.pump.omnipod.ui.wizard.initpod.InitActionPage; - - -/** - * Created by andy on 12/11/2019 - */ -public class RemovePodActionPage extends InitActionPage { - - public RemovePodActionPage(ModelCallbacks callbacks, String title) { - super(callbacks, title); - } - - public RemovePodActionPage(ModelCallbacks callbacks, @StringRes int titleId, PodInitActionType podInitActionType) { - super(callbacks, titleId, podInitActionType); - } - - @Override - public Fragment createFragment() { - return RemoveActionFragment.create(getKey(), this.podInitActionType); - } - -} diff --git a/omnipod/src/main/res/drawable/ic_access_alarm.xml b/omnipod/src/main/res/drawable/ic_access_alarm.xml new file mode 100644 index 0000000000..48a463f81b --- /dev/null +++ b/omnipod/src/main/res/drawable/ic_access_alarm.xml @@ -0,0 +1,9 @@ + + + diff --git a/omnipod/src/main/res/drawable/ic_actions_temptarget.xml b/omnipod/src/main/res/drawable/ic_actions_temptarget.xml index 5dbd5d8b0c..28aed597c8 100644 --- a/omnipod/src/main/res/drawable/ic_actions_temptarget.xml +++ b/omnipod/src/main/res/drawable/ic_actions_temptarget.xml @@ -3,7 +3,7 @@ android:height="48dp" android:viewportWidth="24" android:viewportHeight="24"> - + diff --git a/omnipod/src/main/res/drawable/ic_cp_aaps_offline.xml b/omnipod/src/main/res/drawable/ic_cp_aaps_offline.xml index 0b267a6d88..ab562c35a6 100644 --- a/omnipod/src/main/res/drawable/ic_cp_aaps_offline.xml +++ b/omnipod/src/main/res/drawable/ic_cp_aaps_offline.xml @@ -3,19 +3,19 @@ android:height="48dp" android:viewportWidth="24" android:viewportHeight="24"> - - - - - + + + + + diff --git a/omnipod/src/main/res/drawable/ic_cp_bolus_correction.xml b/omnipod/src/main/res/drawable/ic_cp_bolus_correction.xml index e14bb7c14f..49d6332c8e 100644 --- a/omnipod/src/main/res/drawable/ic_cp_bolus_correction.xml +++ b/omnipod/src/main/res/drawable/ic_cp_bolus_correction.xml @@ -3,10 +3,10 @@ android:height="48dp" android:viewportWidth="24" android:viewportHeight="24"> - - + + diff --git a/omnipod/src/main/res/drawable/ic_cp_pump_canula.xml b/omnipod/src/main/res/drawable/ic_cp_pump_canula.xml index b43de7ceaa..f302f9770c 100644 --- a/omnipod/src/main/res/drawable/ic_cp_pump_canula.xml +++ b/omnipod/src/main/res/drawable/ic_cp_pump_canula.xml @@ -3,7 +3,7 @@ android:height="48dp" android:viewportWidth="24" android:viewportHeight="24"> - + diff --git a/omnipod/src/main/res/drawable/ic_exit_to_app.xml b/omnipod/src/main/res/drawable/ic_exit_to_app.xml deleted file mode 100644 index 37a6c7d058..0000000000 --- a/omnipod/src/main/res/drawable/ic_exit_to_app.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - diff --git a/omnipod/src/main/res/drawable/ic_local_activate.xml b/omnipod/src/main/res/drawable/ic_local_activate.xml index 905ade57d3..c171fe367e 100644 --- a/omnipod/src/main/res/drawable/ic_local_activate.xml +++ b/omnipod/src/main/res/drawable/ic_local_activate.xml @@ -3,10 +3,10 @@ android:height="48dp" android:viewportWidth="24" android:viewportHeight="24"> - - + + diff --git a/omnipod/src/main/res/drawable/ic_loop_disabled.xml b/omnipod/src/main/res/drawable/ic_loop_disabled.xml index ed79c96429..81dabea9d6 100644 --- a/omnipod/src/main/res/drawable/ic_loop_disabled.xml +++ b/omnipod/src/main/res/drawable/ic_loop_disabled.xml @@ -3,13 +3,13 @@ android:height="48dp" android:viewportWidth="24" android:viewportHeight="24"> - - - + + + diff --git a/omnipod/src/main/res/drawable/ic_toast_check.xml b/omnipod/src/main/res/drawable/ic_toast_check.xml new file mode 100644 index 0000000000..01efa0f6e3 --- /dev/null +++ b/omnipod/src/main/res/drawable/ic_toast_check.xml @@ -0,0 +1,10 @@ + + + \ No newline at end of file diff --git a/omnipod/src/main/res/drawable/ic_toast_delete_confirm.xml b/omnipod/src/main/res/drawable/ic_toast_delete_confirm.xml new file mode 100644 index 0000000000..e5be03e8ec --- /dev/null +++ b/omnipod/src/main/res/drawable/ic_toast_delete_confirm.xml @@ -0,0 +1,10 @@ + + + \ No newline at end of file diff --git a/omnipod/src/main/res/layout/omnipod_initpod.xml b/omnipod/src/main/res/layout/omnipod_initpod.xml deleted file mode 100644 index af83f9583c..0000000000 --- a/omnipod/src/main/res/layout/omnipod_initpod.xml +++ /dev/null @@ -1,105 +0,0 @@ - - - - - - - - - - - - - - - - - - - -