Merge pull request #3 from nightscout/dev

Dev merge
This commit is contained in:
teleriddler 2021-02-20 03:22:36 +01:00 committed by GitHub
commit 8c3b155268
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
274 changed files with 2182 additions and 2151 deletions

2
.gitignore vendored
View file

@ -2,7 +2,7 @@
.gradle
/local.properties
.DS_Store
app/jacoco.exec
*/jacoco.exec
/build
/captures
*.apk

View file

@ -1,23 +1,18 @@
buildscript {
repositories {
maven { url "https://plugins.gradle.org/m2/" } // jacoco 0.2
}
dependencies {
//classpath 'com.dicedmelon.gradle:jacoco-android:0.1.4'
classpath 'com.hiya:jacoco-android:0.2'
}
}
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-kapt'
apply plugin: 'com.google.gms.google-services'
//apply plugin: 'jacoco-android'
apply plugin: 'com.hiya.jacoco-android'
apply plugin: 'com.google.firebase.crashlytics'
apply from: "${project.rootDir}/gradle/android_dependencies.gradle"
jacoco {
toolVersion = "0.8.3"
toolVersion = "0.8.6"
}
tasks.withType(Test) {
jacoco.includeNoLocationClasses = true
}
repositories {
@ -109,51 +104,20 @@ tasks.matching { it instanceof Test }.all {
}
android {
compileSdkVersion 28
ndkVersion "21.1.6352462"
defaultConfig {
minSdkVersion 26
targetSdkVersion 28
multiDexEnabled true
versionCode 1500
version "2.8.2.1-dev-a"
version "2.8.2.1-dev-b"
buildConfigField "String", "VERSION", '"' + version + '"'
buildConfigField "String", "BUILDVERSION", '"' + generateGitBuild() + '-' + generateDate() + '"'
buildConfigField "String", "REMOTE", '"' + generateGitRemote() + '"'
buildConfigField "String", "HEAD", '"' + generateGitBuild() + '"'
buildConfigField "String", "COMMITTED", '"' + allCommitted() + '"'
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
// if you change minSdkVersion to less than 11, you need to change executeTask for wear
ndk {
moduleName "BleCommandUtil"
}
}
kotlinOptions {
jvmTarget = '1.8'
}
buildFeatures {
viewBinding true
}
lintOptions {
checkReleaseBuilds false
disable 'MissingTranslation'
disable 'ExtraTranslation'
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
debug {
testCoverageEnabled(project.hasProperty('coverage'))
}
firebaseDisable {
System.setProperty("disableFirebase", "true")
ext.enableCrashlytics = false
}
}
flavorDimensions "standard"
productFlavors {
full {
@ -197,25 +161,8 @@ android {
]
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
testOptions {
unitTests {
returnDefaultValues = true
includeAndroidResources = true
all {
maxParallelForks = 10
forkEvery = 20
}
}
}
useLibrary "org.apache.http.legacy"
}
allprojects {
@ -241,27 +188,9 @@ dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
testImplementation "junit:junit:$junit_version"
testImplementation 'org.json:json:20201115'
testImplementation "org.mockito:mockito-core:${mockitoVersion}"
testImplementation "org.powermock:powermock-api-mockito2:${powermockVersion}"
testImplementation "org.powermock:powermock-module-junit4-rule-agent:${powermockVersion}"
testImplementation "org.powermock:powermock-module-junit4-rule:${powermockVersion}"
testImplementation "org.powermock:powermock-module-junit4:${powermockVersion}"
testImplementation "joda-time:joda-time:$jodatime_version"
testImplementation('com.google.truth:truth:1.1.2') {
exclude group: "com.google.guava", module: "guava"
}
testImplementation "org.skyscreamer:jsonassert:1.5.0"
testImplementation "org.hamcrest:hamcrest-all:1.3"
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0-alpha04'
androidTestImplementation "androidx.test.ext:junit:$androidx_junit"
androidTestImplementation "androidx.test:rules:$androidx_rules"
/* Dagger2 - We are going to use dagger.android which includes
* support for Activity and fragment injection so we need to include
* the following dependencies */
* support for Activity and fragment injection so we need to include
* the following dependencies */
annotationProcessor "com.google.dagger:dagger-compiler:$dagger_version"
@ -270,10 +199,11 @@ dependencies {
/* Dagger2 - default dependency */
kapt "com.google.dagger:dagger-compiler:$dagger_version"
androidTestImplementation 'androidx.test.uiautomator:uiautomator:2.2.0'
}
apply from: "${project.rootDir}/gradle/test_dependencies.gradle"
/*
// Run 'adb' shell command to clear application data of main app for 'debug' variant
task clearMainAppData(type: Exec) {

View file

@ -25,6 +25,7 @@
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="com.dexcom.cgm.EXTERNAL_PERMISSION" />
<uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT" />
<uses-permission android:name="com.android.alarm.permission.SET_ALARM" />
<uses-permission-sdk-23 android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
@ -74,8 +75,12 @@
<activity android:name=".activities.StatsActivity" />
<activity
android:name="com.google.firebase.auth.internal.FederatedSignInActivity"
tools:replace="android:launchMode"
android:launchMode="standard" />
android:excludeFromRecents="true"
android:exported="true"
android:launchMode="singleInstance"
android:permission="com.google.firebase.auth.api.gms.permission.LAUNCH_FEDERATED_SIGN_IN"
android:theme="@android:style/Theme.Translucent.NoTitleBar"
tools:replace="android:launchMode" />
<!-- Receive new BG readings from other local apps -->
<receiver

View file

@ -23,11 +23,7 @@ import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
import info.nightscout.androidaps.plugins.treatments.CarbsGenerator
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.DecimalFormatter
import info.nightscout.androidaps.utils.DefaultValueHelper
import info.nightscout.androidaps.utils.HtmlHelper
import info.nightscout.androidaps.utils.ToastUtils
import info.nightscout.androidaps.utils.*
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.androidaps.utils.extensions.formatColor
import info.nightscout.androidaps.utils.resources.ResourceHelper
@ -48,6 +44,7 @@ class CarbsDialog : DialogFragmentWithDate() {
@Inject lateinit var nsUpload: NSUpload
@Inject lateinit var carbsGenerator: CarbsGenerator
@Inject lateinit var uel: UserEntryLogger
@Inject lateinit var carbTimer: CarbTimer
companion object {
@ -176,6 +173,7 @@ class CarbsDialog : DialogFragmentWithDate() {
val hypoTT = defaultValueHelper.determineHypoTT()
val actions: LinkedList<String?> = LinkedList()
val unitLabel = if (units == Constants.MMOL) resourceHelper.gs(R.string.mmol) else resourceHelper.gs(R.string.mgdl)
val useAlarm = binding.alarmCheckBox.isChecked
val activitySelected = binding.activityTt.isChecked
if (activitySelected)
@ -192,6 +190,8 @@ class CarbsDialog : DialogFragmentWithDate() {
val time = eventTime + timeOffset * 1000 * 60
if (timeOffset != 0)
actions.add(resourceHelper.gs(R.string.time) + ": " + dateUtil.dateAndTimeString(time))
if (useAlarm && carbs > 0 && timeOffset > 0)
actions.add(resourceHelper.gs(R.string.alarminxmin, timeOffset).formatColor(resourceHelper, R.color.info))
val duration = binding.duration.value.toInt()
if (duration > 0)
actions.add(resourceHelper.gs(R.string.duration) + ": " + duration + resourceHelper.gs(R.string.shorthour))
@ -257,6 +257,9 @@ class CarbsDialog : DialogFragmentWithDate() {
nsUpload.uploadEvent(CareportalEvent.NOTE, DateUtil.now() - 2000, resourceHelper.gs(R.string.generated_ecarbs_note, carbsAfterConstraints, duration, timeOffset))
}
}
if (useAlarm && carbs > 0 && timeOffset > 0) {
carbTimer.scheduleReminder(dateUtil._now() + T.mins(timeOffset.toLong()).msecs())
}
}, null)
}
} else

View file

@ -196,7 +196,7 @@ open class LoopPlugin @Inject constructor(
val apsMode = sp.getString(R.string.key_aps_mode, "open")
val pump = activePlugin.activePump
var isLGS = false
if (!isSuspended && !pump.isSuspended) if (closedLoopEnabled.value()) if (maxIobAllowed == hardLimits.MAXIOB_LGS || apsMode == "lgs") isLGS = true
if (!isSuspended && !pump.isSuspended()) if (closedLoopEnabled.value()) if (maxIobAllowed == hardLimits.MAXIOB_LGS || apsMode == "lgs") isLGS = true
return isLGS
}
@ -317,7 +317,7 @@ open class LoopPlugin @Inject constructor(
rxBus.send(EventLoopSetLastRunGui(resourceHelper.gs(R.string.loopsuspended)))
return
}
if (pump.isSuspended) {
if (pump.isSuspended()) {
aapsLogger.debug(LTag.APS, resourceHelper.gs(R.string.pumpsuspended))
rxBus.send(EventLoopSetLastRunGui(resourceHelper.gs(R.string.pumpsuspended)))
return
@ -511,12 +511,12 @@ open class LoopPlugin @Inject constructor(
return
}
val pump = activePlugin.activePump
if (!pump.isInitialized) {
if (!pump.isInitialized()) {
aapsLogger.debug(LTag.APS, "applyAPSRequest: " + resourceHelper.gs(R.string.pumpNotInitialized))
callback?.result(PumpEnactResult(injector).comment(resourceHelper.gs(R.string.pumpNotInitialized)).enacted(false).success(false))?.run()
return
}
if (pump.isSuspended) {
if (pump.isSuspended()) {
aapsLogger.debug(LTag.APS, "applyAPSRequest: " + resourceHelper.gs(R.string.pumpsuspended))
callback?.result(PumpEnactResult(injector).comment(resourceHelper.gs(R.string.pumpsuspended)).enacted(false).success(false))?.run()
return
@ -578,12 +578,12 @@ open class LoopPlugin @Inject constructor(
.enacted(false).success(false))?.run()
return
}
if (!pump.isInitialized) {
if (!pump.isInitialized()) {
aapsLogger.debug(LTag.APS, "applySMBRequest: " + resourceHelper.gs(R.string.pumpNotInitialized))
callback?.result(PumpEnactResult(injector).comment(resourceHelper.gs(R.string.pumpNotInitialized)).enacted(false).success(false))?.run()
return
}
if (pump.isSuspended) {
if (pump.isSuspended()) {
aapsLogger.debug(LTag.APS, "applySMBRequest: " + resourceHelper.gs(R.string.pumpsuspended))
callback?.result(PumpEnactResult(injector).comment(resourceHelper.gs(R.string.pumpsuspended)).enacted(false).success(false))?.run()
return

View file

@ -15,7 +15,6 @@ import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.HardLimits
@ -36,7 +35,7 @@ open class OpenAPSAMAPlugin @Inject constructor(
private val profileFunction: ProfileFunction,
private val context: Context,
private val activePlugin: ActivePluginProvider,
private val treatmentsPlugin: TreatmentsPlugin,
private val treatmentsPlugin: TreatmentsInterface,
private val iobCobCalculatorPlugin: IobCobCalculatorPlugin,
private val hardLimits: HardLimits,
private val profiler: Profiler,

View file

@ -17,7 +17,6 @@ import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.HardLimits
import info.nightscout.androidaps.utils.Profiler
@ -37,7 +36,7 @@ open class OpenAPSSMBPlugin @Inject constructor(
private val profileFunction: ProfileFunction,
private val context: Context,
private val activePlugin: ActivePluginProvider,
private val treatmentsPlugin: TreatmentsPlugin,
private val treatmentsPlugin: TreatmentsInterface,
private val iobCobCalculatorPlugin: IobCobCalculatorPlugin,
private val hardLimits: HardLimits,
private val profiler: Profiler,

View file

@ -13,7 +13,6 @@ import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification
import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref1Plugin
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
import info.nightscout.androidaps.utils.DecimalFormatter
import info.nightscout.androidaps.utils.HardLimits
import info.nightscout.androidaps.utils.Round
@ -38,7 +37,7 @@ class SafetyPlugin @Inject constructor(
private val activePlugin: ActivePluginProvider,
private val hardLimits: HardLimits,
private val buildHelper: BuildHelper,
private val treatmentsPlugin: TreatmentsPlugin,
private val treatmentsPlugin: TreatmentsInterface,
private val config: Config
) : PluginBase(PluginDescription()
.mainType(PluginType.CONSTRAINTS)

View file

@ -256,10 +256,10 @@ class ActionsFragment : DaggerFragment() {
profileSwitch?.visibility = (
activePlugin.activeProfileInterface.profile != null &&
pump.pumpDescription.isSetBasalProfileCapable &&
pump.isInitialized &&
!pump.isSuspended).toVisibility()
pump.isInitialized() &&
!pump.isSuspended()).toVisibility()
if (!pump.pumpDescription.isExtendedBolusCapable || !pump.isInitialized || pump.isSuspended || pump.isFakingTempsByExtendedBoluses) {
if (!pump.pumpDescription.isExtendedBolusCapable || !pump.isInitialized() || pump.isSuspended() || pump.isFakingTempsByExtendedBoluses) {
extendedBolus?.visibility = View.GONE
extendedBolusCancel?.visibility = View.GONE
} else {
@ -275,7 +275,7 @@ class ActionsFragment : DaggerFragment() {
}
}
if (!pump.pumpDescription.isTempBasalCapable || !pump.isInitialized || pump.isSuspended) {
if (!pump.pumpDescription.isTempBasalCapable || !pump.isInitialized() || pump.isSuspended()) {
setTempBasal?.visibility = View.GONE
cancelTempBasal?.visibility = View.GONE
} else {
@ -292,7 +292,7 @@ class ActionsFragment : DaggerFragment() {
}
val activeBgSource = activePlugin.activeBgSource
historyBrowser?.visibility = (profile != null).toVisibility()
fill?.visibility = (pump.pumpDescription.isRefillingCapable && pump.isInitialized && !pump.isSuspended).toVisibility()
fill?.visibility = (pump.pumpDescription.isRefillingCapable && pump.isInitialized() && !pump.isSuspended()).toVisibility()
pumpBatteryChange?.visibility = (pump.pumpDescription.isBatteryReplaceable || (pump is OmnipodErosPumpPlugin && pump.isUseRileyLinkBatteryLevel && pump.isBatteryChangeLoggingEnabled)).toVisibility()
tempTarget?.visibility = (profile != null && config.APS).toVisibility()
tddStats?.visibility = pump.pumpDescription.supportsTDDs.toVisibility()

View file

@ -5,14 +5,16 @@ import android.widget.LinearLayout
import androidx.annotation.DrawableRes
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.R
import info.nightscout.androidaps.activities.ErrorHelperActivity
import info.nightscout.androidaps.data.PumpEnactResult
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.general.automation.elements.InputString
import info.nightscout.androidaps.plugins.general.automation.elements.LabelWithElement
import info.nightscout.androidaps.plugins.general.automation.elements.LayoutBuilder
import info.nightscout.androidaps.queue.Callback
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.JsonHelper
import info.nightscout.androidaps.utils.T
import info.nightscout.androidaps.utils.TimerUtil
import info.nightscout.androidaps.utils.resources.ResourceHelper
import org.json.JSONObject
import javax.inject.Inject
@ -22,6 +24,7 @@ class ActionAlarm(injector: HasAndroidInjector) : Action(injector) {
@Inject lateinit var resourceHelper: ResourceHelper
@Inject lateinit var rxBus: RxBusWrapper
@Inject lateinit var context: Context
@Inject lateinit var timerUtil: TimerUtil
var text = InputString(injector)
@ -33,10 +36,11 @@ class ActionAlarm(injector: HasAndroidInjector) : Action(injector) {
override fun shortDescription(): String = resourceHelper.gs(R.string.alarm_message, text.value)
@DrawableRes override fun icon(): Int = R.drawable.ic_access_alarm_24dp
override fun isValid(): Boolean = text.value.isNotEmpty()
override fun isValid(): Boolean = true // empty alarm will show app name
override fun doAction(callback: Callback) {
ErrorHelperActivity.runAlarm(context, text.value, resourceHelper.gs(R.string.alarm), R.raw.modern_alarm)
timerUtil.scheduleReminder(DateUtil.now() + T.secs(10L).msecs(), text.value.takeIf { it.isNotBlank() }
?: resourceHelper.gs(R.string.app_name))
callback.result(PumpEnactResult(injector).success(true).comment(R.string.ok))?.run()
}

View file

@ -11,15 +11,15 @@ import com.google.common.base.Optional
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.R
import info.nightscout.androidaps.interfaces.ActivePluginProvider
import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.interfaces.TreatmentsInterface
import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.plugins.general.automation.dialogs.ChooseTriggerDialog
import info.nightscout.androidaps.plugins.general.automation.events.EventTriggerChanged
import info.nightscout.androidaps.plugins.general.automation.events.EventTriggerClone
import info.nightscout.androidaps.plugins.general.automation.events.EventTriggerRemove
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
import info.nightscout.androidaps.services.LastLocationDataContainer
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.sharedPreferences.SP
@ -29,13 +29,14 @@ import javax.inject.Inject
import kotlin.reflect.full.primaryConstructor
abstract class Trigger(val injector: HasAndroidInjector) {
@Inject lateinit var aapsLogger: AAPSLogger
@Inject lateinit var rxBus: RxBusWrapper
@Inject lateinit var resourceHelper: ResourceHelper
@Inject lateinit var profileFunction: ProfileFunction
@Inject lateinit var sp: SP
@Inject lateinit var locationDataContainer: LastLocationDataContainer
@Inject lateinit var treatmentsPlugin: TreatmentsPlugin
@Inject lateinit var treatmentsInterface: TreatmentsInterface
@Inject lateinit var activePlugin: ActivePluginProvider
@Inject lateinit var iobCobCalculatorPlugin: IobCobCalculatorPlugin
@ -53,12 +54,13 @@ abstract class Trigger(val injector: HasAndroidInjector) {
abstract fun duplicate(): Trigger
companion object {
@JvmStatic
fun scanForActivity(cont: Context?): AppCompatActivity? {
when (cont) {
null -> return null
null -> return null
is AppCompatActivity -> return cont
is ContextWrapper -> return scanForActivity(cont.baseContext)
is ContextWrapper -> return scanForActivity(cont.baseContext)
else -> return null
}
}

View file

@ -35,7 +35,7 @@ class TriggerBolusAgo(injector: HasAndroidInjector) : Trigger(injector) {
}
override fun shouldRun(): Boolean {
val lastBolusTime = treatmentsPlugin.getLastBolusTime(true)
val lastBolusTime = treatmentsInterface.getLastBolusTime(true)
if (lastBolusTime == 0L)
return if (comparator.value == Comparator.Compare.IS_NOT_AVAILABLE) {
aapsLogger.debug(LTag.AUTOMATION, "Ready for execution: " + friendlyDescription())

View file

@ -28,7 +28,7 @@ class TriggerTempTarget(injector: HasAndroidInjector) : Trigger(injector) {
}
override fun shouldRun(): Boolean {
val tt = treatmentsPlugin.tempTargetFromHistory
val tt = treatmentsInterface.tempTargetFromHistory
if (tt == null && comparator.value == ComparatorExists.Compare.NOT_EXISTS) {
aapsLogger.debug(LTag.AUTOMATION, "Ready for execution: " + friendlyDescription())
return true

View file

@ -363,7 +363,7 @@ class OpenHumansUploader @Inject constructor(
copyDisposable = Completable.fromCallable { MainApp.getDbHelper().clearOpenHumansQueue() }
.andThen(Single.defer { Single.just(MainApp.getDbHelper().countOfAllRows + treatmentsPlugin.service.count()) })
.doOnSuccess { maxProgress = it }
.flatMapObservable { Observable.defer { Observable.fromIterable(treatmentsPlugin.service.treatmentData) } }
.flatMapObservable { Observable.defer { Observable.fromIterable(treatmentsPlugin.service.getTreatmentData()) } }
.map { enqueueTreatment(it); increaseCounter() }
.ignoreElements()
.andThen(Observable.defer { Observable.fromIterable(repository.compatGetBgReadingsDataFromTime(0, true).blockingGet()) })

View file

@ -446,7 +446,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
// QuickWizard button
val quickWizardEntry = quickWizard.getActive()
if (quickWizardEntry != null && lastBG != null && profile != null && pump.isInitialized && !pump.isSuspended) {
if (quickWizardEntry != null && lastBG != null && profile != null && pump.isInitialized() && !pump.isSuspended()) {
binding.buttonsLayout.quickWizardButton.visibility = View.VISIBLE
val wizard = quickWizardEntry.doCalc(profile, profileName, lastBG, false)
binding.buttonsLayout.quickWizardButton.text = quickWizardEntry.buttonText() + "\n" + resourceHelper.gs(R.string.format_carbs, quickWizardEntry.carbs()) +
@ -463,7 +463,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
(lastRun.lastOpenModeAccept == 0L || lastRun.lastOpenModeAccept < lastRun.lastAPSRun) &&// never accepted or before last result
lastRun.constraintsProcessed?.isChangeRequested == true // change is requested
if (showAcceptButton && pump.isInitialized && !pump.isSuspended && loopPlugin.isEnabled(PluginType.LOOP)) {
if (showAcceptButton && pump.isInitialized() && !pump.isSuspended() && loopPlugin.isEnabled(PluginType.LOOP)) {
binding.buttonsLayout.acceptTempButton.visibility = View.VISIBLE
binding.buttonsLayout.acceptTempButton.text = "${resourceHelper.gs(R.string.setbasalquestion)}\n${lastRun!!.constraintsProcessed}"
} else {
@ -471,10 +471,10 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
}
// **** Various treatment buttons ****
binding.buttonsLayout.carbsButton.visibility = ((!activePlugin.activePump.pumpDescription.storesCarbInfo || pump.isInitialized && !pump.isSuspended) && profile != null && sp.getBoolean(R.string.key_show_carbs_button, true)).toVisibility()
binding.buttonsLayout.treatmentButton.visibility = (pump.isInitialized && !pump.isSuspended && profile != null && sp.getBoolean(R.string.key_show_treatment_button, false)).toVisibility()
binding.buttonsLayout.wizardButton.visibility = (pump.isInitialized && !pump.isSuspended && profile != null && sp.getBoolean(R.string.key_show_wizard_button, true)).toVisibility()
binding.buttonsLayout.insulinButton.visibility = (pump.isInitialized && !pump.isSuspended && profile != null && sp.getBoolean(R.string.key_show_insulin_button, true)).toVisibility()
binding.buttonsLayout.carbsButton.visibility = ((!activePlugin.activePump.pumpDescription.storesCarbInfo || pump.isInitialized() && !pump.isSuspended()) && profile != null && sp.getBoolean(R.string.key_show_carbs_button, true)).toVisibility()
binding.buttonsLayout.treatmentButton.visibility = (pump.isInitialized() && !pump.isSuspended() && profile != null && sp.getBoolean(R.string.key_show_treatment_button, false)).toVisibility()
binding.buttonsLayout.wizardButton.visibility = (pump.isInitialized() && !pump.isSuspended() && profile != null && sp.getBoolean(R.string.key_show_wizard_button, true)).toVisibility()
binding.buttonsLayout.insulinButton.visibility = (pump.isInitialized() && !pump.isSuspended() && profile != null && sp.getBoolean(R.string.key_show_insulin_button, true)).toVisibility()
// **** Calibration & CGM buttons ****
val xDripIsBgSource = xdripPlugin.isEnabled(PluginType.BGSOURCE)
@ -633,7 +633,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
binding.infoLayout.apsModeText.visibility = View.VISIBLE
}
pump.isSuspended -> {
pump.isSuspended() -> {
binding.infoLayout.apsMode.setImageResource(if (pump.pumpDescription.pumpType == PumpType.Insulet_Omnipod) {
// For Omnipod, indicate the pump as disconnected when it's suspended.
// The only way to 'reconnect' it, is through the Omnipod tab
@ -898,8 +898,8 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
menuChartSettings[g + 1][OverviewMenus.CharType.BGI.ordinal] -> useBGIForScale = true
menuChartSettings[g + 1][OverviewMenus.CharType.DEVSLOPE.ordinal] -> useDSForScale = true
}
var alignIobScale = menuChartSettings[g + 1][OverviewMenus.CharType.ABS.ordinal] && menuChartSettings[g + 1][OverviewMenus.CharType.IOB.ordinal]
var alignDevBgiScale = menuChartSettings[g + 1][OverviewMenus.CharType.DEV.ordinal] && menuChartSettings[g + 1][OverviewMenus.CharType.BGI.ordinal]
val alignIobScale = menuChartSettings[g + 1][OverviewMenus.CharType.ABS.ordinal] && menuChartSettings[g + 1][OverviewMenus.CharType.IOB.ordinal]
val alignDevBgiScale = menuChartSettings[g + 1][OverviewMenus.CharType.DEV.ordinal] && menuChartSettings[g + 1][OverviewMenus.CharType.BGI.ordinal]
if (menuChartSettings[g + 1][OverviewMenus.CharType.ABS.ordinal]) secondGraphData.addAbsIob(fromTime, now, useABSForScale, 1.0)
if (menuChartSettings[g + 1][OverviewMenus.CharType.IOB.ordinal]) secondGraphData.addIob(fromTime, now, useIobForScale, 1.0, menuChartSettings[g + 1][OverviewMenus.CharType.PRE.ordinal], alignIobScale)

View file

@ -33,17 +33,16 @@ import info.nightscout.androidaps.plugins.general.smsCommunicator.events.EventSm
import info.nightscout.androidaps.plugins.general.smsCommunicator.otp.OneTimePassword
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
import info.nightscout.androidaps.queue.Callback
import info.nightscout.androidaps.receivers.BundleStore
import info.nightscout.androidaps.receivers.DataReceiver
import info.nightscout.androidaps.utils.*
import io.reactivex.rxkotlin.plusAssign
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.androidaps.utils.sharedPreferences.SP
import info.nightscout.androidaps.utils.textValidator.ValidatingEditTextPreference
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.rxkotlin.plusAssign
import org.apache.commons.lang3.StringUtils
import java.text.Normalizer
import java.util.*
@ -270,7 +269,7 @@ class SmsCommunicatorPlugin @Inject constructor(
"BOLUS" ->
if (!remoteCommandsAllowed) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_remotecommandnotallowed)))
else if (divided.size == 2 && DateUtil.now() - lastRemoteBolusTime < minDistance) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_remotebolusnotallowed)))
else if (divided.size == 2 && pump.isSuspended) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.pumpsuspended)))
else if (divided.size == 2 && pump.isSuspended()) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.pumpsuspended)))
else if (divided.size == 2 || divided.size == 3) processBOLUS(divided, receivedSms)
else sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))
"CARBS" ->
@ -450,7 +449,7 @@ class SmsCommunicatorPlugin @Inject constructor(
private fun processTREATMENTS(divided: Array<String>, receivedSms: Sms) {
if (divided[1].toUpperCase(Locale.getDefault()) == "REFRESH") {
(activePlugin.activeTreatments as TreatmentsPlugin).service.resetTreatments()
activePlugin.activeTreatments.service.resetTreatments()
rxBus.send(EventNSClientRestart())
sendSMS(Sms(receivedSms.phoneNumber, "TREATMENTS REFRESH SENT"))
receivedSms.processed = true
@ -589,9 +588,10 @@ class SmsCommunicatorPlugin @Inject constructor(
val finalPercentage = percentage
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(list[pindex - 1] as String, finalPercentage) {
override fun run() {
uel.log("SMS PROFILE", reply)
activePlugin.activeTreatments.doProfileSwitch(store, list[pindex - 1] as String, 0, finalPercentage, 0, DateUtil.now())
sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.profileswitchcreated)))
val replyText = resourceHelper.gs(R.string.profileswitchcreated)
sendSMS(Sms(receivedSms.phoneNumber, replyText))
uel.log("SMS PROFILE", replyText)
}
})
}
@ -607,17 +607,18 @@ class SmsCommunicatorPlugin @Inject constructor(
receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() {
override fun run() {
uel.log("SMS BASAL", reply)
commandQueue.cancelTempBasal(true, object : Callback() {
override fun run() {
if (result.success) {
var replyText = resourceHelper.gs(R.string.smscommunicator_tempbasalcanceled)
replyText += "\n" + activePlugin.activePump.shortStatus(true)
sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText))
uel.log("SMS BASAL", replyText)
} else {
var replyText = resourceHelper.gs(R.string.smscommunicator_tempbasalcancelfailed)
replyText += "\n" + activePlugin.activePump.shortStatus(true)
sendSMS(Sms(receivedSms.phoneNumber, replyText))
uel.log("SMS BASAL", replyText)
}
}
})
@ -639,17 +640,18 @@ class SmsCommunicatorPlugin @Inject constructor(
receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(tempBasalPct, duration) {
override fun run() {
uel.log("SMS BASAL", reply)
commandQueue.tempBasalPercent(anInteger(), secondInteger(), true, profile, object : Callback() {
override fun run() {
if (result.success) {
var replyText = if (result.isPercent) String.format(resourceHelper.gs(R.string.smscommunicator_tempbasalset_percent), result.percent, result.duration) else String.format(resourceHelper.gs(R.string.smscommunicator_tempbasalset), result.absolute, result.duration)
replyText += "\n" + activePlugin.activePump.shortStatus(true)
sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText))
uel.log("SMS BASAL", replyText)
} else {
var replyText = resourceHelper.gs(R.string.smscommunicator_tempbasalfailed)
replyText += "\n" + activePlugin.activePump.shortStatus(true)
sendSMS(Sms(receivedSms.phoneNumber, replyText))
uel.log("SMS BASAL", replyText)
}
}
})
@ -672,7 +674,6 @@ class SmsCommunicatorPlugin @Inject constructor(
receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(tempBasal, duration) {
override fun run() {
uel.log("SMS BASAL", reply)
commandQueue.tempBasalAbsolute(aDouble(), secondInteger(), true, profile, object : Callback() {
override fun run() {
if (result.success) {
@ -680,10 +681,12 @@ class SmsCommunicatorPlugin @Inject constructor(
else String.format(resourceHelper.gs(R.string.smscommunicator_tempbasalset), result.absolute, result.duration)
replyText += "\n" + activePlugin.activePump.shortStatus(true)
sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText))
uel.log("SMS BASAL", replyText)
} else {
var replyText = resourceHelper.gs(R.string.smscommunicator_tempbasalfailed)
replyText += "\n" + activePlugin.activePump.shortStatus(true)
sendSMS(Sms(receivedSms.phoneNumber, replyText))
uel.log("SMS BASAL", replyText)
}
}
})
@ -700,7 +703,6 @@ class SmsCommunicatorPlugin @Inject constructor(
receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() {
override fun run() {
uel.log("SMS EXTENDED", reply)
commandQueue.cancelExtended(object : Callback() {
override fun run() {
if (result.success) {
@ -711,6 +713,7 @@ class SmsCommunicatorPlugin @Inject constructor(
var replyText = resourceHelper.gs(R.string.smscommunicator_extendedcancelfailed)
replyText += "\n" + activePlugin.activePump.shortStatus(true)
sendSMS(Sms(receivedSms.phoneNumber, replyText))
uel.log("SMS EXTENDED", replyText)
}
}
})
@ -729,7 +732,6 @@ class SmsCommunicatorPlugin @Inject constructor(
receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(extended, duration) {
override fun run() {
uel.log("SMS EXTENDED", reply)
commandQueue.extendedBolus(aDouble(), secondInteger(), object : Callback() {
override fun run() {
if (result.success) {
@ -737,10 +739,12 @@ class SmsCommunicatorPlugin @Inject constructor(
if (config.APS) replyText += "\n" + resourceHelper.gs(R.string.loopsuspended)
replyText += "\n" + activePlugin.activePump.shortStatus(true)
sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText))
uel.log("SMS EXTENDED", replyText)
} else {
var replyText = resourceHelper.gs(R.string.smscommunicator_extendedfailed)
replyText += "\n" + activePlugin.activePump.shortStatus(true)
sendSMS(Sms(receivedSms.phoneNumber, replyText))
uel.log("SMS EXTENDED", replyText)
}
}
})
@ -765,7 +769,6 @@ class SmsCommunicatorPlugin @Inject constructor(
receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(bolus) {
override fun run() {
uel.log("SMS BOLUS", reply)
val detailedBolusInfo = DetailedBolusInfo()
detailedBolusInfo.insulin = aDouble()
detailedBolusInfo.source = Source.USER
@ -810,10 +813,12 @@ class SmsCommunicatorPlugin @Inject constructor(
}
}
sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText))
uel.log("SMS BOLUS", replyText)
} else {
var replyText = resourceHelper.gs(R.string.smscommunicator_bolusfailed)
replyText += "\n" + activePlugin.activePump.shortStatus(true)
sendSMS(Sms(receivedSms.phoneNumber, replyText))
uel.log("SMS BOLUS", replyText)
}
}
})
@ -842,7 +847,6 @@ class SmsCommunicatorPlugin @Inject constructor(
receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(grams, time) {
override fun run() {
uel.log("SMS CARBS", reply)
val detailedBolusInfo = DetailedBolusInfo()
detailedBolusInfo.carbs = anInteger().toDouble()
detailedBolusInfo.source = Source.USER
@ -854,10 +858,12 @@ class SmsCommunicatorPlugin @Inject constructor(
var replyText = String.format(resourceHelper.gs(R.string.smscommunicator_carbsset), anInteger)
replyText += "\n" + activePlugin.activePump.shortStatus(true)
sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText))
uel.log("SMS CARBS", replyText)
} else {
var replyText = resourceHelper.gs(R.string.smscommunicator_carbsfailed)
replyText += "\n" + activePlugin.activePump.shortStatus(true)
sendSMS(Sms(receivedSms.phoneNumber, replyText))
uel.log("SMS CARBS", replyText)
}
}
})
@ -866,6 +872,7 @@ class SmsCommunicatorPlugin @Inject constructor(
var replyText = String.format(resourceHelper.gs(R.string.smscommunicator_carbsset), anInteger)
replyText += "\n" + activePlugin.activePump.shortStatus(true)
sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText))
uel.log("SMS CARBS", replyText)
}
}
})
@ -883,7 +890,6 @@ class SmsCommunicatorPlugin @Inject constructor(
receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() {
override fun run() {
uel.log("SMS TARGET", reply)
val units = profileFunction.getUnits()
var keyDuration = 0
var defaultTargetDuration = 0
@ -931,6 +937,7 @@ class SmsCommunicatorPlugin @Inject constructor(
val ttString = if (units == Constants.MMOL) DecimalFormatter.to1Decimal(tt) else DecimalFormatter.to0Decimal(tt)
val replyText = String.format(resourceHelper.gs(R.string.smscommunicator_tt_set), ttString, ttDuration)
sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText))
uel.log("SMS TARGET", replyText)
}
})
} else if (isStop) {
@ -939,7 +946,6 @@ class SmsCommunicatorPlugin @Inject constructor(
receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() {
override fun run() {
uel.log("SMS TARGET", reply)
val tempTarget = TempTarget()
.source(Source.USER)
.date(DateUtil.now())
@ -949,6 +955,7 @@ class SmsCommunicatorPlugin @Inject constructor(
activePlugin.activeTreatments.addToHistoryTempTarget(tempTarget)
val replyText = String.format(resourceHelper.gs(R.string.smscommunicator_tt_canceled))
sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText))
uel.log("SMS TARGET", reply)
}
})
} else
@ -964,10 +971,10 @@ class SmsCommunicatorPlugin @Inject constructor(
receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() {
override fun run() {
uel.log("SMS SMS", reply)
sp.putBoolean(R.string.key_smscommunicator_remotecommandsallowed, false)
val replyText = String.format(resourceHelper.gs(R.string.smscommunicator_stoppedsms))
sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText))
uel.log("SMS SMS", replyText)
}
})
} else sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))
@ -981,9 +988,11 @@ class SmsCommunicatorPlugin @Inject constructor(
receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(cal) {
override fun run() {
uel.log("SMS CAL", reply)
val result = xdripCalibrations.sendIntent(aDouble!!)
if (result) sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_calibrationsent))) else sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_calibrationfailed)))
val replyText =
if (result) resourceHelper.gs(R.string.smscommunicator_calibrationsent) else resourceHelper.gs(R.string.smscommunicator_calibrationfailed)
sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText))
uel.log("SMS CAL", replyText)
}
})
} else sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))

View file

@ -50,7 +50,7 @@ import javax.inject.Singleton
class ActionStringHandler @Inject constructor(
private val sp: SP,
private val rxBus: RxBusWrapper,
private val aapsSchedulers: AapsSchedulers,
aapsSchedulers: AapsSchedulers,
private val resourceHelper: ResourceHelper,
private val injector: HasAndroidInjector,
private val context: Context,
@ -262,7 +262,7 @@ class ActionStringHandler @Inject constructor(
rAction = "statusmessage"
rMessage = "OLD DATA - "
//if pump is not busy: try to fetch data
if (activePump.isBusy) {
if (activePump.isBusy()) {
rMessage += resourceHelper.gs(R.string.pumpbusy)
} else {
rMessage += "trying to fetch data from pump."

View file

@ -41,6 +41,7 @@ import info.nightscout.androidaps.interfaces.ProfileFunction;
import info.nightscout.androidaps.interfaces.PumpDescription;
import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.interfaces.PumpPluginBase;
import info.nightscout.androidaps.interfaces.TreatmentsInterface;
import info.nightscout.androidaps.logging.AAPSLogger;
import info.nightscout.androidaps.logging.LTag;
import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
@ -80,7 +81,7 @@ public class ComboPlugin extends PumpPluginBase implements PumpInterface, Constr
private final ResourceHelper resourceHelper;
private final ProfileFunction profileFunction;
private final TreatmentsPlugin treatmentsPlugin;
private final TreatmentsInterface treatmentsPlugin;
private final info.nightscout.androidaps.utils.sharedPreferences.SP sp;
private RxBusWrapper rxBus;
private final CommandQueueProvider commandQueue;
@ -136,7 +137,7 @@ public class ComboPlugin extends PumpPluginBase implements PumpInterface, Constr
RxBusWrapper rxBus,
ResourceHelper resourceHelper,
ProfileFunction profileFunction,
TreatmentsPlugin treatmentsPlugin,
TreatmentsInterface treatmentsPlugin,
SP sp,
CommandQueueProvider commandQueue,
Context context

View file

@ -49,6 +49,7 @@ import info.nightscout.androidaps.interfaces.ProfileFunction;
import info.nightscout.androidaps.interfaces.PumpDescription;
import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.interfaces.PumpPluginBase;
import info.nightscout.androidaps.interfaces.TreatmentsInterface;
import info.nightscout.androidaps.logging.AAPSLogger;
import info.nightscout.androidaps.logging.LTag;
import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
@ -129,7 +130,6 @@ import info.nightscout.androidaps.plugins.pump.insight.exceptions.app_layer_erro
import info.nightscout.androidaps.plugins.pump.insight.exceptions.app_layer_errors.NoActiveTBRToCanceLException;
import info.nightscout.androidaps.plugins.pump.insight.utils.ExceptionTranslator;
import info.nightscout.androidaps.plugins.pump.insight.utils.ParameterBlockUtil;
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
import info.nightscout.androidaps.utils.DateUtil;
import info.nightscout.androidaps.utils.TimeChangeType;
import info.nightscout.androidaps.utils.resources.ResourceHelper;
@ -141,7 +141,7 @@ public class LocalInsightPlugin extends PumpPluginBase implements PumpInterface,
private final AAPSLogger aapsLogger;
private final RxBusWrapper rxBus;
private final ResourceHelper resourceHelper;
private final TreatmentsPlugin treatmentsPlugin;
private final TreatmentsInterface treatmentsPlugin;
private final SP sp;
private final CommandQueueProvider commandQueue;
private final ProfileFunction profileFunction;
@ -203,7 +203,7 @@ public class LocalInsightPlugin extends PumpPluginBase implements PumpInterface,
AAPSLogger aapsLogger,
RxBusWrapper rxBus,
ResourceHelper resourceHelper,
TreatmentsPlugin treatmentsPlugin,
TreatmentsInterface treatmentsPlugin,
SP sp,
CommandQueueProvider commandQueue,
ProfileFunction profileFunction,

View file

@ -1,280 +0,0 @@
package info.nightscout.androidaps.plugins.pump.mdi;
import androidx.annotation.NonNull;
import org.json.JSONException;
import org.json.JSONObject;
import javax.inject.Inject;
import javax.inject.Singleton;
import dagger.android.HasAndroidInjector;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.DetailedBolusInfo;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.data.PumpEnactResult;
import info.nightscout.androidaps.interfaces.CommandQueueProvider;
import info.nightscout.androidaps.interfaces.PluginDescription;
import info.nightscout.androidaps.interfaces.PluginType;
import info.nightscout.androidaps.interfaces.PumpDescription;
import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.interfaces.PumpPluginBase;
import info.nightscout.androidaps.logging.AAPSLogger;
import info.nightscout.androidaps.logging.LTag;
import info.nightscout.androidaps.plugins.common.ManufacturerType;
import info.nightscout.androidaps.plugins.pump.common.defs.PumpType;
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
import info.nightscout.androidaps.utils.DateUtil;
import info.nightscout.androidaps.utils.InstanceId;
import info.nightscout.androidaps.utils.TimeChangeType;
import info.nightscout.androidaps.utils.resources.ResourceHelper;
/**
* Created by mike on 05.08.2016.
*/
@Singleton
public class MDIPlugin extends PumpPluginBase implements PumpInterface {
private final TreatmentsPlugin treatmentsPlugin;
private final PumpDescription pumpDescription = new PumpDescription();
@Inject
public MDIPlugin(
HasAndroidInjector injector,
AAPSLogger aapsLogger,
ResourceHelper resourceHelper,
CommandQueueProvider commandQueue,
TreatmentsPlugin treatmentsPlugin
) {
super(new PluginDescription()
.mainType(PluginType.PUMP)
.pluginIcon(R.drawable.ic_ict)
.pluginName(R.string.mdi)
.description(R.string.description_pump_mdi),
injector, aapsLogger, resourceHelper, commandQueue
);
this.treatmentsPlugin = treatmentsPlugin;
pumpDescription.isBolusCapable = true;
pumpDescription.bolusStep = 0.5d;
pumpDescription.isExtendedBolusCapable = false;
pumpDescription.isTempBasalCapable = false;
pumpDescription.isSetBasalProfileCapable = false;
pumpDescription.isRefillingCapable = false;
pumpDescription.isBatteryReplaceable = false;
}
@Override
public boolean isFakingTempsByExtendedBoluses() {
return false;
}
@NonNull @Override
public PumpEnactResult loadTDDs() {
//no result, could read DB in the future?
return new PumpEnactResult(getInjector());
}
@Override
public boolean isInitialized() {
return true;
}
@Override
public boolean isSuspended() {
return false;
}
@Override
public boolean isBusy() {
return false;
}
@Override
public boolean isConnected() {
return true;
}
@Override
public boolean isConnecting() {
return false;
}
@Override
public boolean isHandshakeInProgress() {
return false;
}
@Override
public void connect(@NonNull String reason) {
}
@Override
public void disconnect(@NonNull String reason) {
}
@Override public int waitForDisconnectionInSeconds() {
return 0;
}
@Override
public void stopConnecting() {
}
@Override
public void getPumpStatus(@NonNull String reason) {
}
@NonNull @Override
public PumpEnactResult setNewBasalProfile(@NonNull Profile profile) {
// Do nothing here. we are using ConfigBuilderPlugin.getPlugin().getActiveProfile().getProfile();
PumpEnactResult result = new PumpEnactResult(getInjector());
result.success = true;
return result;
}
@Override
public boolean isThisProfileSet(@NonNull Profile profile) {
return false;
}
@Override
public long lastDataTime() {
return System.currentTimeMillis();
}
@Override
public double getBaseBasalRate() {
return 0d;
}
@Override
public double getReservoirLevel() {
return -1;
}
@Override
public int getBatteryLevel() {
return -1;
}
@NonNull @Override
public PumpEnactResult deliverTreatment(DetailedBolusInfo detailedBolusInfo) {
PumpEnactResult result = new PumpEnactResult(getInjector());
result.success = true;
result.bolusDelivered = detailedBolusInfo.insulin;
result.carbsDelivered = detailedBolusInfo.carbs;
result.comment = getResourceHelper().gs(R.string.virtualpump_resultok);
treatmentsPlugin.addToHistoryTreatment(detailedBolusInfo, false);
return result;
}
@Override
public void stopBolusDelivering() {
}
@NonNull @Override
public PumpEnactResult setTempBasalAbsolute(double absoluteRate, int durationInMinutes, @NonNull Profile profile, boolean enforceNew) {
PumpEnactResult result = new PumpEnactResult(getInjector());
result.success = false;
result.comment = getResourceHelper().gs(R.string.pumperror);
getAapsLogger().debug(LTag.PUMPBTCOMM, "Setting temp basal absolute: " + result);
return result;
}
@NonNull @Override
public PumpEnactResult setTempBasalPercent(int percent, int durationInMinutes, @NonNull Profile profile, boolean enforceNew) {
PumpEnactResult result = new PumpEnactResult(getInjector());
result.success = false;
result.comment = getResourceHelper().gs(R.string.pumperror);
getAapsLogger().debug(LTag.PUMPBTCOMM, "Settings temp basal percent: " + result);
return result;
}
@NonNull @Override
public PumpEnactResult setExtendedBolus(double insulin, int durationInMinutes) {
PumpEnactResult result = new PumpEnactResult(getInjector());
result.success = false;
result.comment = getResourceHelper().gs(R.string.pumperror);
getAapsLogger().debug(LTag.PUMPBTCOMM, "Setting extended bolus: " + result);
return result;
}
@NonNull @Override
public PumpEnactResult cancelTempBasal(boolean force) {
PumpEnactResult result = new PumpEnactResult(getInjector());
result.success = false;
result.comment = getResourceHelper().gs(R.string.pumperror);
getAapsLogger().debug(LTag.PUMPBTCOMM, "Cancel temp basal: " + result);
return result;
}
@NonNull @Override
public PumpEnactResult cancelExtendedBolus() {
PumpEnactResult result = new PumpEnactResult(getInjector());
result.success = false;
result.comment = getResourceHelper().gs(R.string.pumperror);
getAapsLogger().debug(LTag.PUMPBTCOMM, "Canceling extended bolus: " + result);
return result;
}
@NonNull @Override
public JSONObject getJSONStatus(@NonNull Profile profile, @NonNull String profileName, @NonNull String version) {
long now = System.currentTimeMillis();
JSONObject pump = new JSONObject();
JSONObject status = new JSONObject();
JSONObject extended = new JSONObject();
try {
status.put("status", "normal");
extended.put("Version", version);
extended.put("ActiveProfile", profileName);
status.put("timestamp", DateUtil.toISOString(now));
pump.put("status", status);
pump.put("extended", extended);
pump.put("clock", DateUtil.toISOString(now));
} catch (JSONException e) {
getAapsLogger().error("Exception: ", e);
}
return pump;
}
@NonNull @Override
public ManufacturerType manufacturer() {
return ManufacturerType.AndroidAPS;
}
@NonNull @Override
public PumpType model() {
return PumpType.MDI;
}
@NonNull @Override
public String serialNumber() {
return InstanceId.INSTANCE.instanceId();
}
@NonNull @Override
public PumpDescription getPumpDescription() {
return pumpDescription;
}
@NonNull @Override
public String shortStatus(boolean veryShort) {
return model().getModel();
}
@Override
public boolean canHandleDST() {
return true;
}
@Override
public void timezoneOrDSTChanged(@NonNull TimeChangeType changeType) {
}
}

View file

@ -0,0 +1,145 @@
package info.nightscout.androidaps.plugins.pump.mdi
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.R
import info.nightscout.androidaps.data.DetailedBolusInfo
import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.data.PumpEnactResult
import info.nightscout.androidaps.interfaces.*
import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.plugins.common.ManufacturerType
import info.nightscout.androidaps.plugins.pump.common.defs.PumpType
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.InstanceId.instanceId
import info.nightscout.androidaps.utils.resources.ResourceHelper
import org.json.JSONException
import org.json.JSONObject
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class MDIPlugin @Inject constructor(
injector: HasAndroidInjector,
aapsLogger: AAPSLogger,
resourceHelper: ResourceHelper,
commandQueue: CommandQueueProvider,
private val treatmentsPlugin: TreatmentsPlugin
) : PumpPluginBase(PluginDescription()
.mainType(PluginType.PUMP)
.pluginIcon(R.drawable.ic_ict)
.pluginName(R.string.mdi)
.description(R.string.description_pump_mdi),
injector, aapsLogger, resourceHelper, commandQueue
), PumpInterface {
override val pumpDescription = PumpDescription()
init {
pumpDescription.isBolusCapable = true
pumpDescription.bolusStep = 0.5
pumpDescription.isExtendedBolusCapable = false
pumpDescription.isTempBasalCapable = false
pumpDescription.isSetBasalProfileCapable = false
pumpDescription.isRefillingCapable = false
pumpDescription.isBatteryReplaceable = false
}
override val isFakingTempsByExtendedBoluses: Boolean = false
override fun loadTDDs(): PumpEnactResult = PumpEnactResult(injector)
override fun isInitialized(): Boolean = true
override fun isSuspended(): Boolean = false
override fun isBusy(): Boolean = false
override fun isConnected(): Boolean = true
override fun isConnecting(): Boolean = false
override fun isHandshakeInProgress(): Boolean = false
override fun connect(reason: String) {}
override fun disconnect(reason: String) {}
override fun waitForDisconnectionInSeconds(): Int = 0
override fun stopConnecting() {}
override fun getPumpStatus(reason: String) {}
override fun setNewBasalProfile(profile: Profile): PumpEnactResult = PumpEnactResult(injector).success(true)
override fun isThisProfileSet(profile: Profile): Boolean = false
override fun lastDataTime(): Long = System.currentTimeMillis()
override val baseBasalRate: Double = 0.0
override val reservoirLevel: Double = -1.0
override val batteryLevel: Int = -1
override fun deliverTreatment(detailedBolusInfo: DetailedBolusInfo): PumpEnactResult {
val result = PumpEnactResult(injector)
result.success = true
result.bolusDelivered = detailedBolusInfo.insulin
result.carbsDelivered = detailedBolusInfo.carbs
result.comment = resourceHelper.gs(R.string.virtualpump_resultok)
treatmentsPlugin.addToHistoryTreatment(detailedBolusInfo, false)
return result
}
override fun stopBolusDelivering() {}
override fun setTempBasalAbsolute(absoluteRate: Double, durationInMinutes: Int, profile: Profile, enforceNew: Boolean): PumpEnactResult {
val result = PumpEnactResult(injector)
result.success = false
result.comment = resourceHelper.gs(R.string.pumperror)
aapsLogger.debug(LTag.PUMPBTCOMM, "Setting temp basal absolute: $result")
return result
}
override fun setTempBasalPercent(percent: Int, durationInMinutes: Int, profile: Profile, enforceNew: Boolean): PumpEnactResult {
val result = PumpEnactResult(injector)
result.success = false
result.comment = resourceHelper.gs(R.string.pumperror)
aapsLogger.debug(LTag.PUMPBTCOMM, "Settings temp basal percent: $result")
return result
}
override fun setExtendedBolus(insulin: Double, durationInMinutes: Int): PumpEnactResult {
val result = PumpEnactResult(injector)
result.success = false
result.comment = resourceHelper.gs(R.string.pumperror)
aapsLogger.debug(LTag.PUMPBTCOMM, "Setting extended bolus: $result")
return result
}
override fun cancelTempBasal(enforceNew: Boolean): PumpEnactResult {
val result = PumpEnactResult(injector)
result.success = false
result.comment = resourceHelper.gs(R.string.pumperror)
aapsLogger.debug(LTag.PUMPBTCOMM, "Cancel temp basal: $result")
return result
}
override fun cancelExtendedBolus(): PumpEnactResult {
val result = PumpEnactResult(injector)
result.success = false
result.comment = resourceHelper.gs(R.string.pumperror)
aapsLogger.debug(LTag.PUMPBTCOMM, "Canceling extended bolus: $result")
return result
}
override fun getJSONStatus(profile: Profile, profileName: String, version: String): JSONObject {
val now = System.currentTimeMillis()
val pump = JSONObject()
val status = JSONObject()
val extended = JSONObject()
try {
status.put("status", "normal")
extended.put("Version", version)
extended.put("ActiveProfile", profileName)
status.put("timestamp", DateUtil.toISOString(now))
pump.put("status", status)
pump.put("extended", extended)
pump.put("clock", DateUtil.toISOString(now))
} catch (e: JSONException) {
aapsLogger.error("Exception: ", e)
}
return pump
}
override fun manufacturer(): ManufacturerType = ManufacturerType.AndroidAPS
override fun model(): PumpType = PumpType.MDI
override fun serialNumber(): String = instanceId()
override fun shortStatus(veryShort: Boolean): String = model().model
override fun canHandleDST(): Boolean = true
}

View file

@ -133,12 +133,12 @@ class VirtualPumpPlugin @Inject constructor(
return PumpEnactResult(injector)
}
override val isInitialized: Boolean = true
override val isSuspended: Boolean = false
override val isBusy: Boolean = false
override val isConnected: Boolean = true
override val isConnecting: Boolean = false
override val isHandshakeInProgress: Boolean = false
override fun isInitialized(): Boolean = true
override fun isSuspended(): Boolean = false
override fun isBusy(): Boolean = false
override fun isConnected(): Boolean = true
override fun isConnecting(): Boolean = false
override fun isHandshakeInProgress(): Boolean = false
override fun connect(reason: String) {
//if (!Config.NSCLIENT) NSUpload.uploadDeviceStatus()

View file

@ -16,6 +16,7 @@ import com.j256.ormlite.support.ConnectionSource;
import com.j256.ormlite.table.TableUtils;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.json.JSONException;
import org.json.JSONObject;
@ -39,6 +40,8 @@ import info.nightscout.androidaps.events.EventNsTreatment;
import info.nightscout.androidaps.events.EventReloadTreatmentData;
import info.nightscout.androidaps.events.EventTreatmentChange;
import info.nightscout.androidaps.interfaces.DatabaseHelperInterface;
import info.nightscout.androidaps.interfaces.TreatmentServiceInterface;
import info.nightscout.androidaps.interfaces.UpdateReturn;
import info.nightscout.androidaps.logging.AAPSLogger;
import info.nightscout.androidaps.logging.LTag;
import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
@ -57,7 +60,7 @@ import io.reactivex.disposables.CompositeDisposable;
* Created by mike on 24.09.2017.
*/
public class TreatmentService extends OrmLiteBaseService<DatabaseHelper> {
public class TreatmentService extends OrmLiteBaseService<DatabaseHelper> implements TreatmentServiceInterface {
@Inject AAPSLogger aapsLogger;
@Inject FabricPrivacy fabricPrivacy;
@ -471,7 +474,7 @@ public class TreatmentService extends OrmLiteBaseService<DatabaseHelper> {
}
public UpdateReturn createOrUpdateMedtronic(Treatment treatment, boolean fromNightScout) {
@NotNull public UpdateReturn createOrUpdateMedtronic(@NotNull Treatment treatment, boolean fromNightScout) {
if (MedtronicHistoryData.doubleBolusDebug)
aapsLogger.debug(LTag.DATATREATMENTS, "DoubleBolusDebug: createOrUpdateMedtronic:: originalTreatment={}, fromNightScout={}", treatment, fromNightScout);
@ -821,22 +824,4 @@ public class TreatmentService extends OrmLiteBaseService<DatabaseHelper> {
return null;
}
public class UpdateReturn {
public UpdateReturn(boolean success, boolean newRecord) {
this.success = success;
this.newRecord = newRecord;
}
boolean newRecord;
boolean success;
@Override
public String toString() {
return "UpdateReturn [" +
"newRecord=" + newRecord +
", success=" + success +
']';
}
}
}

View file

@ -46,7 +46,9 @@ import info.nightscout.androidaps.interfaces.PluginType;
import info.nightscout.androidaps.interfaces.ProfileFunction;
import info.nightscout.androidaps.interfaces.ProfileStore;
import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.interfaces.TreatmentServiceInterface;
import info.nightscout.androidaps.interfaces.TreatmentsInterface;
import info.nightscout.androidaps.interfaces.UpdateReturn;
import info.nightscout.androidaps.logging.AAPSLogger;
import info.nightscout.androidaps.logging.LTag;
import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
@ -82,7 +84,7 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface
private final CompositeDisposable disposable = new CompositeDisposable();
protected TreatmentService service;
protected TreatmentServiceInterface service;
private IobTotal lastTreatmentCalculation;
private IobTotal lastTempBasalsCalculation;
@ -180,7 +182,8 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface
super.onStop();
}
public TreatmentService getService() {
@Override
public TreatmentServiceInterface getService() {
return this.service;
}
@ -620,9 +623,9 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface
}
public TreatmentUpdateReturn createOrUpdateMedtronic(Treatment treatment, boolean fromNightScout) {
TreatmentService.UpdateReturn resultRecord = getService().createOrUpdateMedtronic(treatment, fromNightScout);
UpdateReturn resultRecord = getService().createOrUpdateMedtronic(treatment, fromNightScout);
return new TreatmentUpdateReturn(resultRecord.success, resultRecord.newRecord);
return new TreatmentUpdateReturn(resultRecord.getSuccess(), resultRecord.getNewRecord());
}
// return true if new record is created
@ -643,7 +646,7 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface
treatment.carbs = detailedBolusInfo.carbs;
treatment.mealBolus = treatment.carbs > 0;
treatment.boluscalc = detailedBolusInfo.boluscalc != null ? detailedBolusInfo.boluscalc.toString() : null;
TreatmentService.UpdateReturn creatOrUpdateResult;
UpdateReturn creatOrUpdateResult;
getAapsLogger().debug(medtronicPump && MedtronicHistoryData.doubleBolusDebug, LTag.DATATREATMENTS, "DoubleBolusDebug: addToHistoryTreatment::treatment={} " + treatment);
@ -652,7 +655,7 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface
else
creatOrUpdateResult = getService().createOrUpdateMedtronic(treatment, false);
boolean newRecordCreated = creatOrUpdateResult.newRecord;
boolean newRecordCreated = creatOrUpdateResult.getNewRecord();
//log.debug("Adding new Treatment record" + treatment.toString());
if (detailedBolusInfo.carbTime != 0) {
@ -673,7 +676,7 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface
if (newRecordCreated && detailedBolusInfo.isValid)
nsUpload.uploadTreatmentRecord(detailedBolusInfo);
if (!allowUpdate && !creatOrUpdateResult.success) {
if (!allowUpdate && !creatOrUpdateResult.getSuccess()) {
getAapsLogger().error("Treatment could not be added to DB", new Exception());
String status = String.format(resourceHelper.gs(R.string.error_adding_treatment_message), treatment.insulin, (int) treatment.carbs, dateUtil.dateAndTimeString(treatment.date));

View file

@ -64,11 +64,11 @@ class TreatmentsUserEntryFragment : DaggerFragment() {
val current = entries[position]
holder.binding.date.text = dateUtil.dateAndTimeAndSecondsString(current.timestamp)
holder.binding.action.text = current.action
holder.binding.s.text = current.s
holder.binding.d1.text = if (current.d1 != 0.0) current.d1.toString() else ""
holder.binding.d2.text = if (current.d2 != 0.0) current.d2.toString() else ""
holder.binding.i1.text = if (current.i1 != 0) current.i1.toString() else ""
holder.binding.i1.text = if (current.i2 != 0) current.i2.toString() else ""
if (current.s != "") holder.binding.s.text = current.s else holder.binding.s.visibility = View.GONE
if (current.d1 != 0.0) holder.binding.d1.text = current.d1.toString() else holder.binding.d1.visibility = View.GONE
if (current.d2 != 0.0) holder.binding.d2.text = current.d2.toString() else holder.binding.d2.visibility = View.GONE
if (current.i1 != 0) holder.binding.i1.text = current.i1.toString() else holder.binding.i1.visibility = View.GONE
if (current.i2 != 0) holder.binding.i2.text = current.i2.toString() else holder.binding.i2.visibility = View.GONE
}
inner class UserEntryViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {

View file

@ -31,7 +31,6 @@ class QueueThread internal constructor(
var waitingForDisconnect = false
private var mWakeLock: PowerManager.WakeLock? = null
init {
mWakeLock = (context.getSystemService(Context.POWER_SERVICE) as PowerManager).newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, resourceHelper.gs(R.string.app_name) + ":QueueThread")
}
@ -46,7 +45,7 @@ class QueueThread internal constructor(
while (true) {
val secondsElapsed = (System.currentTimeMillis() - connectionStartTime) / 1000
val pump = activePlugin.activePump
if (!pump.isConnected && secondsElapsed > Constants.PUMP_MAX_CONNECTION_TIME_IN_SECONDS) {
if (!pump.isConnected() && secondsElapsed > Constants.PUMP_MAX_CONNECTION_TIME_IN_SECONDS) {
rxBus.send(EventDismissBolusProgressIfRunning(null))
rxBus.send(EventPumpStatusChanged(resourceHelper.gs(R.string.connectiontimedout)))
aapsLogger.debug(LTag.PUMPQUEUE, "timed out")
@ -86,19 +85,19 @@ class QueueThread internal constructor(
return
}
}
if (pump.isHandshakeInProgress) {
if (pump.isHandshakeInProgress()) {
aapsLogger.debug(LTag.PUMPQUEUE, "handshaking $secondsElapsed")
rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.HANDSHAKING, secondsElapsed.toInt()))
SystemClock.sleep(100)
continue
}
if (pump.isConnecting) {
if (pump.isConnecting()) {
aapsLogger.debug(LTag.PUMPQUEUE, "connecting $secondsElapsed")
rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.CONNECTING, secondsElapsed.toInt()))
SystemClock.sleep(1000)
continue
}
if (!pump.isConnected) {
if (!pump.isConnected()) {
aapsLogger.debug(LTag.PUMPQUEUE, "connect")
rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.CONNECTING, secondsElapsed.toInt()))
pump.connect("Connection needed")

View file

@ -29,6 +29,7 @@ import javax.inject.Inject
import kotlin.math.abs
class KeepAliveReceiver : DaggerBroadcastReceiver() {
@Inject lateinit var aapsLogger: AAPSLogger
@Inject lateinit var rxBus: RxBusWrapper
@Inject lateinit var activePlugin: ActivePluginProvider
@ -44,6 +45,7 @@ class KeepAliveReceiver : DaggerBroadcastReceiver() {
@Inject lateinit var dateUtil: DateUtil
companion object {
private val KEEP_ALIVE_MILLISECONDS = T.mins(5).msecs()
private val STATUS_UPDATE_FREQUENCY = T.mins(15).msecs()
private val IOB_UPDATE_FREQUENCY_IN_MINS = 5L
@ -128,10 +130,10 @@ class KeepAliveReceiver : DaggerBroadcastReceiver() {
}
if (!pump.isThisProfileSet(profile) && !commandQueue.isRunning(Command.CommandType.BASAL_PROFILE)) {
rxBus.send(EventProfileNeedsUpdate())
} else if (isStatusOutdated && !pump.isBusy) {
} else if (isStatusOutdated && !pump.isBusy()) {
lastReadStatus = System.currentTimeMillis()
commandQueue.readStatus("KeepAlive. Status outdated.", null)
} else if (isBasalOutdated && !pump.isBusy) {
} else if (isBasalOutdated && !pump.isBusy()) {
lastReadStatus = System.currentTimeMillis()
commandQueue.readStatus("KeepAlive. Basal outdated.", null)
}

View file

@ -217,9 +217,11 @@ class SWDefinition @Inject constructor(
.updateDelay(5)
.label(R.string.treatmentssafety_maxcarbs_title)
.comment(R.string.common_values))
.validator { sp.contains(R.string.key_age)
&& sp.getDouble(R.string.key_treatmentssafety_maxbolus, 0.0) > 0
&& sp.getDouble(R.string.key_treatmentssafety_maxcarbs, 0.0) > 0 }
.validator {
sp.contains(R.string.key_age)
&& sp.getDouble(R.string.key_treatmentssafety_maxbolus, 0.0) > 0
&& sp.getDouble(R.string.key_treatmentssafety_maxcarbs, 0.0) > 0
}
private val screenInsulin = SWScreen(injector, R.string.configbuilder_insulin)
.skippable(false)
.add(SWPlugin(injector, this)
@ -303,7 +305,7 @@ class SWDefinition @Inject constructor(
// 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 OmnipodErosPumpPlugin && activePump.isRileyLinkReady)
return activePump.isInitialized() || (activePump is OmnipodErosPumpPlugin && activePump.isRileyLinkReady)
}
private val screenAps = SWScreen(injector, R.string.configbuilder_aps)

View file

@ -0,0 +1,63 @@
package info.nightscout.androidaps.utils
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.R
import info.nightscout.androidaps.plugins.general.automation.AutomationEvent
import info.nightscout.androidaps.plugins.general.automation.AutomationPlugin
import info.nightscout.androidaps.plugins.general.automation.actions.ActionAlarm
import info.nightscout.androidaps.plugins.general.automation.elements.Comparator
import info.nightscout.androidaps.plugins.general.automation.elements.InputDelta
import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerBg
import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerConnector
import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerDelta
import info.nightscout.androidaps.utils.resources.ResourceHelper
import java.text.DecimalFormat
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class CarbTimer @Inject constructor(
private val injector: HasAndroidInjector,
private val resourceHelper: ResourceHelper,
private val automationPlugin: AutomationPlugin,
private val timerUtil: TimerUtil
) {
fun scheduleReminder(time: Long, text: String? = null) =
timerUtil.scheduleReminder(time, text ?: resourceHelper.gs(R.string.timetoeat))
fun scheduleEatReminder() {
val event = AutomationEvent(injector).apply {
title = resourceHelper.gs(R.string.bolusadvisor)
readOnly = true
systemAction = true
autoRemove = true
trigger = TriggerConnector(injector, TriggerConnector.Type.OR).apply {
// Bg under 180 mgdl and dropping by 15 mgdl
list.add(TriggerConnector(injector, TriggerConnector.Type.AND).apply {
list.add(TriggerBg(injector, 180.0, Constants.MGDL, Comparator.Compare.IS_LESSER))
list.add(TriggerDelta(injector, InputDelta(injector, -15.0, -360.0, 360.0, 1.0, DecimalFormat("0"), InputDelta.DeltaType.DELTA), Constants.MGDL, Comparator.Compare.IS_EQUAL_OR_LESSER))
list.add(TriggerDelta(injector, InputDelta(injector, -8.0, -360.0, 360.0, 1.0, DecimalFormat("0"), InputDelta.DeltaType.SHORT_AVERAGE), Constants.MGDL, Comparator.Compare.IS_EQUAL_OR_LESSER))
})
// Bg under 160 mgdl and dropping by 9 mgdl
list.add(TriggerConnector(injector, TriggerConnector.Type.AND).apply {
list.add(TriggerBg(injector, 160.0, Constants.MGDL, Comparator.Compare.IS_LESSER))
list.add(TriggerDelta(injector, InputDelta(injector, -9.0, -360.0, 360.0, 1.0, DecimalFormat("0"), InputDelta.DeltaType.DELTA), Constants.MGDL, Comparator.Compare.IS_EQUAL_OR_LESSER))
list.add(TriggerDelta(injector, InputDelta(injector, -5.0, -360.0, 360.0, 1.0, DecimalFormat("0"), InputDelta.DeltaType.SHORT_AVERAGE), Constants.MGDL, Comparator.Compare.IS_EQUAL_OR_LESSER))
})
// Bg under 145 mgdl and dropping
list.add(TriggerConnector(injector, TriggerConnector.Type.AND).apply {
list.add(TriggerBg(injector, 145.0, Constants.MGDL, Comparator.Compare.IS_LESSER))
list.add(TriggerDelta(injector, InputDelta(injector, 0.0, -360.0, 360.0, 1.0, DecimalFormat("0"), InputDelta.DeltaType.DELTA), Constants.MGDL, Comparator.Compare.IS_EQUAL_OR_LESSER))
list.add(TriggerDelta(injector, InputDelta(injector, 0.0, -360.0, 360.0, 1.0, DecimalFormat("0"), InputDelta.DeltaType.SHORT_AVERAGE), Constants.MGDL, Comparator.Compare.IS_EQUAL_OR_LESSER))
})
}
actions.add(ActionAlarm(injector, resourceHelper.gs(R.string.time_to_eat)))
}
automationPlugin.addIfNotExists(event)
}
}

View file

@ -0,0 +1,27 @@
package info.nightscout.androidaps.utils
import android.content.Context
import android.content.Intent
import android.provider.AlarmClock
import info.nightscout.androidaps.R
import info.nightscout.androidaps.utils.resources.ResourceHelper
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class TimerUtil @Inject constructor(
private val context: Context,
private val resourceHelper: ResourceHelper,
) {
fun scheduleReminder(time: Long, text: String? = null) {
Intent(AlarmClock.ACTION_SET_TIMER).apply {
val length: Int = ((time - DateUtil.now()) / 1000).toInt()
flags = flags or Intent.FLAG_ACTIVITY_NEW_TASK
putExtra(AlarmClock.EXTRA_LENGTH, length)
putExtra(AlarmClock.EXTRA_SKIP_UI, true)
putExtra(AlarmClock.EXTRA_MESSAGE, text ?: resourceHelper.gs(R.string.app_name))
context.startActivity(this)
}
}
}

View file

@ -6,7 +6,6 @@ import android.text.Spanned
import com.google.common.base.Joiner
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.Config
import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.R
import info.nightscout.androidaps.activities.ErrorHelperActivity
import info.nightscout.androidaps.data.DetailedBolusInfo
@ -22,18 +21,10 @@ import info.nightscout.androidaps.logging.UserEntryLogger
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
import info.nightscout.androidaps.plugins.general.automation.AutomationEvent
import info.nightscout.androidaps.plugins.general.automation.AutomationPlugin
import info.nightscout.androidaps.plugins.general.automation.actions.ActionAlarm
import info.nightscout.androidaps.plugins.general.automation.elements.Comparator
import info.nightscout.androidaps.plugins.general.automation.elements.InputDelta
import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerBg
import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerConnector
import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerDelta
import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerTime
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
import info.nightscout.androidaps.queue.Callback
import info.nightscout.androidaps.utils.CarbTimer
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.HtmlHelper
import info.nightscout.androidaps.utils.Round
@ -44,7 +35,6 @@ import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.sharedPreferences.SP
import org.json.JSONException
import org.json.JSONObject
import java.text.DecimalFormat
import java.util.*
import javax.inject.Inject
import kotlin.math.abs
@ -63,10 +53,10 @@ class BolusWizard @Inject constructor(
@Inject lateinit var commandQueue: CommandQueueProvider
@Inject lateinit var loopPlugin: LoopPlugin
@Inject lateinit var iobCobCalculatorPlugin: IobCobCalculatorPlugin
@Inject lateinit var automationPlugin: AutomationPlugin
@Inject lateinit var dateUtil: DateUtil
@Inject lateinit var config: Config
@Inject lateinit var uel: UserEntryLogger
@Inject lateinit var carbTimer: CarbTimer
init {
injector.androidInjector().inject(this)
@ -363,7 +353,7 @@ class BolusWizard @Inject constructor(
if (!result.success) {
ErrorHelperActivity.runAlarm(ctx, result.comment, resourceHelper.gs(R.string.treatmentdeliveryerror), R.raw.boluserror)
} else
scheduleEatReminder()
carbTimer.scheduleEatReminder()
}
})
}
@ -434,57 +424,9 @@ class BolusWizard @Inject constructor(
}
}
if (useAlarm && carbs > 0 && carbTime > 0) {
scheduleReminder(dateUtil._now() + T.mins(carbTime.toLong()).msecs())
carbTimer.scheduleReminder(dateUtil._now() + T.mins(carbTime.toLong()).msecs())
}
}
})
}
private fun scheduleEatReminder() {
val event = AutomationEvent(injector).apply {
title = resourceHelper.gs(R.string.bolusadvisor)
readOnly = true
systemAction = true
autoRemove = true
trigger = TriggerConnector(injector, TriggerConnector.Type.OR).apply {
// Bg under 180 mgdl and dropping by 15 mgdl
list.add(TriggerConnector(injector, TriggerConnector.Type.AND).apply {
list.add(TriggerBg(injector, 180.0, Constants.MGDL, Comparator.Compare.IS_LESSER))
list.add(TriggerDelta(injector, InputDelta(injector, -15.0, -360.0, 360.0, 1.0, DecimalFormat("0"), InputDelta.DeltaType.DELTA), Constants.MGDL, Comparator.Compare.IS_EQUAL_OR_LESSER))
list.add(TriggerDelta(injector, InputDelta(injector, -8.0, -360.0, 360.0, 1.0, DecimalFormat("0"), InputDelta.DeltaType.SHORT_AVERAGE), Constants.MGDL, Comparator.Compare.IS_EQUAL_OR_LESSER))
})
// Bg under 160 mgdl and dropping by 9 mgdl
list.add(TriggerConnector(injector, TriggerConnector.Type.AND).apply {
list.add(TriggerBg(injector, 160.0, Constants.MGDL, Comparator.Compare.IS_LESSER))
list.add(TriggerDelta(injector, InputDelta(injector, -9.0, -360.0, 360.0, 1.0, DecimalFormat("0"), InputDelta.DeltaType.DELTA), Constants.MGDL, Comparator.Compare.IS_EQUAL_OR_LESSER))
list.add(TriggerDelta(injector, InputDelta(injector, -5.0, -360.0, 360.0, 1.0, DecimalFormat("0"), InputDelta.DeltaType.SHORT_AVERAGE), Constants.MGDL, Comparator.Compare.IS_EQUAL_OR_LESSER))
})
// Bg under 145 mgdl and dropping
list.add(TriggerConnector(injector, TriggerConnector.Type.AND).apply {
list.add(TriggerBg(injector, 145.0, Constants.MGDL, Comparator.Compare.IS_LESSER))
list.add(TriggerDelta(injector, InputDelta(injector, 0.0, -360.0, 360.0, 1.0, DecimalFormat("0"), InputDelta.DeltaType.DELTA), Constants.MGDL, Comparator.Compare.IS_EQUAL_OR_LESSER))
list.add(TriggerDelta(injector, InputDelta(injector, 0.0, -360.0, 360.0, 1.0, DecimalFormat("0"), InputDelta.DeltaType.SHORT_AVERAGE), Constants.MGDL, Comparator.Compare.IS_EQUAL_OR_LESSER))
})
}
actions.add(ActionAlarm(injector, resourceHelper.gs(R.string.time_to_eat)))
}
automationPlugin.addIfNotExists(event)
}
private fun scheduleReminder(time: Long) {
val event = AutomationEvent(injector).apply {
title = resourceHelper.gs(R.string.timetoeat)
readOnly = true
systemAction = true
autoRemove = true
trigger = TriggerConnector(injector, TriggerConnector.Type.AND).apply {
list.add(TriggerTime(injector, time))
}
actions.add(ActionAlarm(injector, resourceHelper.gs(R.string.timetoeat)))
}
automationPlugin.addIfNotExists(event)
}
}
}

View file

@ -75,107 +75,160 @@
</LinearLayout>
<LinearLayout
<TableLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
android:paddingEnd="5dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:width="120dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:text="@string/time_offset"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
android:textStyle="bold" />
<TableRow
android:layout_width="match_parent"
android:layout_height="wrap_content">
<info.nightscout.androidaps.utils.ui.MinutesNumberPicker
android:id="@+id/time"
android:layout_width="130dp"
android:layout_height="40dp" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:gravity="start"
android:minWidth="45dp"
android:paddingStart="5dp"
android:paddingEnd="5dp"
android:text="@string/unit_minute_short"
android:textAppearance="?android:attr/textAppearanceSmall" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:width="120dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:text="@string/time_offset"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
android:textStyle="bold" />
</LinearLayout>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:src="@drawable/ic_access_alarm_24dp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<CheckBox
android:id="@+id/alarmCheckBox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:checked="false"
android:padding="2dp" />
</LinearLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:width="120dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:text="@string/careportal_newnstreatment_duration_label"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
android:textStyle="bold" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<info.nightscout.androidaps.utils.ui.NumberPicker
android:id="@+id/duration"
android:layout_width="130dp"
android:layout_height="40dp" />
<info.nightscout.androidaps.utils.ui.MinutesNumberPicker
android:id="@+id/time"
android:layout_width="130dp"
android:layout_height="40dp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:gravity="start"
android:minWidth="45dp"
android:paddingStart="5dp"
android:paddingEnd="5dp"
android:text="@string/shorthour"
android:textAppearance="?android:attr/textAppearanceSmall" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:gravity="start"
android:paddingStart="5dp"
android:paddingEnd="5dp"
android:text="@string/unit_minute_short"
android:textAppearance="?android:attr/textAppearanceSmall" />
</LinearLayout>
</LinearLayout>
</TableRow>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TableRow
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:width="120dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:text="@string/treatments_wizard_carbs_label"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
android:textStyle="bold" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<info.nightscout.androidaps.utils.ui.NumberPicker
android:id="@+id/carbs"
android:layout_width="130dp"
android:layout_height="40dp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:width="120dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:text="@string/careportal_newnstreatment_duration_label"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
android:textStyle="bold" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:gravity="start"
android:minWidth="45dp"
android:paddingStart="5dp"
android:paddingEnd="5dp"
android:text="@string/shortgramm"
android:textAppearance="?android:attr/textAppearanceSmall" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<info.nightscout.androidaps.utils.ui.NumberPicker
android:id="@+id/duration"
android:layout_width="130dp"
android:layout_height="40dp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:gravity="start"
android:minWidth="45dp"
android:paddingStart="5dp"
android:paddingEnd="5dp"
android:text="@string/shorthour"
android:textAppearance="?android:attr/textAppearanceSmall" />
</LinearLayout>
</TableRow>
<TableRow
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:width="120dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:text="@string/treatments_wizard_carbs_label"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
android:textStyle="bold" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<info.nightscout.androidaps.utils.ui.NumberPicker
android:id="@+id/carbs"
android:layout_width="130dp"
android:layout_height="40dp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:gravity="start"
android:minWidth="45dp"
android:paddingStart="5dp"
android:paddingEnd="5dp"
android:text="@string/shortgramm"
android:textAppearance="?android:attr/textAppearanceSmall" />
</LinearLayout>
</TableRow>
</TableLayout>
<LinearLayout
android:layout_width="match_parent"

View file

@ -1161,4 +1161,5 @@
<string name="trend_arrow">Šipka trendu</string>
<string name="cannula">Kanyla</string>
<string name="userentry">Vstup uživatele</string>
<string name="common_values">Použijte hodnoty pro největší jídlo, jaké obvykle jíte\n</string>
</resources>

View file

@ -1162,4 +1162,5 @@ Unerwartetes Verhalten.</string>
<string name="trend_arrow">Trendpfeil</string>
<string name="cannula">Kanüle</string>
<string name="userentry">Benutzereingabe</string>
<string name="common_values">Verwende die Werte der größten Mahlzeit, die Du normalerweise zu Dir nimmst\n</string>
</resources>

View file

@ -21,7 +21,7 @@
<string name="objectives_smb_objective">Activation de fonctionnalités supplémentaires pour l\'utilisation en journée, telles que la fonction SMB</string>
<string name="objectives_auto_objective">Activation de l\'automatisation</string>
<string name="objectives_smb_gate">Lisez le wiki et augmentez le maxIA pour que les SMBs fonctionnent correctement ! Un bon début est maxIA = moyenne des Bolus Repas + 3 x maximum débit Basal quotidien</string>
<string name="objectives_auto_gate">Lisez la documentation comment l\'automatisation fonctionne. Configurez vos premières règles simples. Au lieu de mettre une action, configurez une notification. Quand vous êtes sûr que l\'automatisation est déclenchée au bon moment, remplacez la notification par une action réelle. (https://androidaps.readthedocs.io/en/latest/CROWDIN/fr/Usage/Automation.html)</string>
<string name="objectives_auto_gate">Lisez la documentation comment l\'automatisation fonctionne. Configurez vos premières règles simples. Au lieu de mettre une action, configurez une notification. Quand vous êtes sûr que l\'automatisation est déclenchée au bon moment, remplacez la notification par une action réelle. (https://androidaps.readthedocs.io/fr/latest/Usage/Automation.html)</string>
<string name="objectives_bgavailableinns">Glycémie disponible sur NS</string>
<string name="objectives_pumpstatusavailableinns">Statut de la pompe disponible sur NS</string>
<string name="objectives_manualenacts">Activation manuelle</string>
@ -36,7 +36,7 @@
<string name="objectives_useloop">Affichage du contenu du plugin Boucle</string>
<string name="objectives_usescale">Modification de l\'échelle du graphique par un appui long sur la courbe de glycémie</string>
<string name="objectives_button_enter">Entrer</string>
<string name="enter_code_obtained_from_developers_to_bypass_the_rest_of_objectives">Si vous avez au moins 3 mois d\'expérience de boucle fermée avec d\'autres systèmes, vous pourriez avoir droit à un code permettant d\'ignorer les objectifs. Voir https://androidaps.readthedocs.io/en/latest/CROWDIN/fr/Usage/Objectives.html#ignorer-les-objectifs pour plus de détails.</string>
<string name="enter_code_obtained_from_developers_to_bypass_the_rest_of_objectives">Si vous avez au moins 3 mois d\'expérience de boucle fermée avec d\'autres systèmes, vous pourriez avoir droit à un code permettant d\'ignorer les objectifs. Voir https://androidaps.readthedocs.io/fr/latest/Usage/Objectives.html#ignorer-les-objectifs pour plus de détails.</string>
<string name="codeaccepted">Code accepté</string>
<string name="codeinvalid">Code invalide</string>
<string name="objectives_exam_objective">Prouver ses connaissances</string>
@ -46,10 +46,10 @@
<string name="unfinshed_button">Prochain non terminé</string>
<string name="requestcode">Code requis : %1$s</string>
<string name="objectives_hint">(Sélectionnez toutes les bonnes réponses)</string>
<string name="disconnectpump_hint" formatted="false">https://androidaps.readthedocs.io/en/latest/CROWDIN/fr/Getting-Started/FAQ.html#what-to-do-when-taking-a-shower-or-bath</string>
<string name="usetemptarget_hint" formatted="false">https://androidaps.readthedocs.io/en/latest/CROWDIN/fr/Getting-Started/Screenshots.html#the-homescreen</string>
<string name="useaction_hint" formatted="false">https://androidaps.readthedocs.io/en/latest/CROWDIN/fr/Getting-Started/Screenshots.html#config-builder</string>
<string name="usescale_hint" formatted="false">https://androidaps.readthedocs.io/en/latest/CROWDIN/fr/Getting-Started/Screenshots.html#the-homescreen</string>
<string name="disconnectpump_hint" formatted="false">https://androidaps.readthedocs.io/fr/latest/Getting-Started/FAQ.html#que-faire-pour-prendre-une-douche-ou-un-bain</string>
<string name="usetemptarget_hint" formatted="false">https://androidaps.readthedocs.io/fr/latest/Getting-Started/Screenshots.html</string>
<string name="useaction_hint" formatted="false">https://androidaps.readthedocs.io/fr/latest/Configuration/Config-Builder.html</string>
<string name="usescale_hint" formatted="false">https://androidaps.readthedocs.io/fr/latest/Getting-Started/Screenshots.html</string>
<string name="notconnected">Non connecté à Internet</string>
<string name="failedretrievetime">Échec de la récupération de l\'heure</string>
<string name="requirementnotmet">Exigences de l\'objectif non atteintes</string>

View file

@ -1162,4 +1162,5 @@ L\'ENSEMBLE DES RISQUES LIÉS À LA QUALITÉ ET À LA PERFORMANCE DU PROGRAMME S
<string name="trend_arrow">Flèche de tendance</string>
<string name="cannula">Canule</string>
<string name="userentry">Entrées utilisateur</string>
<string name="common_values">Utilisez les valeurs qui correspondent à vos plus gros repas\n</string>
</resources>

View file

@ -1161,4 +1161,5 @@
<string name="trend_arrow">Freccia trend</string>
<string name="cannula">Cannula</string>
<string name="userentry">Inserimento utente</string>
<string name="common_values">Usa i valori del cibo più abbondante che mangi di solito\n</string>
</resources>

View file

@ -180,7 +180,7 @@
<string name="save">שמור</string>
<string name="reloadprofile">טעינה מחדש של הפרופיל</string>
<string name="smscommunicator">תקשורת SMS</string>
<string name="smscommunicator_allowednumbers">מספרי טלפון מותרים</string>
<string name="smscommunicator_allowednumbers">מספרי טלפון מורשים</string>
<string name="smscommunicator_allowednumbers_summary">+ XXXXXXXXXX; + YYYYYYYYYY</string>
<string name="smscommunicator_bolusreplywithcode">לאישור מתן בולוס %1$.2f יחידות יש להשיב עם הקוד %2$s</string>
<string name="smscommunicator_mealbolusreplywithcode">למתן %1$.2f יחידות בולוס ארוחה יש להשיב עם הקוד %2$s</string>
@ -1161,4 +1161,5 @@
<string name="trend_arrow">חץ מגמה</string>
<string name="cannula">צינורית</string>
<string name="userentry">קלט המשתמש</string>
<string name="common_values">השתמשו בערכים הגבוהים ביותר של מזונות שאתם אוכלים בדרך כלל\n</string>
</resources>

View file

@ -1161,4 +1161,5 @@
<string name="trend_arrow">Trend pil</string>
<string name="cannula">Kanyle</string>
<string name="userentry">Bruker registrering</string>
<string name="common_values">Bruk verdiene for det største måltidet du normalt spiser\n</string>
</resources>

View file

@ -1161,4 +1161,5 @@
<string name="trend_arrow">Seta de tendência</string>
<string name="cannula">Cânula</string>
<string name="userentry">Entrada de Utilizador</string>
<string name="common_values">Utilize valores da sua maior refeição que normalmente come\n</string>
</resources>

View file

@ -1163,4 +1163,5 @@ Context | Edit Context</string>
<string name="trend_arrow">Стрелка тренда</string>
<string name="cannula">Катетер помпы</string>
<string name="userentry">Запись пользователя</string>
<string name="common_values">Введите максимальные значения вашего приема пищи \n</string>
</resources>

View file

@ -420,6 +420,7 @@
<string name="basal_shortname">BAZ</string>
<string name="deviation_shortname">DEV</string>
<string name="activity_shortname">AKT</string>
<string name="bgi_shortname">-BGI</string>
<string name="abs_insulin_shortname">ABS</string>
<string name="devslope_shortname">DEVSLOPE</string>
<string name="nav_about">O aplikácii</string>
@ -627,6 +628,7 @@
<string name="ns_autobackfill_summary">Automaticky doplňovať chýbajúcu glykémiu z NS</string>
<string name="loop_smbsetbypump_label">SMB podané pumpou</string>
<string name="overview_show_activity">Aktivita</string>
<string name="overview_show_bgi">Vplyv na glykémiu (BGI)</string>
<string name="overview_show_sensitivity">Citlivosť</string>
<string name="overview_show_deviations">Odchýlky</string>
<string name="overview_show_cob">Aktívne sacharidy</string>
@ -1158,4 +1160,6 @@
<string name="clear_filter">Vyčistiť filter</string>
<string name="trend_arrow">Trendová šípka</string>
<string name="cannula">Kanyla</string>
<string name="userentry">Vstup používateľa</string>
<string name="common_values">Použite hodnoty pre najväčšie jedlo, aké obvykle jete\n</string>
</resources>

View file

@ -125,69 +125,6 @@
<item>YpsoPump</item>
</string-array>
<string-array name="medtronicPumpTypeArray">
<item>Other (unsupported)</item>
<item>512</item>
<item>712</item>
<item>515</item>
<item>715</item>
<item>522</item>
<item>722</item>
<item>523 (Fw 2.4A or lower)</item>
<item>723 (Fw 2.4A or lower)</item>
<item>554 (EU Fw. &lt;= 2.6A)</item>
<item>754 (EU Fw. &lt;= 2.6A)</item>
<item>554 (CA Fw. &lt;= 2.7A)</item>
<item>754 (CA Fw. &lt;= 2.7A)</item>
</string-array>
<string-array name="medtronicPumpFreqArray">
<item>@string/medtronic_pump_frequency_us_ca</item>
<item>@string/medtronic_pump_frequency_worldwide</item>
</string-array>
<string-array name="medtronicPumpFreqValues">
<item>@string/key_medtronic_pump_frequency_us_ca</item>
<item>@string/key_medtronic_pump_frequency_worldwide</item>
</string-array>
<string-array name="medtronicBolusDelay">
<item>5</item>
<item>10</item>
<item>15</item>
</string-array>
<string-array name="medtronicEncoding">
<item>@string/medtronic_pump_encoding_4b6b_local</item>
<item>@string/medtronic_pump_encoding_4b6b_rileylink</item>
</string-array>
<string-array name="onOff">
<item>@string/common_on</item>
<item>@string/common_off</item>
</string-array>
<string-array name="medtronicEncodingValues">
<item>@string/key_medtronic_pump_encoding_4b6b_local</item>
<item>@string/key_medtronic_pump_encoding_4b6b_rileylink</item>
</string-array>
<string-array name="medtronicBatteryType">
<item>@string/medtronic_pump_battery_no</item>
<item>@string/medtronic_pump_battery_alkaline</item>
<item>@string/medtronic_pump_battery_lithium</item>
<item>@string/medtronic_pump_battery_nizn</item>
<item>@string/medtronic_pump_battery_nimh</item>
</string-array>
<string-array name="medtronicBatteryTypeValues">
<item>@string/key_medtronic_pump_battery_no</item>
<item>@string/key_medtronic_pump_battery_alkaline</item>
<item>@string/key_medtronic_pump_battery_lithium</item>
<item>@string/key_medtronic_pump_battery_nizn</item>
<item>@string/key_medtronic_pump_battery_nimh</item>
</string-array>
<string-array name="smbMaxMinutes">
<item>15</item>
<item>30</item>

View file

@ -65,7 +65,4 @@
<color name="splashBackground">#2E2E2E</color>
<color name="importListFileName">#FFFFFF</color>
<color name="importListAdditionalInfo">#BBBBBB</color>
</resources>

View file

@ -1251,7 +1251,6 @@
<string name="key_snoozedTo" translatable="false">snoozedTo</string>
<string name="key_snooze_dst_in24h" translatable="false">snooze_dst_in24h</string>
<string name="key_snooze_loopdisabled" translatable="false">snooze_loopdisabled</string>
<string name="sixdigitnumber" translatable="false">^\\d{6}</string>
<string name="ebstopsloop">Use of Extended bolus feature will stop closed loop mode for the time of running extended bolus. Do you really want it?</string>
<string name="closed_loop_disabled_with_eb">Closed loop disabled because of running Extended bolus</string>
<string name="phonechecker">\"PhoneChecker\"</string>

View file

@ -22,16 +22,6 @@
<item name="colorAccent">@color/colorAccent</item>
</style>
<style name="Theme.AppCompat.NoTitle" parent="Theme.AppCompat.NoActionBar">
<item name="android:windowNoTitle">true</item>
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:colorBackgroundCacheHint">@null</item>
<item name="android:windowIsTranslucent">false</item>
<item name="android:windowAnimationStyle">@android:style/Animation</item>
</style>
<style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" />
<style name="section_header_label">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">wrap_content</item>

View file

@ -3,33 +3,35 @@ package info.nightscout.androidaps
import dagger.android.AndroidInjector
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.interfaces.ProfileStore
import info.nightscout.androidaps.db.ProfileSwitch
import info.nightscout.androidaps.interfaces.ActivePluginProvider
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.db.Treatment
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
import info.nightscout.androidaps.interfaces.ActivePluginProvider
import info.nightscout.androidaps.interfaces.ConfigInterface
import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.interfaces.ProfileStore
import info.nightscout.androidaps.interfaces.TreatmentsInterface
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.DefaultValueHelper
import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.androidaps.utils.rx.TestAapsSchedulers
import org.json.JSONObject
import org.junit.Before
import org.mockito.Mock
import org.powermock.core.classloader.annotations.PrepareForTest
@Suppress("SpellCheckingInspection")
@PrepareForTest(FabricPrivacy::class)
open class TestBaseWithProfile : TestBase() {
@Mock lateinit var activePluginProvider: ActivePluginProvider
@Mock lateinit var resourceHelper: ResourceHelper
@Mock lateinit var treatmentsPlugin: TreatmentsPlugin
@Mock lateinit var treatmentsInterface: TreatmentsInterface
@Mock lateinit var fabricPrivacy: FabricPrivacy
@Mock lateinit var profileFunction: ProfileFunction
@Mock lateinit var defaultValueHelper: DefaultValueHelper
@Mock lateinit var dateUtil: DateUtil
@Mock lateinit var configInterface: ConfigInterface
val rxBus = RxBusWrapper(aapsSchedulers)
@ -41,10 +43,10 @@ open class TestBaseWithProfile : TestBase() {
it.resourceHelper = resourceHelper
it.rxBus = rxBus
it.fabricPrivacy = fabricPrivacy
it.configInterface = Config()
it.configInterface = configInterface
}
if (it is ProfileSwitch) {
it.treatmentsPlugin = treatmentsPlugin
it.treatmentsPlugin = treatmentsInterface
it.aapsLogger = aapsLogger
it.rxBus = rxBus
it.resourceHelper = resourceHelper
@ -61,7 +63,7 @@ open class TestBaseWithProfile : TestBase() {
private lateinit var validProfileJSON: String
lateinit var validProfile: Profile
val TESTPROFILENAME = "someProfile"
@Suppress("PropertyName") val TESTPROFILENAME = "someProfile"
@Before
fun prepareMock() {

View file

@ -14,33 +14,36 @@ import org.json.JSONObject
@Suppress("MemberVisibilityCanBePrivate")
class TestPumpPlugin(val injector: HasAndroidInjector) : PumpInterface {
override var isConnected = false
override var isConnecting = false
override var isHandshakeInProgress = false
var connected = false
var isProfileSet = true
override fun isConnected() = connected
override fun isConnecting() = false
override fun isHandshakeInProgress() = false
val lastData = 0L
val baseBasal = 0.0
override val pumpDescription = PumpDescription()
override val isInitialized: Boolean = true
override val isSuspended: Boolean = false
override val isBusy: Boolean = false
override fun isInitialized(): Boolean = true
override fun isSuspended(): Boolean = false
override fun isBusy(): Boolean = false
override fun connect(reason: String) {
isConnected = true
connected = true
}
override fun disconnect(reason: String) {
isConnected = false
connected = false
}
override fun stopConnecting() {
isConnected = false
connected = false
}
override fun waitForDisconnectionInSeconds(): Int = 0
override fun getPumpStatus(reason: String) {}
override fun setNewBasalProfile(profile: Profile): PumpEnactResult = PumpEnactResult(injector)
override fun isThisProfileSet(profile: Profile): Boolean = true
override fun isThisProfileSet(profile: Profile): Boolean = isProfileSet
override fun lastDataTime(): Long = lastData
override val baseBasalRate: Double = baseBasal
override val reservoirLevel: Double = 0.0

View file

@ -123,13 +123,13 @@ class ConstraintsCheckerTest : TestBaseWithProfile() {
danaPump = DanaPump(aapsLogger, sp, injector)
hardLimits = HardLimits(aapsLogger, rxBus, sp, resourceHelper, context, nsUpload)
objectivesPlugin = ObjectivesPlugin(injector, aapsLogger, resourceHelper, activePlugin, sp, Config(), uel)
comboPlugin = ComboPlugin(injector, aapsLogger, rxBus, resourceHelper, profileFunction, treatmentsPlugin, sp, commandQueue, context)
comboPlugin = ComboPlugin(injector, aapsLogger, rxBus, resourceHelper, profileFunction, treatmentsInterface, sp, commandQueue, context)
danaRPlugin = DanaRPlugin(injector, aapsLogger, aapsSchedulers, rxBus, context, resourceHelper, constraintChecker, activePlugin, sp, commandQueue, danaPump, dateUtil, fabricPrivacy)
danaRSPlugin = DanaRSPlugin(injector, aapsLogger, aapsSchedulers, rxBus, context, resourceHelper, constraintChecker, profileFunction, activePluginProvider, sp, commandQueue, danaPump, detailedBolusInfoStorage, fabricPrivacy, dateUtil)
insightPlugin = LocalInsightPlugin(injector, aapsLogger, rxBus, resourceHelper, treatmentsPlugin, sp, commandQueue, profileFunction, nsUpload, context, uploadQueue, Config(), dateUtil)
openAPSSMBPlugin = OpenAPSSMBPlugin(injector, aapsLogger, rxBus, constraintChecker, resourceHelper, profileFunction, context, activePlugin, treatmentsPlugin, iobCobCalculatorPlugin, hardLimits, profiler, sp)
openAPSAMAPlugin = OpenAPSAMAPlugin(injector, aapsLogger, rxBus, constraintChecker, resourceHelper, profileFunction, context, activePlugin, treatmentsPlugin, iobCobCalculatorPlugin, hardLimits, profiler, fabricPrivacy)
safetyPlugin = SafetyPlugin(injector, aapsLogger, resourceHelper, sp, rxBus, constraintChecker, openAPSAMAPlugin, openAPSSMBPlugin, sensitivityOref1Plugin, activePlugin, hardLimits, BuildHelper(Config(), loggerUtils), treatmentsPlugin, Config())
insightPlugin = LocalInsightPlugin(injector, aapsLogger, rxBus, resourceHelper, treatmentsInterface, sp, commandQueue, profileFunction, nsUpload, context, uploadQueue, Config(), dateUtil)
openAPSSMBPlugin = OpenAPSSMBPlugin(injector, aapsLogger, rxBus, constraintChecker, resourceHelper, profileFunction, context, activePlugin, treatmentsInterface, iobCobCalculatorPlugin, hardLimits, profiler, sp)
openAPSAMAPlugin = OpenAPSAMAPlugin(injector, aapsLogger, rxBus, constraintChecker, resourceHelper, profileFunction, context, activePlugin, treatmentsInterface, iobCobCalculatorPlugin, hardLimits, profiler, fabricPrivacy)
safetyPlugin = SafetyPlugin(injector, aapsLogger, resourceHelper, sp, rxBus, constraintChecker, openAPSAMAPlugin, openAPSSMBPlugin, sensitivityOref1Plugin, activePlugin, hardLimits, BuildHelper(Config(), loggerUtils), treatmentsInterface, Config())
val constraintsPluginsList = ArrayList<PluginBase>()
constraintsPluginsList.add(safetyPlugin)
constraintsPluginsList.add(objectivesPlugin)

View file

@ -43,7 +43,7 @@ class APSResultTest : TestBaseWithProfile() {
it.constraintChecker = constraintChecker
it.sp = sp
it.activePlugin = activePluginProvider
it.treatmentsPlugin = treatmentsPlugin
it.treatmentsPlugin = treatmentsInterface
it.profileFunction = profileFunction
it.resourceHelper = resourceHelper
}
@ -56,7 +56,7 @@ class APSResultTest : TestBaseWithProfile() {
// closed loop mode return original request
closedLoopEnabled.set(aapsLogger, true)
`when`(treatmentsPlugin.getTempBasalFromHistory(ArgumentMatchers.anyLong())).thenReturn(null)
`when`(treatmentsInterface.getTempBasalFromHistory(ArgumentMatchers.anyLong())).thenReturn(null)
apsResult.tempBasalRequested(false)
Assert.assertEquals(false, apsResult.isChangeRequested)
apsResult.tempBasalRequested(true).percent(200).duration(30)
@ -65,46 +65,46 @@ class APSResultTest : TestBaseWithProfile() {
// open loop
closedLoopEnabled.set(aapsLogger, false)
// no change requested
`when`(treatmentsPlugin.getTempBasalFromHistory(ArgumentMatchers.anyLong())).thenReturn(null)
`when`(treatmentsInterface.getTempBasalFromHistory(ArgumentMatchers.anyLong())).thenReturn(null)
apsResult.tempBasalRequested(false)
Assert.assertEquals(false, apsResult.isChangeRequested)
// request 100% when no temp is running
`when`(treatmentsPlugin.getTempBasalFromHistory(ArgumentMatchers.anyLong())).thenReturn(null)
`when`(treatmentsInterface.getTempBasalFromHistory(ArgumentMatchers.anyLong())).thenReturn(null)
apsResult.tempBasalRequested(true).percent(100).duration(30)
Assert.assertEquals(false, apsResult.isChangeRequested)
// request equal temp
`when`(treatmentsPlugin.getTempBasalFromHistory(ArgumentMatchers.anyLong())).thenReturn(TemporaryBasal(injector).percent(70).duration(30))
`when`(treatmentsInterface.getTempBasalFromHistory(ArgumentMatchers.anyLong())).thenReturn(TemporaryBasal(injector).percent(70).duration(30))
apsResult.tempBasalRequested(true).percent(70).duration(30)
Assert.assertEquals(false, apsResult.isChangeRequested)
// request zero temp
`when`(treatmentsPlugin.getTempBasalFromHistory(ArgumentMatchers.anyLong())).thenReturn(TemporaryBasal(injector).percent(10).duration(30))
`when`(treatmentsInterface.getTempBasalFromHistory(ArgumentMatchers.anyLong())).thenReturn(TemporaryBasal(injector).percent(10).duration(30))
apsResult.tempBasalRequested(true).percent(0).duration(30)
Assert.assertEquals(true, apsResult.isChangeRequested)
// request high temp
`when`(treatmentsPlugin.getTempBasalFromHistory(ArgumentMatchers.anyLong())).thenReturn(TemporaryBasal(injector).percent(190).duration(30))
`when`(treatmentsInterface.getTempBasalFromHistory(ArgumentMatchers.anyLong())).thenReturn(TemporaryBasal(injector).percent(190).duration(30))
apsResult.tempBasalRequested(true).percent(200).duration(30)
Assert.assertEquals(true, apsResult.isChangeRequested)
// request slightly different temp
`when`(treatmentsPlugin.getTempBasalFromHistory(ArgumentMatchers.anyLong())).thenReturn(TemporaryBasal(injector).percent(70).duration(30))
`when`(treatmentsInterface.getTempBasalFromHistory(ArgumentMatchers.anyLong())).thenReturn(TemporaryBasal(injector).percent(70).duration(30))
apsResult.tempBasalRequested(true).percent(80).duration(30)
Assert.assertEquals(false, apsResult.isChangeRequested)
// request different temp
`when`(treatmentsPlugin.getTempBasalFromHistory(ArgumentMatchers.anyLong())).thenReturn(TemporaryBasal(injector).percent(70).duration(30))
`when`(treatmentsInterface.getTempBasalFromHistory(ArgumentMatchers.anyLong())).thenReturn(TemporaryBasal(injector).percent(70).duration(30))
apsResult.tempBasalRequested(true).percent(120).duration(30)
Assert.assertEquals(true, apsResult.isChangeRequested)
// it should work with absolute temps too
// request different temp
`when`(treatmentsPlugin.getTempBasalFromHistory(ArgumentMatchers.anyLong())).thenReturn(TemporaryBasal(injector).absolute(1.0).duration(30))
`when`(treatmentsInterface.getTempBasalFromHistory(ArgumentMatchers.anyLong())).thenReturn(TemporaryBasal(injector).absolute(1.0).duration(30))
apsResult.tempBasalRequested(true).percent(100).duration(30)
Assert.assertEquals(false, apsResult.isChangeRequested)
`when`(treatmentsPlugin.getTempBasalFromHistory(ArgumentMatchers.anyLong())).thenReturn(TemporaryBasal(injector).absolute(2.0).duration(30))
`when`(treatmentsInterface.getTempBasalFromHistory(ArgumentMatchers.anyLong())).thenReturn(TemporaryBasal(injector).absolute(2.0).duration(30))
apsResult.tempBasalRequested(true).percent(50).duration(30)
Assert.assertEquals(true, apsResult.isChangeRequested)
@ -115,44 +115,44 @@ class APSResultTest : TestBaseWithProfile() {
// open loop
closedLoopEnabled.set(aapsLogger, false)
// request 100% when no temp is running
`when`(treatmentsPlugin.getTempBasalFromHistory(ArgumentMatchers.anyLong())).thenReturn(null)
`when`(treatmentsInterface.getTempBasalFromHistory(ArgumentMatchers.anyLong())).thenReturn(null)
apsResult.tempBasalRequested(true).rate(1.0).duration(30)
Assert.assertEquals(false, apsResult.isChangeRequested)
// request equal temp
`when`(treatmentsPlugin.getTempBasalFromHistory(ArgumentMatchers.anyLong())).thenReturn(TemporaryBasal(injector).absolute(2.0).duration(30))
`when`(treatmentsInterface.getTempBasalFromHistory(ArgumentMatchers.anyLong())).thenReturn(TemporaryBasal(injector).absolute(2.0).duration(30))
apsResult.tempBasalRequested(true).rate(2.0).duration(30)
Assert.assertEquals(false, apsResult.isChangeRequested)
`when`(treatmentsPlugin.getTempBasalFromHistory(ArgumentMatchers.anyLong())).thenReturn(TemporaryBasal(injector).percent(200).duration(30))
`when`(treatmentsInterface.getTempBasalFromHistory(ArgumentMatchers.anyLong())).thenReturn(TemporaryBasal(injector).percent(200).duration(30))
apsResult.tempBasalRequested(true).rate(2.0).duration(30)
Assert.assertEquals(false, apsResult.isChangeRequested)
// request zero temp
`when`(treatmentsPlugin.getTempBasalFromHistory(ArgumentMatchers.anyLong())).thenReturn(TemporaryBasal(injector).absolute(0.1).duration(30))
`when`(treatmentsInterface.getTempBasalFromHistory(ArgumentMatchers.anyLong())).thenReturn(TemporaryBasal(injector).absolute(0.1).duration(30))
apsResult.tempBasalRequested(true).rate(0.0).duration(30)
Assert.assertEquals(true, apsResult.isChangeRequested)
// request high temp
`when`(treatmentsPlugin.getTempBasalFromHistory(ArgumentMatchers.anyLong())).thenReturn(TemporaryBasal(injector).absolute(34.9).duration(30))
`when`(treatmentsInterface.getTempBasalFromHistory(ArgumentMatchers.anyLong())).thenReturn(TemporaryBasal(injector).absolute(34.9).duration(30))
apsResult.tempBasalRequested(true).rate(35.0).duration(30)
Assert.assertEquals(true, apsResult.isChangeRequested)
// request slightly different temp
`when`(treatmentsPlugin.getTempBasalFromHistory(ArgumentMatchers.anyLong())).thenReturn(TemporaryBasal(injector).absolute(1.1).duration(30))
`when`(treatmentsInterface.getTempBasalFromHistory(ArgumentMatchers.anyLong())).thenReturn(TemporaryBasal(injector).absolute(1.1).duration(30))
apsResult.tempBasalRequested(true).rate(1.2).duration(30)
Assert.assertEquals(false, apsResult.isChangeRequested)
// request different temp
`when`(treatmentsPlugin.getTempBasalFromHistory(ArgumentMatchers.anyLong())).thenReturn(TemporaryBasal(injector).absolute(1.1).duration(30))
`when`(treatmentsInterface.getTempBasalFromHistory(ArgumentMatchers.anyLong())).thenReturn(TemporaryBasal(injector).absolute(1.1).duration(30))
apsResult.tempBasalRequested(true).rate(1.5).duration(30)
Assert.assertEquals(true, apsResult.isChangeRequested)
// it should work with percent temps too
// request different temp
`when`(treatmentsPlugin.getTempBasalFromHistory(ArgumentMatchers.anyLong())).thenReturn(TemporaryBasal(injector).percent(110).duration(30))
`when`(treatmentsInterface.getTempBasalFromHistory(ArgumentMatchers.anyLong())).thenReturn(TemporaryBasal(injector).percent(110).duration(30))
apsResult.tempBasalRequested(true).rate(1.1).duration(30)
Assert.assertEquals(false, apsResult.isChangeRequested)
`when`(treatmentsPlugin.getTempBasalFromHistory(ArgumentMatchers.anyLong())).thenReturn(TemporaryBasal(injector).percent(200).duration(30))
`when`(treatmentsInterface.getTempBasalFromHistory(ArgumentMatchers.anyLong())).thenReturn(TemporaryBasal(injector).percent(200).duration(30))
apsResult.tempBasalRequested(true).rate(0.5).duration(30)
Assert.assertEquals(true, apsResult.isChangeRequested)
}
@ -164,7 +164,7 @@ class APSResultTest : TestBaseWithProfile() {
it.constraintChecker = constraintChecker
it.sp = sp
it.activePlugin = activePluginProvider
it.treatmentsPlugin = treatmentsPlugin
it.treatmentsPlugin = treatmentsInterface
it.profileFunction = profileFunction
it.resourceHelper = resourceHelper
}
@ -181,7 +181,7 @@ class APSResultTest : TestBaseWithProfile() {
it.constraintChecker = constraintChecker
it.sp = sp
it.activePlugin = activePluginProvider
it.treatmentsPlugin = treatmentsPlugin
it.treatmentsPlugin = treatmentsInterface
it.profileFunction = profileFunction
it.resourceHelper = resourceHelper
}

View file

@ -76,7 +76,7 @@ class SafetyPluginTest : TestBaseWithProfile() {
`when`(activePlugin.activePump).thenReturn(virtualPumpPlugin)
`when`(virtualPumpPlugin.pumpDescription).thenReturn(pumpDescription)
hardLimits = HardLimits(aapsLogger, rxBus, sp, resourceHelper, context, nsUpload)
safetyPlugin = SafetyPlugin(injector, aapsLogger, resourceHelper, sp, rxBus, constraintChecker, openAPSAMAPlugin, openAPSSMBPlugin, sensitivityOref1Plugin, activePlugin, hardLimits, buildHelper, treatmentsPlugin, Config())
safetyPlugin = SafetyPlugin(injector, aapsLogger, resourceHelper, sp, rxBus, constraintChecker, openAPSAMAPlugin, openAPSSMBPlugin, sensitivityOref1Plugin, activePlugin, hardLimits, buildHelper, treatmentsInterface, Config())
}
@Test fun pumpDescriptionShouldLimitLoopInvocation() {

View file

@ -10,6 +10,7 @@ import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.general.automation.elements.InputString
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
import info.nightscout.androidaps.queue.Callback
import info.nightscout.androidaps.utils.TimerUtil
import info.nightscout.androidaps.utils.resources.ResourceHelper
import org.junit.Assert
import org.junit.Before
@ -22,12 +23,13 @@ import org.powermock.core.classloader.annotations.PrepareForTest
import org.powermock.modules.junit4.PowerMockRunner
@RunWith(PowerMockRunner::class)
@PrepareForTest(NSUpload::class, RxBusWrapper::class)
@PrepareForTest(NSUpload::class, RxBusWrapper::class, TimerUtil::class)
class ActionAlarmTest : TestBase() {
@Mock lateinit var resourceHelper: ResourceHelper
@Mock lateinit var rxBus: RxBusWrapper
@Mock lateinit var context: Context
@Mock lateinit var timerUtil: TimerUtil
private lateinit var sut: ActionAlarm
var injector: HasAndroidInjector = HasAndroidInjector {
@ -36,6 +38,7 @@ class ActionAlarmTest : TestBase() {
it.resourceHelper = resourceHelper
it.rxBus = rxBus
it.context = context
it.timerUtil = timerUtil
}
if (it is PumpEnactResult) {
it.aapsLogger = aapsLogger

View file

@ -20,7 +20,7 @@ class ActionProfileSwitchPercentTest : ActionsTestBase() {
@Before
fun setup() {
`when`(activePlugin.activeTreatments).thenReturn(treatmentsPlugin)
`when`(activePlugin.activeTreatments).thenReturn(treatmentsInterface)
`when`(resourceHelper.gs(R.string.startprofileforever)).thenReturn("Start profile %d%%")
`when`(resourceHelper.gs(R.string.startprofile)).thenReturn("Start profile %d%% for %d min")
@ -49,7 +49,7 @@ class ActionProfileSwitchPercentTest : ActionsTestBase() {
Assert.assertTrue(result.success)
}
})
Mockito.verify(treatmentsPlugin, Mockito.times(1)).doProfileSwitch(30, 110, 0)
Mockito.verify(treatmentsInterface, Mockito.times(1)).doProfileSwitch(30, 110, 0)
}
@Test fun hasDialogTest() {

View file

@ -26,7 +26,7 @@ class ActionProfileSwitchTest : ActionsTestBase() {
private val stringJson = "{\"data\":{\"profileToSwitchTo\":\"Test\"},\"type\":\"info.nightscout.androidaps.plugins.general.automation.actions.ActionProfileSwitch\"}"
@Before fun setUp() {
`when`(activePlugin.activeTreatments).thenReturn(treatmentsPlugin)
`when`(activePlugin.activeTreatments).thenReturn(treatmentsInterface)
`when`(resourceHelper.gs(R.string.profilename)).thenReturn("Change profile to")
`when`(resourceHelper.gs(ArgumentMatchers.eq(R.string.changengetoprofilename), ArgumentMatchers.anyString())).thenReturn("Change profile to %s")
`when`(resourceHelper.gs(R.string.alreadyset)).thenReturn("Already set")
@ -97,7 +97,7 @@ class ActionProfileSwitchTest : ActionsTestBase() {
Assert.assertEquals("OK", result.comment)
}
})
Mockito.verify(treatmentsPlugin, Mockito.times(1)).doProfileSwitch(anyObject(), anyString(), anyInt(), anyInt(), anyInt(), anyLong())
Mockito.verify(treatmentsInterface, Mockito.times(1)).doProfileSwitch(anyObject(), anyString(), anyInt(), anyInt(), anyInt(), anyLong())
}
@Test fun hasDialogTest() {

View file

@ -12,7 +12,6 @@ import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mockito
import org.mockito.Mockito.`when`
import org.powermock.api.mockito.PowerMockito
import org.powermock.core.classloader.annotations.PrepareForTest
import org.powermock.modules.junit4.PowerMockRunner
@ -45,13 +44,13 @@ class ActionStartTempTargetTest : ActionsTestBase() {
}
@Test fun doActionTest() {
`when`(activePlugin.activeTreatments).thenReturn(treatmentsPlugin)
`when`(activePlugin.activeTreatments).thenReturn(treatmentsInterface)
sut.doAction(object : Callback() {
override fun run() {
Assert.assertTrue(result.success)
}
})
Mockito.verify(treatmentsPlugin, Mockito.times(1)).addToHistoryTempTarget(anyObject())
Mockito.verify(treatmentsInterface, Mockito.times(1)).addToHistoryTempTarget(anyObject())
}
@Test fun hasDialogTest() {

View file

@ -38,13 +38,13 @@ class ActionStopTempTargetTest : ActionsTestBase() {
}
@Test fun doActionTest() {
`when`(activePlugin.activeTreatments).thenReturn(treatmentsPlugin)
`when`(activePlugin.activeTreatments).thenReturn(treatmentsInterface)
sut.doAction(object : Callback() {
override fun run() {
Assert.assertTrue(result.success)
}
})
Mockito.verify(treatmentsPlugin, Mockito.times(1)).addToHistoryTempTarget(anyObject())
Mockito.verify(treatmentsInterface, Mockito.times(1)).addToHistoryTempTarget(anyObject())
}
@Test fun hasDialogTest() {

View file

@ -9,19 +9,21 @@ import org.junit.Test
import org.junit.runner.RunWith
import org.powermock.modules.junit4.PowerMockRunner
@Suppress("SpellCheckingInspection")
@RunWith(PowerMockRunner::class)
class TriggerBTDeviceTest : TriggerTestBase() {
var now = 1514766900000L
var someName = "Headset"
var btJson = "{\"data\":{\"comparator\":\"ON_CONNECT\",\"name\":\"Headset\"},\"type\":\"info.nightscout.androidaps.plugins.general.automation.triggers.TriggerBTDevice\"}"
private var someName = "Headset"
private var btJson = "{\"data\":{\"comparator\":\"ON_CONNECT\",\"name\":\"Headset\"},\"type\":\"info.nightscout.androidaps.plugins.general.automation.triggers.TriggerBTDevice\"}"
@Test fun shouldRun() {
val t: TriggerBTDevice = TriggerBTDevice(injector)
@Suppress("UNUSED_VARIABLE")
val t = TriggerBTDevice(injector)
}
@Test fun toJSON() {
val t: TriggerBTDevice = TriggerBTDevice(injector)
val t = TriggerBTDevice(injector)
t.btDevice.value = someName
Assert.assertEquals(btJson, t.toJSON())
}

View file

@ -30,7 +30,7 @@ class TriggerBolusAgoTest : TriggerTestBase() {
@Test
fun shouldRunTest() {
`when`(treatmentsPlugin.getLastBolusTime(true)).thenReturn(now) // Set last bolus time to now
`when`(treatmentsInterface.getLastBolusTime(true)).thenReturn(now) // Set last bolus time to now
`when`(DateUtil.now()).thenReturn(now + 10 * 60 * 1000) // set current time to now + 10 min
var t = TriggerBolusAgo(injector).setValue(110).comparator(Comparator.Compare.IS_EQUAL)
Assert.assertEquals(110, t.minutesAgo.value)
@ -53,7 +53,7 @@ class TriggerBolusAgoTest : TriggerTestBase() {
Assert.assertTrue(t.shouldRun())
t = TriggerBolusAgo(injector).setValue(390).comparator(Comparator.Compare.IS_EQUAL_OR_LESSER)
Assert.assertTrue(t.shouldRun())
PowerMockito.`when`(treatmentsPlugin.getLastBolusTime(true)).thenReturn(0L) // Set last bolus time to 0
PowerMockito.`when`(treatmentsInterface.getLastBolusTime(true)).thenReturn(0L) // Set last bolus time to 0
t = TriggerBolusAgo(injector).comparator(Comparator.Compare.IS_NOT_AVAILABLE)
Assert.assertTrue(t.shouldRun())
}

View file

@ -28,12 +28,12 @@ class TriggerTempTargetTest : TriggerTestBase() {
}
@Test fun shouldRunTest() {
`when`(treatmentsPlugin.tempTargetFromHistory).thenReturn(null)
`when`(treatmentsInterface.tempTargetFromHistory).thenReturn(null)
var t: TriggerTempTarget = TriggerTempTarget(injector).comparator(ComparatorExists.Compare.EXISTS)
Assert.assertFalse(t.shouldRun())
t = TriggerTempTarget(injector).comparator(ComparatorExists.Compare.NOT_EXISTS)
Assert.assertTrue(t.shouldRun())
PowerMockito.`when`(treatmentsPlugin.tempTargetFromHistory).thenReturn(TempTarget())
PowerMockito.`when`(treatmentsInterface.tempTargetFromHistory).thenReturn(TempTarget())
t = TriggerTempTarget(injector).comparator(ComparatorExists.Compare.NOT_EXISTS)
Assert.assertFalse(t.shouldRun())
t = TriggerTempTarget(injector).comparator(ComparatorExists.Compare.EXISTS)

View file

@ -45,7 +45,7 @@ open class TriggerTestBase : TestBaseWithProfile() {
it.profileFunction = profileFunction
it.sp = sp
it.locationDataContainer = locationDataContainer
it.treatmentsPlugin = treatmentsPlugin
it.treatmentsInterface = treatmentsInterface
it.activePlugin = activePlugin
it.iobCobCalculatorPlugin = iobCobCalculatorPlugin
}

View file

@ -6,7 +6,6 @@ import info.nightscout.androidaps.plugins.general.maintenance.formats.Prefs
import info.nightscout.androidaps.testing.utils.SingleStringStorage
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.sharedPreferences.SP
import org.hamcrest.CoreMatchers
import org.junit.Assert
import org.junit.Test
import org.junit.runner.RunWith
@ -32,9 +31,9 @@ class ClassicPrefsFormatTest : TestBase() {
val classicFormat = ClassicPrefsFormat(resourceHelper, SingleStringStorage(test))
val prefs = classicFormat.loadPreferences(getMockedFile(), "")
Assert.assertThat(prefs.values.size, CoreMatchers.`is`(2))
Assert.assertThat(prefs.values["key1"], CoreMatchers.`is`("val1"))
Assert.assertThat(prefs.values["keyB"], CoreMatchers.`is`("valB"))
Assert.assertEquals(prefs.values.size, 2)
Assert.assertEquals(prefs.values["key1"], "val1")
Assert.assertEquals(prefs.values["keyB"], "valB")
Assert.assertNull(prefs.values["key3"])
}

View file

@ -4,11 +4,11 @@ import info.nightscout.androidaps.TestBase
import info.nightscout.androidaps.plugins.general.maintenance.formats.*
import info.nightscout.androidaps.testing.utils.SingleStringStorage
import info.nightscout.androidaps.utils.CryptoUtil
import info.nightscout.androidaps.utils.assumeAES256isSupported
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.sharedPreferences.SP
import org.hamcrest.CoreMatchers
import org.junit.Assert
import org.junit.Assume
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@ -20,6 +20,7 @@ import org.powermock.core.classloader.annotations.PrepareForTest
import org.powermock.modules.junit4.PowerMockRunner
import java.io.File
@Suppress("SpellCheckingInspection")
@PowerMockIgnore("javax.crypto.*")
@RunWith(PowerMockRunner::class)
@PrepareForTest(File::class)
@ -32,6 +33,16 @@ class EncryptedPrefsFormatTest : TestBase() {
private var cryptoUtil: CryptoUtil = CryptoUtil(aapsLogger)
// https://stackoverflow.com/questions/52344522/joseexception-couldnt-create-aes-gcm-nopadding-cipher-illegal-key-size
// https://stackoverflow.com/questions/47708951/can-aes-256-work-on-android-devices-with-api-level-26
// Java prior to Oracle Java 8u161 does not have policy for 256 bit AES - but Android support it
// when test is run in Vanilla JVM without policy - Invalid key size exception is thrown
private fun assumeAES256isSupported(cryptoUtil: CryptoUtil) {
cryptoUtil.lastException?.message?.let { exceptionMessage ->
Assume.assumeThat("Upgrade your testing environment Java (OpenJDK or Java 8u161) and JAVA_HOME - AES 256 is supported by Android so this exception should not happen!", exceptionMessage, CoreMatchers.not(CoreMatchers.containsString("key size")))
}
}
@Before
fun mock() {
Mockito.`when`(resourceHelper.gs(ArgumentMatchers.anyInt())).thenReturn("mock translation")
@ -57,13 +68,13 @@ class EncryptedPrefsFormatTest : TestBase() {
assumeAES256isSupported(cryptoUtil)
Assert.assertThat(prefs.values.size, CoreMatchers.`is`(2))
Assert.assertThat(prefs.values["key1"], CoreMatchers.`is`("A"))
Assert.assertThat(prefs.values["keyB"], CoreMatchers.`is`("2"))
Assert.assertEquals(prefs.values.size, 2)
Assert.assertEquals(prefs.values["key1"], "A")
Assert.assertEquals(prefs.values["keyB"], "2")
Assert.assertThat(prefs.metadata[PrefsMetadataKey.FILE_FORMAT]?.status, CoreMatchers.`is`(PrefsStatus.OK))
Assert.assertThat(prefs.metadata[PrefsMetadataKey.FILE_FORMAT]?.value, CoreMatchers.`is`(EncryptedPrefsFormat.FORMAT_KEY_ENC))
Assert.assertThat(prefs.metadata[PrefsMetadataKey.ENCRYPTION]?.status, CoreMatchers.`is`(PrefsStatus.OK))
Assert.assertEquals(prefs.metadata[PrefsMetadataKey.FILE_FORMAT]?.status, PrefsStatus.OK)
Assert.assertEquals(prefs.metadata[PrefsMetadataKey.FILE_FORMAT]?.value, EncryptedPrefsFormat.FORMAT_KEY_ENC)
Assert.assertEquals(prefs.metadata[PrefsMetadataKey.ENCRYPTION]?.status, PrefsStatus.OK)
}
@Test
@ -101,13 +112,13 @@ class EncryptedPrefsFormatTest : TestBase() {
assumeAES256isSupported(cryptoUtil)
Assert.assertThat(prefsOut.values.size, CoreMatchers.`is`(2))
Assert.assertThat(prefsOut.values["testpref1"], CoreMatchers.`is`("--1--"))
Assert.assertThat(prefsOut.values["testpref2"], CoreMatchers.`is`("another"))
Assert.assertEquals(prefsOut.values.size, 2)
Assert.assertEquals(prefsOut.values["testpref1"], "--1--")
Assert.assertEquals(prefsOut.values["testpref2"], "another")
Assert.assertThat(prefsOut.metadata[PrefsMetadataKey.FILE_FORMAT]?.status, CoreMatchers.`is`(PrefsStatus.OK))
Assert.assertThat(prefsOut.metadata[PrefsMetadataKey.FILE_FORMAT]?.value, CoreMatchers.`is`(EncryptedPrefsFormat.FORMAT_KEY_ENC))
Assert.assertThat(prefsOut.metadata[PrefsMetadataKey.ENCRYPTION]?.status, CoreMatchers.`is`(PrefsStatus.OK))
Assert.assertEquals(prefsOut.metadata[PrefsMetadataKey.FILE_FORMAT]?.status, PrefsStatus.OK)
Assert.assertEquals(prefsOut.metadata[PrefsMetadataKey.FILE_FORMAT]?.value, EncryptedPrefsFormat.FORMAT_KEY_ENC)
Assert.assertEquals(prefsOut.metadata[PrefsMetadataKey.ENCRYPTION]?.status, PrefsStatus.OK)
}
@Test
@ -128,11 +139,11 @@ class EncryptedPrefsFormatTest : TestBase() {
val encryptedFormat = EncryptedPrefsFormat(resourceHelper, cryptoUtil, storage)
val prefs = encryptedFormat.loadPreferences(getMockedFile(), "it-is-NOT-right-secret")
Assert.assertThat(prefs.values.size, CoreMatchers.`is`(0))
Assert.assertEquals(prefs.values.size, 0)
Assert.assertThat(prefs.metadata[PrefsMetadataKey.FILE_FORMAT]?.status, CoreMatchers.`is`(PrefsStatus.OK))
Assert.assertThat(prefs.metadata[PrefsMetadataKey.FILE_FORMAT]?.value, CoreMatchers.`is`(EncryptedPrefsFormat.FORMAT_KEY_ENC))
Assert.assertThat(prefs.metadata[PrefsMetadataKey.ENCRYPTION]?.status, CoreMatchers.`is`(PrefsStatus.ERROR))
Assert.assertEquals(prefs.metadata[PrefsMetadataKey.FILE_FORMAT]?.status, PrefsStatus.OK)
Assert.assertEquals(prefs.metadata[PrefsMetadataKey.FILE_FORMAT]?.value, EncryptedPrefsFormat.FORMAT_KEY_ENC)
Assert.assertEquals(prefs.metadata[PrefsMetadataKey.ENCRYPTION]?.status, PrefsStatus.ERROR)
}
@Test
@ -158,10 +169,10 @@ class EncryptedPrefsFormatTest : TestBase() {
assumeAES256isSupported(cryptoUtil)
// contents were not tampered and we can decrypt them
Assert.assertThat(prefs.values.size, CoreMatchers.`is`(2))
Assert.assertEquals(prefs.values.size, 2)
// but checksum fails on metadata, so overall security fails
Assert.assertThat(prefs.metadata[PrefsMetadataKey.ENCRYPTION]?.status, CoreMatchers.`is`(PrefsStatus.ERROR))
Assert.assertEquals(prefs.metadata[PrefsMetadataKey.ENCRYPTION]?.status, PrefsStatus.ERROR)
}
@Test
@ -182,8 +193,8 @@ class EncryptedPrefsFormatTest : TestBase() {
val encryptedFormat = EncryptedPrefsFormat(resourceHelper, cryptoUtil, storage)
val prefs = encryptedFormat.loadPreferences(getMockedFile(), "sikret")
Assert.assertThat(prefs.values.size, CoreMatchers.`is`(0))
Assert.assertThat(prefs.metadata[PrefsMetadataKey.ENCRYPTION]?.status, CoreMatchers.`is`(PrefsStatus.ERROR))
Assert.assertEquals(prefs.values.size, 0)
Assert.assertEquals(prefs.metadata[PrefsMetadataKey.ENCRYPTION]?.status, PrefsStatus.ERROR)
}
@Test
@ -197,8 +208,8 @@ class EncryptedPrefsFormatTest : TestBase() {
val encryptedFormat = EncryptedPrefsFormat(resourceHelper, cryptoUtil, storage)
val prefs = encryptedFormat.loadPreferences(getMockedFile(), "sikret")
Assert.assertThat(prefs.values.size, CoreMatchers.`is`(0))
Assert.assertThat(prefs.metadata[PrefsMetadataKey.FILE_FORMAT]?.status, CoreMatchers.`is`(PrefsStatus.ERROR))
Assert.assertEquals(prefs.values.size, 0)
Assert.assertEquals(prefs.metadata[PrefsMetadataKey.FILE_FORMAT]?.status, PrefsStatus.ERROR)
}
@Test(expected = PrefFormatError::class)

View file

@ -1,3 +1,5 @@
@file:Suppress("SpellCheckingInspection")
package info.nightscout.androidaps.plugins.general.smsCommunicator
import android.content.Context
@ -152,16 +154,16 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() {
}.`when`(commandQueue).extendedBolus(ArgumentMatchers.anyDouble(), ArgumentMatchers.anyInt(), ArgumentMatchers.any(Callback::class.java))
`when`(activePlugin.activePump).thenReturn(virtualPumpPlugin)
`when`(activePlugin.activeTreatments).thenReturn(treatmentsPlugin)
`when`(activePlugin.activeTreatments).thenReturn(treatmentsInterface)
`when`(virtualPumpPlugin.shortStatus(ArgumentMatchers.anyBoolean())).thenReturn("Virtual Pump")
`when`(virtualPumpPlugin.isSuspended).thenReturn(false)
`when`(virtualPumpPlugin.isSuspended()).thenReturn(false)
`when`(virtualPumpPlugin.pumpDescription).thenReturn(PumpDescription())
`when`(virtualPumpPlugin.model()).thenReturn(PumpType.GenericAAPS);
`when`(virtualPumpPlugin.model()).thenReturn(PumpType.GenericAAPS)
`when`(treatmentsPlugin.lastCalculationTreatments).thenReturn(IobTotal(0))
`when`(treatmentsPlugin.lastCalculationTempBasals).thenReturn(IobTotal(0))
`when`(treatmentsPlugin.service).thenReturn(treatmentService)
`when`(treatmentsInterface.lastCalculationTreatments).thenReturn(IobTotal(0))
`when`(treatmentsInterface.lastCalculationTempBasals).thenReturn(IobTotal(0))
`when`(treatmentsInterface.service).thenReturn(treatmentService)
`when`(activePlugin.activeProfileInterface).thenReturn(localProfilePlugin)
@ -187,7 +189,7 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() {
`when`(resourceHelper.gs(R.string.smscommunicator_loopisdisabled)).thenReturn("Loop is disabled")
`when`(resourceHelper.gs(R.string.smscommunicator_loopisenabled)).thenReturn("Loop is enabled")
`when`(resourceHelper.gs(R.string.wrongformat)).thenReturn("Wrong format")
`when`(resourceHelper.gs(ArgumentMatchers.eq(R.string.wrongTbrDuration), ArgumentMatchers.any())).thenAnswer({ i: InvocationOnMock -> "TBR duration must be a multiple of " + i.getArguments()[1] + " minutes and greater than 0." })
`when`(resourceHelper.gs(ArgumentMatchers.eq(R.string.wrongTbrDuration), ArgumentMatchers.any())).thenAnswer { i: InvocationOnMock -> "TBR duration must be a multiple of " + i.arguments[1] + " minutes and greater than 0." }
`when`(resourceHelper.gs(R.string.smscommunicator_loophasbeendisabled)).thenReturn("Loop has been disabled")
`when`(resourceHelper.gs(R.string.smscommunicator_loophasbeenenabled)).thenReturn("Loop has been enabled")
`when`(resourceHelper.gs(R.string.smscommunicator_tempbasalcanceled)).thenReturn("Temp basal canceled")
@ -241,8 +243,8 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() {
@Test
fun processSettingsTest() {
// called from constructor
Assert.assertEquals("1234", smsCommunicatorPlugin.allowedNumbers.get(0))
Assert.assertEquals("5678", smsCommunicatorPlugin.allowedNumbers.get(1))
Assert.assertEquals("1234", smsCommunicatorPlugin.allowedNumbers[0])
Assert.assertEquals("5678", smsCommunicatorPlugin.allowedNumbers[1])
Assert.assertEquals(2, smsCommunicatorPlugin.allowedNumbers.size)
}
@ -259,17 +261,16 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() {
smsCommunicatorPlugin.messageToConfirm = null
}
@Test fun _isAllowedNumberTest() {
@Test fun isAllowedNumberTest() {
Assert.assertTrue(smsCommunicatorPlugin.isAllowedNumber("5678"))
Assert.assertFalse(smsCommunicatorPlugin.isAllowedNumber("56"))
}
@Test fun processSmsTest() {
var sms: Sms
// SMS from not allowed number should be ignored
smsCommunicatorPlugin.messages = ArrayList()
sms = Sms("12", "aText")
var sms = Sms("12", "aText")
smsCommunicatorPlugin.processSms(sms)
Assert.assertTrue(sms.ignored)
Assert.assertEquals("aText", smsCommunicatorPlugin.messages[0].text)
@ -348,7 +349,7 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() {
//LOOP DISABLE : from enabled
hasBeenRun = false
PowerMockito.`when`(loopPlugin.isEnabled(PluginType.LOOP)).thenReturn(true)
PowerMockito.doAnswer(Answer { _: InvocationOnMock? ->
PowerMockito.doAnswer(Answer {
hasBeenRun = true
null
} as Answer<*>).`when`(loopPlugin).setPluginEnabled(PluginType.LOOP, false)
@ -376,7 +377,7 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() {
//LOOP ENABLE : from disabled
hasBeenRun = false
PowerMockito.`when`(loopPlugin.isEnabled(PluginType.LOOP)).thenReturn(false)
PowerMockito.doAnswer(Answer { _: InvocationOnMock? ->
PowerMockito.doAnswer(Answer {
hasBeenRun = true
null
} as Answer<*>).`when`(loopPlugin).setPluginEnabled(PluginType.LOOP, true)
@ -660,11 +661,10 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() {
}
@Test fun processProfileTest() {
var sms: Sms
//PROFILE
smsCommunicatorPlugin.messages = ArrayList()
sms = Sms("1234", "PROFILE")
var sms = Sms("1234", "PROFILE")
smsCommunicatorPlugin.processSms(sms)
Assert.assertEquals("PROFILE", smsCommunicatorPlugin.messages[0].text)
Assert.assertEquals("Remote command is not allowed", smsCommunicatorPlugin.messages[1].text)
@ -699,7 +699,7 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() {
sms = Sms("1234", "PROFILE LIST")
smsCommunicatorPlugin.processSms(sms)
Assert.assertEquals("PROFILE LIST", smsCommunicatorPlugin.messages[0].text)
Assert.assertEquals("1. " + TESTPROFILENAME, smsCommunicatorPlugin.messages[1].text)
Assert.assertEquals("1. $TESTPROFILENAME", smsCommunicatorPlugin.messages[1].text)
//PROFILE 2 (non existing)
smsCommunicatorPlugin.messages = ArrayList()
@ -742,11 +742,10 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() {
}
@Test fun processBasalTest() {
var sms: Sms
//BASAL
smsCommunicatorPlugin.messages = ArrayList()
sms = Sms("1234", "BASAL")
var sms = Sms("1234", "BASAL")
smsCommunicatorPlugin.processSms(sms)
Assert.assertEquals("BASAL", smsCommunicatorPlugin.messages[0].text)
Assert.assertEquals("Remote command is not allowed", smsCommunicatorPlugin.messages[1].text)
@ -817,7 +816,7 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() {
smsCommunicatorPlugin.processSms(sms)
Assert.assertEquals("BASAL 1 0", smsCommunicatorPlugin.messages[0].text)
Assert.assertEquals("TBR duration must be a multiple of 30 minutes and greater than 0.", smsCommunicatorPlugin.messages[1].text)
`when`(constraintChecker.applyBasalConstraints(anyObject(), anyObject())).thenReturn(Constraint<Double>(1.0))
`when`(constraintChecker.applyBasalConstraints(anyObject(), anyObject())).thenReturn(Constraint(1.0))
//BASAL 1 20
smsCommunicatorPlugin.messages = ArrayList()
@ -825,7 +824,7 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() {
smsCommunicatorPlugin.processSms(sms)
Assert.assertEquals("BASAL 1 20", smsCommunicatorPlugin.messages[0].text)
Assert.assertEquals("TBR duration must be a multiple of 30 minutes and greater than 0.", smsCommunicatorPlugin.messages[1].text)
`when`(constraintChecker.applyBasalConstraints(anyObject(), anyObject())).thenReturn(Constraint<Double>(1.0))
`when`(constraintChecker.applyBasalConstraints(anyObject(), anyObject())).thenReturn(Constraint(1.0))
//BASAL 1 30
smsCommunicatorPlugin.messages = ArrayList()
@ -840,11 +839,10 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() {
}
@Test fun processExtendedTest() {
var sms: Sms
//EXTENDED
smsCommunicatorPlugin.messages = ArrayList()
sms = Sms("1234", "EXTENDED")
var sms = Sms("1234", "EXTENDED")
smsCommunicatorPlugin.processSms(sms)
Assert.assertEquals("EXTENDED", smsCommunicatorPlugin.messages[0].text)
Assert.assertEquals("Remote command is not allowed", smsCommunicatorPlugin.messages[1].text)
@ -874,7 +872,7 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() {
smsCommunicatorPlugin.processSms(sms)
Assert.assertEquals("EXTENDED a%", smsCommunicatorPlugin.messages[0].text)
Assert.assertEquals("Wrong format", smsCommunicatorPlugin.messages[1].text)
`when`(constraintChecker.applyExtendedBolusConstraints(anyObject())).thenReturn(Constraint<Double>(1.0))
`when`(constraintChecker.applyExtendedBolusConstraints(anyObject())).thenReturn(Constraint(1.0))
//EXTENDED 1 0
smsCommunicatorPlugin.messages = ArrayList()
@ -896,11 +894,10 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() {
}
@Test fun processBolusTest() {
var sms: Sms
//BOLUS
smsCommunicatorPlugin.messages = ArrayList()
sms = Sms("1234", "BOLUS")
var sms = Sms("1234", "BOLUS")
smsCommunicatorPlugin.processSms(sms)
Assert.assertEquals("BOLUS", smsCommunicatorPlugin.messages[0].text)
Assert.assertEquals("Remote command is not allowed", smsCommunicatorPlugin.messages[1].text)
@ -912,7 +909,7 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() {
smsCommunicatorPlugin.processSms(sms)
Assert.assertEquals("BOLUS", smsCommunicatorPlugin.messages[0].text)
Assert.assertEquals("Wrong format", smsCommunicatorPlugin.messages[1].text)
`when`(constraintChecker.applyBolusConstraints(anyObject())).thenReturn(Constraint<Double>(1.0))
`when`(constraintChecker.applyBolusConstraints(anyObject())).thenReturn(Constraint(1.0))
PowerMockito.`when`(DateUtil.now()).thenReturn(1000L)
`when`(sp.getLong(R.string.key_smscommunicator_remotebolusmindistance, T.msecs(Constants.remoteBolusMinDistance).mins())).thenReturn(15L)
//BOLUS 1
@ -921,7 +918,7 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() {
smsCommunicatorPlugin.processSms(sms)
Assert.assertEquals("BOLUS 1", smsCommunicatorPlugin.messages[0].text)
Assert.assertEquals("Remote bolus not available. Try again later.", smsCommunicatorPlugin.messages[1].text)
`when`(constraintChecker.applyBolusConstraints(anyObject())).thenReturn(Constraint<Double>(0.0))
`when`(constraintChecker.applyBolusConstraints(anyObject())).thenReturn(Constraint(0.0))
PowerMockito.`when`(DateUtil.now()).thenReturn(Constants.remoteBolusMinDistance + 1002L)
//BOLUS 0
@ -937,8 +934,8 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() {
smsCommunicatorPlugin.processSms(sms)
Assert.assertEquals("BOLUS a", smsCommunicatorPlugin.messages[0].text)
Assert.assertEquals("Wrong format", smsCommunicatorPlugin.messages[1].text)
`when`(constraintChecker.applyExtendedBolusConstraints(anyObject())).thenReturn(Constraint<Double>(1.0))
`when`(constraintChecker.applyBolusConstraints(anyObject())).thenReturn(Constraint<Double>(1.0))
`when`(constraintChecker.applyExtendedBolusConstraints(anyObject())).thenReturn(Constraint(1.0))
`when`(constraintChecker.applyBolusConstraints(anyObject())).thenReturn(Constraint(1.0))
//BOLUS 1
smsCommunicatorPlugin.messages = ArrayList()
@ -953,13 +950,13 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() {
//BOLUS 1 (Suspended pump)
smsCommunicatorPlugin.lastRemoteBolusTime = 0
PowerMockito.`when`(virtualPumpPlugin.isSuspended).thenReturn(true)
PowerMockito.`when`(virtualPumpPlugin.isSuspended()).thenReturn(true)
smsCommunicatorPlugin.messages = ArrayList()
sms = Sms("1234", "BOLUS 1")
smsCommunicatorPlugin.processSms(sms)
Assert.assertEquals("BOLUS 1", smsCommunicatorPlugin.messages[0].text)
Assert.assertEquals("Pump suspended", smsCommunicatorPlugin.messages[1].text)
PowerMockito.`when`(virtualPumpPlugin.isSuspended).thenReturn(false)
PowerMockito.`when`(virtualPumpPlugin.isSuspended()).thenReturn(false)
//BOLUS 1 a
smsCommunicatorPlugin.messages = ArrayList()
@ -982,11 +979,10 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() {
}
@Test fun processCalTest() {
var sms: Sms
//CAL
smsCommunicatorPlugin.messages = ArrayList()
sms = Sms("1234", "CAL")
var sms = Sms("1234", "CAL")
smsCommunicatorPlugin.processSms(sms)
Assert.assertEquals("CAL", smsCommunicatorPlugin.messages[0].text)
Assert.assertEquals("Remote command is not allowed", smsCommunicatorPlugin.messages[1].text)
@ -1019,12 +1015,11 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() {
}
@Test fun processCarbsTest() {
var sms: Sms
PowerMockito.`when`(DateUtil.now()).thenReturn(1000000L)
`when`(sp.getBoolean(R.string.key_smscommunicator_remotecommandsallowed, false)).thenReturn(false)
//CAL
smsCommunicatorPlugin.messages = ArrayList()
sms = Sms("1234", "CARBS")
var sms = Sms("1234", "CARBS")
smsCommunicatorPlugin.processSms(sms)
Assert.assertEquals("CARBS", smsCommunicatorPlugin.messages[0].text)
Assert.assertEquals("Remote command is not allowed", smsCommunicatorPlugin.messages[1].text)

View file

@ -2,23 +2,22 @@ package info.nightscout.androidaps.plugins.pump.common.utils;
import android.util.Log;
import junit.framework.Assert;
import org.junit.Assert;
import org.junit.Test;
public class DateTimeUtilUTest {
@Test
public void getATechDateDiferenceAsMinutes() {
public void getATechDateDifferenceAsMinutes() {
long dt1 = 20191001182301L;
long dt2 = 20191001192805L;
int aTechDateDiferenceAsMinutes = DateTimeUtil.getATechDateDiferenceAsMinutes(dt1, dt2);
int aTechDateDifferenceAsMinutes = DateTimeUtil.getATechDateDiferenceAsMinutes(dt1, dt2);
Assert.assertEquals(65, aTechDateDiferenceAsMinutes);
Assert.assertEquals(65, aTechDateDifferenceAsMinutes);
Log.d("DateTimeUtilUTest", "Time difference: " + aTechDateDiferenceAsMinutes);
Log.d("DateTimeUtilUTest", "Time difference: " + aTechDateDifferenceAsMinutes);
}
}

View file

@ -25,6 +25,7 @@ import org.powermock.api.mockito.PowerMockito
import org.powermock.core.classloader.annotations.PrepareForTest
import org.powermock.modules.junit4.PowerMockRunner
@Suppress("SpellCheckingInspection")
@RunWith(PowerMockRunner::class)
@PrepareForTest(FabricPrivacy::class, MainApp::class, DatabaseHelper::class)
class TreatmentsPluginTest : TestBaseWithProfile() {
@ -47,8 +48,8 @@ class TreatmentsPluginTest : TestBaseWithProfile() {
}
}
lateinit var insulinOrefRapidActingPlugin: InsulinOrefRapidActingPlugin
lateinit var sot: TreatmentsPlugin
private lateinit var insulinOrefRapidActingPlugin: InsulinOrefRapidActingPlugin
private lateinit var sot: TreatmentsPlugin
@Before
fun prepare() {
@ -77,7 +78,7 @@ class TreatmentsPluginTest : TestBaseWithProfile() {
}
@Test
fun `90% TBR and should produce less absolute insulin`() {
fun `90pct TBR and should produce less absolute insulin`() {
val now = DateUtil.now()
val tbrs: MutableList<TemporaryBasal> = ArrayList()
`when`(databaseHelper.getTemporaryBasalsDataFromTime(ArgumentMatchers.anyLong(), ArgumentMatchers.anyBoolean())).thenReturn(tbrs)
@ -91,7 +92,7 @@ class TreatmentsPluginTest : TestBaseWithProfile() {
}
@Test
fun `110% TBR and should produce 10% more absolute insulin`() {
fun `110pct TBR and should produce 10pct more absolute insulin`() {
val now = DateUtil.now()
val tbrs: MutableList<TemporaryBasal> = ArrayList()
`when`(databaseHelper.getTemporaryBasalsDataFromTime(ArgumentMatchers.anyLong(), ArgumentMatchers.anyBoolean())).thenReturn(tbrs)

View file

@ -107,8 +107,8 @@ class CommandQueueTest : TestBaseWithProfile() {
`when`(context.getSystemService(Context.POWER_SERVICE)).thenReturn(powerManager)
`when`(lazyActivePlugin.get()).thenReturn(activePlugin)
`when`(activePlugin.activePump).thenReturn(testPumpPlugin)
`when`(activePlugin.activeTreatments).thenReturn(treatmentsPlugin)
`when`(treatmentsPlugin.lastBolusTime).thenReturn(Calendar.getInstance().also { it.set(2000, 0, 1) }.timeInMillis)
`when`(activePlugin.activeTreatments).thenReturn(treatmentsInterface)
`when`(treatmentsInterface.lastBolusTime).thenReturn(Calendar.getInstance().also { it.set(2000, 0, 1) }.timeInMillis)
`when`(profileFunction.getProfile()).thenReturn(validProfile)
val bolusConstraint = Constraint(0.0)
@ -344,6 +344,42 @@ class CommandQueueTest : TestBaseWithProfile() {
Assert.assertEquals(1, commandQueue.size())
}
@Test
fun isProfileSetCommandInQueue() {
// given
Assert.assertEquals(0, commandQueue.size())
// when
testPumpPlugin.isProfileSet = true
commandQueue.setProfile(validProfile, object : Callback() {
override fun run() {
Assert.assertTrue(result.success)
Assert.assertFalse(result.enacted)
}
})
// then
// the same profile -> ignore
Assert.assertEquals(0, commandQueue.size())
// different should be added
testPumpPlugin.isProfileSet = false
commandQueue.setProfile(validProfile, object : Callback() {
override fun run() {
Assert.assertTrue(result.success)
Assert.assertTrue(result.enacted)
}
})
Assert.assertEquals(1, commandQueue.size())
// next should be ignored
commandQueue.setProfile(validProfile, object : Callback() {
override fun run() {
Assert.assertTrue(result.success)
}
})
Assert.assertEquals(1, commandQueue.size())
testPumpPlugin.isProfileSet = true
}
@Test
fun isStopCommandInQueue() {
// given

View file

@ -72,8 +72,8 @@ class QueueThreadTest : TestBaseWithProfile() {
Mockito.`when`(context.getSystemService(Context.POWER_SERVICE)).thenReturn(powerManager)
Mockito.`when`(lazyActivePlugin.get()).thenReturn(activePlugin)
Mockito.`when`(activePlugin.activePump).thenReturn(pumpPlugin)
Mockito.`when`(activePlugin.activeTreatments).thenReturn(treatmentsPlugin)
Mockito.`when`(treatmentsPlugin.lastBolusTime).thenReturn(Calendar.getInstance().also { it.set(2000, 0, 1) }.timeInMillis)
Mockito.`when`(activePlugin.activeTreatments).thenReturn(treatmentsInterface)
Mockito.`when`(treatmentsInterface.lastBolusTime).thenReturn(Calendar.getInstance().also { it.set(2000, 0, 1) }.timeInMillis)
Mockito.`when`(profileFunction.getProfile()).thenReturn(validProfile)
val bolusConstraint = Constraint(0.0)

View file

@ -1,158 +0,0 @@
package info.nightscout.androidaps.testing.mocks;
import android.content.SharedPreferences;
import androidx.annotation.Nullable;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class SharedPreferencesMock implements SharedPreferences {
private final EditorInternals editor = new EditorInternals();
class EditorInternals implements Editor {
Map<String, Object> innerMap = new HashMap<>();
@Override
public Editor putString(String k, @Nullable String v) {
innerMap.put(k, v);
return this;
}
@Override
public Editor putStringSet(String k, @Nullable Set<String> set) {
innerMap.put(k, set);
return this;
}
@Override
public Editor putInt(String k, int i) {
innerMap.put(k, i);
return this;
}
@Override
public Editor putLong(String k, long l) {
innerMap.put(k, l);
return this;
}
@Override
public Editor putFloat(String k, float v) {
innerMap.put(k, v);
return this;
}
@Override
public Editor putBoolean(String k, boolean b) {
innerMap.put(k, b);
return this;
}
@Override
public Editor remove(String k) {
innerMap.remove(k);
return this;
}
@Override
public Editor clear() {
innerMap.clear();
return this;
}
@Override
public boolean commit() {
return true;
}
@Override
public void apply() {
}
}
@Override
public Map<String, ?> getAll() {
return editor.innerMap;
}
@Nullable
@Override
public String getString(String k, @Nullable String s) {
if (editor.innerMap.containsKey(k)) {
return (String) editor.innerMap.get(k);
} else {
return s;
}
}
@Nullable
@Override
public Set<String> getStringSet(String k, @Nullable Set<String> set) {
if (editor.innerMap.containsKey(k)) {
return (Set<String>) editor.innerMap.get(k);
} else {
return set;
}
}
@Override
public int getInt(String k, int i) {
if (editor.innerMap.containsKey(k)) {
return (Integer) editor.innerMap.get(k);
} else {
return i;
}
}
@Override
public long getLong(String k, long l) {
if (editor.innerMap.containsKey(k)) {
return (Long) editor.innerMap.get(k);
} else {
return l;
}
}
@Override
public float getFloat(String k, float v) {
if (editor.innerMap.containsKey(k)) {
return (Float) editor.innerMap.get(k);
} else {
return v;
}
}
@Override
public boolean getBoolean(String k, boolean b) {
if (editor.innerMap.containsKey(k)) {
return (Boolean) editor.innerMap.get(k);
} else {
return b;
}
}
@Override
public boolean contains(String k) {
return editor.innerMap.containsKey(k);
}
@Override
public Editor edit() {
return editor;
}
@Override
public void registerOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener onSharedPreferenceChangeListener) {
}
@Override
public void unregisterOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener onSharedPreferenceChangeListener) {
}
}

View file

@ -1,42 +0,0 @@
package info.nightscout.androidaps.utils;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.modules.junit4.PowerMockRunner;
@RunWith(PowerMockRunner.class)
public class DecimalFormatterTest {
@Test
public void to0DecimalTest() {
Assert.assertEquals("1", DecimalFormatter.to0Decimal(1.33d).replace(",", "."));
Assert.assertEquals("1U", DecimalFormatter.to0Decimal(1.33d, "U").replace(",", "."));
}
@Test
public void to1DecimalTest() {
Assert.assertEquals("1.3", DecimalFormatter.to1Decimal(1.33d).replace(",", "."));
Assert.assertEquals("1.3U", DecimalFormatter.to1Decimal(1.33d, "U").replace(",", "."));
}
@Test
public void to2DecimalTest() {
Assert.assertEquals("1.33", DecimalFormatter.to2Decimal(1.3333d).replace(",", "."));
Assert.assertEquals("1.33U", DecimalFormatter.to2Decimal(1.3333d, "U").replace(",", "."));
}
@Test
public void to3DecimalTest() {
Assert.assertEquals("1.333", DecimalFormatter.to3Decimal(1.3333d).replace(",", "."));
Assert.assertEquals("1.333U", DecimalFormatter.to3Decimal(1.3333d, "U").replace(",", "."));
}
@Test
public void toPumpSupportedBolus() {
}
@Test
public void pumpSupportedBolusFormat() {
}
}

View file

@ -1,93 +0,0 @@
package info.nightscout.androidaps.utils;
import org.json.JSONException;
import org.json.JSONObject;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
/**
* Created by mike on 12.03.2018.
*/
public class JsonHelperTest {
private String jsonString = "{\"d\":\"3.0\",\"i\":\"4\",\"s\":\"5\",\"b\":\"true\",\"j\":{\"a\": \"1\"}}";
@Test
public void safeGetObjectTest() throws JSONException {
JSONObject object = new JSONObject(jsonString);
Object o = new Object();
assertEquals(o, JsonHelper.safeGetObject(null, "x", o));
assertEquals(o, JsonHelper.safeGetObject(object, "x", o));
assertNotEquals(o, JsonHelper.safeGetObject(object, "d", o));
}
@Test
public void safeGetJSONObjectTest() throws JSONException {
JSONObject object = new JSONObject(jsonString);
JSONObject o = new JSONObject();
assertEquals(o, JsonHelper.safeGetJSONObject(null, "x", o));
assertTrue(JsonHelper.safeGetJSONObject(object, "j", o).has("a"));
assertEquals(o, JsonHelper.safeGetJSONObject(object, "d", o));
}
@Test
public void safeGetStringTest() throws JSONException {
JSONObject object = new JSONObject(jsonString);
Object o = new Object();
assertNull(JsonHelper.safeGetString(null, "s"));
assertNull(JsonHelper.safeGetString(object, "notexisting"));
assertEquals("5", JsonHelper.safeGetString(object, "s"));
assertEquals("default", JsonHelper.safeGetString(null, "notexisting", "default"));
assertEquals("default", JsonHelper.safeGetString(object, "notexisting", "default"));
assertEquals("5", JsonHelper.safeGetString(object, "s", "default"));
assertEquals("default", JsonHelper.safeGetStringAllowNull(null, "notexisting", "default"));
assertEquals("default", JsonHelper.safeGetStringAllowNull(object, "notexisting", "default"));
assertNull(JsonHelper.safeGetStringAllowNull(object, "notexisting", null));
assertEquals("5", JsonHelper.safeGetStringAllowNull(object, "s", "default"));
}
@Test
public void safeGetDoubleTest() throws JSONException {
JSONObject object = new JSONObject(jsonString);
assertEquals(0.0d, JsonHelper.safeGetDouble(object, "notexisting"), 0.0d);
assertEquals(0.0d, JsonHelper.safeGetDouble(null, "notexisting"), 0.0d);
assertEquals(3.0d, JsonHelper.safeGetDouble(object, "d"), 0.000001d);
assertEquals(6d, JsonHelper.safeGetDouble(null, "notexisting", 6d), 0.0d);
assertEquals(6d, JsonHelper.safeGetDouble(object, "notexisting", 6d), 0.0d);
assertEquals(3d, JsonHelper.safeGetDouble(object, "d", 6d), 0.0d);
}
@Test
public void safeGetLntTest() throws JSONException {
JSONObject object = new JSONObject(jsonString);
assertEquals(0, JsonHelper.safeGetInt(null, "notexisting"));
assertEquals(0, JsonHelper.safeGetInt(object, "notexisting"));
assertEquals(4, JsonHelper.safeGetInt(object, "i"));
}
@Test
public void safeGetLongTest() throws JSONException {
JSONObject object = new JSONObject(jsonString);
assertEquals(0, JsonHelper.safeGetInt(null, "notexisting"));
assertEquals(0, JsonHelper.safeGetInt(object, "notexisting"));
assertEquals(4, JsonHelper.safeGetInt(object, "i"));
}
@Test
public void safeGetBooleanTest() throws JSONException {
JSONObject object = new JSONObject(jsonString);
assertFalse(JsonHelper.safeGetBoolean(null, "notexisting"));
assertFalse(JsonHelper.safeGetBoolean(object, "notexisting"));
assertTrue(JsonHelper.safeGetBoolean(object, "b"));
}
}

View file

@ -1,41 +0,0 @@
package info.nightscout.androidaps.utils;
import org.junit.Test;
import static org.junit.Assert.*;
public class RoundTest {
public RoundTest(){
super();
}
@Test
public void roundToTest() throws Exception {
assertEquals( 0.55d, Round.roundTo(0.54d, 0.05d), 0.00000000000000000001d );
assertEquals( -3.26d, Round.roundTo(-3.2553715764602713d, 0.01d), 0.00000000000000000001d );
assertEquals( 0.816d, Round.roundTo(0.8156666666666667d, 0.001d), 0.00000000000000000001d );
assertEquals( 0.235d, Round.roundTo(0.235d, 0.001d), 0.00000000000000000001d );
assertEquals( 0.3d, Round.roundTo(0.3d, 0.1d), 0.00000000000000001d );
assertEquals( 0.0017d, Round.roundTo(0.0016960652144170627d, 0.0001d), 0.00000000000000000001d );
assertEquals( 0.0078d, Round.roundTo(0.007804436682291013d, 0.0001d), 0.00000000000000000001d );
assertEquals( 0.6d, Round.roundTo(0.6d, 0.05d), 0.00000000000000000001d );
assertEquals( 1d, Round.roundTo(1.49d, 1d), 0.00000000000000000001d );
assertEquals( 0d, Round.roundTo(0d, 1d), 0.00000000000000000001d );
}
@Test
public void floorToTest() throws Exception {
assertEquals( 0.5d, Round.floorTo(0.54d, 0.05d), 0.00000001d );
assertEquals( 1d, Round.floorTo(1.59d, 1d), 0.00000001d );
assertEquals( 0d, Round.floorTo(0d, 1d), 0.00000001d );
}
@Test
public void ceilToTest() throws Exception {
assertEquals( 0.6d, Round.ceilTo(0.54d, 0.1d), 0.00000001d );
assertEquals( 2d, Round.ceilTo(1.49999d, 1d), 0.00000001d );
assertEquals( 0d, Round.ceilTo(0d, 1d), 0.00000001d );
}
}

View file

@ -1,22 +0,0 @@
package info.nightscout.androidaps.utils;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
public class StringUtilsTest {
@Test
public void removeSurroundingQuotesTest() {
String compareString = "test";
assertEquals(compareString, StringUtils.removeSurroundingQuotes(compareString));
assertEquals(compareString, StringUtils.removeSurroundingQuotes("\"" + compareString + "\""));
assertEquals("\"" + compareString, StringUtils.removeSurroundingQuotes("\"" + compareString));
compareString = "te\"st";
assertEquals(compareString, StringUtils.removeSurroundingQuotes(compareString));
assertEquals(compareString, StringUtils.removeSurroundingQuotes("\"" + compareString + "\""));
assertEquals("\"" + compareString, StringUtils.removeSurroundingQuotes("\"" + compareString));
}
}

View file

@ -1,49 +0,0 @@
package info.nightscout.androidaps.utils;
import org.junit.Assert;
import org.junit.Test;
/**
* Created by mike on 26.03.2018.
*/
//@RunWith(PowerMockRunner.class)
public class TTest {
@Test
public void toUnits() {
Assert.assertEquals(1, T.msecs(1000).secs());
Assert.assertEquals(1, T.secs(60).mins());
Assert.assertEquals(1, T.mins(60).hours());
Assert.assertEquals(1, T.hours(24).days());
Assert.assertEquals(24, T.days(1).hours());
Assert.assertEquals(60000, T.mins(1).msecs());
}
@Test
public void now() {
Assert.assertTrue(Math.abs(T.now().msecs() - System.currentTimeMillis()) < 5000);
}
@Test
public void additions() {
long nowMsecs = System.currentTimeMillis();
T now = T.msecs(nowMsecs);
Assert.assertEquals(now.plus(T.secs(5)).msecs(), nowMsecs + 5 * 1000);
Assert.assertEquals(now.plus(T.mins(5)).msecs(), nowMsecs + 5 * 60 * 1000);
Assert.assertEquals(now.plus(T.hours(5)).msecs(), nowMsecs + 5 * 60 * 60 * 1000);
Assert.assertEquals(now.plus(T.days(5)).msecs(), nowMsecs + 5 * 24 * 60 * 60 * 1000);
}
@Test
public void subtractions() {
long nowMsecs = System.currentTimeMillis();
T now = T.msecs(nowMsecs);
Assert.assertEquals(now.minus(T.secs(5)).msecs(), nowMsecs - 5 * 1000);
Assert.assertEquals(now.minus(T.mins(5)).msecs(), nowMsecs - 5 * 60 * 1000);
Assert.assertEquals(now.minus(T.hours(5)).msecs(), nowMsecs - 5 * 60 * 60 * 1000);
Assert.assertEquals(now.minus(T.days(5)).msecs(), nowMsecs - 5 * 24 * 60 * 60 * 1000);
}
}

View file

@ -42,6 +42,7 @@ buildscript {
includeModule("org.jetbrains.trove4j", "trove4j")
}
}
maven { url "https://plugins.gradle.org/m2/" } // jacoco 0.2
}
dependencies {
classpath 'com.android.tools.build:gradle:4.0.1'
@ -52,6 +53,7 @@ buildscript {
// in the individual module build.gradle files
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath 'com.hiya:jacoco-android:0.2'
}
}

View file

@ -2,48 +2,21 @@ apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-kapt'
apply plugin: 'kotlin-parcelize'
apply plugin: 'com.hiya.jacoco-android'
apply from: 'core_dependencies.gradle'
apply from: "${project.rootDir}/gradle/android_dependencies.gradle"
apply from: "${project.rootDir}/gradle/android_module_dependencies.gradle"
apply from: "${project.rootDir}/gradle/test_dependencies.gradle"
android {
compileSdkVersion 28
defaultConfig {
minSdkVersion 26
targetSdkVersion 28
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles 'consumer-rules.pro'
}
kotlinOptions {
jvmTarget = '1.8'
}
buildFeatures {
viewBinding true
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
debug {
testCoverageEnabled(project.hasProperty('coverage'))
}
firebaseDisable {
System.setProperty("disableFirebase", "true")
ext.enableCrashlytics = false
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
implementation project(':database')
}
apply from: 'core_dependencies.gradle'

View file

@ -22,10 +22,6 @@ dependencies {
api "com.google.dagger:dagger-android:$dagger_version"
api "com.google.dagger:dagger-android-support:$dagger_version"
annotationProcessor "com.google.dagger:dagger-compiler:$dagger_version"
annotationProcessor "com.google.dagger:dagger-android-processor:$dagger_version"
kapt "com.google.dagger:dagger-android-processor:$dagger_version"
kapt "com.google.dagger:dagger-compiler:$dagger_version"
//Logger
api 'org.slf4j:slf4j-api:1.7.30'
@ -105,10 +101,8 @@ dependencies {
api 'com.github.kenglxn.QRGen:android:2.6.0'
api 'com.eatthepath:java-otp:0.2.0'
api "commons-codec:commons-codec:$commonscodec_version"
// Phone checker
api 'com.scottyab:rootbeer-lib:0.0.8'
testImplementation "junit:junit:$junit_version"
androidTestImplementation "androidx.test.ext:junit:$androidx_junit"
androidTestImplementation "androidx.test:rules:$androidx_rules"
}

View file

@ -16,12 +16,12 @@ import org.json.JSONObject
*/
interface PumpInterface {
val isInitialized: Boolean // true if pump status has been read and is ready to accept commands
val isSuspended: Boolean // true if suspended (not delivering insulin)
val isBusy: Boolean // if true pump is not ready to accept commands right now
val isConnected: Boolean // true if BT connection is established
val isConnecting: Boolean // true if BT connection is in progress
val isHandshakeInProgress: Boolean // true if BT is connected but initial handshake is still in progress
fun isInitialized(): Boolean // true if pump status has been read and is ready to accept commands
fun isSuspended(): Boolean // true if suspended (not delivering insulin)
fun isBusy(): Boolean // if true pump is not ready to accept commands right now
fun isConnected(): Boolean // true if BT connection is established
fun isConnecting(): Boolean // true if BT connection is in progress
fun isHandshakeInProgress(): Boolean // true if BT is connected but initial handshake is still in progress
@JvmDefault fun finishHandshaking() {} // set initial handshake completed
fun connect(reason: String)
fun disconnect(reason: String)

View file

@ -0,0 +1,18 @@
package info.nightscout.androidaps.interfaces
import info.nightscout.androidaps.db.Treatment
interface TreatmentServiceInterface {
fun getTreatmentDataFromTime(mills: Long, ascending: Boolean): List<Treatment>
fun getTreatmentDataFromTime(from: Long, to: Long, ascending: Boolean): List<Treatment>
fun getTreatmentData(): List<Treatment>
fun getLastBolus(excludeSMB: Boolean): Treatment?
fun getLastCarb(): Treatment?
fun createOrUpdateMedtronic(treatment: Treatment, fromNightScout: Boolean): UpdateReturn
fun createOrUpdate(treatment: Treatment): UpdateReturn
fun resetTreatments()
fun delete(data: Treatment)
fun update(data: Treatment)
fun count(): Long
}

View file

@ -21,6 +21,8 @@ import info.nightscout.androidaps.plugins.treatments.TreatmentUpdateReturn;
*/
public interface TreatmentsInterface {
TreatmentServiceInterface getService();
void updateTotalIOBTreatments();
void updateTotalIOBTempBasals();
@ -40,6 +42,7 @@ public interface TreatmentsInterface {
List<Treatment> getTreatmentsFromHistoryAfterTimestamp(long timestamp);
long getLastBolusTime();
long getLastBolusTime(boolean excludeSMB);
// real basals (not faked by extended bolus)
boolean isInHistoryRealTempBasalInProgress();

View file

@ -0,0 +1,11 @@
package info.nightscout.androidaps.interfaces
class UpdateReturn(var success: Boolean, var newRecord: Boolean) {
override fun toString(): String {
return "UpdateReturn [" +
"newRecord=" + newRecord +
", success=" + success +
']'
}
}

View file

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/careportal_cardview"
@ -29,7 +30,7 @@
android:layout_marginEnd="6dp"
android:layout_marginBottom="1dp"
card_view:srcCompat="@drawable/ic_meta_format"
android:tint="@color/importListFileName" />
app:tint="@color/importListFileName" />
<TextView
android:id="@+id/filelist_name"
@ -90,7 +91,7 @@
android:layout_marginEnd="8dp"
android:layout_marginBottom="1dp"
card_view:srcCompat="@drawable/ic_meta_name"
android:tint="@color/importListAdditionalInfo" />
app:tint="@color/importListAdditionalInfo" />
<TextView
android:id="@+id/meta_device_name"
@ -122,7 +123,7 @@
android:layout_marginEnd="8dp"
android:layout_marginBottom="1dp"
card_view:srcCompat="@drawable/ic_meta_date"
android:tint="@color/importListAdditionalInfo" />
app:tint="@color/importListAdditionalInfo" />
<TextView
android:id="@+id/meta_date_time"

View file

@ -104,7 +104,7 @@
<string name="unit_days">ימים</string>
<string name="unit_weeks">שבועות</string>
<string name="shortminute">דק\'</string>
<string name="shortday">י\'</string>
<string name="shortday">י\' </string>
<!-- Protection-->
<string name="wrongpassword">סיסמה שגויה</string>
<string name="passwords_dont_match">הסיסמאות אינן תואמות</string>

View file

@ -2,6 +2,7 @@
<resources>
<!-- Keys-->
<!-- General-->
<string name="refresh">Atnaujinti</string>
<string name="error">Klaida</string>
<string name="not_set_short">Nenustatyta</string>
<string name="failedupdatebasalprofile">Nepavyko atnaujinti bazės profilio</string>
@ -255,4 +256,29 @@
<string name="versionavailable">Versiją %1$s jau galima naudoti</string>
<!-- Permissions -->
<!-- WeekdayPicker -->
<string name="monday_short">P</string>
<string name="tuesday_short">A</string>
<string name="wednesday_short">T</string>
<string name="thursday_short">K</string>
<string name="friday_short">Pn</string>
<string name="saturday_short">Š</string>
<string name="sunday_short">S</string>
<plurals name="days">
<item quantity="one">%1$d d.</item>
<item quantity="few">%1$d d.</item>
<item quantity="many">%1$d d.</item>
<item quantity="other">%1$d d.</item>
</plurals>
<plurals name="hours">
<item quantity="one">%1$d val.</item>
<item quantity="few">%1$d val.</item>
<item quantity="many">%1$d val.</item>
<item quantity="other">%1$d val.</item>
</plurals>
<plurals name="minutes">
<item quantity="one">%1$d min.</item>
<item quantity="few">%1$d min.</item>
<item quantity="many">%1$d min.</item>
<item quantity="other">%1$d min.</item>
</plurals>
</resources>

View file

@ -258,6 +258,13 @@
<!-- Permissions -->
<string name="alert_dialog_storage_permission_text">Vennligst start mobilen på nytt eller restart AndroidAPS fra Innstillinger \nellers vil ikke AndroidAPS ha aktivert loggføring (viktig for å spore og kontrollere at algoritmene fungerer riktig!)</string>
<!-- WeekdayPicker -->
<string name="monday_short">M</string>
<string name="tuesday_short">T</string>
<string name="wednesday_short">O</string>
<string name="thursday_short">T</string>
<string name="friday_short">F</string>
<string name="saturday_short">L</string>
<string name="sunday_short">S</string>
<plurals name="days">
<item quantity="one">%1$d dag</item>
<item quantity="other">%1$d dager</item>

View file

@ -258,6 +258,13 @@
<!-- Permissions -->
<string name="alert_dialog_storage_permission_text">Prosím reštartujte Váš telefón, alebo reštartujte AndroidAPS z nastavení \nv opačnom prípade AndroidAPS nebude mocť zaznamenávať logy (dôležité kvôli sledovaniu a overovaniu, že algoritmus pracuje správne)!</string>
<!-- WeekdayPicker -->
<string name="monday_short">Po</string>
<string name="tuesday_short">Ut</string>
<string name="wednesday_short">St</string>
<string name="thursday_short">Št</string>
<string name="friday_short">Pi</string>
<string name="saturday_short">So</string>
<string name="sunday_short">Ne</string>
<plurals name="days">
<item quantity="one">%1$d deň</item>
<item quantity="few">%1$d dní</item>

View file

@ -85,5 +85,9 @@
<color name="metadataTextWarning">#FF8C00</color>
<color name="metadataTextError">#FF5555</color>
<!-- Import/Export -->
<color name="importListAdditionalInfo">#BBBBBB</color>
<color name="importListFileName">#FFFFFF</color>
</resources>

View file

@ -18,6 +18,16 @@
<item name="android:windowAnimationStyle">@android:style/Animation</item>
</style>
<style name="Theme.AppCompat.NoTitle" parent="Theme.AppCompat.NoActionBar">
<item name="android:windowNoTitle">true</item>
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:colorBackgroundCacheHint">@null</item>
<item name="android:windowIsTranslucent">false</item>
<item name="android:windowAnimationStyle">@android:style/Animation</item>
</style>
<style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" />
<style name="AppThemeWarningDialog" parent="AppTheme">
<item name="alertDialogTheme">@style/AppThemeWarningDialogTheme</item>
<item name="dialogTitleBackground">@color/warningAlertBackground</item>

View file

@ -0,0 +1,40 @@
package info.nightscout.androidaps
import info.nightscout.androidaps.logging.AAPSLoggerTest
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.androidaps.utils.rx.TestAapsSchedulers
import org.junit.Before
import org.junit.Rule
import org.mockito.Mockito
import org.mockito.junit.MockitoJUnit
import org.mockito.junit.MockitoRule
import java.util.*
@Suppress("SpellCheckingInspection")
open class TestBase {
val aapsLogger = AAPSLoggerTest()
val aapsSchedulers: AapsSchedulers = TestAapsSchedulers()
// Add a JUnit rule that will setup the @Mock annotated vars and log.
// Another possibility would be to add `MockitoAnnotations.initMocks(this) to the setup method.
@get:Rule
val mockitoRule: MockitoRule = MockitoJUnit.rule()
@Before
fun setupLocale() {
Locale.setDefault(Locale.ENGLISH)
System.setProperty("disableFirebase", "true")
}
// Workaround for Kotlin nullability.
// https://medium.com/@elye.project/befriending-kotlin-and-mockito-1c2e7b0ef791
// https://stackoverflow.com/questions/30305217/is-it-possible-to-use-mockito-in-kotlin
fun <T> anyObject(): T {
Mockito.any<T>()
return uninitialized()
}
@Suppress("Unchecked_Cast")
fun <T> uninitialized(): T = null as T
}

View file

@ -1,97 +1,98 @@
package info.nightscout.androidaps.utils
import info.nightscout.androidaps.TestBase
import org.hamcrest.CoreMatchers.containsString
import org.hamcrest.CoreMatchers.not
import org.junit.Assert
import org.junit.Assume.assumeThat
import org.junit.Test
import org.junit.runner.RunWith
import org.powermock.core.classloader.annotations.PowerMockIgnore
import org.powermock.modules.junit4.PowerMockRunner
// https://stackoverflow.com/questions/52344522/joseexception-couldnt-create-aes-gcm-nopadding-cipher-illegal-key-size
// https://stackoverflow.com/questions/47708951/can-aes-256-work-on-android-devices-with-api-level-26
// Java prior to Oracle Java 8u161 does not have policy for 256 bit AES - but Android support it
// when test is run in Vanilla JVM without policy - Invalid key size exception is thrown
fun assumeAES256isSupported(cryptoUtil: CryptoUtil) {
cryptoUtil.lastException?.message?.let { exceptionMessage ->
assumeThat("Upgrade your testing environment Java (OpenJDK or Java 8u161) and JAVA_HOME - AES 256 is supported by Android so this exception should not happen!", exceptionMessage, not(containsString("key size")))
}
}
@PowerMockIgnore("javax.crypto.*")
@RunWith(PowerMockRunner::class)
class CryptoUtilTest: TestBase() {
var cryptoUtil: CryptoUtil = CryptoUtil(aapsLogger)
@Test
fun testFixedSaltCrypto() {
val salt = byteArrayOf(
-33, -29, 16, -19, 99, -111, -3, 2, 116, 106, 47, 38, -54, 11, -77, 28,
111, -15, -65, -110, 4, -32, -29, -70, -95, -88, -53, 19, 87, -103, 123, -15)
val password = "thisIsFixedPassword"
val payload = "FIXED-PAYLOAD"
val encrypted = cryptoUtil.encrypt(password, salt, payload)
assumeAES256isSupported(cryptoUtil)
Assert.assertNotNull(encrypted)
val decrypted = cryptoUtil.decrypt(password, salt, encrypted!!)
assumeAES256isSupported(cryptoUtil)
Assert.assertEquals(decrypted, payload)
}
@Test
fun testStandardCrypto() {
val salt = cryptoUtil.mineSalt()
val password = "topSikret"
val payload = "{what:payloadYouWantToProtect}"
val encrypted = cryptoUtil.encrypt(password, salt, payload)
assumeAES256isSupported(cryptoUtil)
Assert.assertNotNull(encrypted)
val decrypted = cryptoUtil.decrypt(password, salt, encrypted!!)
assumeAES256isSupported(cryptoUtil)
Assert.assertEquals(decrypted, payload)
}
@Test
fun testHashVector() {
val payload = "{what:payloadYouWantToProtect}"
val hash = cryptoUtil.sha256(payload)
Assert.assertEquals(hash, "a1aafe3ed6cc127e6d102ddbc40a205147230e9cfd178daf108c83543bbdcd13")
}
@Test
fun testHmac() {
val payload = "{what:payloadYouWantToProtect}"
val password = "topSikret"
val expectedHmac = "ea2213953d0f2e55047cae2d23fb4f0de1b805d55e6271efa70d6b85fb692bea" // generated using other HMAC tool
val hash = cryptoUtil.hmac256(payload, password)
Assert.assertEquals(hash, expectedHmac)
}
@Test
fun testPlainPasswordCheck() {
Assert.assertTrue(cryptoUtil.checkPassword("same", "same"))
Assert.assertFalse(cryptoUtil.checkPassword("same", "other"))
}
@Test
fun testHashedPasswordCheck() {
Assert.assertTrue(cryptoUtil.checkPassword("givenSecret", cryptoUtil.hashPassword("givenSecret")))
Assert.assertFalse(cryptoUtil.checkPassword("givenSecret", cryptoUtil.hashPassword("otherSecret")))
Assert.assertTrue(cryptoUtil.checkPassword("givenHashToCheck", "hmac:7fe5f9c7b4b97c5d32d5cfad9d07473543a9938dc07af48a46dbbb49f4f68c12:a0c7cee14312bbe31b51359a67f0d2dfdf46813f319180269796f1f617a64be1"))
Assert.assertFalse(cryptoUtil.checkPassword("givenMashToCheck", "hmac:7fe5f9c7b4b97c5d32d5cfad9d07473543a9938dc07af48a46dbbb49f4f68c12:a0c7cee14312bbe31b51359a67f0d2dfdf46813f319180269796f1f617a64be1"))
Assert.assertFalse(cryptoUtil.checkPassword("givenHashToCheck", "hmac:0fe5f9c7b4b97c5d32d5cfad9d07473543a9938dc07af48a46dbbb49f4f68c12:a0c7cee14312bbe31b51359a67f0d2dfdf46813f319180269796f1f617a64be1"))
Assert.assertFalse(cryptoUtil.checkPassword("givenHashToCheck", "hmac:7fe5f9c7b4b97c5d32d5cfad9d07473543a9938dc07af48a46dbbb49f4f68c12:b0c7cee14312bbe31b51359a67f0d2dfdf46813f319180269796f1f617a64be1"))
}
}
package info.nightscout.androidaps.utils
import info.nightscout.androidaps.TestBase
import org.hamcrest.CoreMatchers.containsString
import org.hamcrest.CoreMatchers.not
import org.junit.Assert
import org.junit.Assume.assumeThat
import org.junit.Test
import org.junit.runner.RunWith
import org.powermock.core.classloader.annotations.PowerMockIgnore
import org.powermock.modules.junit4.PowerMockRunner
// https://stackoverflow.com/questions/52344522/joseexception-couldnt-create-aes-gcm-nopadding-cipher-illegal-key-size
// https://stackoverflow.com/questions/47708951/can-aes-256-work-on-android-devices-with-api-level-26
// Java prior to Oracle Java 8u161 does not have policy for 256 bit AES - but Android support it
// when test is run in Vanilla JVM without policy - Invalid key size exception is thrown
fun assumeAES256isSupported(cryptoUtil: CryptoUtil) {
cryptoUtil.lastException?.message?.let { exceptionMessage ->
assumeThat("Upgrade your testing environment Java (OpenJDK or Java 8u161) and JAVA_HOME - AES 256 is supported by Android so this exception should not happen!", exceptionMessage, not(containsString("key size")))
}
}
@Suppress("SpellCheckingInspection")
@PowerMockIgnore("javax.crypto.*")
@RunWith(PowerMockRunner::class)
class CryptoUtilTest: TestBase() {
private var cryptoUtil: CryptoUtil = CryptoUtil(aapsLogger)
@Test
fun testFixedSaltCrypto() {
val salt = byteArrayOf(
-33, -29, 16, -19, 99, -111, -3, 2, 116, 106, 47, 38, -54, 11, -77, 28,
111, -15, -65, -110, 4, -32, -29, -70, -95, -88, -53, 19, 87, -103, 123, -15)
val password = "thisIsFixedPassword"
val payload = "FIXED-PAYLOAD"
val encrypted = cryptoUtil.encrypt(password, salt, payload)
assumeAES256isSupported(cryptoUtil)
Assert.assertNotNull(encrypted)
val decrypted = cryptoUtil.decrypt(password, salt, encrypted!!)
assumeAES256isSupported(cryptoUtil)
Assert.assertEquals(decrypted, payload)
}
@Test
fun testStandardCrypto() {
val salt = cryptoUtil.mineSalt()
val password = "topSikret"
val payload = "{what:payloadYouWantToProtect}"
val encrypted = cryptoUtil.encrypt(password, salt, payload)
assumeAES256isSupported(cryptoUtil)
Assert.assertNotNull(encrypted)
val decrypted = cryptoUtil.decrypt(password, salt, encrypted!!)
assumeAES256isSupported(cryptoUtil)
Assert.assertEquals(decrypted, payload)
}
@Test
fun testHashVector() {
val payload = "{what:payloadYouWantToProtect}"
val hash = cryptoUtil.sha256(payload)
Assert.assertEquals(hash, "a1aafe3ed6cc127e6d102ddbc40a205147230e9cfd178daf108c83543bbdcd13")
}
@Test
fun testHmac() {
val payload = "{what:payloadYouWantToProtect}"
val password = "topSikret"
val expectedHmac = "ea2213953d0f2e55047cae2d23fb4f0de1b805d55e6271efa70d6b85fb692bea" // generated using other HMAC tool
val hash = cryptoUtil.hmac256(payload, password)
Assert.assertEquals(hash, expectedHmac)
}
@Test
fun testPlainPasswordCheck() {
Assert.assertTrue(cryptoUtil.checkPassword("same", "same"))
Assert.assertFalse(cryptoUtil.checkPassword("same", "other"))
}
@Test
fun testHashedPasswordCheck() {
Assert.assertTrue(cryptoUtil.checkPassword("givenSecret", cryptoUtil.hashPassword("givenSecret")))
Assert.assertFalse(cryptoUtil.checkPassword("givenSecret", cryptoUtil.hashPassword("otherSecret")))
Assert.assertTrue(cryptoUtil.checkPassword("givenHashToCheck", "hmac:7fe5f9c7b4b97c5d32d5cfad9d07473543a9938dc07af48a46dbbb49f4f68c12:a0c7cee14312bbe31b51359a67f0d2dfdf46813f319180269796f1f617a64be1"))
Assert.assertFalse(cryptoUtil.checkPassword("givenMashToCheck", "hmac:7fe5f9c7b4b97c5d32d5cfad9d07473543a9938dc07af48a46dbbb49f4f68c12:a0c7cee14312bbe31b51359a67f0d2dfdf46813f319180269796f1f617a64be1"))
Assert.assertFalse(cryptoUtil.checkPassword("givenHashToCheck", "hmac:0fe5f9c7b4b97c5d32d5cfad9d07473543a9938dc07af48a46dbbb49f4f68c12:a0c7cee14312bbe31b51359a67f0d2dfdf46813f319180269796f1f617a64be1"))
Assert.assertFalse(cryptoUtil.checkPassword("givenHashToCheck", "hmac:7fe5f9c7b4b97c5d32d5cfad9d07473543a9938dc07af48a46dbbb49f4f68c12:b0c7cee14312bbe31b51359a67f0d2dfdf46813f319180269796f1f617a64be1"))
}
}

View file

@ -2,7 +2,7 @@ package info.nightscout.androidaps.utils
import android.content.Context
import info.nightscout.androidaps.TestBase
import info.nightscout.androidaps.R
import info.nightscout.androidaps.core.R
import info.nightscout.androidaps.utils.resources.ResourceHelper
import org.junit.Assert
import org.junit.Test

View file

@ -0,0 +1,30 @@
package info.nightscout.androidaps.utils
import org.junit.Assert
import org.junit.Test
import org.junit.runner.RunWith
import org.powermock.modules.junit4.PowerMockRunner
@RunWith(PowerMockRunner::class)
class DecimalFormatterTest {
@Test fun to0DecimalTest() {
Assert.assertEquals("1", DecimalFormatter.to0Decimal(1.33).replace(",", "."))
Assert.assertEquals("1U", DecimalFormatter.to0Decimal(1.33, "U").replace(",", "."))
}
@Test fun to1DecimalTest() {
Assert.assertEquals("1.3", DecimalFormatter.to1Decimal(1.33).replace(",", "."))
Assert.assertEquals("1.3U", DecimalFormatter.to1Decimal(1.33, "U").replace(",", "."))
}
@Test fun to2DecimalTest() {
Assert.assertEquals("1.33", DecimalFormatter.to2Decimal(1.3333).replace(",", "."))
Assert.assertEquals("1.33U", DecimalFormatter.to2Decimal(1.3333, "U").replace(",", "."))
}
@Test fun to3DecimalTest() {
Assert.assertEquals("1.333", DecimalFormatter.to3Decimal(1.3333).replace(",", "."))
Assert.assertEquals("1.333U", DecimalFormatter.to3Decimal(1.3333, "U").replace(",", "."))
}
}

Some files were not shown because too many files have changed in this diff Show more