Merge pull request #73 from 0pen-dash/avereha/stats

add connection quality and delivery status
This commit is contained in:
Andrei Vereha 2021-08-05 21:38:16 +02:00 committed by GitHub
commit 6cda6e9a9a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
23 changed files with 276 additions and 107 deletions

View file

@ -3,27 +3,10 @@
<option name="AUTODETECT_INDENTS" value="false" /> <option name="AUTODETECT_INDENTS" value="false" />
<option name="WRAP_WHEN_TYPING_REACHES_RIGHT_MARGIN" value="true" /> <option name="WRAP_WHEN_TYPING_REACHES_RIGHT_MARGIN" value="true" />
<JetCodeStyleSettings> <JetCodeStyleSettings>
<option name="PACKAGES_TO_USE_STAR_IMPORTS">
<value>
<package name="java.util" alias="false" withSubpackages="false" />
<package name="kotlinx.android.synthetic" alias="false" withSubpackages="true" />
<package name="io.ktor" alias="false" withSubpackages="true" />
</value>
</option>
<option name="PACKAGES_IMPORT_LAYOUT">
<value>
<package name="" alias="false" withSubpackages="true" />
<package name="java" alias="false" withSubpackages="true" />
<package name="javax" alias="false" withSubpackages="true" />
<package name="kotlin" alias="false" withSubpackages="true" />
<package name="" alias="true" withSubpackages="true" />
</value>
</option>
<option name="ALIGN_IN_COLUMNS_CASE_BRANCH" value="true" /> <option name="ALIGN_IN_COLUMNS_CASE_BRANCH" value="true" />
<option name="NAME_COUNT_TO_USE_STAR_IMPORT" value="6" /> <option name="NAME_COUNT_TO_USE_STAR_IMPORT" value="6" />
<option name="NAME_COUNT_TO_USE_STAR_IMPORT_FOR_MEMBERS" value="6" /> <option name="NAME_COUNT_TO_USE_STAR_IMPORT_FOR_MEMBERS" value="6" />
<option name="BLANK_LINES_AROUND_BLOCK_WHEN_BRANCHES" value="1" /> <option name="BLANK_LINES_AROUND_BLOCK_WHEN_BRANCHES" value="1" />
<option name="WRAP_EXPRESSION_BODY_FUNCTIONS" value="1" />
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" /> <option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
</JetCodeStyleSettings> </JetCodeStyleSettings>
<codeStyleSettings language="JAVA"> <codeStyleSettings language="JAVA">
@ -143,8 +126,8 @@
</arrangement> </arrangement>
</codeStyleSettings> </codeStyleSettings>
<codeStyleSettings language="kotlin"> <codeStyleSettings language="kotlin">
<option name="RIGHT_MARGIN" value="120" />
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" /> <option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
<option name="RIGHT_MARGIN" value="120" />
<option name="LINE_COMMENT_AT_FIRST_COLUMN" value="false" /> <option name="LINE_COMMENT_AT_FIRST_COLUMN" value="false" />
<option name="LINE_COMMENT_ADD_SPACE" value="true" /> <option name="LINE_COMMENT_ADD_SPACE" value="true" />
<option name="KEEP_BLANK_LINES_IN_DECLARATIONS" value="1" /> <option name="KEEP_BLANK_LINES_IN_DECLARATIONS" value="1" />
@ -152,13 +135,6 @@
<option name="KEEP_BLANK_LINES_BEFORE_RBRACE" value="1" /> <option name="KEEP_BLANK_LINES_BEFORE_RBRACE" value="1" />
<option name="BLANK_LINES_AFTER_CLASS_HEADER" value="1" /> <option name="BLANK_LINES_AFTER_CLASS_HEADER" value="1" />
<option name="ALIGN_MULTILINE_PARAMETERS_IN_CALLS" value="true" /> <option name="ALIGN_MULTILINE_PARAMETERS_IN_CALLS" value="true" />
<option name="CALL_PARAMETERS_WRAP" value="5" />
<option name="CALL_PARAMETERS_LPAREN_ON_NEXT_LINE" value="true" />
<option name="CALL_PARAMETERS_RPAREN_ON_NEXT_LINE" value="true" />
<option name="METHOD_PARAMETERS_WRAP" value="5" />
<option name="METHOD_PARAMETERS_LPAREN_ON_NEXT_LINE" value="true" />
<option name="METHOD_PARAMETERS_RPAREN_ON_NEXT_LINE" value="true" />
<option name="METHOD_CALL_CHAIN_WRAP" value="1" />
<option name="ASSIGNMENT_WRAP" value="5" /> <option name="ASSIGNMENT_WRAP" value="5" />
<option name="METHOD_ANNOTATION_WRAP" value="5" /> <option name="METHOD_ANNOTATION_WRAP" value="5" />
<option name="CLASS_ANNOTATION_WRAP" value="1" /> <option name="CLASS_ANNOTATION_WRAP" value="1" />

View file

@ -15,6 +15,7 @@ import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin
import info.nightscout.androidaps.plugins.configBuilder.PluginStore import info.nightscout.androidaps.plugins.configBuilder.PluginStore
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctionImplementation import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctionImplementation
import info.nightscout.androidaps.plugins.general.maintenance.ImportExportPrefsImpl import info.nightscout.androidaps.plugins.general.maintenance.ImportExportPrefsImpl
import info.nightscout.androidaps.plugins.general.maintenance.PrefFileListProvider
import info.nightscout.androidaps.plugins.general.nsclient.DataSyncSelectorImplementation import info.nightscout.androidaps.plugins.general.nsclient.DataSyncSelectorImplementation
import info.nightscout.androidaps.plugins.general.smsCommunicator.SmsCommunicatorPlugin import info.nightscout.androidaps.plugins.general.smsCommunicator.SmsCommunicatorPlugin
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
@ -22,6 +23,8 @@ import info.nightscout.androidaps.plugins.pump.PumpSyncImplementation
import info.nightscout.androidaps.queue.CommandQueue import info.nightscout.androidaps.queue.CommandQueue
import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.androidNotification.NotificationHolderImpl import info.nightscout.androidaps.utils.androidNotification.NotificationHolderImpl
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
import info.nightscout.androidaps.utils.buildHelper.BuildHelperImpl
import info.nightscout.androidaps.utils.buildHelper.ConfigImpl import info.nightscout.androidaps.utils.buildHelper.ConfigImpl
import info.nightscout.androidaps.utils.resources.IconsProviderImplementation import info.nightscout.androidaps.utils.resources.IconsProviderImplementation
import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.resources.ResourceHelper
@ -56,6 +59,10 @@ open class AppModule {
@Singleton @Singleton
fun provideStorage(): Storage = FileStorage() fun provideStorage(): Storage = FileStorage()
@Provides
@Singleton
fun provideBuildHelper(config: Config, fileListProvider: PrefFileListProvider): BuildHelper = BuildHelperImpl(config, fileListProvider)
@Provides @Provides
@Singleton @Singleton
internal fun provideSchedulers(): AapsSchedulers = DefaultAapsSchedulers() internal fun provideSchedulers(): AapsSchedulers = DefaultAapsSchedulers()

View file

@ -4,14 +4,11 @@ import info.nightscout.androidaps.BuildConfig
import info.nightscout.androidaps.interfaces.Config import info.nightscout.androidaps.interfaces.Config
import info.nightscout.androidaps.plugins.general.maintenance.PrefFileListProvider import info.nightscout.androidaps.plugins.general.maintenance.PrefFileListProvider
import java.io.File import java.io.File
import javax.inject.Inject
import javax.inject.Singleton
@Singleton class BuildHelperImpl constructor(
class BuildHelper @Inject constructor(
private val config: Config, private val config: Config,
fileListProvider: PrefFileListProvider fileListProvider: PrefFileListProvider
) { ) : BuildHelper {
private var devBranch = false private var devBranch = false
private var engineeringMode = false private var engineeringMode = false
@ -23,11 +20,10 @@ class BuildHelper @Inject constructor(
devBranch = BuildConfig.VERSION.contains("-") || BuildConfig.VERSION.matches(Regex(".*[a-zA-Z]+.*")) devBranch = BuildConfig.VERSION.contains("-") || BuildConfig.VERSION.matches(Regex(".*[a-zA-Z]+.*"))
} }
fun isEngineeringModeOrRelease(): Boolean = override fun isEngineeringModeOrRelease(): Boolean =
if (!config.APS) true else engineeringMode || !devBranch if (!config.APS) true else engineeringMode || !devBranch
fun isEngineeringMode(): Boolean = override fun isEngineeringMode(): Boolean = engineeringMode
engineeringMode
fun isDev(): Boolean = devBranch override fun isDev(): Boolean = devBranch
} }

View file

@ -19,7 +19,6 @@ import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
import info.nightscout.androidaps.plugins.constraints.objectives.ObjectivesPlugin import info.nightscout.androidaps.plugins.constraints.objectives.ObjectivesPlugin
import info.nightscout.androidaps.plugins.constraints.objectives.objectives.Objective import info.nightscout.androidaps.plugins.constraints.objectives.objectives.Objective
import info.nightscout.androidaps.plugins.constraints.safety.SafetyPlugin import info.nightscout.androidaps.plugins.constraints.safety.SafetyPlugin
import info.nightscout.androidaps.plugins.general.maintenance.LoggerUtils
import info.nightscout.androidaps.plugins.general.maintenance.PrefFileListProvider import info.nightscout.androidaps.plugins.general.maintenance.PrefFileListProvider
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatusProvider import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatusProvider
import info.nightscout.androidaps.plugins.pump.combo.ComboPlugin import info.nightscout.androidaps.plugins.pump.combo.ComboPlugin

View file

@ -12,7 +12,6 @@ import info.nightscout.androidaps.interfaces.Constraint
import info.nightscout.androidaps.interfaces.PumpDescription import info.nightscout.androidaps.interfaces.PumpDescription
import info.nightscout.androidaps.interfaces.PumpSync import info.nightscout.androidaps.interfaces.PumpSync
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
import info.nightscout.androidaps.plugins.general.maintenance.LoggerUtils
import info.nightscout.androidaps.plugins.general.maintenance.PrefFileListProvider import info.nightscout.androidaps.plugins.general.maintenance.PrefFileListProvider
import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin
import info.nightscout.androidaps.queue.commands.Command import info.nightscout.androidaps.queue.commands.Command

View file

@ -0,0 +1,8 @@
package info.nightscout.androidaps.utils.buildHelper
interface BuildHelper {
fun isEngineeringModeOrRelease(): Boolean
fun isEngineeringMode(): Boolean
fun isDev(): Boolean
}

View file

@ -147,13 +147,12 @@ class OmnipodDashPumpPlugin @Inject constructor(
} else { } else {
rxBus.send(EventDismissNotification(Notification.OMNIPOD_POD_NOT_ATTACHED)) rxBus.send(EventDismissNotification(Notification.OMNIPOD_POD_NOT_ATTACHED))
if (podStateManager.isSuspended) { if (podStateManager.isSuspended) {
val notification = showNotification(
Notification(
Notification.OMNIPOD_POD_SUSPENDED, Notification.OMNIPOD_POD_SUSPENDED,
"Insulin delivery suspended", "Insulin delivery suspended",
Notification.NORMAL Notification.NORMAL,
R.raw.boluserror
) )
rxBus.send(EventNewNotification(notification))
} else { } else {
rxBus.send(EventDismissNotification(Notification.OMNIPOD_POD_SUSPENDED)) rxBus.send(EventDismissNotification(Notification.OMNIPOD_POD_SUSPENDED))
if (!podStateManager.sameTimeZone) { if (!podStateManager.sameTimeZone) {
@ -246,13 +245,13 @@ class OmnipodDashPumpPlugin @Inject constructor(
override fun disconnect(reason: String) { override fun disconnect(reason: String) {
aapsLogger.info(LTag.PUMP, "disconnect reason=$reason") aapsLogger.info(LTag.PUMP, "disconnect reason=$reason")
stopConnecting?.let { it.countDown() } stopConnecting?.countDown()
omnipodManager.disconnect(false) omnipodManager.disconnect(false)
} }
override fun stopConnecting() { override fun stopConnecting() {
aapsLogger.info(LTag.PUMP, "stopConnecting") aapsLogger.info(LTag.PUMP, "stopConnecting")
stopConnecting?.let { it.countDown() } stopConnecting?.countDown()
omnipodManager.disconnect(true) omnipodManager.disconnect(true)
} }
@ -328,6 +327,15 @@ class OmnipodDashPumpPlugin @Inject constructor(
Notification.URGENT, Notification.URGENT,
R.raw.boluserror R.raw.boluserror
) )
if (!podStateManager.alarmSynced) {
pumpSync.insertAnnouncement(
error = podStateManager.alarmType?.toString() ?: "Unknown pod failure",
pumpId = Random.Default.nextLong(),
pumpType = PumpType.OMNIPOD_DASH,
pumpSerial = serialNumber()
)
podStateManager.alarmSynced = true
}
} }
Completable.complete() Completable.complete()
} }
@ -817,7 +825,7 @@ class OmnipodDashPumpPlugin @Inject constructor(
val ret = pumpSync.syncTemporaryBasalWithPumpId( val ret = pumpSync.syncTemporaryBasalWithPumpId(
timestamp = historyEntry.createdAt, timestamp = historyEntry.createdAt,
rate = absoluteRate, rate = absoluteRate,
duration = T.mins(durationInMinutes.toLong()).msecs(), duration = T.mins(durationInMinutes).msecs(),
isAbsolute = true, isAbsolute = true,
type = tbrType, type = tbrType,
pumpId = historyEntry.pumpId(), pumpId = historyEntry.pumpId(),
@ -833,7 +841,7 @@ class OmnipodDashPumpPlugin @Inject constructor(
when { when {
podStateManager.deliveryStatus !in podStateManager.deliveryStatus !in
arrayOf(DeliveryStatus.TEMP_BASAL_ACTIVE, DeliveryStatus.BOLUS_AND_TEMP_BASAL_ACTIVE) -> { arrayOf(DeliveryStatus.TEMP_BASAL_ACTIVE, DeliveryStatus.BOLUS_AND_TEMP_BASAL_ACTIVE) -> {
// TODO: what happens if we try to cancel inexistent temp basal? // TODO: what happens if we try to cancel nonexistent temp basal?
aapsLogger.info(LTag.PUMP, "No temporary basal to cancel") aapsLogger.info(LTag.PUMP, "No temporary basal to cancel")
Completable.complete() Completable.complete()
} }
@ -841,7 +849,7 @@ class OmnipodDashPumpPlugin @Inject constructor(
!enforceNew -> !enforceNew ->
Completable.error( Completable.error(
IllegalStateException( IllegalStateException(
"Temporary basal already active and enforeNew is not set." "Temporary basal already active and enforceNew is not set."
) )
) )
@ -979,7 +987,7 @@ class OmnipodDashPumpPlugin @Inject constructor(
aapsLogger.warn(LTag.PUMP, "Unsupported custom action: $customActionType") aapsLogger.warn(LTag.PUMP, "Unsupported custom action: $customActionType")
} }
override fun executeCustomCommand(customCommand: CustomCommand): PumpEnactResult? { override fun executeCustomCommand(customCommand: CustomCommand): PumpEnactResult {
return when (customCommand) { return when (customCommand) {
is CommandSilenceAlerts -> is CommandSilenceAlerts ->
silenceAlerts() silenceAlerts()
@ -1068,7 +1076,8 @@ class OmnipodDashPumpPlugin @Inject constructor(
private fun deactivatePod(): PumpEnactResult { private fun deactivatePod(): PumpEnactResult {
val ret = executeProgrammingCommand( val ret = executeProgrammingCommand(
historyEntry = history.createRecord(OmnipodCommandType.DEACTIVATE_POD), historyEntry = history.createRecord(OmnipodCommandType.DEACTIVATE_POD),
command = omnipodManager.deactivatePod().ignoreElements() command = omnipodManager.deactivatePod().ignoreElements(),
checkNoActiveCommand = false,
).doOnComplete { ).doOnComplete {
rxBus.send(EventDismissNotification(Notification.OMNIPOD_POD_FAULT)) rxBus.send(EventDismissNotification(Notification.OMNIPOD_POD_FAULT))
}.toPumpEnactResult() }.toPumpEnactResult()
@ -1381,11 +1390,9 @@ class OmnipodDashPumpPlugin @Inject constructor(
sp.getBoolean(R.string.key_omnipod_common_notification_uncertain_tbr_sound_enabled, true) sp.getBoolean(R.string.key_omnipod_common_notification_uncertain_tbr_sound_enabled, true)
Notification.OMNIPOD_UNCERTAIN_SMB -> Notification.OMNIPOD_UNCERTAIN_SMB ->
sp.getBoolean(R.string.key_omnipod_common_notification_uncertain_smb_sound_enabled, true) sp.getBoolean(R.string.key_omnipod_common_notification_uncertain_smb_sound_enabled, true)
Notification.OMNIPOD_POD_SUSPENDED ->
sp.getBoolean(R.string.key_omnipod_common_notification_delivery_suspended_sound_enabled, true)
else -> true else -> true
} }
} }
private fun dismissNotification(id: Int) {
rxBus.send(EventDismissNotification(id))
}
} }

View file

@ -166,7 +166,7 @@ class OmnipodDashBleManagerImpl @Inject constructor(
throw SessionEstablishmentException("Received resynchronization SQN for the second time") throw SessionEstablishmentException("Received resynchronization SQN for the second time")
} }
} }
podState.successfulConnections++
podState.commitEapAkaSequenceNumber() podState.commitEapAkaSequenceNumber()
} }
@ -223,6 +223,7 @@ class OmnipodDashBleManagerImpl @Inject constructor(
} }
emitter.onNext(PodEvent.EstablishingSession) emitter.onNext(PodEvent.EstablishingSession)
establishSession(pairResult.msgSeq) establishSession(pairResult.msgSeq)
podState.successfulConnections++
emitter.onNext(PodEvent.Connected) emitter.onNext(PodEvent.Connected)
emitter.onComplete() emitter.onComplete()
} catch (ex: Exception) { } catch (ex: Exception) {

View file

@ -211,8 +211,8 @@ class BleCommCallbacks(
fun resetConnection() { fun resetConnection() {
aapsLogger.debug(LTag.PUMPBTCOMM, "Reset connection") aapsLogger.debug(LTag.PUMPBTCOMM, "Reset connection")
connected?.countDown() connected.countDown()
serviceDiscoveryComplete?.countDown() serviceDiscoveryComplete.countDown()
connected = CountDownLatch(1) connected = CountDownLatch(1)
serviceDiscoveryComplete = CountDownLatch(1) serviceDiscoveryComplete = CountDownLatch(1)
flushConfirmationQueue() flushConfirmationQueue()

View file

@ -1,5 +1,3 @@
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.exceptions
open class FailedToConnectException : Exception { open class FailedToConnectException(message: String? = null) : Exception("Failed to connect: ${message ?: ""}")
constructor(message: String? = null) : super("Failed to connect: ${message ?: ""}")
}

View file

@ -37,8 +37,8 @@ class MessageIO(
fun sendMessage(msg: MessagePacket): MessageSendResult { fun sendMessage(msg: MessagePacket): MessageSendResult {
val foundRTS = cmdBleIO.flushIncomingQueue() val foundRTS = cmdBleIO.flushIncomingQueue()
if (foundRTS) { if (foundRTS) {
val msg = receiveMessage(false) val receivedMessage = receiveMessage(false)
aapsLogger.warn(LTag.PUMPBTCOMM, "sendMessage received message=$msg") aapsLogger.warn(LTag.PUMPBTCOMM, "sendMessage received message=$receivedMessage")
throw IllegalStateException("Received message while trying to send") throw IllegalStateException("Received message while trying to send")
} }
dataBleIO.flushIncomingQueue() dataBleIO.flushIncomingQueue()

View file

@ -2,6 +2,5 @@ package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.scan
import android.os.ParcelUuid import android.os.ParcelUuid
class DiscoveredInvalidPodException : Exception { class DiscoveredInvalidPodException(message: String, serviceUUIds: List<ParcelUuid?>) :
constructor(message: String, serviceUUIds: List<ParcelUuid?>) : super("$message service UUIDs: $serviceUUIds") Exception("$message service UUIDs: $serviceUUIds")
}

View file

@ -64,7 +64,7 @@ class Connection(
fun connect(connectionWaitCond: ConnectionWaitCondition) { fun connect(connectionWaitCond: ConnectionWaitCondition) {
aapsLogger.debug("Connecting connectionWaitCond=$connectionWaitCond") aapsLogger.debug("Connecting connectionWaitCond=$connectionWaitCond")
podState.connectionAttempts++
podState.bluetoothConnectionState = OmnipodDashPodStateManager.BluetoothConnectionState.CONNECTING podState.bluetoothConnectionState = OmnipodDashPodStateManager.BluetoothConnectionState.CONNECTING
val autoConnect = false val autoConnect = false
val gatt = gattConnection val gatt = gattConnection

View file

@ -15,8 +15,6 @@ class BasalProgram(
fun hasZeroUnitSegments() = segments.any { it.basalRateInHundredthUnitsPerHour == 0 } fun hasZeroUnitSegments() = segments.any { it.basalRateInHundredthUnitsPerHour == 0 }
fun isZeroBasal() = segments.sumBy(Segment::basalRateInHundredthUnitsPerHour) == 0
fun rateAt(date: Date): Double { fun rateAt(date: Date): Double {
val instance = Calendar.getInstance() val instance = Calendar.getInstance()
instance.time = date instance.time = date

View file

@ -8,6 +8,6 @@ enum class BeepRepetitionType(
XXX(0x01.toByte()), // Used in lump of coal alert, LOW_RESERVOIR XXX(0x01.toByte()), // Used in lump of coal alert, LOW_RESERVOIR
XXX2(0x03.toByte()), // Used in USER_SET_EXPIRATION XXX2(0x03.toByte()), // Used in USER_SET_EXPIRATION
XXX3(0x05.toByte()), // published system expiration alert XXX3(0x05.toByte()), // published system expiration alert
XXX4(0x06.toByte()), // Used in imminent pod expiration alert XXX4(0x06.toByte()), // Used in imminent pod expiration alert, suspend in progress
XXX5(0x08.toByte()); // Lump of coal alert XXX5(0x08.toByte()); // Lump of coal alert
} }

View file

@ -4,5 +4,6 @@ enum class BeepType(val value: Byte) {
SILENT(0x00.toByte()), SILENT(0x00.toByte()),
FOUR_TIMES_BIP_BEEP(0x02.toByte()), // Used in low reservoir alert, user expiration alert, expiration alert, imminent expiration alert, lump of coal alert FOUR_TIMES_BIP_BEEP(0x02.toByte()), // Used in low reservoir alert, user expiration alert, expiration alert, imminent expiration alert, lump of coal alert
XXX(0x04.toByte()), // Used during suspend
LONG_SINGLE_BEEP(0x06.toByte()); // Used in stop delivery command LONG_SINGLE_BEEP(0x06.toByte()); // Used in stop delivery command
} }

View file

@ -4,6 +4,6 @@ import java.time.Duration
class PodConstants { class PodConstants {
companion object { companion object {
val MAX_POD_LIFETIME = Duration.ofMinutes(80) val MAX_POD_LIFETIME = Duration.ofHours(80)
} }
} }

View file

@ -31,6 +31,8 @@ interface OmnipodDashPodStateManager {
val isPodRunning: Boolean val isPodRunning: Boolean
val isPodKaput: Boolean val isPodKaput: Boolean
var bluetoothConnectionState: BluetoothConnectionState var bluetoothConnectionState: BluetoothConnectionState
var connectionAttempts: Int
var successfulConnections: Int
var timeZone: TimeZone var timeZone: TimeZone
val sameTimeZone: Boolean // The TimeZone is the same on the phone and on the pod val sameTimeZone: Boolean // The TimeZone is the same on the phone and on the pod
@ -39,6 +41,7 @@ interface OmnipodDashPodStateManager {
val time: ZonedDateTime? val time: ZonedDateTime?
val timeDrift: java.time.Duration? val timeDrift: java.time.Duration?
val expiry: ZonedDateTime? val expiry: ZonedDateTime?
var alarmSynced: Boolean
val messageSequenceNumber: Short val messageSequenceNumber: Short
val sequenceNumberOfLastProgrammingCommand: Short? val sequenceNumberOfLastProgrammingCommand: Short?
@ -81,6 +84,7 @@ interface OmnipodDashPodStateManager {
fun updateFromAlarmStatusResponse(response: AlarmStatusResponse) fun updateFromAlarmStatusResponse(response: AlarmStatusResponse)
fun updateFromPairing(uniqueId: Id, pairResult: PairResult) fun updateFromPairing(uniqueId: Id, pairResult: PairResult)
fun reset() fun reset()
fun connectionSuccessRatio(): Float
fun createActiveCommand( fun createActiveCommand(
historyId: String, historyId: String,

View file

@ -98,6 +98,22 @@ class OmnipodDashPodStateManagerImpl @Inject constructor(
} }
} }
override var connectionAttempts: Int
@Synchronized
get() = podState.connectionAttempts
@Synchronized
set(value) {
podState.connectionAttempts = value
}
override var successfulConnections: Int
@Synchronized
get() = podState.successfulConnections
@Synchronized
set(value) {
podState.successfulConnections = value
}
override var timeZone: TimeZone override var timeZone: TimeZone
get() = TimeZone.getTimeZone(podState.timeZone) get() = TimeZone.getTimeZone(podState.timeZone)
set(tz) { set(tz) {
@ -108,7 +124,19 @@ class OmnipodDashPodStateManagerImpl @Inject constructor(
override val sameTimeZone: Boolean override val sameTimeZone: Boolean
get() { get() {
val now = System.currentTimeMillis() val now = System.currentTimeMillis()
return TimeZone.getDefault().getOffset(now) == timeZone.getOffset(now) val currentTimezone = TimeZone.getDefault()
val currentOffset = currentTimezone.getOffset(now)
val podOffset = timeZone.getOffset(now)
logger.debug(
LTag.PUMPCOMM,
"sameTimeZone currentTimezone=${currentTimezone.getDisplayName(
true,
TimeZone.SHORT
)} " +
"currentOffset=$currentOffset " +
"podOffset=$podOffset"
)
return currentOffset == podOffset
} }
override val bluetoothVersion: SoftwareVersion? override val bluetoothVersion: SoftwareVersion?
@ -217,6 +245,13 @@ class OmnipodDashPodStateManagerImpl @Inject constructor(
return null return null
} }
override var alarmSynced: Boolean
get() = podState.alarmSynced
set(value) {
podState.alarmSynced = value
store()
}
override var bluetoothConnectionState: OmnipodDashPodStateManager.BluetoothConnectionState override var bluetoothConnectionState: OmnipodDashPodStateManager.BluetoothConnectionState
@Synchronized @Synchronized
get() = podState.bluetoothConnectionState get() = podState.bluetoothConnectionState
@ -482,8 +517,10 @@ class OmnipodDashPodStateManagerImpl @Inject constructor(
podState.lastStatusResponseReceived = 0 podState.lastStatusResponseReceived = 0
} }
CommandSendingFailure, NoActiveCommand -> CommandSendingFailure, NoActiveCommand -> {
podState.activeCommand = null podState.activeCommand = null
podState.lastStatusResponseReceived = 0
}
} }
} }
@ -560,7 +597,7 @@ class OmnipodDashPodStateManagerImpl @Inject constructor(
override fun updateFromAlarmStatusResponse(response: AlarmStatusResponse) { override fun updateFromAlarmStatusResponse(response: AlarmStatusResponse) {
logger.info( logger.info(
LTag.PUMP, LTag.PUMP,
"Received AlarmStatusReponse: $response" "Received AlarmStatusResponse: $response"
) )
podState.deliveryStatus = response.deliveryStatus podState.deliveryStatus = response.deliveryStatus
podState.podStatus = response.podStatus podState.podStatus = response.podStatus
@ -588,6 +625,14 @@ class OmnipodDashPodStateManagerImpl @Inject constructor(
podState.uniqueId = uniqueId.toLong() podState.uniqueId = uniqueId.toLong()
} }
override fun connectionSuccessRatio(): Float {
val attempts = connectionAttempts
if (attempts == 0) {
return 1.0F
}
return successfulConnections.toFloat() * 100 / attempts.toFloat()
}
override fun reset() { override fun reset() {
podState = PodState() podState = PodState()
store() store()
@ -625,6 +670,8 @@ class OmnipodDashPodStateManagerImpl @Inject constructor(
var lastStatusResponseReceived: Long = 0 var lastStatusResponseReceived: Long = 0
var bluetoothConnectionState: OmnipodDashPodStateManager.BluetoothConnectionState = var bluetoothConnectionState: OmnipodDashPodStateManager.BluetoothConnectionState =
OmnipodDashPodStateManager.BluetoothConnectionState.DISCONNECTED OmnipodDashPodStateManager.BluetoothConnectionState.DISCONNECTED
var connectionAttempts = 0
var successfulConnections = 0
var messageSequenceNumber: Short = 0 var messageSequenceNumber: Short = 0
var sequenceNumberOfLastProgrammingCommand: Short? = null var sequenceNumberOfLastProgrammingCommand: Short? = null
var activationTime: Long? = null var activationTime: Long? = null
@ -634,6 +681,7 @@ class OmnipodDashPodStateManagerImpl @Inject constructor(
var eapAkaSequenceNumber: Long = 1 var eapAkaSequenceNumber: Long = 1
var bolusPulsesRemaining: Short = 0 var bolusPulsesRemaining: Short = 0
var timeZone: String = "" // TimeZone ID (e.g. "Europe/Amsterdam") var timeZone: String = "" // TimeZone ID (e.g. "Europe/Amsterdam")
var alarmSynced: Boolean = false
var bleVersion: SoftwareVersion? = null var bleVersion: SoftwareVersion? = null
var firmwareVersion: SoftwareVersion? = null var firmwareVersion: SoftwareVersion? = null

View file

@ -24,7 +24,6 @@ import info.nightscout.androidaps.plugins.pump.omnipod.common.queue.command.Comm
import info.nightscout.androidaps.plugins.pump.omnipod.common.queue.command.CommandResumeDelivery import info.nightscout.androidaps.plugins.pump.omnipod.common.queue.command.CommandResumeDelivery
import info.nightscout.androidaps.plugins.pump.omnipod.common.queue.command.CommandSilenceAlerts import info.nightscout.androidaps.plugins.pump.omnipod.common.queue.command.CommandSilenceAlerts
import info.nightscout.androidaps.plugins.pump.omnipod.common.queue.command.CommandSuspendDelivery import info.nightscout.androidaps.plugins.pump.omnipod.common.queue.command.CommandSuspendDelivery
import info.nightscout.androidaps.plugins.pump.omnipod.dash.BuildConfig
import info.nightscout.androidaps.plugins.pump.omnipod.dash.EventOmnipodDashPumpValuesChanged import info.nightscout.androidaps.plugins.pump.omnipod.dash.EventOmnipodDashPumpValuesChanged
import info.nightscout.androidaps.plugins.pump.omnipod.dash.OmnipodDashPumpPlugin import info.nightscout.androidaps.plugins.pump.omnipod.dash.OmnipodDashPumpPlugin
import info.nightscout.androidaps.plugins.pump.omnipod.dash.R import info.nightscout.androidaps.plugins.pump.omnipod.dash.R
@ -37,6 +36,7 @@ import info.nightscout.androidaps.queue.events.EventQueueChanged
import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.alertDialogs.OKDialog import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.androidaps.utils.sharedPreferences.SP import info.nightscout.androidaps.utils.sharedPreferences.SP
@ -63,6 +63,7 @@ class OmnipodDashOverviewFragment : DaggerFragment() {
@Inject lateinit var dateUtil: DateUtil @Inject lateinit var dateUtil: DateUtil
@Inject lateinit var aapsSchedulers: AapsSchedulers @Inject lateinit var aapsSchedulers: AapsSchedulers
@Inject lateinit var pumpSync: PumpSync @Inject lateinit var pumpSync: PumpSync
@Inject lateinit var buildHelper: BuildHelper
companion object { companion object {
@ -83,17 +84,17 @@ class OmnipodDashOverviewFragment : DaggerFragment() {
} }
} }
var _binding: OmnipodDashOverviewBinding? = null private var _binding: OmnipodDashOverviewBinding? = null
var _bluetoothStatusBinding: OmnipodDashOverviewBluetoothStatusBinding? = null private var _bluetoothStatusBinding: OmnipodDashOverviewBluetoothStatusBinding? = null
var _podInfoBinding: OmnipodCommonOverviewPodInfoBinding? = null private var _podInfoBinding: OmnipodCommonOverviewPodInfoBinding? = null
var _buttonBinding: OmnipodCommonOverviewButtonsBinding? = null private var _buttonBinding: OmnipodCommonOverviewButtonsBinding? = null
// These properties are only valid between onCreateView and // These properties are only valid between onCreateView and
// onDestroyView. // onDestroyView.
val binding get() = _binding!! val binding get() = _binding!!
val bluetoothStatusBinding get() = _bluetoothStatusBinding!! val bluetoothStatusBinding get() = _bluetoothStatusBinding!!
val podInfoBinding get() = _podInfoBinding!! private val podInfoBinding get() = _podInfoBinding!!
val buttonBinding get() = _buttonBinding!! private val buttonBinding get() = _buttonBinding!!
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View = override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View =
OmnipodDashOverviewBinding.inflate(inflater, container, false).also { OmnipodDashOverviewBinding.inflate(inflater, container, false).also {
@ -166,6 +167,10 @@ class OmnipodDashOverviewFragment : DaggerFragment() {
.messageOnSuccess(resourceHelper.gs(R.string.omnipod_common_confirmation_time_on_pod_updated)) .messageOnSuccess(resourceHelper.gs(R.string.omnipod_common_confirmation_time_on_pod_updated))
) )
} }
if (buildHelper.isEngineeringMode()) {
bluetoothStatusBinding.deliveryStatus.visibility = View.VISIBLE
bluetoothStatusBinding.connectionQuality.visibility = View.VISIBLE
}
} }
override fun onResume() { override fun onResume() {
@ -213,6 +218,9 @@ class OmnipodDashOverviewFragment : DaggerFragment() {
override fun onDestroyView() { override fun onDestroyView() {
super.onDestroyView() super.onDestroyView()
_binding = null _binding = null
_bluetoothStatusBinding = null
_buttonBinding = null
_podInfoBinding = null
} }
private fun updateUi() { private fun updateUi() {
@ -234,6 +242,24 @@ class OmnipodDashOverviewFragment : DaggerFragment() {
OmnipodDashPodStateManager.BluetoothConnectionState.CONNECTING -> OmnipodDashPodStateManager.BluetoothConnectionState.CONNECTING ->
"{fa-bluetooth-b spin}" "{fa-bluetooth-b spin}"
} }
val connectionSuccessPercentage = podStateManager.connectionSuccessRatio() * 100
val successPercentageString = String.format("%.2f %%", podStateManager.connectionSuccessRatio())
val quality =
"${podStateManager.successfulConnections}/${podStateManager.connectionAttempts} :: $successPercentageString"
bluetoothStatusBinding.omnipodDashBluetoothConnectionQuality.text = quality
val connectionStatsColor = when {
connectionSuccessPercentage > 90 ->
Color.WHITE
connectionSuccessPercentage > 60 ->
Color.YELLOW
else ->
Color.RED
}
bluetoothStatusBinding.omnipodDashBluetoothConnectionQuality.setTextColor(connectionStatsColor)
bluetoothStatusBinding.omnipodDashDeliveryStatus.text = podStateManager.deliveryStatus?.let {
podStateManager.deliveryStatus.toString()
} ?: PLACEHOLDER
} }
private fun updateOmnipodStatus() { private fun updateOmnipodStatus() {
@ -316,7 +342,8 @@ class OmnipodDashOverviewFragment : DaggerFragment() {
} }
// base basal rate // base basal rate
podInfoBinding.baseBasalRate.text = if (podStateManager.basalProgram != null && !podStateManager.isSuspended) { podInfoBinding.baseBasalRate.text =
if (podStateManager.basalProgram != null && !podStateManager.isSuspended) {
resourceHelper.gs( resourceHelper.gs(
R.string.pump_basebasalrate, R.string.pump_basebasalrate,
omnipodDashPumpPlugin.model() omnipodDashPumpPlugin.model()
@ -361,8 +388,8 @@ class OmnipodDashOverviewFragment : DaggerFragment() {
) )
} }
podInfoBinding.podActiveAlerts.text = podStateManager.activeAlerts?.let { podInfoBinding.podActiveAlerts.text = podStateManager.activeAlerts?.let { it ->
it.map { it.toString() }.joinToString(",") it.joinToString(",") { it.toString() }
} ?: PLACEHOLDER } ?: PLACEHOLDER
} }
@ -415,12 +442,8 @@ class OmnipodDashOverviewFragment : DaggerFragment() {
if (podStateManager.isSuspended) { if (podStateManager.isSuspended) {
resourceHelper.gs(R.string.omnipod_common_pod_status_suspended) resourceHelper.gs(R.string.omnipod_common_pod_status_suspended)
} else { } else {
resourceHelper.gs(R.string.omnipod_common_pod_status_running) + resourceHelper.gs(R.string.omnipod_common_pod_status_running)
if (BuildConfig.DEBUG)
podStateManager.deliveryStatus?.let { " " + podStateManager.deliveryStatus.toString() }
else ""
} }
// TODO
/* /*
} else if (podStateManager.podStatus == PodProgressStatus.FAULT_EVENT_OCCURRED) { } else if (podStateManager.podStatus == PodProgressStatus.FAULT_EVENT_OCCURRED) {
resourceHelper.gs(R.string.omnipod_common_pod_status_pod_fault) resourceHelper.gs(R.string.omnipod_common_pod_status_pod_fault)
@ -466,10 +489,10 @@ class OmnipodDashOverviewFragment : DaggerFragment() {
podInfoBinding.lastBolus.setTextColor(textColor) podInfoBinding.lastBolus.setTextColor(textColor)
podStateManager.lastBolus?.let { podStateManager.lastBolus?.let {
// display requested units if delivery is in progress // display requested units if delivery is in progress
var bolusSize = it.deliveredUnits() val bolusSize = it.deliveredUnits()
?: it.requestedUnits ?: it.requestedUnits
var text = resourceHelper.gs( val text = resourceHelper.gs(
R.string.omnipod_common_overview_last_bolus_value, R.string.omnipod_common_overview_last_bolus_value,
omnipodDashPumpPlugin.model().determineCorrectBolusSize(bolusSize), omnipodDashPumpPlugin.model().determineCorrectBolusSize(bolusSize),
resourceHelper.gs(R.string.insulin_unit_shortname), resourceHelper.gs(R.string.insulin_unit_shortname),
@ -623,7 +646,10 @@ class OmnipodDashOverviewFragment : DaggerFragment() {
} }
seconds < 60 * 60 -> { // < 1 hour seconds < 60 * 60 -> { // < 1 hour
return resourceHelper.gs(R.string.omnipod_common_time_ago, resourceHelper.gq(R.plurals.omnipod_common_minutes, minutes, minutes)) return resourceHelper.gs(
R.string.omnipod_common_time_ago,
resourceHelper.gq(R.plurals.omnipod_common_minutes, minutes, minutes)
)
} }
seconds < 24 * 60 * 60 -> { // < 1 day seconds < 24 * 60 * 60 -> { // < 1 day
@ -631,9 +657,16 @@ class OmnipodDashOverviewFragment : DaggerFragment() {
if (minutesLeft > 0) if (minutesLeft > 0)
return resourceHelper.gs( return resourceHelper.gs(
R.string.omnipod_common_time_ago, R.string.omnipod_common_time_ago,
resourceHelper.gs(R.string.omnipod_common_composite_time, resourceHelper.gq(R.plurals.omnipod_common_hours, hours, hours), resourceHelper.gq(R.plurals.omnipod_common_minutes, minutesLeft, minutesLeft)) resourceHelper.gs(
R.string.omnipod_common_composite_time,
resourceHelper.gq(R.plurals.omnipod_common_hours, hours, hours),
resourceHelper.gq(R.plurals.omnipod_common_minutes, minutesLeft, minutesLeft)
)
)
return resourceHelper.gs(
R.string.omnipod_common_time_ago,
resourceHelper.gq(R.plurals.omnipod_common_hours, hours, hours)
) )
return resourceHelper.gs(R.string.omnipod_common_time_ago, resourceHelper.gq(R.plurals.omnipod_common_hours, hours, hours))
} }
else -> { else -> {
@ -642,9 +675,16 @@ class OmnipodDashOverviewFragment : DaggerFragment() {
if (hoursLeft > 0) if (hoursLeft > 0)
return resourceHelper.gs( return resourceHelper.gs(
R.string.omnipod_common_time_ago, R.string.omnipod_common_time_ago,
resourceHelper.gs(R.string.omnipod_common_composite_time, resourceHelper.gq(R.plurals.omnipod_common_days, days, days), resourceHelper.gq(R.plurals.omnipod_common_hours, hoursLeft, hoursLeft)) resourceHelper.gs(
R.string.omnipod_common_composite_time,
resourceHelper.gq(R.plurals.omnipod_common_days, days, days),
resourceHelper.gq(R.plurals.omnipod_common_hours, hoursLeft, hoursLeft)
)
)
return resourceHelper.gs(
R.string.omnipod_common_time_ago,
resourceHelper.gq(R.plurals.omnipod_common_days, days, days)
) )
return resourceHelper.gs(R.string.omnipod_common_time_ago, resourceHelper.gq(R.plurals.omnipod_common_days, days, days))
} }
} }
} }

View file

@ -13,7 +13,7 @@
android:gravity="end" android:gravity="end"
android:paddingStart="5dp" android:paddingStart="5dp"
android:paddingEnd="5dp" android:paddingEnd="5dp"
android:text="@string/omnipod_dash_overview_bluetooth_status" android:text="@string/omnipod_dash_overview_bluetooth_address"
android:textSize="14sp" /> android:textSize="14sp" />
<TextView <TextView
@ -51,7 +51,7 @@
android:gravity="end" android:gravity="end"
android:paddingStart="5dp" android:paddingStart="5dp"
android:paddingEnd="5dp" android:paddingEnd="5dp"
android:text="@string/omnipod_dash_overview_bluetooth_address" android:text="@string/omnipod_dash_overview_bluetooth_status"
android:textSize="14sp" /> android:textSize="14sp" />
<TextView <TextView
@ -78,6 +78,85 @@
tools:ignore="HardcodedText" /> tools:ignore="HardcodedText" />
</LinearLayout> </LinearLayout>
<LinearLayout
android:id="@+id/connectionQuality"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:visibility="gone">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1.5"
android:gravity="end"
android:paddingStart="5dp"
android:paddingEnd="5dp"
android:text="@string/omnipod_dash_overview_bluetooth_connection_quality"
android:textSize="14sp" />
<TextView
android:layout_width="5dp"
android:layout_height="wrap_content"
android:layout_weight="0"
android:gravity="center_horizontal"
android:paddingStart="2dp"
android:paddingEnd="2dp"
android:text=":"
android:textSize="14sp"
tools:ignore="HardcodedText" />
<com.joanzapata.iconify.widget.IconTextView
android:id="@+id/omnipod_dash_bluetooth_connection_quality"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="start"
android:paddingStart="5dp"
android:paddingEnd="5dp"
android:textSize="14sp"
tools:ignore="HardcodedText" />
</LinearLayout>
<LinearLayout
android:id="@+id/deliveryStatus"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:visibility="gone">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1.5"
android:gravity="end"
android:paddingStart="5dp"
android:paddingEnd="5dp"
android:text="@string/omnipod_dash_overview_delivery_status"
android:textSize="14sp" />
<TextView
android:layout_width="5dp"
android:layout_height="wrap_content"
android:layout_weight="0"
android:gravity="center_horizontal"
android:paddingStart="2dp"
android:paddingEnd="2dp"
android:text=":"
android:textSize="14sp"
tools:ignore="HardcodedText" />
<com.joanzapata.iconify.widget.IconTextView
android:id="@+id/omnipod_dash_delivery_status"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="start"
android:paddingStart="5dp"
android:paddingEnd="5dp"
android:textSize="14sp"
tools:ignore="HardcodedText" />
</LinearLayout>
<View <View
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="2dip" android:layout_height="2dip"

View file

@ -12,6 +12,8 @@
<string name="omnipod_dash_overview_bluetooth_status">Bluetooth Status</string> <string name="omnipod_dash_overview_bluetooth_status">Bluetooth Status</string>
<string name="omnipod_dash_overview_bluetooth_address">Bluetooth Address</string> <string name="omnipod_dash_overview_bluetooth_address">Bluetooth Address</string>
<string name="omnipod_dash_overview_firmware_version_value">Firmware %1$s / Bluetooth %2$s</string> <string name="omnipod_dash_overview_firmware_version_value">Firmware %1$s / Bluetooth %2$s</string>
<string name="omnipod_dash_overview_bluetooth_connection_quality">Connection quality</string>
<string name="omnipod_dash_overview_delivery_status">Delivery Status</string>
<!-- Omnipod Dash - Pod Activation Wizard --> <!-- Omnipod Dash - Pod Activation Wizard -->
<string name="omnipod_dash_pod_activation_wizard_start_pod_activation_text">Fill a new Pod with enough insulin for 3 days.\n\nListen for two beeps from the Pod during the filling process. These indicate that the minimum amount of 85U has been inserted. Be sure to completely empty the fill syringe, even after hearing the two beeps.\n\nAfter filling the Pod, please press <b>Next</b>.\n\n<b>Note:</b> do not remove the Pod\'s needle cap at this time.</string> <string name="omnipod_dash_pod_activation_wizard_start_pod_activation_text">Fill a new Pod with enough insulin for 3 days.\n\nListen for two beeps from the Pod during the filling process. These indicate that the minimum amount of 85U has been inserted. Be sure to completely empty the fill syringe, even after hearing the two beeps.\n\nAfter filling the Pod, please press <b>Next</b>.\n\n<b>Note:</b> do not remove the Pod\'s needle cap at this time.</string>
@ -19,4 +21,6 @@
<string name="key_omnipod_common_preferences_category_confirmation_beeps" translatable="false">omnipod_common_preferences_category_confirmation</string> <string name="key_omnipod_common_preferences_category_confirmation_beeps" translatable="false">omnipod_common_preferences_category_confirmation</string>
<string name="key_common_preferences_category_other_settings" translatable="false">common_preferences_category_other</string> <string name="key_common_preferences_category_other_settings" translatable="false">common_preferences_category_other</string>
<string name="key_omnipod_common_notification_delivery_suspended_sound_enabled">AAPS.Omnipod.notification_delivery_suspended_sound_enabled</string>
<string name="omnipod_common_preferences_notification_delivery_suspended_sound_enabled">Sound when delivery suspended notification enabled</string>
</resources> </resources>

View file

@ -93,6 +93,11 @@
android:key="@string/key_omnipod_common_notification_uncertain_bolus_sound_enabled" android:key="@string/key_omnipod_common_notification_uncertain_bolus_sound_enabled"
android:title="@string/omnipod_common_preferences_notification_uncertain_bolus_sound_enabled" /> android:title="@string/omnipod_common_preferences_notification_uncertain_bolus_sound_enabled" />
<SwitchPreference
android:defaultValue="true"
android:key="@string/key_omnipod_common_notification_delivery_suspended_sound_enabled"
android:title="@string/omnipod_common_preferences_notification_delivery_suspended_sound_enabled" />
</PreferenceCategory> </PreferenceCategory>
<PreferenceCategory <PreferenceCategory