diff --git a/.gitignore b/.gitignore
index 98b73cb7cb4..c7ed9df2f5c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,10 +6,17 @@
/captures
*.apk
build/
-.idea/
+.idea/*
+!.idea/codeStyles/
app/src/main/jniLibs
full/
debug/
release/
app/com.crashlytics.settings.json
-app/session_analytics.tap
\ No newline at end of file
+app/session_analytics.tap
+.project
+.settings/org.eclipse.buildship.core.prefs
+app/.classpath
+app/.settings/org.eclipse.buildship.core.prefs
+wear/.classpath
+wear/.settings/org.eclipse.buildship.core.prefs
diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
new file mode 100644
index 00000000000..d1c3d63de51
--- /dev/null
+++ b/.idea/codeStyles/Project.xml
@@ -0,0 +1,134 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ xmlns:android
+
+ ^$
+
+
+
+
+
+
+
+
+ xmlns:.*
+
+ ^$
+
+
+ BY_NAME
+
+
+
+
+
+
+ .*:id
+
+ http://schemas.android.com/apk/res/android
+
+
+
+
+
+
+
+
+ .*:name
+
+ http://schemas.android.com/apk/res/android
+
+
+
+
+
+
+
+
+ name
+
+ ^$
+
+
+
+
+
+
+
+
+ style
+
+ ^$
+
+
+
+
+
+
+
+
+ .*
+
+ ^$
+
+
+ BY_NAME
+
+
+
+
+
+
+ .*
+
+ http://schemas.android.com/apk/res/android
+
+
+ ANDROID_ATTRIBUTE_ORDER
+
+
+
+
+
+
+ .*
+
+ .*
+
+
+ BY_NAME
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml
new file mode 100644
index 00000000000..79ee123c2b2
--- /dev/null
+++ b/.idea/codeStyles/codeStyleConfig.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
index 5c6309f817d..165a1eff9a5 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,24 +1,25 @@
language: android
jdk: oraclejdk8
+dist: trusty
env:
matrix:
- - ANDROID_TARGET=android-23 ANDROID_ABI=x86 org.gradle.jvmargs=-XX:-OmitStackTraceInFastThrow
+ - ANDROID_TARGET=android-28 ANDROID_ABI=x86 org.gradle.jvmargs=-XX:-OmitStackTraceInFastThrow
android:
components:
- platform-tools
- tools
- - build-tools-27.0.2
- - android-23
+ - build-tools-28.0.3
+ - android-28
- extra-google-m2repository
- extra-android-m2repository
- extra-google-google_play_services
before_install:
-- yes | sdkmanager "platforms;android-27"
+#- yes | sdkmanager "platforms;android-28"
script:
# Unit Test
- - ./gradlew -Pcoverage testFullDebugUnitTest jacocoTestFullDebugUnitTestReport
+ - ./gradlew -Pcoverage -PfirebaseDisable testFullDebugUnitTest jacocoTestFullDebugUnitTestReport
after_success:
- bash <(curl -s https://codecov.io/bash)
@@ -31,4 +32,4 @@ cache:
directories:
- $HOME/.gradle/caches/
- $HOME/.gradle/wrapper/
- - $HOME/.android/build-cache
\ No newline at end of file
+ - $HOME/.android/build-cache
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 00000000000..d15d2440fd8
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,48 @@
+This document speciffy hints and good practices for source code contributions.
+
+AndroidAPS is community effort and all contributions are welcome! If you wish help us improving AndroidAPS - please read and try to adhere to
+this guidelines, to make the development and process of change aproval as smooth as possible :)
+
+General rules
+=============
+
+* There are plenty of ways you can help, some of them are listed on wiki:
+ https://androidaps.readthedocs.io/en/latest/EN/Getting-Started/How-can-I-help.html
+* If you wish to help with documentation or translating:
+ https://androidaps.readthedocs.io/en/latest/EN/translations.html
+
+Development guidelines
+======================
+
+Coding convetions
+-----------------
+1. Use Android Studio with default indents (4 chars, use spaces)
+2. Use autoformat feature CTRL-ALT-L in every changed file before commit
+
+Commiting Changes / Pull Requests
+---------------------------------
+
+1. Make fork of repository on github
+2. Create separate branch for each feature, branch from most recent dev
+3. Commit all changes to your fork
+4. When ready, rebase on top of dev and make pull request to main repo
+
+Naming Conventions for Pull Requests / Branches
+-----------------------------------------------
+
+TODO
+
+Translations
+------------
+
+* If possible, always use Android translation mechanism (with strings.xml and @strings/id) instead of hardcoded texts
+* Provide only English strings - all other languages will be crowd translated via Crowdn https://translations.androidaps.org/
+
+Hints
+-----
+
+* Start small, it is easier to review smaller changes that affect fewer parts of code
+* Take a look into Issues list (https://github.com/MilosKozak/AndroidAPS/issues) - maybe there is somthing you can fix or implement
+* For new features, make sure there is Issue to track progress and have on-topic discussion
+* Reach out to community, discuss idea on Gitter (https://gitter.im/MilosKozak/AndroidAPS)
+* Speak with other developers to minimise merge conflicts. Find out who worked, working or plan to work on speciffic issue or part of app
diff --git a/README.md b/README.md
index d1e1e8a47c6..32aef48cd9b 100644
--- a/README.md
+++ b/README.md
@@ -11,4 +11,4 @@
dev: [](https://codecov.io/gh/MilosKozak/AndroidAPS)
-[](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=Y4LHGJJESAVB8)
+[](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=Y4LHGJJESAVB8)
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
index 8c153a9e81d..bd7509a670d 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -6,23 +6,28 @@ buildscript {
dependencies {
classpath 'io.fabric.tools:gradle:1.+'
- classpath 'com.dicedmelon.gradle:jacoco-android:0.1.3'
+ classpath 'com.dicedmelon.gradle:jacoco-android:0.1.4'
+ classpath 'de.undercouch:gradle-download-task:3.4.3'
}
}
-apply plugin: "com.android.application"
-apply plugin: 'kotlin-android-extensions'
+apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
+apply plugin: 'kotlin-android-extensions'
apply plugin: 'com.google.gms.google-services'
-apply plugin: "io.fabric"
-apply plugin: "jacoco-android"
-apply plugin: 'com.jakewharton.butterknife'
+apply plugin: 'io.fabric'
+apply plugin: 'jacoco-android'
+apply plugin: 'de.undercouch.download'
+
+
+jacoco {
+ toolVersion = "0.8.3"
+}
ext {
- supportLibraryVersion = "27.1.1"
+ supportLibraryVersion = "28.0.0"
ormLiteVersion = "4.46"
powermockVersion = "1.7.3"
dexmakerVersion = "1.2"
- butterknifeVersion = "8.8.1"
}
@@ -33,7 +38,7 @@ repositories {
}
def generateGitBuild = { ->
- StringBuilder stringBuilder = new StringBuilder();
+ StringBuilder stringBuilder = new StringBuilder()
try {
def stdout = new ByteArrayOutputStream()
exec {
@@ -49,7 +54,7 @@ def generateGitBuild = { ->
}
def generateGitRemote = { ->
- StringBuilder stringBuilder = new StringBuilder();
+ StringBuilder stringBuilder = new StringBuilder()
try {
def stdout = new ByteArrayOutputStream()
exec {
@@ -65,7 +70,7 @@ def generateGitRemote = { ->
}
def generateDate = { ->
- StringBuilder stringBuilder = new StringBuilder();
+ StringBuilder stringBuilder = new StringBuilder()
stringBuilder.append((new Date()).format('yyyy.MM.dd-HH:mm'))
return stringBuilder.toString()
}
@@ -75,7 +80,7 @@ def isMaster = { ->
}
def allCommited = { ->
- StringBuilder stringBuilder = new StringBuilder();
+ StringBuilder stringBuilder = new StringBuilder()
try {
def stdout = new ByteArrayOutputStream()
exec {
@@ -85,7 +90,7 @@ def allCommited = { ->
String commitObject = stdout.toString().trim()
stringBuilder.append(commitObject)
} catch (ignored) {
- return false; // NoGitSystemAvailable
+ return false // NoGitSystemAvailable
}
return stringBuilder.toString().isEmpty()
@@ -97,21 +102,26 @@ tasks.matching { it instanceof Test }.all {
}
android {
- compileSdkVersion 27
+ compileSdkVersion 28
defaultConfig {
- minSdkVersion 21
- targetSdkVersion 25
+ minSdkVersion 23
+ targetSdkVersion 28
multiDexEnabled true
versionCode 1500
- version "2.3"
+ version "2.7-omnipod-0.3"
buildConfigField "String", "VERSION", '"' + version + '"'
buildConfigField "String", "BUILDVERSION", '"' + generateGitBuild() + '-' + generateDate() + '"'
buildConfigField "String", "REMOTE", '"' + generateGitRemote() + '"'
buildConfigField "String", "HEAD", '"' + generateGitBuild() + '"'
- testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
// if you change minSdkVersion to less than 11, you need to change executeTask for wear
+ // OMNIPOD: Keep track of what commit from the main repository we're on, these fields aren't actually used anywhere
+ buildConfigField "String", "DEV_VERSION", '"2.7-dev"'
+ buildConfigField "String", "DEV_VERSION_COMMIT", '"c3dbd1ec2446647169bb8ee1e3067a96ff8af394"'
+ buildConfigField "String", "DEV_VERSION_COMMIT_DATE", '"1.3.2020"' // 1st of March
+
ndk {
moduleName "BleCommandUtil"
}
@@ -138,6 +148,9 @@ android {
debug {
testCoverageEnabled(project.hasProperty('coverage'))
}
+ firebaseDisable {
+ System.setProperty("disableFirebase", "true")
+ }
}
productFlavors {
flavorDimensions "standard"
@@ -188,8 +201,15 @@ android {
}
testOptions {
- unitTests.returnDefaultValues = true
- unitTests.includeAndroidResources = true
+ unitTests {
+ returnDefaultValues = true
+ includeAndroidResources = true
+
+ all {
+ maxParallelForks = 10
+ forkEvery = 20
+ }
+ }
}
useLibrary "org.apache.http.legacy"
@@ -201,46 +221,48 @@ allprojects {
flatDir {
dirs 'libs'
}
+ maven { url 'https://jitpack.io' }
}
}
-configurations {
- libs
-}
-
dependencies {
wearApp project(':wear')
implementation fileTree(include: ['*.jar'], dir: 'libs')
- implementation 'com.google.android.gms:play-services-wearable:16.0.1'
- implementation 'com.google.firebase:firebase-core:16.0.8'
- implementation("com.crashlytics.sdk.android:crashlytics:2.9.9@aar") {
+ implementation 'com.google.android.gms:play-services-wearable:17.0.0'
+ implementation 'com.google.firebase:firebase-core:17.2.1'
+ implementation 'com.google.firebase:firebase-auth:19.2.0'
+ implementation 'com.google.firebase:firebase-database:19.2.0'
+ implementation('com.crashlytics.sdk.android:crashlytics:2.10.1@aar') {
transitive = true;
}
- libs "MilosKozak:danars-support-lib:master@zip"
-
- implementation "com.android.support:appcompat-v7:${supportLibraryVersion}"
- implementation "com.android.support:support-v13:${supportLibraryVersion}"
- implementation "com.android.support:support-v4:${supportLibraryVersion}"
- implementation "com.android.support:cardview-v7:${supportLibraryVersion}"
- implementation "com.android.support:recyclerview-v7:${supportLibraryVersion}"
- implementation "com.android.support:gridlayout-v7:${supportLibraryVersion}"
- implementation "com.android.support:design:${supportLibraryVersion}"
- implementation "com.android.support:percent:${supportLibraryVersion}"
- implementation "com.wdullaer:materialdatetimepicker:2.3.0"
- implementation "com.squareup:otto:1.3.7"
+
+ implementation 'androidx.appcompat:appcompat:1.1.0'
+ implementation 'androidx.legacy:legacy-support-v13:1.0.0'
+ implementation 'androidx.legacy:legacy-support-v4:1.0.0'
+ implementation 'androidx.cardview:cardview:1.0.0'
+ implementation 'androidx.recyclerview:recyclerview:1.1.0'
+ implementation 'androidx.gridlayout:gridlayout:1.0.0'
+ implementation 'com.google.android.material:material:1.0.0'
+ implementation 'androidx.percentlayout:percentlayout:1.0.0'
+ implementation 'com.wdullaer:materialdatetimepicker:4.2.3'
+
+ implementation "io.reactivex.rxjava2:rxandroid:2.1.1"
+
implementation "com.j256.ormlite:ormlite-core:${ormLiteVersion}"
implementation "com.j256.ormlite:ormlite-android:${ormLiteVersion}"
implementation("com.github.tony19:logback-android-classic:1.1.1-6") {
exclude group: "com.google.android", module: "android"
}
- implementation "org.apache.commons:commons-lang3:3.7"
- implementation "org.slf4j:slf4j-api:1.7.21"
+ implementation "org.apache.commons:commons-lang3:3.9"
+ implementation "org.slf4j:slf4j-api:1.7.29"
// Graphview cannot be upgraded
implementation "com.jjoe64:graphview:4.0.1"
- implementation "com.joanzapata.iconify:android-iconify-fontawesome:2.1.1"
- implementation 'com.android.support.constraint:constraint-layout:1.1.3'
+ implementation "com.joanzapata.iconify:android-iconify-fontawesome:2.2.2"
+ implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation(name: "android-edittext-validator-v1.3.4-mod", ext: "aar")
+ implementation(name: "com.atech-software.android.library.wizardpager-1.1.1", ext: "aar")
+
implementation 'com.madgag.spongycastle:core:1.58.0.0'
implementation("com.google.android:flexbox:0.3.0") {
@@ -250,45 +272,73 @@ dependencies {
// excluding org.json which is provided by Android
exclude group: "org.json", module: "json"
}
- implementation "com.google.code.gson:gson:2.8.2"
- implementation "com.google.guava:guava:24.1-jre"
+ implementation "com.google.code.gson:gson:2.8.6"
+ implementation ("com.google.guava:guava:24.1-jre") {
+ exclude group: "com.google.code.findbugs", module: "jsr305"
+ }
+ implementation 'com.google.code.findbugs:jsr305:3.0.2'
- implementation "net.danlew:android.joda:2.9.9.1"
- implementation "uk.com.robust-it:cloning:1.9.9"
+ implementation "net.danlew:android.joda:2.10.3"
- implementation 'org.mozilla:rhino:1.7.7.2'
+ implementation 'org.mozilla:rhino:1.7.11'
- implementation "com.jakewharton:butterknife:${butterknifeVersion}"
- annotationProcessor "com.jakewharton:butterknife-compiler:${butterknifeVersion}"
+ implementation 'com.github.DavidProdinger:weekdays-selector:1.1.0'
testImplementation "junit:junit:4.12"
- testImplementation "org.json:json:20140107"
+ testImplementation "org.json:json:20190722"
testImplementation "org.mockito:mockito-core:2.8.47"
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:2.9.9"
- testImplementation "com.google.truth:truth:0.39"
- testImplementation 'org.robolectric:robolectric:3.8'
+ testImplementation "joda-time:joda-time:2.10.5"
+ testImplementation("com.google.truth:truth:0.39") {
+ exclude group: "com.google.guava", module: "guava"
+ exclude group: "com.google.code.findbugs", module: "jsr305"
+ }
testImplementation "org.skyscreamer:jsonassert:1.5.0"
+ testImplementation "org.hamcrest:hamcrest-all:1.3"
+/*
+ testImplementation("uk.org.lidalia:slf4j-test:1.2.0") {
+ exclude group: "com.google.guava", module: "guava"
+ }
+*/
- androidTestImplementation "org.mockito:mockito-core:2.8.47"
- androidTestImplementation "com.google.dexmaker:dexmaker:${dexmakerVersion}"
- androidTestImplementation "com.google.dexmaker:dexmaker-mockito:${dexmakerVersion}"
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
+ implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
+
+
+ // new for tidepool
+ implementation 'com.squareup.okhttp3:okhttp:4.2.2'
+ implementation 'com.squareup.okhttp3:logging-interceptor:4.2.2'
+ implementation "com.squareup.retrofit2:retrofit:2.6.2"
+ implementation "com.squareup.retrofit2:adapter-rxjava2:2.6.2"
+ implementation "com.squareup.retrofit2:converter-gson:2.6.2"
+
+ // Phone checker
+ implementation 'com.scottyab:rootbeer-lib:0.0.7'
+
+ androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0-alpha03'
+ androidTestImplementation 'androidx.test.ext:junit:1.1.1'
+ androidTestImplementation 'androidx.test:rules:1.3.0-alpha03'
+ androidTestImplementation 'com.google.code.findbugs:jsr305:3.0.2'
+ androidTestImplementation 'androidx.test.uiautomator:uiautomator:2.2.0'
}
-task unzip(type: Copy) {
- def zipPath = configurations.libs.find { it.name.startsWith("danars") }
- def zipFile = file(zipPath)
- def outputDir = file("${buildDir}/unpacked/dist")
- from zipTree(zipFile)
+task downloadZipFile(type: Download) {
+ src 'https://github.com/MilosKozak/danars-support-lib/archive/master.zip'
+ dest new File(buildDir, 'danars.zip')
+}
+
+task downloadAndUnzipFile(dependsOn: downloadZipFile, type: Copy) {
+ from zipTree(downloadZipFile.dest)
+ def outputDir = file("${buildDir}/unpacked/dist")
into outputDir
}
-task copyLibs(dependsOn: unzip, type: Copy) {
+
+task copyLibs(dependsOn: downloadAndUnzipFile, type: Copy) {
def src = file("${buildDir}/unpacked/dist/danars-support-lib-master")
def target = file("src/main/jniLibs/")
@@ -299,7 +349,37 @@ task copyLibs(dependsOn: unzip, type: Copy) {
task full_clean(type: Delete) {
delete file("src/main/jniLibs")
}
-
+/*
+// Run 'adb' shell command to clear application data of main app for 'debug' variant
+task clearMainAppData(type: Exec) {
+ // we have to iterate to find the 'debug' variant to obtain a variant reference
+ android.applicationVariants.all { variant ->
+ if (variant.name == "fullDebug") {
+ def applicationId = [variant.mergedFlavor.applicationId, variant.buildType.applicationIdSuffix].findAll().join()
+ def clearDataCommand = ['adb', 'shell', 'pm', 'clear', applicationId]
+ println "Clearing application data of ${variant.name} variant: [${clearDataCommand}]"
+ def stdout = new ByteArrayOutputStream()
+ exec {
+ commandLine clearDataCommand
+ standardOutput = stdout
+ }
+ String result = stdout.toString().trim()
+ if (!result.startsWith("Success")) {
+ println result
+ throw new GradleException(clearDataCommand.join(" "))
+ }
+ }
+ }
+}
+// Clear Application Data (once) before running instrumentation test
+tasks.whenTaskAdded { task ->
+ // Both of these targets are equivalent today, although in future connectedCheck
+ // will also include connectedUiAutomatorTest (not implemented yet)
+ if(task.name == "connectedAndroidTest" || task.name == "connectedCheck"){
+ task.dependsOn(clearMainAppData)
+ }
+}
+*/
clean.dependsOn full_clean
preBuild.dependsOn copyLibs
diff --git a/app/google-services.json b/app/google-services.json
index 42db6f42895..507c792c936 100644
--- a/app/google-services.json
+++ b/app/google-services.json
@@ -13,7 +13,12 @@
"package_name": "info.nightscout.aapspumpcontrol"
}
},
- "oauth_client": [],
+ "oauth_client": [
+ {
+ "client_id": "477603612366-a925drvlvs7qn7gt73r585erbqto8c79.apps.googleusercontent.com",
+ "client_type": 3
+ }
+ ],
"api_key": [
{
"current_key": "AIzaSyDcZpDRMaGjdhihXp531cVYM6LkEL8KbgM"
@@ -37,7 +42,12 @@
"package_name": "info.nightscout.androidaps"
}
},
- "oauth_client": [],
+ "oauth_client": [
+ {
+ "client_id": "477603612366-a925drvlvs7qn7gt73r585erbqto8c79.apps.googleusercontent.com",
+ "client_type": 3
+ }
+ ],
"api_key": [
{
"current_key": "AIzaSyDcZpDRMaGjdhihXp531cVYM6LkEL8KbgM"
@@ -61,7 +71,12 @@
"package_name": "info.nightscout.nsclient"
}
},
- "oauth_client": [],
+ "oauth_client": [
+ {
+ "client_id": "477603612366-a925drvlvs7qn7gt73r585erbqto8c79.apps.googleusercontent.com",
+ "client_type": 3
+ }
+ ],
"api_key": [
{
"current_key": "AIzaSyDcZpDRMaGjdhihXp531cVYM6LkEL8KbgM"
@@ -85,7 +100,12 @@
"package_name": "info.nightscout.nsclient2"
}
},
- "oauth_client": [],
+ "oauth_client": [
+ {
+ "client_id": "477603612366-a925drvlvs7qn7gt73r585erbqto8c79.apps.googleusercontent.com",
+ "client_type": 3
+ }
+ ],
"api_key": [
{
"current_key": "AIzaSyDcZpDRMaGjdhihXp531cVYM6LkEL8KbgM"
diff --git a/app/libs/com.atech-software.android.library.wizardpager-1.1.1.aar b/app/libs/com.atech-software.android.library.wizardpager-1.1.1.aar
new file mode 100644
index 00000000000..57e2f806bb1
Binary files /dev/null and b/app/libs/com.atech-software.android.library.wizardpager-1.1.1.aar differ
diff --git a/app/libs/ustwo-clockwise-debug.aar b/app/libs/ustwo-clockwise-debug.aar
new file mode 100644
index 00000000000..8257a991be6
Binary files /dev/null and b/app/libs/ustwo-clockwise-debug.aar differ
diff --git a/app/src/androidTest/java/info/nightscout/androidaps/ApplicationTest.java b/app/src/androidTest/java/info/nightscout/androidaps/ApplicationTest.java
deleted file mode 100644
index a047e606a91..00000000000
--- a/app/src/androidTest/java/info/nightscout/androidaps/ApplicationTest.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package info.nightscout.androidaps;
-
-import android.app.Application;
-import android.test.ApplicationTestCase;
-
-/**
- * Testing Fundamentals
- */
-public class ApplicationTest extends ApplicationTestCase {
- public ApplicationTest() {
- super(Application.class);
- }
-}
\ No newline at end of file
diff --git a/app/src/androidTest/java/info/nightscout/androidaps/EspressoHelper.kt b/app/src/androidTest/java/info/nightscout/androidaps/EspressoHelper.kt
new file mode 100644
index 00000000000..cf7118ebd28
--- /dev/null
+++ b/app/src/androidTest/java/info/nightscout/androidaps/EspressoHelper.kt
@@ -0,0 +1,35 @@
+package info.nightscout.androidaps
+
+import androidx.test.espresso.ViewAction
+import androidx.test.espresso.ViewInteraction
+import androidx.test.espresso.assertion.ViewAssertions.matches
+import androidx.test.espresso.matcher.ViewMatchers
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.uiautomator.UiDevice
+import androidx.test.uiautomator.UiSelector
+
+fun ViewInteraction.isDisplayed(): Boolean {
+ try {
+ check(matches(ViewMatchers.isDisplayed()))
+ return true
+ } catch (e: Throwable) {
+ return false
+ }
+}
+
+fun ViewInteraction.waitAndPerform(viewActions: ViewAction): ViewInteraction? {
+ val startTime = System.currentTimeMillis()
+ while (!isDisplayed()) {
+ Thread.sleep(100)
+ if (System.currentTimeMillis() - startTime >= 5000) {
+ throw AssertionError("View not visible after 5000 milliseconds")
+ }
+ }
+ return perform(viewActions)
+}
+
+fun clickOkInDialog() {
+ val uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
+ val button = uiDevice.findObject(UiSelector().clickable(true).checkable(false).index(1))
+ if (button.exists() && button.isEnabled) button.click()
+}
diff --git a/app/src/androidTest/java/info/nightscout/androidaps/RealPumpTest.kt b/app/src/androidTest/java/info/nightscout/androidaps/RealPumpTest.kt
new file mode 100644
index 00000000000..5463fbcd26e
--- /dev/null
+++ b/app/src/androidTest/java/info/nightscout/androidaps/RealPumpTest.kt
@@ -0,0 +1,116 @@
+package info.nightscout.androidaps
+
+import android.os.SystemClock
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.LargeTest
+import androidx.test.rule.ActivityTestRule
+import androidx.test.rule.GrantPermissionRule
+import info.nightscout.androidaps.data.Profile
+import info.nightscout.androidaps.interfaces.PluginBase
+import info.nightscout.androidaps.interfaces.PluginType
+import info.nightscout.androidaps.interfaces.PumpInterface
+import info.nightscout.androidaps.logging.L
+import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin
+import info.nightscout.androidaps.plugins.aps.openAPSSMB.OpenAPSSMBPlugin
+import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions
+import info.nightscout.androidaps.plugins.constraints.objectives.ObjectivesPlugin
+import info.nightscout.androidaps.plugins.general.actions.ActionsPlugin
+import info.nightscout.androidaps.plugins.insulin.InsulinOrefUltraRapidActingPlugin
+import info.nightscout.androidaps.plugins.profile.local.LocalProfilePlugin
+import info.nightscout.androidaps.plugins.pump.danaRv2.DanaRv2Plugin
+import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref1Plugin
+import info.nightscout.androidaps.plugins.source.RandomBgPlugin
+import info.nightscout.androidaps.utils.DateUtil
+import info.nightscout.androidaps.utils.SP
+import info.nightscout.androidaps.utils.isRunningTest
+import org.json.JSONObject
+import org.junit.Assert
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.slf4j.LoggerFactory
+
+@LargeTest
+@RunWith(AndroidJUnit4::class)
+class RealPumpTest {
+
+ private val log = LoggerFactory.getLogger(L.CORE)
+
+ companion object {
+ val pump: PumpInterface = DanaRv2Plugin.getPlugin()
+ const val R_PASSWORD = 1234
+ const val R_SERIAL = "PBB00013LR_P"
+ }
+
+ private val validProfile = "{\"dia\":\"6\",\"carbratio\":[{\"time\":\"00:00\",\"value\":\"30\"}],\"carbs_hr\":\"20\",\"delay\":\"20\",\"sens\":[{\"time\":\"00:00\",\"value\":\"10\"},{\"time\":\"2:00\",\"value\":\"11\"}],\"timezone\":\"UTC\",\"basal\":[{\"time\":\"00:00\",\"value\":\"0.1\"}],\"target_low\":[{\"time\":\"00:00\",\"value\":\"4\"}],\"target_high\":[{\"time\":\"00:00\",\"value\":\"5\"}],\"startDate\":\"1970-01-01T00:00:00.000Z\",\"units\":\"mmol\"}"
+
+ @Rule
+ @JvmField
+ var mActivityTestRule = ActivityTestRule(MainActivity::class.java)
+
+ @Rule
+ @JvmField
+ var mGrantPermissionRule: GrantPermissionRule =
+ GrantPermissionRule.grant(
+ android.Manifest.permission.ACCESS_FINE_LOCATION,
+ android.Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS,
+ android.Manifest.permission.WRITE_EXTERNAL_STORAGE
+ )
+
+ @Before
+ fun clear() {
+ SP.clear()
+ SP.putBoolean(R.string.key_setupwizard_processed, true)
+ SP.putString(R.string.key_aps_mode, "closed")
+ MainApp.getDbHelper().resetDatabases()
+ MainApp.devBranch = false
+ }
+
+ private fun preparePlugins() {
+ // Source
+ RandomBgPlugin.performPluginSwitch(true, PluginType.BGSOURCE)
+ // Profile
+ LocalProfilePlugin.performPluginSwitch(true, PluginType.PROFILE)
+ val profile = Profile(JSONObject(validProfile), Constants.MGDL)
+ Assert.assertTrue(profile.isValid("Test"))
+ LocalProfilePlugin.profiles.clear()
+ LocalProfilePlugin.numOfProfiles = 0
+ val singleProfile = LocalProfilePlugin.SingleProfile().copyFrom(profile, "TestProfile")
+ LocalProfilePlugin.addProfile(singleProfile)
+ ProfileFunctions.doProfileSwitch(LocalProfilePlugin.createProfileStore(), "TestProfile", 0, 100, 0, DateUtil.now())
+ // Insulin
+ InsulinOrefUltraRapidActingPlugin.getPlugin().performPluginSwitch(true, PluginType.INSULIN)
+ // Pump
+ SP.putInt(R.string.key_danar_password, R_PASSWORD)
+ SP.putString(R.string.key_danar_bt_name, R_SERIAL)
+ (pump as PluginBase).performPluginSwitch(true, PluginType.PUMP)
+ // Sensitivity
+ SensitivityOref1Plugin.getPlugin().performPluginSwitch(true, PluginType.SENSITIVITY)
+ // APS
+ OpenAPSSMBPlugin.getPlugin().performPluginSwitch(true, PluginType.APS)
+ LoopPlugin.getPlugin().performPluginSwitch(true, PluginType.LOOP)
+
+ // Enable common
+ ActionsPlugin.performPluginSwitch(true, PluginType.GENERAL)
+
+ // Disable unneeded
+ MainApp.getPluginsList().remove(ObjectivesPlugin)
+ }
+
+ @Test
+ fun doTest() {
+ Assert.assertTrue(isRunningTest())
+ preparePlugins()
+
+ while (!pump.isInitialized) {
+ log.debug("Waiting for initialization")
+ SystemClock.sleep(1000)
+ }
+
+ while (true) {
+ log.debug("Tick")
+ SystemClock.sleep(1000)
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/androidTest/java/info/nightscout/androidaps/SetupWizardActivityTest.kt b/app/src/androidTest/java/info/nightscout/androidaps/SetupWizardActivityTest.kt
new file mode 100644
index 00000000000..a2742c2a348
--- /dev/null
+++ b/app/src/androidTest/java/info/nightscout/androidaps/SetupWizardActivityTest.kt
@@ -0,0 +1,231 @@
+package info.nightscout.androidaps
+
+import android.os.SystemClock
+import android.view.View
+import android.view.ViewGroup
+import androidx.test.espresso.Espresso.onData
+import androidx.test.espresso.Espresso.onView
+import androidx.test.espresso.action.ViewActions
+import androidx.test.espresso.action.ViewActions.click
+import androidx.test.espresso.action.ViewActions.scrollTo
+import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
+import androidx.test.espresso.matcher.ViewMatchers.withClassName
+import androidx.test.espresso.matcher.ViewMatchers.withId
+import androidx.test.espresso.matcher.ViewMatchers.withTagValue
+import androidx.test.espresso.matcher.ViewMatchers.withText
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.LargeTest
+import androidx.test.rule.ActivityTestRule
+import androidx.test.rule.GrantPermissionRule
+import info.nightscout.androidaps.interfaces.PluginType
+import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin
+import info.nightscout.androidaps.plugins.aps.openAPSSMB.OpenAPSSMBPlugin
+import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions
+import info.nightscout.androidaps.plugins.constraints.objectives.ObjectivesPlugin
+import info.nightscout.androidaps.plugins.profile.local.LocalProfilePlugin
+import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin
+import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref1Plugin
+import info.nightscout.androidaps.plugins.source.RandomBgPlugin
+import info.nightscout.androidaps.setupwizard.SetupWizardActivity
+import info.nightscout.androidaps.utils.HardLimits
+import info.nightscout.androidaps.utils.SP
+import info.nightscout.androidaps.utils.isRunningTest
+import org.hamcrest.CoreMatchers.allOf
+import org.hamcrest.Description
+import org.hamcrest.Matcher
+import org.hamcrest.Matchers
+import org.hamcrest.TypeSafeMatcher
+import org.junit.Assert
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@LargeTest
+@RunWith(AndroidJUnit4::class)
+class SetupWizardActivityTest {
+
+ @Rule
+ @JvmField
+ var mActivityTestRule = ActivityTestRule(SetupWizardActivity::class.java)
+
+ @Rule
+ @JvmField
+ var mGrantPermissionRule: GrantPermissionRule =
+ GrantPermissionRule.grant(
+ android.Manifest.permission.ACCESS_FINE_LOCATION,
+ android.Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS,
+ android.Manifest.permission.WRITE_EXTERNAL_STORAGE
+ )
+
+ @Before
+ fun clear() {
+ SP.clear()
+ }
+/*
+
+To run from command line
+gradlew connectedFullDebugAndroidTest
+
+do not run when your production phone is connected !!!
+
+do this before for running in emulator
+adb shell settings put global window_animation_scale 0 &
+adb shell settings put global transition_animation_scale 0 &
+adb shell settings put global animator_duration_scale 0 &
+ */
+
+ @Test
+ fun setupWizardActivityTest() {
+ SP.clear()
+ Assert.assertTrue(isRunningTest())
+ // Welcome page
+ onView(withId(R.id.next_button)).perform(click())
+ // Language selection
+ onView(withText("English")).perform(scrollTo(), click())
+ onView(withId(R.id.next_button)).waitAndPerform(click())
+ // Agreement page
+ onView(withText("I UNDERSTAND AND AGREE")).perform(scrollTo(), click())
+ onView(withId(R.id.next_button)).waitAndPerform(click())
+ // Location permission
+ var askButton = onView(withText("Ask for permission"))
+ if (askButton.isDisplayed()) {
+ askButton.perform(scrollTo(), click())
+ onView(withId(R.id.next_button)).waitAndPerform(click())
+ }
+ // Store permission
+ askButton = onView(withText("Ask for permission"))
+ if (askButton.isDisplayed()) {
+ askButton.perform(scrollTo(), click())
+ onView(withText("OK")).perform(click())
+ onView(withId(R.id.next_button)).waitAndPerform(click())
+ }
+ // Import settings : skip of found
+ askButton = onView(withText("IMPORT SETTINGS"))
+ if (askButton.isDisplayed()) {
+ onView(withId(R.id.next_button)).waitAndPerform(click())
+ }
+ // Units selection
+ onView(withText("mmol/L")).perform(scrollTo(), click())
+ onView(withId(R.id.next_button)).perform(click())
+ // Display target selection
+ onView(withText("4.2")).perform(scrollTo(), ViewActions.replaceText("5"))
+ onView(withText("10.0")).perform(scrollTo(), ViewActions.replaceText("11"))
+ onView(withId(R.id.next_button)).perform(click())
+ // NSClient
+ onView(withId(R.id.next_button)).perform(click())
+ // Age selection
+ onView(withText("Adult")).perform(scrollTo(), click())
+ onView(withId(R.id.next_button)).waitAndPerform(click())
+ // Insulin selection
+ onView(withText("Ultra-Rapid Oref")).perform(scrollTo(), click())
+ onView(withId(R.id.next_button)).waitAndPerform(click())
+ // BG source selection
+ onView(withText("Random BG")).perform(scrollTo(), click())
+ onView(withId(R.id.next_button)).waitAndPerform(click())
+ // Profile selection
+ onView(withText("Local Profile")).perform(scrollTo(), click())
+ onView(withId(R.id.next_button)).waitAndPerform(click())
+ // Local profile - DIA
+ onView(withTagValue(Matchers.`is`("LP_DIA"))).perform(scrollTo(), ViewActions.replaceText("6.0"))
+ // Local profile - IC
+ onView(withId(R.id.ic_tab)).perform(scrollTo(), click())
+ onView(Matchers.allOf(withTagValue(Matchers.`is`("IC-1-0")), isDisplayed()))
+ .perform(ViewActions.replaceText("2"), ViewActions.closeSoftKeyboard())
+ // Local profile - ISF
+ onView(withId(R.id.isf_tab)).perform(scrollTo(), click())
+ onView(Matchers.allOf(withTagValue(Matchers.`is`("ISF-1-0")), isDisplayed()))
+ .perform(ViewActions.replaceText("3"), ViewActions.closeSoftKeyboard())
+ // Local profile - BAS
+ onView(withId(R.id.basal_tab)).perform(scrollTo(), click())
+ onView(childAtPosition(Matchers.allOf(withId(R.id.localprofile_basal), childAtPosition(withClassName(Matchers.`is`("android.widget.LinearLayout")), 6)), 2))
+ .perform(scrollTo(), click())
+ onView(Matchers.allOf(withTagValue(Matchers.`is`("BASAL-1-0")), isDisplayed()))
+ .perform(ViewActions.replaceText("1.1"), ViewActions.closeSoftKeyboard())
+ onView(Matchers.allOf(withTagValue(Matchers.`is`("BASAL-1-1")), isDisplayed()))
+ .perform(ViewActions.replaceText("1.2"), ViewActions.closeSoftKeyboard())
+ onView(Matchers.allOf(withId(R.id.timelistedit_time), childAtPosition(childAtPosition(withId(R.id.localprofile_basal), 2), 0)))
+ .perform(scrollTo(), click())
+ onData(Matchers.anything()).inAdapterView(childAtPosition(withClassName(Matchers.`is`("android.widget.PopupWindow\$PopupBackgroundView")), 0)).atPosition(13)
+ .perform(click())
+ // Local profile - TARGET
+ onView(withId(R.id.target_tab)).perform(scrollTo(), click())
+ onView(Matchers.allOf(withTagValue(Matchers.`is`("TARGET-1-0")), isDisplayed()))
+ .perform(ViewActions.replaceText("6"), ViewActions.closeSoftKeyboard())
+ onView(Matchers.allOf(withTagValue(Matchers.`is`("TARGET-2-0")), isDisplayed()))
+ .perform(ViewActions.replaceText("6.5"), ViewActions.closeSoftKeyboard())
+ onView(withText("Save")).perform(scrollTo(), click())
+ onView(Matchers.allOf(withId(R.id.localprofile_profileswitch), isDisplayed()))
+ .perform(scrollTo(), click())
+ onView(allOf(withId(R.id.ok), isDisplayed())).perform(click())
+ // confirm dialog
+ //onView(Matchers.allOf(withText("OK"), isDisplayed())).perform(click()) not working on real phone
+ clickOkInDialog()
+ onView(withId(R.id.next_button)).waitAndPerform(click())
+ // Profile switch
+ askButton = onView(withText("Do Profile Switch"))
+ if (askButton.isDisplayed()) {
+ askButton.perform(scrollTo(), click())
+ onView(allOf(withId(R.id.ok), isDisplayed())).perform(click())
+ // onView(Matchers.allOf(withText("OK"), isDisplayed())).perform(click()) not working on real phone
+ clickOkInDialog()
+ while (ProfileFunctions.getInstance().profile == null) SystemClock.sleep(100)
+ onView(withId(R.id.next_button)).waitAndPerform(click())
+ }
+ // Pump
+ onView(withText("Virtual Pump")).perform(scrollTo(), click())
+ onView(withId(R.id.next_button)).waitAndPerform(click())
+ // APS
+ onView(withText("OpenAPS SMB")).perform(scrollTo(), click())
+ onView(withId(R.id.next_button)).waitAndPerform(click())
+ // Open Closed Loop
+ onView(withText("Closed Loop")).perform(scrollTo(), click())
+ onView(withId(R.id.next_button)).waitAndPerform(click())
+ // Loop
+ askButton = onView(withText("Enable loop"))
+ if (askButton.isDisplayed()) {
+ askButton.perform(scrollTo(), click())
+ onView(withId(R.id.next_button)).waitAndPerform(click())
+ }
+ // Sensitivity
+ onView(withText("Sensitivity Oref1")).perform(scrollTo(), click())
+ onView(withId(R.id.next_button)).waitAndPerform(click())
+ // Objectives
+ onView(allOf(withText("Start"), isDisplayed())).perform(scrollTo(), click())
+ onView(withId(R.id.finish_button)).waitAndPerform(click())
+
+ // Verify settings
+ Assert.assertEquals(Constants.MMOL, ProfileFunctions.getSystemUnits())
+ Assert.assertEquals(17.0, HardLimits.maxBolus(), 0.0001) // Adult
+ Assert.assertTrue(RandomBgPlugin.isEnabled(PluginType.BGSOURCE))
+ Assert.assertTrue(LocalProfilePlugin.isEnabled(PluginType.PROFILE))
+ val p = ProfileFunctions.getInstance().profile
+ Assert.assertNotNull(p)
+ Assert.assertEquals(2.0, p!!.ic, 0.0001)
+ Assert.assertEquals(3.0 * Constants.MMOLL_TO_MGDL, p.isfMgdl, 0.0001)
+ Assert.assertEquals(1.1, p.getBasalTimeFromMidnight(0), 0.0001)
+ Assert.assertEquals(6.0 * Constants.MMOLL_TO_MGDL, p.targetLowMgdl, 0.0001)
+ Assert.assertTrue(VirtualPumpPlugin.getPlugin().isEnabled(PluginType.PUMP))
+ Assert.assertTrue(OpenAPSSMBPlugin.getPlugin().isEnabled(PluginType.APS))
+ Assert.assertTrue(LoopPlugin.getPlugin().isEnabled(PluginType.LOOP))
+ Assert.assertTrue(SensitivityOref1Plugin.getPlugin().isEnabled(PluginType.SENSITIVITY))
+ Assert.assertTrue(ObjectivesPlugin.objectives[0].isStarted)
+ }
+
+ private fun childAtPosition(
+ parentMatcher: Matcher, position: Int): Matcher {
+
+ return object : TypeSafeMatcher() {
+ override fun describeTo(description: Description) {
+ description.appendText("Child at position $position in parent ")
+ parentMatcher.describeTo(description)
+ }
+
+ public override fun matchesSafely(view: View): Boolean {
+ val parent = view.parent
+ return parent is ViewGroup && parentMatcher.matches(parent)
+ && view == parent.getChildAt(position)
+ }
+ }
+ }
+}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 3eaa81ba45a..2b020f56db1 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -17,10 +17,12 @@
+
+
-
+
@@ -34,25 +36,27 @@
android:label="@string/app_name"
android:roundIcon="${appIconRound}"
android:supportsRtl="true"
- android:theme="@style/AppTheme.NoActionBar">
+ android:theme="@style/AppTheme.Launcher"
+ android:fullBackupContent="true">
+
+
-
@@ -72,38 +76,38 @@
+
+
+ android:name=".receivers.DataReceiver"
+ android:enabled="true"
+ android:exported="true">
-
+
-
+
-
-
-
-
-
+
+
+
-
+
-
+
+ android:name=".receivers.SmsReceiver"
+ android:enabled="true"
+ android:exported="true"
+ android:permission="android.permission.BROADCAST_SMS">
-
+
@@ -112,7 +116,7 @@
@@ -120,24 +124,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
@@ -147,7 +133,7 @@
@@ -159,6 +145,10 @@
+
+ android:exported="false" />
@@ -242,11 +232,11 @@
+ android:exported="false" />
+ android:exported="false" />
@@ -281,6 +271,41 @@
android:name=".plugins.pump.insight.activities.InsightPairingInformationActivity"
android:label="@string/pairing_information"
android:theme="@style/AppTheme" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/assets/OpenAPSAMA/loggerhelper.js b/app/src/main/assets/OpenAPSAMA/loggerhelper.js
index e790f465c8f..81c19b5a38b 100644
--- a/app/src/main/assets/OpenAPSAMA/loggerhelper.js
+++ b/app/src/main/assets/OpenAPSAMA/loggerhelper.js
@@ -1,12 +1,33 @@
var console = { };
console.error = function error(){
+ var s = '';
for (var i = 0, len = arguments.length; i < len; i++) {
- console2.log(arguments[i]);
+ if (i > 0) s = s + ' ';
+ if (typeof arguments[i] === 'undefined') {
+ s = s + 'undefined';
+ } else if (typeof arguments[i] === 'object') {
+ s = s + JSON.stringify(arguments[i]);
+ } else {
+ s = s + arguments[i].toString();
+ }
}
+ s = s + "\n";
+ console2.log(s);
};
console.log = function log(){
+ var s = '';
for (var i = 0, len = arguments.length; i < len; i++) {
- console2.log(arguments[i]);
+ if (i > 0) s = s + ' ';
+ if (typeof arguments[i] === 'undefined') {
+ s = s + 'undefined';
+ } else if (typeof arguments[i] === 'object') {
+ s = s + JSON.stringify(arguments[i]);
+ } else {
+ s = s + arguments[i].toString();
+ }
+ //console2.log(arguments[i]);
}
+ s = s + "\n";
+ console2.log(s);
};
diff --git a/app/src/main/assets/revoked_certs.txt b/app/src/main/assets/revoked_certs.txt
new file mode 100644
index 00000000000..41177d5667b
--- /dev/null
+++ b/app/src/main/assets/revoked_certs.txt
@@ -0,0 +1,4 @@
+#Demo certificate
+51:6D:12:67:4C:27:F4:9B:9F:E5:42:9B:01:B3:98:E4:66:2B:85:B7:A8:DD:70:32:B7:6A:D7:97:9A:0D:97:10
+#Leaked
+55:5D:70:C9:BE:10:41:7E:4B:01:A9:C4:C6:44:4A:F8:69:71:35:25:ED:95:23:16:C7:15:E8:EB:C6:08:FC:B1
diff --git a/app/src/main/java/com/squareup/otto/LoggingBus.java b/app/src/main/java/com/squareup/otto/LoggingBus.java
deleted file mode 100644
index d9758a9a24e..00000000000
--- a/app/src/main/java/com/squareup/otto/LoggingBus.java
+++ /dev/null
@@ -1,96 +0,0 @@
-package com.squareup.otto;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-import java.util.ConcurrentModificationException;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-import info.nightscout.androidaps.events.Event;
-import info.nightscout.androidaps.logging.L;
-
-/**
- * Logs events has they're being posted to and dispatched from the event bus.
- *
- * A summary of event-receiver calls that occurred so far is logged
- * after 10s (after startup) and then again every 60s.
- */
-public class LoggingBus extends Bus {
- private static Logger log = LoggerFactory.getLogger(L.EVENTS);
-
- private static long everyMinute = System.currentTimeMillis() + 10 * 1000;
- private Map> event2Receiver = new HashMap<>();
-
- public LoggingBus(ThreadEnforcer enforcer) {
- super(enforcer);
- }
-
- @Override
- public void post(Object event) {
- if (event instanceof DeadEvent) {
- log.debug("Event has no receiver: " + ((DeadEvent) event).event + ", source: " + ((DeadEvent) event).source);
- return;
- }
-
- if (!(event instanceof Event)) {
- log.error("Posted event not an event class: " + event.getClass());
- }
-
- log.debug("<<< " + event);
- try {
- StackTraceElement caller = new Throwable().getStackTrace()[1];
- String className = caller.getClassName();
- className = className.substring(className.lastIndexOf(".") + 1);
- log.debug(" source: " + className + "." + caller.getMethodName() + ":" + caller.getLineNumber());
- } catch (RuntimeException e) {
- log.debug(" source: ");
- }
-
- try {
- super.post(event);
- } catch (IllegalStateException ignored) {
- }
- }
-
- @Override
- protected void dispatch(Object event, EventHandler wrapper) {
- try {
- log.debug(">>> " + event);
- Field methodField = wrapper.getClass().getDeclaredField("method");
- methodField.setAccessible(true);
- Method targetMethod = (Method) methodField.get(wrapper);
- String className = targetMethod.getDeclaringClass().getSimpleName();
- String methodName = targetMethod.getName();
- String receiverMethod = className + "." + methodName;
- log.debug(" receiver: " + receiverMethod);
-
- String key = event.getClass().getSimpleName();
- if (!event2Receiver.containsKey(key)) event2Receiver.put(key, new HashSet());
- event2Receiver.get(key).add(receiverMethod);
- } catch (ReflectiveOperationException e) {
- log.debug(" receiver: ");
- }
-
- try {
- if (everyMinute < System.currentTimeMillis()) {
- log.debug("***************** Event -> receiver pairings seen so far ****************");
- for (Map.Entry> stringSetEntry : event2Receiver.entrySet()) {
- log.debug(" " + stringSetEntry.getKey());
- for (String s : stringSetEntry.getValue()) {
- log.debug(" -> " + s);
- }
- }
- log.debug("*************************************************************************");
- everyMinute = System.currentTimeMillis() + 60 * 1000;
- }
- } catch (ConcurrentModificationException ignored) {
- }
-
- super.dispatch(event, wrapper);
- }
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/Config.java b/app/src/main/java/info/nightscout/androidaps/Config.java
index ae0e14c9b69..bb967cdeb67 100644
--- a/app/src/main/java/info/nightscout/androidaps/Config.java
+++ b/app/src/main/java/info/nightscout/androidaps/Config.java
@@ -12,13 +12,4 @@ public class Config {
public static final boolean PUMPCONTROL = BuildConfig.FLAVOR.equals("pumpcontrol");
public static final boolean PUMPDRIVERS = BuildConfig.FLAVOR.equals("full") || BuildConfig.FLAVOR.equals("pumpcontrol");
-
- public static final boolean ACTION = !NSCLIENT;
- public static final boolean MDI = !NSCLIENT;
- public static final boolean OTHERPROFILES = !NSCLIENT;
- public static final boolean SAFETY = !NSCLIENT;
-
- public static final boolean SMSCOMMUNICATORENABLED = !NSCLIENT;
-
-
}
diff --git a/app/src/main/java/info/nightscout/androidaps/Constants.java b/app/src/main/java/info/nightscout/androidaps/Constants.java
index 2ecabfe9659..fb322a82394 100644
--- a/app/src/main/java/info/nightscout/androidaps/Constants.java
+++ b/app/src/main/java/info/nightscout/androidaps/Constants.java
@@ -25,17 +25,17 @@ public class Constants {
public static final int hoursToKeepInDatabase = 72;
public static final int daysToKeepHistoryInDatabase = 30;
- public static final long keepAliveMsecs = 5 * 60 * 1000L;
-
// SMS COMMUNICATOR
public static final long remoteBolusMinDistance = 15 * 60 * 1000L;
// Circadian Percentage Profile
- public static final int CPP_MIN_PERCENTAGE = 50;
+ public static final int CPP_MIN_PERCENTAGE = 30;
public static final int CPP_MAX_PERCENTAGE = 200;
public static final int CPP_MIN_TIMESHIFT = -6;
public static final int CPP_MAX_TIMESHIFT = 23;
+ public static final double MAX_PROFILE_SWITCH_DURATION = 7 * 24 * 60; // [min] ~ 7 days
+
//DanaR
public static final double dailyLimitWarning = 0.95d;
@@ -50,6 +50,11 @@ public class Constants {
public static final double defaultHypoTTmgdl = 120d;
public static final double defaultHypoTTmmol = 6.5d;
+ public static final double MIN_TT_MGDL = 72d;
+ public static final double MAX_TT_MGDL = 180d;
+ public static final double MIN_TT_MMOL = 4d;
+ public static final double MAX_TT_MMOL = 10d;
+
//NSClientInternal
public static final int MAX_LOG_LINES = 100;
@@ -71,4 +76,15 @@ public class Constants {
//Storage [MB]
public static final long MINIMUM_FREE_SPACE = 200;
+ // Overview
+ public static final double LOWMARK = 76.0;
+ public static final double HIGHMARK = 180.0;
+
+ // STATISTICS
+ public static final double STATS_TARGET_LOW_MMOL = 3.9;
+ public static final double STATS_TARGET_HIGH_MMOL = 7.8;
+ public static final double STATS_RANGE_LOW_MMOL = 3.9;
+ public static final double STATS_RANGE_HIGH_MMOL = 10.0;
+
+
}
diff --git a/app/src/main/java/info/nightscout/androidaps/MainActivity.java b/app/src/main/java/info/nightscout/androidaps/MainActivity.java
index 6779b0a4673..c152c415cb5 100644
--- a/app/src/main/java/info/nightscout/androidaps/MainActivity.java
+++ b/app/src/main/java/info/nightscout/androidaps/MainActivity.java
@@ -6,17 +6,6 @@
import android.graphics.Rect;
import android.os.Bundle;
import android.os.PersistableBundle;
-import android.os.PowerManager;
-import android.support.annotation.Nullable;
-import android.support.design.widget.NavigationView;
-import android.support.design.widget.TabLayout;
-import android.support.v4.app.ActivityCompat;
-import android.support.v4.view.ViewPager;
-import android.support.v4.widget.DrawerLayout;
-import android.support.v7.app.ActionBarDrawerToggle;
-import android.support.v7.app.AlertDialog;
-import android.support.v7.app.AppCompatActivity;
-import android.support.v7.widget.Toolbar;
import android.text.SpannableString;
import android.text.method.LinkMovementMethod;
import android.text.util.Linkify;
@@ -31,29 +20,38 @@
import android.widget.LinearLayout;
import android.widget.TextView;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.ActionBarDrawerToggle;
+import androidx.appcompat.app.AlertDialog;
+import androidx.appcompat.widget.Toolbar;
+import androidx.core.app.ActivityCompat;
+import androidx.drawerlayout.widget.DrawerLayout;
+import androidx.viewpager.widget.ViewPager;
+
+import com.google.android.material.navigation.NavigationView;
+import com.google.android.material.tabs.TabLayout;
import com.joanzapata.iconify.Iconify;
import com.joanzapata.iconify.fonts.FontAwesomeModule;
-import com.squareup.otto.Subscribe;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import info.nightscout.androidaps.activities.AgreementActivity;
import info.nightscout.androidaps.activities.HistoryBrowseActivity;
+import info.nightscout.androidaps.activities.NoSplashAppCompatActivity;
import info.nightscout.androidaps.activities.PreferencesActivity;
import info.nightscout.androidaps.activities.SingleFragmentActivity;
-import info.nightscout.androidaps.data.Profile;
+import info.nightscout.androidaps.activities.StatsActivity;
import info.nightscout.androidaps.events.EventAppExit;
-import info.nightscout.androidaps.events.EventFeatureRunning;
import info.nightscout.androidaps.events.EventPreferenceChange;
-import info.nightscout.androidaps.events.EventRefreshGui;
+import info.nightscout.androidaps.events.EventRebuildTabs;
import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.PluginType;
import info.nightscout.androidaps.logging.L;
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin;
-import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions;
+import info.nightscout.androidaps.plugins.bus.RxBus;
+import info.nightscout.androidaps.plugins.constraints.versionChecker.VersionCheckerUtilsKt;
import info.nightscout.androidaps.plugins.general.nsclient.data.NSSettingsStatus;
-import info.nightscout.androidaps.plugins.general.versionChecker.VersionCheckerUtilsKt;
import info.nightscout.androidaps.setupwizard.SetupWizardActivity;
import info.nightscout.androidaps.tabs.TabPageAdapter;
import info.nightscout.androidaps.utils.AndroidPermission;
@@ -62,25 +60,25 @@
import info.nightscout.androidaps.utils.OKDialog;
import info.nightscout.androidaps.utils.PasswordProtection;
import info.nightscout.androidaps.utils.SP;
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.disposables.CompositeDisposable;
-public class MainActivity extends AppCompatActivity {
- private static Logger log = LoggerFactory.getLogger(L.CORE);
+import static info.nightscout.androidaps.utils.EspressoTestHelperKt.isRunningRealPumpTest;
- protected PowerManager.WakeLock mWakeLock;
+public class MainActivity extends NoSplashAppCompatActivity {
+ private static Logger log = LoggerFactory.getLogger(L.CORE);
+ private CompositeDisposable disposable = new CompositeDisposable();
private ActionBarDrawerToggle actionBarDrawerToggle;
private MenuItem pluginPreferencesMenuItem;
@Override
- protected void onCreate(Bundle savedInstanceState) {
+ public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- if (L.isEnabled(L.CORE))
- log.debug("onCreate");
-
Iconify.with(new FontAwesomeModule());
- LocaleHelper.onCreate(this, "en");
+ LocaleHelper.INSTANCE.update(getApplicationContext());
setContentView(R.layout.activity_main);
setSupportActionBar(findViewById(R.id.toolbar));
@@ -94,13 +92,7 @@ protected void onCreate(Bundle savedInstanceState) {
actionBarDrawerToggle.syncState();
// initialize screen wake lock
- onEventPreferenceChange(new EventPreferenceChange(R.string.key_keep_screen_on));
-
- doMigrations();
-
- registerBus();
- setupTabs();
- setupViews(false);
+ processPreferenceChange(new EventPreferenceChange(R.string.key_keep_screen_on));
final ViewPager viewPager = findViewById(R.id.pager);
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@@ -123,6 +115,42 @@ public void onPageScrollStateChanged(int state) {
VersionCheckerUtilsKt.triggerCheckVersion();
FabricPrivacy.setUserStats();
+
+ setupTabs();
+ setupViews();
+
+ disposable.add(RxBus.INSTANCE
+ .toObservable(EventRebuildTabs.class)
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(event -> {
+ LocaleHelper.INSTANCE.update(getApplicationContext());
+ if (event.getRecreate()) {
+ recreate();
+ } else {
+ setupTabs();
+ setupViews();
+ }
+ setWakeLock();
+ }, FabricPrivacy::logException)
+ );
+ disposable.add(RxBus.INSTANCE
+ .toObservable(EventPreferenceChange.class)
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(this::processPreferenceChange, FabricPrivacy::logException)
+ );
+
+ if (!SP.getBoolean(R.string.key_setupwizard_processed, false) && !isRunningRealPumpTest()) {
+ Intent intent = new Intent(this, SetupWizardActivity.class);
+ startActivity(intent);
+ }
+
+ AndroidPermission.notifyForStoragePermission(this);
+ AndroidPermission.notifyForBatteryOptimizationPermission(this);
+ if (Config.PUMPDRIVERS) {
+ AndroidPermission.notifyForLocationPermissions(this);
+ AndroidPermission.notifyForSMSPermissions(this);
+ AndroidPermission.notifyForSystemWindowPermissions(this);
+ }
}
private void checkPluginPreferences(ViewPager viewPager) {
@@ -138,86 +166,29 @@ public void onPostCreate(@Nullable Bundle savedInstanceState, @Nullable Persista
actionBarDrawerToggle.syncState();
}
- @Override
- protected void onResume() {
- super.onResume();
-
- if (L.isEnabled(L.CORE))
- log.debug("onResume");
-
- if (!SP.getBoolean(R.string.key_setupwizard_processed, false)) {
- Intent intent = new Intent(this, SetupWizardActivity.class);
- startActivity(intent);
- } else {
- checkEula();
- }
-
- AndroidPermission.notifyForStoragePermission(this);
- AndroidPermission.notifyForBatteryOptimizationPermission(this);
- if (Config.PUMPDRIVERS) {
- AndroidPermission.notifyForLocationPermissions(this);
- AndroidPermission.notifyForSMSPermissions(this);
- }
-
- MainApp.bus().post(new EventFeatureRunning(EventFeatureRunning.Feature.MAIN));
- }
-
@Override
public void onDestroy() {
- if (L.isEnabled(L.CORE))
- log.debug("onDestroy");
- if (mWakeLock != null)
- if (mWakeLock.isHeld())
- mWakeLock.release();
super.onDestroy();
+ disposable.clear();
}
- @Subscribe
- public void onEventPreferenceChange(final EventPreferenceChange ev) {
- if (ev.isChanged(R.string.key_keep_screen_on)) {
- boolean keepScreenOn = SP.getBoolean(R.string.key_keep_screen_on, false);
- final PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
- if (keepScreenOn) {
- mWakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "AndroidAPS:MainActivity_onEventPreferenceChange");
- if (!mWakeLock.isHeld())
- mWakeLock.acquire();
- } else {
- if (mWakeLock != null && mWakeLock.isHeld())
- mWakeLock.release();
- }
- }
+ private void setWakeLock() {
+ boolean keepScreenOn = SP.getBoolean(R.string.key_keep_screen_on, false);
+ if (keepScreenOn)
+ getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+ else
+ getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
- @Subscribe
- public void onStatusEvent(final EventRefreshGui ev) {
- String lang = SP.getString(R.string.key_language, "en");
- LocaleHelper.setLocale(getApplicationContext(), lang);
- runOnUiThread(() -> {
- if (ev.recreate) {
- recreate();
- } else {
- try { // activity may be destroyed
- setupTabs();
- setupViews(true);
- } catch (IllegalStateException e) {
- log.error("Unhandled exception", e);
- }
- }
-
- boolean keepScreenOn = Config.NSCLIENT && SP.getBoolean(R.string.key_keep_screen_on, false);
- if (keepScreenOn)
- getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
- else
- getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
- });
+ public void processPreferenceChange(final EventPreferenceChange ev) {
+ if (ev.isChanged(R.string.key_keep_screen_on))
+ setWakeLock();
}
- private void setupViews(boolean switchToLast) {
+ private void setupViews() {
TabPageAdapter pageAdapter = new TabPageAdapter(getSupportFragmentManager(), this);
NavigationView navigationView = findViewById(R.id.navigation_view);
- navigationView.setNavigationItemSelectedListener(menuItem -> {
- return true;
- });
+ navigationView.setNavigationItemSelectedListener(menuItem -> true);
Menu menu = navigationView.getMenu();
menu.clear();
for (PluginBase p : MainApp.getPluginsList()) {
@@ -236,8 +207,8 @@ private void setupViews(boolean switchToLast) {
}
ViewPager mPager = findViewById(R.id.pager);
mPager.setAdapter(pageAdapter);
- if (switchToLast)
- mPager.setCurrentItem(pageAdapter.getCount() - 1, false);
+ //if (switchToLast)
+ // mPager.setCurrentItem(pageAdapter.getCount() - 1, false);
checkPluginPreferences(mPager);
}
@@ -263,78 +234,21 @@ private void setupTabs() {
}
}
- private void registerBus() {
- try {
- MainApp.bus().unregister(this);
- } catch (RuntimeException x) {
- // Ignore
- }
- MainApp.bus().register(this);
- }
-
- private void checkEula() {
- //SP.removeBoolean(R.string.key_i_understand);
- boolean IUnderstand = SP.getBoolean(R.string.key_i_understand, false);
- if (!IUnderstand) {
- Intent intent = new Intent(getApplicationContext(), AgreementActivity.class);
- startActivity(intent);
- finish();
- }
- }
-
- private void doMigrations() {
-
- checkUpgradeToProfileTarget();
-
- // guarantee that the unreachable threshold is at least 30 and of type String
- // Added in 1.57 at 21.01.2018
- Integer unreachable_threshold = SP.getInt(R.string.key_pump_unreachable_threshold, 30);
- SP.remove(R.string.key_pump_unreachable_threshold);
- if (unreachable_threshold < 30) unreachable_threshold = 30;
- SP.putString(R.string.key_pump_unreachable_threshold, unreachable_threshold.toString());
- }
-
-
- private void checkUpgradeToProfileTarget() { // TODO: can be removed in the future
- boolean oldKeyExists = SP.contains("openapsma_min_bg");
- if (oldKeyExists) {
- Profile profile = ProfileFunctions.getInstance().getProfile();
- String oldRange = SP.getDouble("openapsma_min_bg", 0d) + " - " + SP.getDouble("openapsma_max_bg", 0d);
- String newRange = "";
- if (profile != null) {
- newRange = profile.getTargetLow() + " - " + profile.getTargetHigh();
- }
- String message = "Target range is changed in current version.\n\nIt's not taken from preferences but from profile.\n\n!!! REVIEW YOUR SETTINGS !!!";
- message += "\n\nOld settings: " + oldRange;
- message += "\nProfile settings: " + newRange;
- OKDialog.show(this, "Target range change", message, new Runnable() {
- @Override
- public void run() {
- SP.remove("openapsma_min_bg");
- SP.remove("openapsma_max_bg");
- SP.remove("openapsma_target_bg");
- }
- });
- }
- }
-
@Override
- public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
+ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (permissions.length != 0) {
if (ActivityCompat.checkSelfPermission(this, permissions[0]) == PackageManager.PERMISSION_GRANTED) {
switch (requestCode) {
case AndroidPermission.CASE_STORAGE:
//show dialog after permission is granted
- AlertDialog.Builder alert = new AlertDialog.Builder(this);
- alert.setMessage(R.string.alert_dialog_storage_permission_text);
- alert.setPositiveButton(R.string.ok, null);
- alert.show();
+ OKDialog.show(this, "", MainApp.gs(R.string.alert_dialog_storage_permission_text));
break;
case AndroidPermission.CASE_LOCATION:
case AndroidPermission.CASE_SMS:
case AndroidPermission.CASE_BATTERY:
- case AndroidPermission.CASE_PHONESTATE:
+ case AndroidPermission.CASE_PHONE_STATE:
+ case AndroidPermission.CASE_SYSTEM_WINDOW:
break;
}
}
@@ -403,9 +317,7 @@ public boolean onOptionsItemSelected(MenuItem item) {
return true;
case R.id.nav_exit:
log.debug("Exiting");
- MainApp.instance().stopKeepAliveService();
- MainApp.bus().post(new EventAppExit());
- MainApp.closeDbHelper();
+ RxBus.INSTANCE.send(new EventAppExit());
finish();
System.runFinalization();
System.exit(0);
@@ -419,6 +331,14 @@ public boolean onOptionsItemSelected(MenuItem item) {
startActivity(i);
}, null);
return true;
+/*
+ case R.id.nav_survey:
+ startActivity(new Intent(this, SurveyActivity.class));
+ return true;
+*/
+ case R.id.nav_stats:
+ startActivity(new Intent(this, StatsActivity.class));
+ return true;
}
return actionBarDrawerToggle.onOptionsItemSelected(item);
}
diff --git a/app/src/main/java/info/nightscout/androidaps/MainApp.java b/app/src/main/java/info/nightscout/androidaps/MainApp.java
index 32594830332..da4ad4a1b3e 100644
--- a/app/src/main/java/info/nightscout/androidaps/MainApp.java
+++ b/app/src/main/java/info/nightscout/androidaps/MainApp.java
@@ -4,19 +4,20 @@
import android.content.IntentFilter;
import android.content.res.Resources;
import android.os.SystemClock;
-import android.support.annotation.Nullable;
-import android.support.annotation.PluralsRes;
-import android.support.v4.content.LocalBroadcastManager;
+
+import androidx.annotation.ColorRes;
+import androidx.annotation.PluralsRes;
+import androidx.annotation.StringRes;
+import androidx.core.content.ContextCompat;
+import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import com.crashlytics.android.Crashlytics;
import com.google.firebase.analytics.FirebaseAnalytics;
import com.j256.ormlite.android.apptools.OpenHelperManager;
-import com.squareup.otto.Bus;
-import com.squareup.otto.LoggingBus;
-import com.squareup.otto.ThreadEnforcer;
import net.danlew.android.joda.JodaTimeAndroid;
+import org.json.JSONException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -24,6 +25,7 @@
import java.util.ArrayList;
import info.nightscout.androidaps.data.ConstraintChecker;
+import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.db.DatabaseHelper;
import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.PluginType;
@@ -34,23 +36,24 @@
import info.nightscout.androidaps.plugins.aps.openAPSMA.OpenAPSMAPlugin;
import info.nightscout.androidaps.plugins.aps.openAPSSMB.OpenAPSSMBPlugin;
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin;
+import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions;
import info.nightscout.androidaps.plugins.constraints.dstHelper.DstHelperPlugin;
import info.nightscout.androidaps.plugins.constraints.objectives.ObjectivesPlugin;
import info.nightscout.androidaps.plugins.constraints.safety.SafetyPlugin;
+import info.nightscout.androidaps.plugins.constraints.signatureVerifier.SignatureVerifierPlugin;
import info.nightscout.androidaps.plugins.constraints.storage.StorageConstraintPlugin;
-import info.nightscout.androidaps.plugins.general.actions.ActionsFragment;
+import info.nightscout.androidaps.plugins.constraints.versionChecker.VersionCheckerPlugin;
+import info.nightscout.androidaps.plugins.general.actions.ActionsPlugin;
+import info.nightscout.androidaps.plugins.general.automation.AutomationPlugin;
import info.nightscout.androidaps.plugins.general.careportal.CareportalPlugin;
import info.nightscout.androidaps.plugins.general.food.FoodPlugin;
import info.nightscout.androidaps.plugins.general.maintenance.LoggerUtils;
import info.nightscout.androidaps.plugins.general.maintenance.MaintenancePlugin;
import info.nightscout.androidaps.plugins.general.nsclient.NSClientPlugin;
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload;
-import info.nightscout.androidaps.plugins.general.nsclient.receivers.AckAlarmReceiver;
-import info.nightscout.androidaps.plugins.general.nsclient.receivers.DBAccessReceiver;
import info.nightscout.androidaps.plugins.general.overview.OverviewPlugin;
import info.nightscout.androidaps.plugins.general.persistentNotification.PersistentNotificationPlugin;
import info.nightscout.androidaps.plugins.general.smsCommunicator.SmsCommunicatorPlugin;
-import info.nightscout.androidaps.plugins.general.versionChecker.VersionCheckerPlugin;
import info.nightscout.androidaps.plugins.general.wear.WearPlugin;
import info.nightscout.androidaps.plugins.general.xdripStatusline.StatuslinePlugin;
import info.nightscout.androidaps.plugins.insulin.InsulinOrefFreePeakPlugin;
@@ -59,7 +62,6 @@
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin;
import info.nightscout.androidaps.plugins.profile.local.LocalProfilePlugin;
import info.nightscout.androidaps.plugins.profile.ns.NSProfilePlugin;
-import info.nightscout.androidaps.plugins.profile.simple.SimpleProfilePlugin;
import info.nightscout.androidaps.plugins.pump.combo.ComboPlugin;
import info.nightscout.androidaps.plugins.pump.danaR.DanaRPlugin;
import info.nightscout.androidaps.plugins.pump.danaRKorean.DanaRKoreanPlugin;
@@ -67,13 +69,15 @@
import info.nightscout.androidaps.plugins.pump.danaRv2.DanaRv2Plugin;
import info.nightscout.androidaps.plugins.pump.insight.LocalInsightPlugin;
import info.nightscout.androidaps.plugins.pump.mdi.MDIPlugin;
+import info.nightscout.androidaps.plugins.pump.medtronic.MedtronicPumpPlugin;
+import info.nightscout.androidaps.plugins.pump.omnipod.OmnipodPumpPlugin;
import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin;
import info.nightscout.androidaps.plugins.sensitivity.SensitivityAAPSPlugin;
import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref0Plugin;
import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref1Plugin;
import info.nightscout.androidaps.plugins.sensitivity.SensitivityWeightedAveragePlugin;
-import info.nightscout.androidaps.plugins.source.SourceDexcomG5Plugin;
-import info.nightscout.androidaps.plugins.source.SourceDexcomG6Plugin;
+import info.nightscout.androidaps.plugins.source.RandomBgPlugin;
+import info.nightscout.androidaps.plugins.source.SourceDexcomPlugin;
import info.nightscout.androidaps.plugins.source.SourceEversensePlugin;
import info.nightscout.androidaps.plugins.source.SourceGlimpPlugin;
import info.nightscout.androidaps.plugins.source.SourceMM640gPlugin;
@@ -85,18 +89,20 @@
import info.nightscout.androidaps.receivers.DataReceiver;
import info.nightscout.androidaps.receivers.KeepAliveReceiver;
import info.nightscout.androidaps.receivers.NSAlarmReceiver;
+import info.nightscout.androidaps.receivers.TimeDateOrTZChangeReceiver;
import info.nightscout.androidaps.services.Intents;
+import info.nightscout.androidaps.utils.ActivityMonitor;
import info.nightscout.androidaps.utils.FabricPrivacy;
+import info.nightscout.androidaps.utils.LocaleHelper;
+import info.nightscout.androidaps.utils.SP;
import io.fabric.sdk.android.Fabric;
-import static info.nightscout.androidaps.plugins.general.versionChecker.VersionCheckerUtilsKt.triggerCheckVersion;
+import static info.nightscout.androidaps.plugins.constraints.versionChecker.VersionCheckerUtilsKt.triggerCheckVersion;
public class MainApp extends Application {
private static Logger log = LoggerFactory.getLogger(L.CORE);
- private static KeepAliveReceiver keepAliveReceiver;
- private static Bus sBus;
private static MainApp sInstance;
public static Resources sResources;
@@ -108,10 +114,8 @@ public class MainApp extends Application {
private static ArrayList pluginsList = null;
private static DataReceiver dataReceiver = new DataReceiver();
- private static NSAlarmReceiver alarmReciever = new NSAlarmReceiver();
- private static AckAlarmReceiver ackAlarmReciever = new AckAlarmReceiver();
- private static DBAccessReceiver dbAccessReciever = new DBAccessReceiver();
- private LocalBroadcastManager lbm;
+ private static NSAlarmReceiver alarmReceiver = new NSAlarmReceiver();
+ TimeDateOrTZChangeReceiver timeDateOrTZChangeReceiver;
public static boolean devBranch;
public static boolean engineeringMode;
@@ -122,9 +126,19 @@ public void onCreate() {
log.debug("onCreate");
sInstance = this;
sResources = getResources();
+ LocaleHelper.INSTANCE.update(this);
sConstraintsChecker = new ConstraintChecker();
sDatabaseHelper = OpenHelperManager.getHelper(sInstance, DatabaseHelper.class);
+ Thread.setDefaultUncaughtExceptionHandler((thread, ex) -> {
+ if (ex instanceof InternalError) {
+ // usually the app trying to spawn a thread while being killed
+ return;
+ }
+
+ log.error("Uncaught exception crashing app", ex);
+ });
+
try {
if (FabricPrivacy.fabricEnabled()) {
Fabric.with(this, new Crashlytics());
@@ -133,7 +147,10 @@ public void onCreate() {
log.error("Error with Fabric init! " + e);
}
+ registerActivityLifecycleCallbacks(ActivityMonitor.INSTANCE);
+
mFirebaseAnalytics = FirebaseAnalytics.getInstance(this);
+ mFirebaseAnalytics.setAnalyticsCollectionEnabled(!Boolean.getBoolean("disableFirebase"));
JodaTimeAndroid.init(this);
@@ -145,9 +162,7 @@ public void onCreate() {
File engineeringModeSemaphore = new File(extFilesDir, "engineering_mode");
engineeringMode = engineeringModeSemaphore.exists() && engineeringModeSemaphore.isFile();
- devBranch = BuildConfig.VERSION.contains("dev");
-
- sBus = L.isEnabled(L.EVENTS) && devBranch ? new LoggingBus(ThreadEnforcer.ANY) : new Bus(ThreadEnforcer.ANY);
+ devBranch = BuildConfig.VERSION.contains("-") || BuildConfig.VERSION.matches(".*[a-zA-Z]+.*");
registerLocalBroadcastReceiver();
@@ -157,9 +172,9 @@ public void onCreate() {
if (pluginsList == null) {
pluginsList = new ArrayList<>();
// Register all tabs in app here
- pluginsList.add(OverviewPlugin.getPlugin());
+ pluginsList.add(OverviewPlugin.INSTANCE);
pluginsList.add(IobCobCalculatorPlugin.getPlugin());
- if (Config.ACTION) pluginsList.add(ActionsFragment.getPlugin());
+ if (!Config.NSCLIENT) pluginsList.add(ActionsPlugin.INSTANCE);
pluginsList.add(InsulinOrefRapidActingPlugin.getPlugin());
pluginsList.add(InsulinOrefUltraRapidActingPlugin.getPlugin());
pluginsList.add(InsulinOrefFreePeakPlugin.getPlugin());
@@ -172,39 +187,44 @@ public void onCreate() {
if (Config.PUMPDRIVERS) pluginsList.add(DanaRv2Plugin.getPlugin());
if (Config.PUMPDRIVERS) pluginsList.add(DanaRSPlugin.getPlugin());
if (Config.PUMPDRIVERS) pluginsList.add(LocalInsightPlugin.getPlugin());
- pluginsList.add(CareportalPlugin.getPlugin());
if (Config.PUMPDRIVERS) pluginsList.add(ComboPlugin.getPlugin());
- if (Config.MDI) pluginsList.add(MDIPlugin.getPlugin());
+ if (Config.PUMPDRIVERS) pluginsList.add(MedtronicPumpPlugin.getPlugin());
+ if (Config.PUMPDRIVERS && engineeringMode)
+ pluginsList.add(OmnipodPumpPlugin.getPlugin());
+ if (!Config.NSCLIENT) pluginsList.add(MDIPlugin.getPlugin());
pluginsList.add(VirtualPumpPlugin.getPlugin());
+ if (Config.NSCLIENT) pluginsList.add(CareportalPlugin.getPlugin());
if (Config.APS) pluginsList.add(LoopPlugin.getPlugin());
if (Config.APS) pluginsList.add(OpenAPSMAPlugin.getPlugin());
if (Config.APS) pluginsList.add(OpenAPSAMAPlugin.getPlugin());
if (Config.APS) pluginsList.add(OpenAPSSMBPlugin.getPlugin());
pluginsList.add(NSProfilePlugin.getPlugin());
- if (Config.OTHERPROFILES) pluginsList.add(SimpleProfilePlugin.getPlugin());
- if (Config.OTHERPROFILES) pluginsList.add(LocalProfilePlugin.getPlugin());
+ if (!Config.NSCLIENT) pluginsList.add(LocalProfilePlugin.INSTANCE);
pluginsList.add(TreatmentsPlugin.getPlugin());
- if (Config.SAFETY) pluginsList.add(SafetyPlugin.getPlugin());
- if (Config.SAFETY) pluginsList.add(VersionCheckerPlugin.INSTANCE);
- if (Config.SAFETY) pluginsList.add(StorageConstraintPlugin.getPlugin());
- if (Config.APS) pluginsList.add(ObjectivesPlugin.getPlugin());
+ if (!Config.NSCLIENT) pluginsList.add(SafetyPlugin.getPlugin());
+ if (!Config.NSCLIENT) pluginsList.add(VersionCheckerPlugin.INSTANCE);
+ if (Config.APS) pluginsList.add(StorageConstraintPlugin.getPlugin());
+ if (Config.APS) pluginsList.add(SignatureVerifierPlugin.getPlugin());
+ if (Config.APS) pluginsList.add(ObjectivesPlugin.INSTANCE);
pluginsList.add(SourceXdripPlugin.getPlugin());
pluginsList.add(SourceNSClientPlugin.getPlugin());
pluginsList.add(SourceMM640gPlugin.getPlugin());
pluginsList.add(SourceGlimpPlugin.getPlugin());
- pluginsList.add(SourceDexcomG5Plugin.getPlugin());
- pluginsList.add(SourceDexcomG6Plugin.getPlugin());
+ pluginsList.add(SourceDexcomPlugin.INSTANCE);
pluginsList.add(SourcePoctechPlugin.getPlugin());
pluginsList.add(SourceTomatoPlugin.getPlugin());
pluginsList.add(SourceEversensePlugin.getPlugin());
- if (Config.SMSCOMMUNICATORENABLED) pluginsList.add(SmsCommunicatorPlugin.getPlugin());
+ pluginsList.add(RandomBgPlugin.INSTANCE);
+ if (!Config.NSCLIENT) pluginsList.add(SmsCommunicatorPlugin.INSTANCE);
pluginsList.add(FoodPlugin.getPlugin());
pluginsList.add(WearPlugin.initPlugin(this));
pluginsList.add(StatuslinePlugin.initPlugin(this));
pluginsList.add(PersistentNotificationPlugin.getPlugin());
pluginsList.add(NSClientPlugin.getPlugin());
+// if (engineeringMode) pluginsList.add(TidepoolPlugin.INSTANCE);
pluginsList.add(MaintenancePlugin.initPlugin(this));
+ pluginsList.add(AutomationPlugin.INSTANCE);
pluginsList.add(ConfigBuilderPlugin.getPlugin());
@@ -221,13 +241,40 @@ public void onCreate() {
new Thread(() -> {
SystemClock.sleep(5000);
ConfigBuilderPlugin.getPlugin().getCommandQueue().readStatus("Initialization", null);
- startKeepAliveService();
}).start();
}
+
+ new Thread(() -> KeepAliveReceiver.setAlarm(this)).start();
+ doMigrations();
+ }
+
+ private void doMigrations() {
+
+ // guarantee that the unreachable threshold is at least 30 and of type String
+ // Added in 1.57 at 21.01.2018
+ int unreachable_threshold = SP.getInt(R.string.key_pump_unreachable_threshold, 30);
+ SP.remove(R.string.key_pump_unreachable_threshold);
+ if (unreachable_threshold < 30) unreachable_threshold = 30;
+ SP.putString(R.string.key_pump_unreachable_threshold, Integer.toString(unreachable_threshold));
+
+ // 2.5 -> 2.6
+ if (!SP.contains(R.string.key_units)) {
+ String newUnits = Constants.MGDL;
+ Profile p = ProfileFunctions.getInstance().getProfile();
+ if (p != null && p.getData() != null && p.getData().has("units")) {
+ try {
+ newUnits = p.getData().getString("units");
+ } catch (JSONException e) {
+ log.error("Unhandled exception", e);
+ }
+ }
+ SP.putString(R.string.key_units, newUnits);
+ }
}
+
private void registerLocalBroadcastReceiver() {
- lbm = LocalBroadcastManager.getInstance(this);
+ LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(this);
lbm.registerReceiver(dataReceiver, new IntentFilter(Intents.ACTION_NEW_TREATMENT));
lbm.registerReceiver(dataReceiver, new IntentFilter(Intents.ACTION_CHANGED_TREATMENT));
lbm.registerReceiver(dataReceiver, new IntentFilter(Intents.ACTION_REMOVED_TREATMENT));
@@ -242,55 +289,21 @@ private void registerLocalBroadcastReceiver() {
lbm.registerReceiver(dataReceiver, new IntentFilter(Intents.ACTION_NEW_CAL));
//register alarms
- lbm.registerReceiver(alarmReciever, new IntentFilter(Intents.ACTION_ALARM));
- lbm.registerReceiver(alarmReciever, new IntentFilter(Intents.ACTION_ANNOUNCEMENT));
- lbm.registerReceiver(alarmReciever, new IntentFilter(Intents.ACTION_CLEAR_ALARM));
- lbm.registerReceiver(alarmReciever, new IntentFilter(Intents.ACTION_URGENT_ALARM));
-
- //register ack alarm
- lbm.registerReceiver(ackAlarmReciever, new IntentFilter(Intents.ACTION_ACK_ALARM));
-
- //register dbaccess
- lbm.registerReceiver(dbAccessReciever, new IntentFilter(Intents.ACTION_DATABASE));
- }
-
- private void startKeepAliveService() {
- if (keepAliveReceiver == null) {
- keepAliveReceiver = new KeepAliveReceiver();
- keepAliveReceiver.setAlarm(this);
- }
- }
-
- public void stopKeepAliveService() {
- if (keepAliveReceiver != null)
- KeepAliveReceiver.cancelAlarm(this);
- }
-
- public static void subscribe(Object subscriber) {
- try {
- bus().register(subscriber);
- } catch (IllegalArgumentException e) {
- // already registered
- }
- }
+ lbm.registerReceiver(alarmReceiver, new IntentFilter(Intents.ACTION_ALARM));
+ lbm.registerReceiver(alarmReceiver, new IntentFilter(Intents.ACTION_ANNOUNCEMENT));
+ lbm.registerReceiver(alarmReceiver, new IntentFilter(Intents.ACTION_CLEAR_ALARM));
+ lbm.registerReceiver(alarmReceiver, new IntentFilter(Intents.ACTION_URGENT_ALARM));
- public static void unsubscribe(Object subscriber) {
- try {
- bus().unregister(subscriber);
- } catch (IllegalArgumentException e) {
- // already unregistered
- }
- }
+ this.timeDateOrTZChangeReceiver = new TimeDateOrTZChangeReceiver();
+ this.timeDateOrTZChangeReceiver.registerBroadcasts(this);
- public static Bus bus() {
- return sBus;
}
- public static String gs(int id) {
+ public static String gs(@StringRes int id) {
return sResources.getString(id);
}
- public static String gs(int id, Object... args) {
+ public static String gs(@StringRes int id, Object... args) {
return sResources.getString(id, args);
}
@@ -298,8 +311,8 @@ public static String gq(@PluralsRes int id, int quantity, Object... args) {
return sResources.getQuantityString(id, quantity, args);
}
- public static int gc(int id) {
- return sResources.getColor(id);
+ public static int gc(@ColorRes int id) {
+ return ContextCompat.getColor(instance(), id);
}
public static MainApp instance() {
@@ -310,13 +323,6 @@ public static DatabaseHelper getDbHelper() {
return sDatabaseHelper;
}
- public static void closeDbHelper() {
- if (sDatabaseHelper != null) {
- sDatabaseHelper.close();
- sDatabaseHelper = null;
- }
- }
-
public static FirebaseAnalytics getFirebaseAnalytics() {
return mFirebaseAnalytics;
}
@@ -387,19 +393,6 @@ public static ArrayList getSpecificPluginsVisibleInListByInterface(C
return newList;
}
- @Nullable
- public static T getSpecificPlugin(Class pluginClass) {
- if (pluginsList != null) {
- for (PluginBase p : pluginsList) {
- if (pluginClass.isAssignableFrom(p.getClass()))
- return (T) p;
- }
- } else {
- log.error("pluginsList=null");
- }
- return null;
- }
-
public static boolean isEngineeringModeOrRelease() {
if (!Config.APS)
return true;
@@ -432,10 +425,16 @@ else if (Config.PUMPCONTROL)
public void onTerminate() {
if (L.isEnabled(L.CORE))
log.debug("onTerminate");
+
+ if (timeDateOrTZChangeReceiver != null)
+ unregisterReceiver(timeDateOrTZChangeReceiver);
+ unregisterActivityLifecycleCallbacks(ActivityMonitor.INSTANCE);
+ KeepAliveReceiver.cancelAlarm(this);
super.onTerminate();
- if (sDatabaseHelper != null) {
- sDatabaseHelper.close();
- sDatabaseHelper = null;
- }
+ }
+
+ public static int dpToPx(int dp) {
+ float scale = sResources.getDisplayMetrics().density;
+ return (int) (dp * scale + 0.5f);
}
}
diff --git a/app/src/main/java/info/nightscout/androidaps/activities/AgreementActivity.java b/app/src/main/java/info/nightscout/androidaps/activities/AgreementActivity.java
deleted file mode 100644
index 32352e13710..00000000000
--- a/app/src/main/java/info/nightscout/androidaps/activities/AgreementActivity.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package info.nightscout.androidaps.activities;
-
-import android.app.Activity;
-import android.content.Intent;
-import android.os.Bundle;
-import android.view.View;
-import android.widget.Button;
-import android.widget.CheckBox;
-
-import info.nightscout.androidaps.MainActivity;
-import info.nightscout.androidaps.R;
-import info.nightscout.androidaps.utils.SP;
-
-public class AgreementActivity extends Activity {
- boolean IUnderstand;
- CheckBox agreeCheckBox;
- Button saveButton;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_agreement);
- IUnderstand = SP.getBoolean(R.string.key_i_understand, false);
- setContentView(R.layout.activity_agreement);
- agreeCheckBox = (CheckBox)findViewById(R.id.agreementCheckBox);
- agreeCheckBox.setChecked(IUnderstand);
- saveButton = (Button)findViewById(R.id.agreementSaveButton);
- addListenerOnButton();
- }
-
- public void addListenerOnButton() {
- saveButton.setOnClickListener(new View.OnClickListener() {
- public void onClick(View v) {
-
- SP.putBoolean(R.string.key_i_understand, agreeCheckBox.isChecked());
-
- Intent intent = new Intent(getApplicationContext(), MainActivity.class);
- startActivity(intent);
- finish();
- }
-
- });
- }
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/activities/BolusProgressHelperActivity.kt b/app/src/main/java/info/nightscout/androidaps/activities/BolusProgressHelperActivity.kt
new file mode 100644
index 00000000000..fe55cdcdf2a
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/activities/BolusProgressHelperActivity.kt
@@ -0,0 +1,14 @@
+package info.nightscout.androidaps.activities
+
+import android.os.Bundle
+import info.nightscout.androidaps.dialogs.BolusProgressDialog
+
+class BolusProgressHelperActivity : DialogAppCompatActivity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ BolusProgressDialog()
+ .setHelperActivity(this)
+ .setInsulin(intent.getDoubleExtra("insulin", 0.0))
+ .show(supportFragmentManager, "BolusProgress")
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/activities/DialogAppCompatActivity.kt b/app/src/main/java/info/nightscout/androidaps/activities/DialogAppCompatActivity.kt
new file mode 100644
index 00000000000..a1c6dd12365
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/activities/DialogAppCompatActivity.kt
@@ -0,0 +1,11 @@
+package info.nightscout.androidaps.activities
+
+import android.content.Context
+import androidx.appcompat.app.AppCompatActivity
+import info.nightscout.androidaps.utils.LocaleHelper
+
+open class DialogAppCompatActivity : AppCompatActivity() {
+ public override fun attachBaseContext(newBase: Context) {
+ super.attachBaseContext(LocaleHelper.wrap(newBase))
+ }
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/activities/ErrorHelperActivity.kt b/app/src/main/java/info/nightscout/androidaps/activities/ErrorHelperActivity.kt
new file mode 100644
index 00000000000..4cf828825fa
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/activities/ErrorHelperActivity.kt
@@ -0,0 +1,27 @@
+package info.nightscout.androidaps.activities
+
+import android.os.Bundle
+import info.nightscout.androidaps.R
+import info.nightscout.androidaps.dialogs.ErrorDialog
+import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
+import info.nightscout.androidaps.utils.SP
+
+class ErrorHelperActivity : DialogAppCompatActivity() {
+
+ @Override
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ val errorDialog = ErrorDialog()
+ errorDialog.helperActivity = this
+ errorDialog.status = intent.getStringExtra("status")
+ errorDialog.sound = intent.getIntExtra("soundid", R.raw.error)
+ errorDialog.title = intent.getStringExtra("title")
+ if (intent.hasExtra("clipboardContent"))
+ errorDialog.clipboardContent = intent.getStringExtra("clipboardContent")
+ errorDialog.show(supportFragmentManager, "Error")
+
+ if (SP.getBoolean(R.string.key_ns_create_announcements_from_errors, true)) {
+ NSUpload.uploadError(intent.getStringExtra("status"))
+ }
+ }
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/activities/HistoryBrowseActivity.java b/app/src/main/java/info/nightscout/androidaps/activities/HistoryBrowseActivity.java
index c007d1fcede..c0f654bbbb5 100644
--- a/app/src/main/java/info/nightscout/androidaps/activities/HistoryBrowseActivity.java
+++ b/app/src/main/java/info/nightscout/androidaps/activities/HistoryBrowseActivity.java
@@ -2,9 +2,6 @@
import android.os.Bundle;
import android.os.SystemClock;
-import android.support.v4.content.res.ResourcesCompat;
-import android.support.v7.app.AppCompatActivity;
-import android.support.v7.widget.PopupMenu;
import android.text.SpannableString;
import android.text.style.ForegroundColorSpan;
import android.view.Menu;
@@ -15,8 +12,10 @@
import android.widget.SeekBar;
import android.widget.TextView;
+import androidx.appcompat.widget.PopupMenu;
+import androidx.core.content.res.ResourcesCompat;
+
import com.jjoe64.graphview.GraphView;
-import com.squareup.otto.Subscribe;
import com.wdullaer.materialdatetimepicker.date.DatePickerDialog;
import org.slf4j.Logger;
@@ -25,49 +24,43 @@
import java.util.Calendar;
import java.util.Date;
-import butterknife.BindView;
-import butterknife.ButterKnife;
-import butterknife.OnClick;
-import butterknife.OnLongClick;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.events.EventCustomCalculationFinished;
import info.nightscout.androidaps.interfaces.PumpInterface;
+import info.nightscout.androidaps.plugins.bus.RxBus;
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions;
-import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin;
-import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventAutosensCalculationFinished;
-import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventIobCalculationProgress;
import info.nightscout.androidaps.plugins.general.overview.OverviewFragment;
import info.nightscout.androidaps.plugins.general.overview.OverviewPlugin;
import info.nightscout.androidaps.plugins.general.overview.graphData.GraphData;
+import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin;
+import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventAutosensCalculationFinished;
+import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventIobCalculationProgress;
import info.nightscout.androidaps.utils.DateUtil;
+import info.nightscout.androidaps.utils.FabricPrivacy;
+import info.nightscout.androidaps.utils.SP;
import info.nightscout.androidaps.utils.T;
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.disposables.CompositeDisposable;
-public class HistoryBrowseActivity extends AppCompatActivity {
+public class HistoryBrowseActivity extends NoSplashAppCompatActivity {
private static Logger log = LoggerFactory.getLogger(HistoryBrowseActivity.class);
-
+ private CompositeDisposable disposable = new CompositeDisposable();
ImageButton chartButton;
boolean showBasal = true;
- boolean showIob, showCob, showDev, showRat, showDevslope;
+ boolean showIob, showCob, showDev, showRat, showActPrim, showActSec, showDevslope;
- @BindView(R.id.historybrowse_date)
Button buttonDate;
- @BindView(R.id.historybrowse_zoom)
Button buttonZoom;
- @BindView(R.id.historyybrowse_bggraph)
GraphView bgGraph;
- @BindView(R.id.historybrowse_iobgraph)
GraphView iobGraph;
- @BindView(R.id.historybrowse_seekBar)
SeekBar seekBar;
- @BindView(R.id.historybrowse_noprofile)
TextView noProfile;
- @BindView(R.id.overview_iobcalculationprogess)
TextView iobCalculationProgressView;
private int rangeToDisplay = 24; // for graph
@@ -82,11 +75,83 @@ public HistoryBrowseActivity() {
}
@Override
- protected void onCreate(Bundle savedInstanceState) {
+ public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_historybrowse);
- ButterKnife.bind(this);
+ buttonDate = findViewById(R.id.historybrowse_date);
+ buttonZoom = findViewById(R.id.historybrowse_zoom);
+ bgGraph = findViewById(R.id.historyybrowse_bggraph);
+ iobGraph = findViewById(R.id.historybrowse_iobgraph);
+ seekBar = findViewById(R.id.historybrowse_seekBar);
+ noProfile = findViewById(R.id.historybrowse_noprofile);
+ iobCalculationProgressView = findViewById(R.id.overview_iobcalculationprogess);
+
+ findViewById(R.id.historybrowse_left).setOnClickListener(v -> {
+ start -= T.hours(rangeToDisplay).msecs();
+ updateGUI("onClickLeft");
+ runCalculation("onClickLeft");
+ });
+
+ findViewById(R.id.historybrowse_right).setOnClickListener(v -> {
+ start += T.hours(rangeToDisplay).msecs();
+ updateGUI("onClickRight");
+ runCalculation("onClickRight");
+ });
+
+ findViewById(R.id.historybrowse_end).setOnClickListener(v -> {
+ Calendar calendar = Calendar.getInstance();
+ calendar.setTimeInMillis(System.currentTimeMillis());
+ calendar.set(Calendar.MILLISECOND, 0);
+ calendar.set(Calendar.SECOND, 0);
+ calendar.set(Calendar.MINUTE, 0);
+ calendar.set(Calendar.HOUR_OF_DAY, 0);
+ start = calendar.getTimeInMillis();
+ updateGUI("onClickEnd");
+ runCalculation("onClickEnd");
+ });
+
+ findViewById(R.id.historybrowse_zoom).setOnClickListener(v -> {
+ rangeToDisplay += 6;
+ rangeToDisplay = rangeToDisplay > 24 ? 6 : rangeToDisplay;
+ updateGUI("rangeChange");
+ });
+
+ findViewById(R.id.historybrowse_zoom).setOnLongClickListener(v -> {
+ Calendar calendar = Calendar.getInstance();
+ calendar.setTimeInMillis(start);
+ calendar.set(Calendar.MILLISECOND, 0);
+ calendar.set(Calendar.SECOND, 0);
+ calendar.set(Calendar.MINUTE, 0);
+ calendar.set(Calendar.HOUR_OF_DAY, 0);
+ start = calendar.getTimeInMillis();
+ updateGUI("resetToMidnight");
+ runCalculation("onLongClickZoom");
+ return true;
+ });
+
+ findViewById(R.id.historybrowse_date).setOnClickListener(v -> {
+ Calendar calendar = Calendar.getInstance();
+ calendar.setTime(new Date(start));
+ DatePickerDialog dpd = DatePickerDialog.newInstance(
+ (view, year, monthOfYear, dayOfMonth) -> {
+ Date date = new Date(0);
+ date.setYear(year - 1900);
+ date.setMonth(monthOfYear);
+ date.setDate(dayOfMonth);
+ date.setHours(0);
+ start = date.getTime();
+ updateGUI("onClickDate");
+ runCalculation("onClickDate");
+ },
+ calendar.get(Calendar.YEAR),
+ calendar.get(Calendar.MONTH),
+ calendar.get(Calendar.DAY_OF_MONTH)
+ );
+ dpd.setThemeDark(true);
+ dpd.dismissOnPause(true);
+ dpd.show(getSupportFragmentManager(), "Datepickerdialog");
+ });
bgGraph.getGridLabelRenderer().setGridColor(MainApp.gc(R.color.graphgrid));
bgGraph.getGridLabelRenderer().reloadStyles();
@@ -103,14 +168,33 @@ protected void onCreate(Bundle savedInstanceState) {
@Override
public void onPause() {
super.onPause();
- MainApp.bus().unregister(this);
+ disposable.clear();
iobCobCalculatorPlugin.stopCalculation("onPause");
}
@Override
public void onResume() {
super.onResume();
- MainApp.bus().register(this);
+ disposable.add(RxBus.INSTANCE
+ .toObservable(EventAutosensCalculationFinished.class)
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(event -> {
+ if (event.getCause() == eventCustomCalculationFinished) {
+ log.debug("EventAutosensCalculationFinished");
+ synchronized (HistoryBrowseActivity.this) {
+ updateGUI("EventAutosensCalculationFinished");
+ }
+ }
+ }, FabricPrivacy::logException)
+ );
+ disposable.add(RxBus.INSTANCE
+ .toObservable(EventIobCalculationProgress.class)
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(event -> {
+ if (iobCalculationProgressView != null)
+ iobCalculationProgressView.setText(event.getProgress());
+ }, FabricPrivacy::logException)
+ );
// set start of current day
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
@@ -124,78 +208,6 @@ public void onResume() {
updateGUI("onResume");
}
- @OnClick(R.id.historybrowse_left)
- void onClickLeft() {
- start -= T.hours(rangeToDisplay).msecs();
- updateGUI("onClickLeft");
- runCalculation("onClickLeft");
- }
-
- @OnClick(R.id.historybrowse_right)
- void onClickRight() {
- start += T.hours(rangeToDisplay).msecs();
- updateGUI("onClickRight");
- runCalculation("onClickRight");
- }
-
- @OnClick(R.id.historybrowse_end)
- void onClickEnd() {
- Calendar calendar = Calendar.getInstance();
- calendar.setTimeInMillis(System.currentTimeMillis());
- calendar.set(Calendar.MILLISECOND, 0);
- calendar.set(Calendar.SECOND, 0);
- calendar.set(Calendar.MINUTE, 0);
- calendar.set(Calendar.HOUR_OF_DAY, 0);
- start = calendar.getTimeInMillis();
- updateGUI("onClickEnd");
- runCalculation("onClickEnd");
- }
-
- @OnClick(R.id.historybrowse_zoom)
- void onClickZoom() {
- rangeToDisplay += 6;
- rangeToDisplay = rangeToDisplay > 24 ? 6 : rangeToDisplay;
- updateGUI("rangeChange");
- }
-
- @OnLongClick(R.id.historybrowse_zoom)
- boolean onLongClickZoom() {
- Calendar calendar = Calendar.getInstance();
- calendar.setTimeInMillis(start);
- calendar.set(Calendar.MILLISECOND, 0);
- calendar.set(Calendar.SECOND, 0);
- calendar.set(Calendar.MINUTE, 0);
- calendar.set(Calendar.HOUR_OF_DAY, 0);
- start = calendar.getTimeInMillis();
- updateGUI("resetToMidnight");
- runCalculation("onLongClickZoom");
- return true;
- }
-
- @OnClick(R.id.historybrowse_date)
- void onClickDate() {
- Calendar calendar = Calendar.getInstance();
- calendar.setTime(new Date(start));
- DatePickerDialog dpd = DatePickerDialog.newInstance(
- (view, year, monthOfYear, dayOfMonth) -> {
- Date date = new Date(0);
- date.setYear(year - 1900);
- date.setMonth(monthOfYear);
- date.setDate(dayOfMonth);
- date.setHours(0);
- start = date.getTime();
- updateGUI("onClickDate");
- runCalculation("onClickDate");
- },
- calendar.get(Calendar.YEAR),
- calendar.get(Calendar.MONTH),
- calendar.get(Calendar.DAY_OF_MONTH)
- );
- dpd.setThemeDark(true);
- dpd.dismissOnPause(true);
- dpd.show(getFragmentManager(), "Datepickerdialog");
- }
-
private void runCalculation(String from) {
long end = start + T.hours(rangeToDisplay).msecs();
iobCobCalculatorPlugin.stopCalculation(from);
@@ -203,26 +215,6 @@ private void runCalculation(String from) {
iobCobCalculatorPlugin.runCalculation(from, end, true, false, eventCustomCalculationFinished);
}
- @Subscribe
- public void onStatusEvent(final EventAutosensCalculationFinished e) {
- if (e.cause == eventCustomCalculationFinished) {
- log.debug("EventAutosensCalculationFinished");
- runOnUiThread(() -> {
- synchronized (HistoryBrowseActivity.this) {
- updateGUI("EventAutosensCalculationFinished");
- }
- });
- }
- }
-
- @Subscribe
- public void onStatusEvent(final EventIobCalculationProgress e) {
- runOnUiThread(() -> {
- if (iobCalculationProgressView != null)
- iobCalculationProgressView.setText(e.progress);
- });
- }
-
void updateGUI(String from) {
log.debug("updateGUI from: " + from);
@@ -239,15 +231,23 @@ void updateGUI(String from) {
noProfile.setVisibility(View.GONE);
}
- final String units = profile.getUnits();
- final double lowLine = OverviewPlugin.getPlugin().determineLowLine(units);
- final double highLine = OverviewPlugin.getPlugin().determineHighLine(units);
+ final double lowLine = OverviewPlugin.INSTANCE.determineLowLine();
+ final double highLine = OverviewPlugin.INSTANCE.determineHighLine();
buttonDate.setText(DateUtil.dateAndTimeString(start));
buttonZoom.setText(String.valueOf(rangeToDisplay));
final boolean showPrediction = false;
+ showBasal = SP.getBoolean("hist_showbasals", true);
+ showIob = SP.getBoolean("hist_showiob", true);
+ showCob = SP.getBoolean("hist_showcob", true);
+ showDev = SP.getBoolean("hist_showdeviations", false);
+ showRat = SP.getBoolean("hist_showratios", false);
+ showActPrim = SP.getBoolean("hist_showactivityprimary", false);
+ showActSec = SP.getBoolean("hist_showactivitysecondary", false);
+ showDevslope = SP.getBoolean("hist_showdevslope", false);
+
int hoursToFetch;
final long toTime;
final long fromTime;
@@ -285,6 +285,10 @@ void updateGUI(String from) {
// set manual x bounds to have nice steps
graphData.formatAxis(fromTime, toTime);
+ if (showActPrim) {
+ graphData.addActivity(fromTime, toTime, false, 1d);
+ }
+
// Treatments
graphData.addTreatments(fromTime, toTime);
@@ -305,6 +309,7 @@ void updateGUI(String from) {
boolean useCobForScale = false;
boolean useDevForScale = false;
boolean useRatioForScale = false;
+ boolean useIAForScale = false;
boolean useDSForScale = false;
if (showIob) {
@@ -315,18 +320,22 @@ void updateGUI(String from) {
useDevForScale = true;
} else if (showRat) {
useRatioForScale = true;
+ } else if (showActSec) {
+ useIAForScale = true;
} else if (showDevslope) {
useDSForScale = true;
}
if (showIob)
- secondGraphData.addIob(fromTime, toTime, useIobForScale, 1d);
+ secondGraphData.addIob(fromTime, toTime, useIobForScale, 1d, showPrediction);
if (showCob)
secondGraphData.addCob(fromTime, toTime, useCobForScale, useCobForScale ? 1d : 0.5d);
if (showDev)
secondGraphData.addDeviations(fromTime, toTime, useDevForScale, 1d);
if (showRat)
secondGraphData.addRatio(fromTime, toTime, useRatioForScale, 1d);
+ if (showActSec)
+ secondGraphData.addActivity(fromTime, toTime, useIAForScale, useIAForScale ? 2d : 1d);
if (showDevslope)
secondGraphData.addDeviationSlope(fromTime, toTime, useDSForScale, 1d);
@@ -337,14 +346,14 @@ void updateGUI(String from) {
// do GUI update
runOnUiThread(() -> {
- if (showIob || showCob || showDev || showRat || showDevslope) {
+ if (showIob || showCob || showDev || showRat || showActSec || showDevslope) {
iobGraph.setVisibility(View.VISIBLE);
} else {
iobGraph.setVisibility(View.GONE);
}
// finally enforce drawing of graphs
graphData.performUpdate();
- if (showIob || showCob || showDev || showRat || showDevslope)
+ if (showIob || showCob || showDev || showRat || showActSec || showDevslope)
secondGraphData.performUpdate();
});
}).start();
@@ -353,22 +362,37 @@ void updateGUI(String from) {
private void setupChartMenu() {
chartButton = (ImageButton) findViewById(R.id.overview_chartMenuButton);
chartButton.setOnClickListener(v -> {
- MenuItem item;
+ MenuItem item, dividerItem;
CharSequence title;
+ int titleMaxChars = 0;
SpannableString s;
PopupMenu popup = new PopupMenu(v.getContext(), v);
item = popup.getMenu().add(Menu.NONE, OverviewFragment.CHARTTYPE.BAS.ordinal(), Menu.NONE, MainApp.gs(R.string.overview_show_basals));
title = item.getTitle();
+ if (titleMaxChars < title.length()) titleMaxChars = title.length();
s = new SpannableString(title);
s.setSpan(new ForegroundColorSpan(ResourcesCompat.getColor(getResources(), R.color.basal, null)), 0, s.length(), 0);
item.setTitle(s);
item.setCheckable(true);
item.setChecked(showBasal);
+ item = popup.getMenu().add(Menu.NONE, OverviewFragment.CHARTTYPE.ACTPRIM.ordinal(), Menu.NONE, MainApp.gs(R.string.overview_show_activity));
+ title = item.getTitle();
+ if (titleMaxChars < title.length()) titleMaxChars = title.length();
+ s = new SpannableString(title);
+ s.setSpan(new ForegroundColorSpan(ResourcesCompat.getColor(getResources(), R.color.activity, null)), 0, s.length(), 0);
+ item.setTitle(s);
+ item.setCheckable(true);
+ item.setChecked(showActPrim);
+
+ dividerItem = popup.getMenu().add("");
+ dividerItem.setEnabled(false);
+
item = popup.getMenu().add(Menu.NONE, OverviewFragment.CHARTTYPE.IOB.ordinal(), Menu.NONE, MainApp.gs(R.string.overview_show_iob));
title = item.getTitle();
+ if (titleMaxChars < title.length()) titleMaxChars = title.length();
s = new SpannableString(title);
s.setSpan(new ForegroundColorSpan(ResourcesCompat.getColor(getResources(), R.color.iob, null)), 0, s.length(), 0);
item.setTitle(s);
@@ -377,6 +401,7 @@ private void setupChartMenu() {
item = popup.getMenu().add(Menu.NONE, OverviewFragment.CHARTTYPE.COB.ordinal(), Menu.NONE, MainApp.gs(R.string.overview_show_cob));
title = item.getTitle();
+ if (titleMaxChars < title.length()) titleMaxChars = title.length();
s = new SpannableString(title);
s.setSpan(new ForegroundColorSpan(ResourcesCompat.getColor(getResources(), R.color.cob, null)), 0, s.length(), 0);
item.setTitle(s);
@@ -385,6 +410,7 @@ private void setupChartMenu() {
item = popup.getMenu().add(Menu.NONE, OverviewFragment.CHARTTYPE.DEV.ordinal(), Menu.NONE, MainApp.gs(R.string.overview_show_deviations));
title = item.getTitle();
+ if (titleMaxChars < title.length()) titleMaxChars = title.length();
s = new SpannableString(title);
s.setSpan(new ForegroundColorSpan(ResourcesCompat.getColor(getResources(), R.color.deviations, null)), 0, s.length(), 0);
item.setTitle(s);
@@ -393,15 +419,27 @@ private void setupChartMenu() {
item = popup.getMenu().add(Menu.NONE, OverviewFragment.CHARTTYPE.SEN.ordinal(), Menu.NONE, MainApp.gs(R.string.overview_show_sensitivity));
title = item.getTitle();
+ if (titleMaxChars < title.length()) titleMaxChars = title.length();
s = new SpannableString(title);
s.setSpan(new ForegroundColorSpan(ResourcesCompat.getColor(getResources(), R.color.ratio, null)), 0, s.length(), 0);
item.setTitle(s);
item.setCheckable(true);
item.setChecked(showRat);
+ item = popup.getMenu().add(Menu.NONE, OverviewFragment.CHARTTYPE.ACTSEC.ordinal(), Menu.NONE, MainApp.gs(R.string.overview_show_activity));
+ title = item.getTitle();
+ if (titleMaxChars < title.length()) titleMaxChars = title.length();
+ s = new SpannableString(title);
+ s.setSpan(new ForegroundColorSpan(ResourcesCompat.getColor(getResources(), R.color.activity, null)), 0, s.length(), 0);
+ item.setTitle(s);
+ item.setCheckable(true);
+ item.setChecked(showActSec);
+
+
if (MainApp.devBranch) {
item = popup.getMenu().add(Menu.NONE, OverviewFragment.CHARTTYPE.DEVSLOPE.ordinal(), Menu.NONE, "Deviation slope");
title = item.getTitle();
+ if (titleMaxChars < title.length()) titleMaxChars = title.length();
s = new SpannableString(title);
s.setSpan(new ForegroundColorSpan(ResourcesCompat.getColor(getResources(), R.color.devslopepos, null)), 0, s.length(), 0);
item.setTitle(s);
@@ -409,19 +447,27 @@ private void setupChartMenu() {
item.setChecked(showDevslope);
}
+ // Fairly good guestimate for required divider text size...
+ title = new String(new char[titleMaxChars + 10]).replace("\0", "_");
+ dividerItem.setTitle(title);
+
popup.setOnMenuItemClickListener(item1 -> {
if (item1.getItemId() == OverviewFragment.CHARTTYPE.BAS.ordinal()) {
- showBasal = !item1.isChecked();
+ SP.putBoolean("hist_showbasals", !item1.isChecked());
} else if (item1.getItemId() == OverviewFragment.CHARTTYPE.IOB.ordinal()) {
- showIob = !item1.isChecked();
+ SP.putBoolean("hist_showiob", !item1.isChecked());
} else if (item1.getItemId() == OverviewFragment.CHARTTYPE.COB.ordinal()) {
- showCob = !item1.isChecked();
+ SP.putBoolean("hist_showcob", !item1.isChecked());
} else if (item1.getItemId() == OverviewFragment.CHARTTYPE.DEV.ordinal()) {
- showDev = !item1.isChecked();
+ SP.putBoolean("hist_showdeviations", !item1.isChecked());
} else if (item1.getItemId() == OverviewFragment.CHARTTYPE.SEN.ordinal()) {
- showRat = !item1.isChecked();
+ SP.putBoolean("hist_showratios", !item1.isChecked());
+ } else if (item1.getItemId() == OverviewFragment.CHARTTYPE.ACTPRIM.ordinal()) {
+ SP.putBoolean("hist_showactivityprimary", !item1.isChecked());
+ } else if (item1.getItemId() == OverviewFragment.CHARTTYPE.ACTSEC.ordinal()) {
+ SP.putBoolean("hist_showactivitysecondary", !item1.isChecked());
} else if (item1.getItemId() == OverviewFragment.CHARTTYPE.DEVSLOPE.ordinal()) {
- showDevslope = !item1.isChecked();
+ SP.putBoolean("hist_showdevslope", !item1.isChecked());
}
updateGUI("onGraphCheckboxesCheckedChanged");
return true;
diff --git a/app/src/main/java/info/nightscout/androidaps/activities/NoSplashAppCompatActivity.kt b/app/src/main/java/info/nightscout/androidaps/activities/NoSplashAppCompatActivity.kt
new file mode 100644
index 00000000000..3f59cd56ef3
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/activities/NoSplashAppCompatActivity.kt
@@ -0,0 +1,18 @@
+package info.nightscout.androidaps.activities
+
+import android.content.Context
+import android.os.Bundle
+import androidx.appcompat.app.AppCompatActivity
+import info.nightscout.androidaps.R
+import info.nightscout.androidaps.utils.LocaleHelper
+
+open class NoSplashAppCompatActivity : AppCompatActivity() {
+ public override fun onCreate(savedInstanceState: Bundle?) {
+ setTheme(R.style.AppTheme_NoActionBar)
+ super.onCreate(savedInstanceState)
+ }
+
+ public override fun attachBaseContext(newBase: Context) {
+ super.attachBaseContext(LocaleHelper.wrap(newBase))
+ }
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/activities/PreferencesActivity.java b/app/src/main/java/info/nightscout/androidaps/activities/PreferencesActivity.java
index aea7bcfca6a..e0407d876f3 100644
--- a/app/src/main/java/info/nightscout/androidaps/activities/PreferencesActivity.java
+++ b/app/src/main/java/info/nightscout/androidaps/activities/PreferencesActivity.java
@@ -1,5 +1,6 @@
package info.nightscout.androidaps.activities;
+import android.content.Context;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.EditTextPreference;
@@ -10,47 +11,58 @@
import android.preference.PreferenceGroup;
import android.preference.PreferenceManager;
import android.preference.PreferenceScreen;
-import android.text.TextUtils;
+import android.preference.SwitchPreference;
+
+import java.util.Arrays;
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
+import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.events.EventPreferenceChange;
-import info.nightscout.androidaps.events.EventRefreshGui;
+import info.nightscout.androidaps.events.EventRebuildTabs;
import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.PluginType;
-import info.nightscout.androidaps.plugins.general.careportal.CareportalPlugin;
-import info.nightscout.androidaps.plugins.constraints.safety.SafetyPlugin;
-import info.nightscout.androidaps.plugins.insulin.InsulinOrefFreePeakPlugin;
+import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin;
-import info.nightscout.androidaps.plugins.general.nsclient.NSClientPlugin;
import info.nightscout.androidaps.plugins.aps.openAPSAMA.OpenAPSAMAPlugin;
import info.nightscout.androidaps.plugins.aps.openAPSMA.OpenAPSMAPlugin;
import info.nightscout.androidaps.plugins.aps.openAPSSMB.OpenAPSSMBPlugin;
+import info.nightscout.androidaps.plugins.bus.RxBus;
+import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin;
+import info.nightscout.androidaps.plugins.constraints.safety.SafetyPlugin;
+import info.nightscout.androidaps.plugins.general.automation.AutomationPlugin;
+import info.nightscout.androidaps.plugins.general.careportal.CareportalPlugin;
+import info.nightscout.androidaps.plugins.general.nsclient.NSClientPlugin;
+import info.nightscout.androidaps.plugins.general.smsCommunicator.SmsCommunicatorPlugin;
+import info.nightscout.androidaps.plugins.general.tidepool.TidepoolPlugin;
+import info.nightscout.androidaps.plugins.general.wear.WearPlugin;
+import info.nightscout.androidaps.plugins.general.xdripStatusline.StatuslinePlugin;
+import info.nightscout.androidaps.plugins.insulin.InsulinOrefFreePeakPlugin;
import info.nightscout.androidaps.plugins.pump.combo.ComboPlugin;
import info.nightscout.androidaps.plugins.pump.danaR.DanaRPlugin;
import info.nightscout.androidaps.plugins.pump.danaRKorean.DanaRKoreanPlugin;
import info.nightscout.androidaps.plugins.pump.danaRS.DanaRSPlugin;
import info.nightscout.androidaps.plugins.pump.danaRv2.DanaRv2Plugin;
import info.nightscout.androidaps.plugins.pump.insight.LocalInsightPlugin;
+import info.nightscout.androidaps.plugins.pump.medtronic.MedtronicPumpPlugin;
import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin;
import info.nightscout.androidaps.plugins.sensitivity.SensitivityAAPSPlugin;
import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref0Plugin;
import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref1Plugin;
import info.nightscout.androidaps.plugins.sensitivity.SensitivityWeightedAveragePlugin;
-import info.nightscout.androidaps.plugins.general.smsCommunicator.SmsCommunicatorPlugin;
-import info.nightscout.androidaps.plugins.source.SourceDexcomG5Plugin;
-import info.nightscout.androidaps.plugins.general.wear.WearPlugin;
-import info.nightscout.androidaps.plugins.general.xdripStatusline.StatuslinePlugin;
+import info.nightscout.androidaps.plugins.source.SourceDexcomPlugin;
import info.nightscout.androidaps.utils.LocaleHelper;
import info.nightscout.androidaps.utils.OKDialog;
import info.nightscout.androidaps.utils.SP;
+import info.nightscout.androidaps.utils.SafeParse;
public class PreferencesActivity extends PreferenceActivity implements SharedPreferences.OnSharedPreferenceChangeListener {
MyPreferenceFragment myPreferenceFragment;
@Override
protected void onCreate(Bundle savedInstanceState) {
+ setTheme(R.style.AppTheme_NoActionBar);
super.onCreate(savedInstanceState);
myPreferenceFragment = new MyPreferenceFragment();
Bundle args = new Bundle();
@@ -60,23 +72,47 @@ protected void onCreate(Bundle savedInstanceState) {
PreferenceManager.getDefaultSharedPreferences(this).registerOnSharedPreferenceChangeListener(this);
}
+ @Override
+ public void attachBaseContext(Context newBase) {
+ super.attachBaseContext(LocaleHelper.INSTANCE.wrap(newBase));
+ }
+
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
- MainApp.bus().post(new EventPreferenceChange(key));
- if (key.equals("language")) {
- String lang = sharedPreferences.getString("language", "en");
- LocaleHelper.setLocale(getApplicationContext(), lang);
- MainApp.bus().post(new EventRefreshGui(true));
+ RxBus.INSTANCE.send(new EventPreferenceChange(key));
+ if (key.equals(MainApp.gs(R.string.key_language))) {
+ RxBus.INSTANCE.send(new EventRebuildTabs(true));
//recreate() does not update language so better close settings
finish();
}
- if (key.equals("short_tabtitles")) {
- MainApp.bus().post(new EventRefreshGui());
+ if (key.equals(MainApp.gs(R.string.key_short_tabtitles))) {
+ RxBus.INSTANCE.send(new EventRebuildTabs());
+ }
+ if (key.equals(MainApp.gs(R.string.key_units))) {
+ recreate();
+ return;
}
if (key.equals(MainApp.gs(R.string.key_openapsama_useautosens)) && SP.getBoolean(R.string.key_openapsama_useautosens, false)) {
- OKDialog.show(this, MainApp.gs(R.string.configbuilder_sensitivity), MainApp.gs(R.string.sensitivity_warning), null);
+ OKDialog.show(this, MainApp.gs(R.string.configbuilder_sensitivity), MainApp.gs(R.string.sensitivity_warning));
+ }
+ updatePrefSummary(myPreferenceFragment.findPreference(key));
+ }
+
+ private static void adjustUnitDependentPrefs(Preference pref) {
+ // convert preferences values to current units
+ String[] unitDependent = new String[]{
+ MainApp.gs(R.string.key_hypo_target),
+ MainApp.gs(R.string.key_activity_target),
+ MainApp.gs(R.string.key_eatingsoon_target),
+ MainApp.gs(R.string.key_high_mark),
+ MainApp.gs(R.string.key_low_mark)
+ };
+ if (Arrays.asList(unitDependent).contains(pref.getKey())) {
+ EditTextPreference editTextPref = (EditTextPreference) pref;
+ String converted = Profile.toCurrentUnitsString(SafeParse.stringToDouble(editTextPref.getText()));
+ editTextPref.setSummary(converted);
+ editTextPref.setText(converted);
}
- updatePrefSummary(myPreferenceFragment.getPreference(key));
}
private static void updatePrefSummary(Preference pref) {
@@ -88,15 +124,17 @@ private static void updatePrefSummary(Preference pref) {
EditTextPreference editTextPref = (EditTextPreference) pref;
if (pref.getKey().contains("password") || pref.getKey().contains("secret")) {
pref.setSummary("******");
- } else if (pref.getKey().equals(MainApp.gs(R.string.key_danars_name))) {
- pref.setSummary(SP.getString(R.string.key_danars_name, ""));
} else if (editTextPref.getText() != null) {
((EditTextPreference) pref).setDialogMessage(editTextPref.getDialogMessage());
pref.setSummary(editTextPref.getText());
- } else if (pref.getKey().contains("smscommunicator_allowednumbers") && TextUtils.isEmpty(editTextPref.getText().trim())) {
- pref.setSummary(MainApp.gs(R.string.smscommunicator_allowednumbers_summary));
+ } else {
+ for (PluginBase plugin : MainApp.getPluginsList()) {
+ plugin.updatePreferenceSummary(pref);
+ }
}
}
+ if (pref != null)
+ adjustUnitDependentPrefs(pref);
}
public static void initSummary(Preference p) {
@@ -139,12 +177,12 @@ public void onCreate(final Bundle savedInstanceState) {
if (!Config.NSCLIENT) {
addPreferencesFromResource(R.xml.pref_password);
}
+ addPreferencesFromResource(R.xml.pref_general);
addPreferencesFromResource(R.xml.pref_age);
- addPreferencesFromResource(R.xml.pref_language);
addPreferencesFromResource(R.xml.pref_overview);
- addPreferencesFromResourceIfEnabled(SourceDexcomG5Plugin.getPlugin(), PluginType.BGSOURCE);
+ addPreferencesFromResourceIfEnabled(SourceDexcomPlugin.INSTANCE, PluginType.BGSOURCE);
addPreferencesFromResourceIfEnabled(CareportalPlugin.getPlugin(), PluginType.GENERAL);
addPreferencesFromResourceIfEnabled(SafetyPlugin.getPlugin(), PluginType.CONSTRAINTS);
if (Config.APS) {
@@ -166,6 +204,7 @@ public void onCreate(final Bundle savedInstanceState) {
addPreferencesFromResourceIfEnabled(DanaRSPlugin.getPlugin(), PluginType.PUMP);
addPreferencesFromResourceIfEnabled(LocalInsightPlugin.getPlugin(), PluginType.PUMP);
addPreferencesFromResourceIfEnabled(ComboPlugin.getPlugin(), PluginType.PUMP);
+ addPreferencesFromResourceIfEnabled(MedtronicPumpPlugin.getPlugin(), PluginType.PUMP);
if (DanaRPlugin.getPlugin().isEnabled(PluginType.PROFILE)
|| DanaRKoreanPlugin.getPlugin().isEnabled(PluginType.PROFILE)
@@ -182,7 +221,9 @@ public void onCreate(final Bundle savedInstanceState) {
addPreferencesFromResourceIfEnabled(InsulinOrefFreePeakPlugin.getPlugin(), PluginType.INSULIN);
addPreferencesFromResourceIfEnabled(NSClientPlugin.getPlugin(), PluginType.GENERAL);
- addPreferencesFromResourceIfEnabled(SmsCommunicatorPlugin.getPlugin(), PluginType.GENERAL);
+ addPreferencesFromResourceIfEnabled(TidepoolPlugin.INSTANCE, PluginType.GENERAL);
+ addPreferencesFromResourceIfEnabled(SmsCommunicatorPlugin.INSTANCE, PluginType.GENERAL);
+ addPreferencesFromResourceIfEnabled(AutomationPlugin.INSTANCE, PluginType.GENERAL);
addPreferencesFromResource(R.xml.pref_others);
addPreferencesFromResource(R.xml.pref_datachoices);
@@ -191,18 +232,27 @@ public void onCreate(final Bundle savedInstanceState) {
addPreferencesFromResourceIfEnabled(StatuslinePlugin.getPlugin(), PluginType.GENERAL);
}
- if (Config.NSCLIENT) {
- PreferenceScreen scrnAdvancedSettings = (PreferenceScreen)findPreference(getString(R.string.key_advancedsettings));
- if (scrnAdvancedSettings != null) {
- scrnAdvancedSettings.removePreference(getPreference(getString(R.string.key_statuslights_res_warning)));
- scrnAdvancedSettings.removePreference(getPreference(getString(R.string.key_statuslights_res_critical)));
- scrnAdvancedSettings.removePreference(getPreference(getString(R.string.key_statuslights_bat_warning)));
- scrnAdvancedSettings.removePreference(getPreference(getString(R.string.key_statuslights_bat_critical)));
- scrnAdvancedSettings.removePreference(getPreference(getString(R.string.key_show_statuslights)));
- }
+ initSummary(getPreferenceScreen());
+
+ for (PluginBase plugin : MainApp.getPluginsList()) {
+ plugin.preprocessPreferences(this);
}
- initSummary(getPreferenceScreen());
+ PumpInterface activePump = ConfigBuilderPlugin.getPlugin().getActivePump();
+ PreferenceScreen localAlertsPreferenceScreen = (PreferenceScreen) findPreference(MainApp.gs(R.string.key_preferences_screen_local_alerts));
+ if (activePump != null && localAlertsPreferenceScreen != null && activePump.getPumpDescription().hasFixedUnreachableAlert) {
+ Preference pumpUnreachableEnabledPreference = findPreference(MainApp.gs(R.string.key_enable_pump_unreachable_alert));
+ if (pumpUnreachableEnabledPreference != null) {
+ ((SwitchPreference) pumpUnreachableEnabledPreference).setChecked(true);
+ pumpUnreachableEnabledPreference.setEnabled(false);
+ pumpUnreachableEnabledPreference.setShouldDisableView(true);
+ }
+
+ Preference pumpUnreachableThresholdPreference = findPreference(MainApp.gs(R.string.key_pump_unreachable_threshold));
+ if (pumpUnreachableThresholdPreference != null) {
+ pumpUnreachableThresholdPreference.setDependency(null);
+ }
+ }
}
@Override
@@ -210,9 +260,5 @@ public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("id", id);
}
-
- public Preference getPreference(String key) {
- return findPreference(key);
- }
}
}
diff --git a/app/src/main/java/info/nightscout/androidaps/activities/RequestDexcomPermissionActivity.kt b/app/src/main/java/info/nightscout/androidaps/activities/RequestDexcomPermissionActivity.kt
new file mode 100644
index 00000000000..f50212dadd9
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/activities/RequestDexcomPermissionActivity.kt
@@ -0,0 +1,19 @@
+package info.nightscout.androidaps.activities
+
+import android.os.Bundle
+import info.nightscout.androidaps.plugins.source.SourceDexcomPlugin
+
+class RequestDexcomPermissionActivity : DialogAppCompatActivity() {
+
+ private val requestCode = "AndroidAPS <3".map { it.toInt() }.sum()
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ requestPermissions(arrayOf(SourceDexcomPlugin.PERMISSION), requestCode)
+ }
+
+ override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) {
+ finish()
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/activities/SingleFragmentActivity.java b/app/src/main/java/info/nightscout/androidaps/activities/SingleFragmentActivity.java
deleted file mode 100644
index 2a381cd0a83..00000000000
--- a/app/src/main/java/info/nightscout/androidaps/activities/SingleFragmentActivity.java
+++ /dev/null
@@ -1,59 +0,0 @@
-package info.nightscout.androidaps.activities;
-
-import android.content.Intent;
-import android.os.Bundle;
-import android.support.annotation.Nullable;
-import android.support.v4.app.Fragment;
-import android.support.v7.app.AppCompatActivity;
-import android.view.Menu;
-import android.view.MenuItem;
-
-import info.nightscout.androidaps.MainApp;
-import info.nightscout.androidaps.R;
-import info.nightscout.androidaps.interfaces.PluginBase;
-import info.nightscout.androidaps.utils.PasswordProtection;
-
-public class SingleFragmentActivity extends AppCompatActivity {
-
- private PluginBase plugin;
-
- @Override
- protected void onCreate(@Nullable Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_single_fragment);
-
- this.plugin = MainApp.getPluginsList().get(getIntent().getIntExtra("plugin", -1));
- setTitle(plugin.getName());
- getSupportActionBar().setDisplayHomeAsUpEnabled(true);
- getSupportActionBar().setDisplayShowHomeEnabled(true);
-
- if (savedInstanceState == null) {
- getSupportFragmentManager().beginTransaction().replace(R.id.frame_layout,
- Fragment.instantiate(this, plugin.pluginDescription.getFragmentClass())).commit();
- }
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- if (item.getItemId() == android.R.id.home) {
- finish();
- return true;
- }
- else if (item.getItemId() == R.id.nav_plugin_preferences) {
- PasswordProtection.QueryPassword(this, R.string.settings_password, "settings_password", () -> {
- Intent i = new Intent(this, PreferencesActivity.class);
- i.putExtra("id", plugin.getPreferencesId());
- startActivity(i);
- }, null);
- return true;
- }
- return false;
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- if (plugin.getPreferencesId() != -1)
- getMenuInflater().inflate(R.menu.menu_single_fragment, menu);
- return super.onCreateOptionsMenu(menu);
- }
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/activities/SingleFragmentActivity.kt b/app/src/main/java/info/nightscout/androidaps/activities/SingleFragmentActivity.kt
new file mode 100644
index 00000000000..3bf329debe2
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/activities/SingleFragmentActivity.kt
@@ -0,0 +1,53 @@
+package info.nightscout.androidaps.activities
+
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import android.view.Menu
+import android.view.MenuItem
+import androidx.appcompat.app.AppCompatActivity
+import info.nightscout.androidaps.MainApp
+import info.nightscout.androidaps.R
+import info.nightscout.androidaps.interfaces.PluginBase
+import info.nightscout.androidaps.utils.LocaleHelper
+import info.nightscout.androidaps.utils.PasswordProtection
+
+class SingleFragmentActivity : AppCompatActivity() {
+ private var plugin: PluginBase? = null
+ public override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_single_fragment)
+ plugin = MainApp.getPluginsList()[intent.getIntExtra("plugin", -1)]
+ title = plugin?.name
+ supportActionBar?.setDisplayHomeAsUpEnabled(true)
+ supportActionBar?.setDisplayShowHomeEnabled(true)
+ if (savedInstanceState == null) {
+ supportFragmentManager.beginTransaction().replace(R.id.frame_layout,
+ supportFragmentManager.fragmentFactory.instantiate(ClassLoader.getSystemClassLoader(), plugin?.pluginDescription?.fragmentClass!!)).commit()
+ }
+ }
+
+ override fun onOptionsItemSelected(item: MenuItem): Boolean {
+ if (item.itemId == android.R.id.home) {
+ finish()
+ return true
+ } else if (item.itemId == R.id.nav_plugin_preferences) {
+ PasswordProtection.QueryPassword(this, R.string.settings_password, "settings_password", Runnable {
+ val i = Intent(this, PreferencesActivity::class.java)
+ i.putExtra("id", plugin?.preferencesId)
+ startActivity(i)
+ }, null)
+ return true
+ }
+ return false
+ }
+
+ override fun onCreateOptionsMenu(menu: Menu): Boolean {
+ if (plugin?.preferencesId != -1) menuInflater.inflate(R.menu.menu_single_fragment, menu)
+ return super.onCreateOptionsMenu(menu)
+ }
+
+ public override fun attachBaseContext(newBase: Context) {
+ super.attachBaseContext(LocaleHelper.wrap(newBase))
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/activities/StatsActivity.kt b/app/src/main/java/info/nightscout/androidaps/activities/StatsActivity.kt
new file mode 100644
index 00000000000..d0ac8e3f6f1
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/activities/StatsActivity.kt
@@ -0,0 +1,30 @@
+package info.nightscout.androidaps.activities
+
+import android.os.Bundle
+import info.nightscout.androidaps.MainApp
+import info.nightscout.androidaps.R
+import info.nightscout.androidaps.utils.ActivityMonitor
+import info.nightscout.androidaps.utils.OKDialog
+import info.nightscout.androidaps.utils.TddCalculator
+import info.nightscout.androidaps.utils.TirCalculator
+import kotlinx.android.synthetic.main.stats_activity.*
+
+class StatsActivity : NoSplashAppCompatActivity() {
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.stats_activity)
+
+ stats_tdds.text = TddCalculator.stats()
+ stats_tir.text = TirCalculator.stats()
+ stats_activity.text = ActivityMonitor.stats()
+
+ ok.setOnClickListener { finish() }
+ stats_reset.setOnClickListener {
+ OKDialog.showConfirmation(this, MainApp.gs(R.string.doyouwantresetstats), Runnable {
+ ActivityMonitor.reset()
+ recreate()
+ })
+ }
+ }
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/activities/SurveyActivity.kt b/app/src/main/java/info/nightscout/androidaps/activities/SurveyActivity.kt
new file mode 100644
index 00000000000..bf07eda9afa
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/activities/SurveyActivity.kt
@@ -0,0 +1,110 @@
+package info.nightscout.androidaps.activities
+
+import android.os.Bundle
+import android.widget.ArrayAdapter
+import com.google.firebase.auth.FirebaseAuth
+import com.google.firebase.database.FirebaseDatabase
+import info.nightscout.androidaps.R
+import info.nightscout.androidaps.data.defaultProfile.DefaultProfile
+import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin
+import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions
+import info.nightscout.androidaps.dialogs.ProfileViewerDialog
+import info.nightscout.androidaps.utils.*
+import kotlinx.android.synthetic.main.survey_activity.*
+import org.slf4j.LoggerFactory
+
+class SurveyActivity : NoSplashAppCompatActivity() {
+ private val log = LoggerFactory.getLogger(SurveyActivity::class.java)
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.survey_activity)
+
+ survey_id.text = InstanceId.instanceId()
+
+ val profileStore = ConfigBuilderPlugin.getPlugin().activeProfileInterface?.profile
+ val profileList = profileStore?.getProfileList() ?: return
+ survey_spinner.adapter = ArrayAdapter(this, R.layout.spinner_centered, profileList)
+
+ survey_tdds.text = TddCalculator.stats()
+ survey_tir.text = TirCalculator.stats()
+ survey_activity.text = ActivityMonitor.stats()
+
+ survey_profile.setOnClickListener {
+ val age = SafeParse.stringToDouble(survey_age.text.toString())
+ val weight = SafeParse.stringToDouble(survey_weight.text.toString())
+ val tdd = SafeParse.stringToDouble(survey_tdd.text.toString())
+ if (age < 1 || age > 120) {
+ ToastUtils.showToastInUiThread(this, R.string.invalidage)
+ return@setOnClickListener
+ }
+ if ((weight < 5 || weight > 150) && tdd == 0.0) {
+ ToastUtils.showToastInUiThread(this, R.string.invalidweight)
+ return@setOnClickListener
+ }
+ if ((tdd < 5 || tdd > 150) && weight == 0.0) {
+ ToastUtils.showToastInUiThread(this, R.string.invalidweight)
+ return@setOnClickListener
+ }
+ val profile = DefaultProfile().profile(age, tdd, weight, ProfileFunctions.getSystemUnits())
+ val args = Bundle()
+ args.putLong("time", DateUtil.now())
+ args.putInt("mode", ProfileViewerDialog.Mode.CUSTOM_PROFILE.ordinal)
+ args.putString("customProfile", profile.data.toString())
+ args.putString("customProfileUnits", profile.units)
+ args.putString("customProfileName", "Age: $age TDD: $tdd Weight: $weight")
+ val pvd = ProfileViewerDialog()
+ pvd.arguments = args
+ pvd.show(supportFragmentManager, "ProfileViewDialog")
+ }
+
+ survey_submit.setOnClickListener {
+ val r = FirebaseRecord()
+ r.id = InstanceId.instanceId()
+ r.age = SafeParse.stringToInt(survey_age.text.toString())
+ r.weight = SafeParse.stringToInt(survey_weight.text.toString())
+ if (r.age < 1 || r.age > 120) {
+ ToastUtils.showToastInUiThread(this, R.string.invalidage)
+ return@setOnClickListener
+ }
+ if (r.weight < 5 || r.weight > 150) {
+ ToastUtils.showToastInUiThread(this, R.string.invalidweight)
+ return@setOnClickListener
+ }
+
+ if (survey_spinner.selectedItem == null)
+ return@setOnClickListener
+ val profileName = survey_spinner.selectedItem.toString()
+ val specificProfile = profileStore.getSpecificProfile(profileName)
+
+ r.profileJson = specificProfile.toString()
+
+ val auth = FirebaseAuth.getInstance()
+ auth.signInAnonymously()
+ .addOnCompleteListener(this) { task ->
+ if (task.isSuccessful) {
+ log.debug("signInAnonymously:success")
+ val user = auth.currentUser // TODO: do we need this, seems unused?
+
+ val database = FirebaseDatabase.getInstance().reference
+ database.child("survey").child(r.id).setValue(r)
+ } else {
+ log.error("signInAnonymously:failure", task.exception)
+ ToastUtils.showToastInUiThread(this, "Authentication failed.")
+ //updateUI(null)
+ }
+
+ // ...
+ }
+ finish()
+ }
+ }
+
+ inner class FirebaseRecord {
+ var id = ""
+ var age: Int = 0
+ var weight: Int = 0
+ var profileJson = "ghfg"
+ }
+
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/activities/TDDStatsActivity.java b/app/src/main/java/info/nightscout/androidaps/activities/TDDStatsActivity.java
index e42d31d7c07..03fb034c5cb 100644
--- a/app/src/main/java/info/nightscout/androidaps/activities/TDDStatsActivity.java
+++ b/app/src/main/java/info/nightscout/androidaps/activities/TDDStatsActivity.java
@@ -1,10 +1,8 @@
package info.nightscout.androidaps.activities;
-import android.app.Activity;
import android.graphics.Color;
import android.graphics.Rect;
import android.os.Bundle;
-import android.support.v7.widget.LinearLayoutManager;
import android.text.TextUtils;
import android.view.KeyEvent;
import android.view.MotionEvent;
@@ -18,7 +16,7 @@
import android.widget.TableRow;
import android.widget.TextView;
-import com.squareup.otto.Subscribe;
+import androidx.recyclerview.widget.LinearLayoutManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -39,6 +37,7 @@
import info.nightscout.androidaps.db.TDD;
import info.nightscout.androidaps.events.EventPumpStatusChanged;
import info.nightscout.androidaps.interfaces.PumpInterface;
+import info.nightscout.androidaps.plugins.bus.RxBus;
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions;
import info.nightscout.androidaps.plugins.pump.danaR.DanaRPlugin;
@@ -49,11 +48,15 @@
import info.nightscout.androidaps.plugins.pump.insight.LocalInsightPlugin;
import info.nightscout.androidaps.queue.Callback;
import info.nightscout.androidaps.utils.DecimalFormatter;
+import info.nightscout.androidaps.utils.FabricPrivacy;
import info.nightscout.androidaps.utils.SP;
import info.nightscout.androidaps.utils.SafeParse;
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.disposables.CompositeDisposable;
-public class TDDStatsActivity extends Activity {
+public class TDDStatsActivity extends NoSplashAppCompatActivity {
private static Logger log = LoggerFactory.getLogger(TDDStatsActivity.class);
+ private CompositeDisposable disposable = new CompositeDisposable();
TextView statusView, statsMessage, totalBaseBasal2;
EditText totalBaseBasal;
@@ -74,13 +77,25 @@ public TDDStatsActivity() {
@Override
protected void onResume() {
super.onResume();
- MainApp.bus().register(this);
+ disposable.add(RxBus.INSTANCE
+ .toObservable(EventPumpStatusChanged.class)
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(event -> statusView.setText(event.getStatus()), FabricPrivacy::logException)
+ );
+ disposable.add(RxBus.INSTANCE
+ .toObservable(EventDanaRSyncStatus.class)
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(event -> {
+ log.debug("EventDanaRSyncStatus: " + event.getMessage());
+ statusView.setText(event.getMessage());
+ }, FabricPrivacy::logException)
+ );
}
@Override
protected void onPause() {
super.onPause();
- MainApp.bus().unregister(this);
+ disposable.clear();
}
@Override
@@ -99,7 +114,7 @@ public boolean dispatchTouchEvent(MotionEvent event) {
}
@Override
- protected void onCreate(Bundle savedInstanceState) {
+ public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.danar_statsactivity);
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
@@ -239,7 +254,7 @@ public void run() {
statsMessage.setText(MainApp.gs(R.string.danar_stats_warning_Message));
}
});
- ConfigBuilderPlugin.getPlugin().getCommandQueue().loadTDDs( new Callback() {
+ ConfigBuilderPlugin.getPlugin().getCommandQueue().loadTDDs(new Callback() {
@Override
public void run() {
loadDataFromDB();
@@ -399,7 +414,7 @@ public void run() {
//cumulative TDDs
for (TDD record : historyList) {
- if(!historyList.isEmpty() && df.format(new Date(record.date)).equals(df.format(new Date()))) {
+ if (!historyList.isEmpty() && df.format(new Date(record.date)).equals(df.format(new Date()))) {
//Today should not be included
continue;
}
@@ -448,7 +463,7 @@ public void run() {
tl.setBackgroundColor(Color.TRANSPARENT);
}
- if(!historyList.isEmpty() && df.format(new Date(historyList.get(0).date)).equals(df.format(new Date()))) {
+ if (!historyList.isEmpty() && df.format(new Date(historyList.get(0).date)).equals(df.format(new Date()))) {
//Today should not be included
historyList.remove(0);
}
@@ -519,42 +534,17 @@ private void cleanTable(TableLayout table) {
}
}
- @Subscribe
- public void onStatusEvent(final EventDanaRSyncStatus s) {
- log.debug("EventDanaRSyncStatus: " + s.message);
- runOnUiThread(
- new Runnable() {
- @Override
- public void run() {
- statusView.setText(s.message);
- }
- });
- }
-
- @Subscribe
- public void onStatusEvent(final EventPumpStatusChanged c) {
- runOnUiThread(
- new Runnable() {
- @Override
- public void run() {
- statusView.setText(c.textStatus());
- }
- }
- );
- }
-
-
public static boolean isOldData(List historyList) {
Object activePump = ConfigBuilderPlugin.getPlugin().getActivePump();
- PumpInterface dana = MainApp.getSpecificPlugin(DanaRPlugin.class);
- PumpInterface danaRS = MainApp.getSpecificPlugin(DanaRSPlugin.class);
- PumpInterface danaV2 = MainApp.getSpecificPlugin(DanaRv2Plugin.class);
- PumpInterface danaKorean = MainApp.getSpecificPlugin(DanaRKoreanPlugin.class);
- PumpInterface insight = MainApp.getSpecificPlugin(LocalInsightPlugin.class);
+ PumpInterface dana = DanaRPlugin.getPlugin();
+ PumpInterface danaRS = DanaRSPlugin.getPlugin();
+ PumpInterface danaV2 = DanaRv2Plugin.getPlugin();
+ PumpInterface danaKorean = DanaRKoreanPlugin.getPlugin();
+ PumpInterface insight = LocalInsightPlugin.getPlugin();
boolean startsYesterday = activePump == dana || activePump == danaRS || activePump == danaV2 || activePump == danaKorean || activePump == insight;
DateFormat df = new SimpleDateFormat("dd.MM.");
- return (historyList.size() < 3 || !(df.format(new Date(historyList.get(0).date)).equals(df.format(new Date(System.currentTimeMillis() - (startsYesterday?1000 * 60 * 60 * 24:0))))));
+ return (historyList.size() < 3 || !(df.format(new Date(historyList.get(0).date)).equals(df.format(new Date(System.currentTimeMillis() - (startsYesterday ? 1000 * 60 * 60 * 24 : 0))))));
}
}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/data/ConstraintChecker.java b/app/src/main/java/info/nightscout/androidaps/data/ConstraintChecker.java
index b1267e81bc4..9d7a49493b6 100644
--- a/app/src/main/java/info/nightscout/androidaps/data/ConstraintChecker.java
+++ b/app/src/main/java/info/nightscout/androidaps/data/ConstraintChecker.java
@@ -1,11 +1,9 @@
package info.nightscout.androidaps.data;
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
import java.util.ArrayList;
-import javax.annotation.Nonnull;
-
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.interfaces.Constraint;
diff --git a/app/src/main/java/info/nightscout/androidaps/data/Intervals.java b/app/src/main/java/info/nightscout/androidaps/data/Intervals.java
index 66d567d9bd3..efb3b76aea2 100644
--- a/app/src/main/java/info/nightscout/androidaps/data/Intervals.java
+++ b/app/src/main/java/info/nightscout/androidaps/data/Intervals.java
@@ -1,7 +1,7 @@
package info.nightscout.androidaps.data;
-import android.support.annotation.Nullable;
-import android.support.v4.util.LongSparseArray;
+import androidx.annotation.Nullable;
+import androidx.collection.LongSparseArray;
import java.util.ArrayList;
import java.util.List;
@@ -22,7 +22,7 @@ public Intervals() {
rawData = new LongSparseArray();
}
- public synchronized Intervals reset() {
+ public synchronized Intervals reset() {
rawData = new LongSparseArray();
return this;
}
diff --git a/app/src/main/java/info/nightscout/androidaps/data/IobTotal.java b/app/src/main/java/info/nightscout/androidaps/data/IobTotal.java
index 73f75b9c7d4..60e1b210489 100644
--- a/app/src/main/java/info/nightscout/androidaps/data/IobTotal.java
+++ b/app/src/main/java/info/nightscout/androidaps/data/IobTotal.java
@@ -1,7 +1,5 @@
package info.nightscout.androidaps.data;
-import com.rits.cloning.Cloner;
-
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
@@ -9,10 +7,12 @@
import java.util.Date;
+import info.nightscout.androidaps.plugins.general.overview.graphExtensions.DataPointWithLabelInterface;
+import info.nightscout.androidaps.plugins.general.overview.graphExtensions.PointsWithLabelGraphSeries;
import info.nightscout.androidaps.utils.DateUtil;
import info.nightscout.androidaps.utils.Round;
-public class IobTotal {
+public class IobTotal implements DataPointWithLabelInterface {
private static Logger log = LoggerFactory.getLogger(IobTotal.class);
public double iob;
@@ -35,8 +35,19 @@ public class IobTotal {
public IobTotal copy() {
- Cloner cloner = new Cloner();
- return cloner.deepClone(this);
+ IobTotal i = new IobTotal(time);
+ i.iob = iob;
+ i.activity = activity;
+ i.bolussnooze = bolussnooze;
+ i.basaliob = basaliob;
+ i.netbasalinsulin = netbasalinsulin;
+ i.hightempinsulin = hightempinsulin;
+ i.lastBolusTime = lastBolusTime;
+ if (iobWithZeroTemp != null) i.iobWithZeroTemp = iobWithZeroTemp.copy();
+ i.netInsulin = netInsulin;
+ i.netRatio = netRatio;
+ i.extendedBolusInsulin = extendedBolusInsulin;
+ return i;
}
public IobTotal(long time) {
@@ -133,4 +144,52 @@ public JSONObject determineBasalJson() {
return json;
}
+ // DataPoint interface
+
+ private int color;
+
+ @Override
+ public double getX() {
+ return time;
+ }
+
+ @Override
+ public double getY() {
+ return iob;
+ }
+
+ @Override
+ public void setY(double y) {
+
+ }
+
+ @Override
+ public String getLabel() {
+ return null;
+ }
+
+ @Override
+ public long getDuration() {
+ return 0;
+ }
+
+ @Override
+ public PointsWithLabelGraphSeries.Shape getShape() {
+ return PointsWithLabelGraphSeries.Shape.IOBPREDICTION;
+ }
+
+ @Override
+ public float getSize() {
+ return 0.5f;
+ }
+
+ @Override
+ public int getColor() {
+ return color;
+ }
+
+ public IobTotal setColor(int color) {
+ this.color = color;
+ return this;
+ }
}
diff --git a/app/src/main/java/info/nightscout/androidaps/data/NonOverlappingIntervals.java b/app/src/main/java/info/nightscout/androidaps/data/NonOverlappingIntervals.java
index 8e0c286e7ea..c426aede402 100644
--- a/app/src/main/java/info/nightscout/androidaps/data/NonOverlappingIntervals.java
+++ b/app/src/main/java/info/nightscout/androidaps/data/NonOverlappingIntervals.java
@@ -1,10 +1,8 @@
package info.nightscout.androidaps.data;
-import android.support.annotation.Nullable;
-import android.support.v4.util.LongSparseArray;
+import androidx.annotation.Nullable;
-import info.nightscout.androidaps.db.TemporaryBasal;
import info.nightscout.androidaps.interfaces.Interval;
/**
@@ -21,7 +19,7 @@ public NonOverlappingIntervals (Intervals other) {
rawData = other.rawData.clone();
}
- protected synchronized void merge() {
+ public synchronized void merge() {
for (int index = 0; index < rawData.size() - 1; index++) {
Interval i = rawData.valueAt(index);
long startOfNewer = rawData.valueAt(index + 1).start();
diff --git a/app/src/main/java/info/nightscout/androidaps/data/OverlappingIntervals.java b/app/src/main/java/info/nightscout/androidaps/data/OverlappingIntervals.java
index 76c2ff36154..5515ea15e1f 100644
--- a/app/src/main/java/info/nightscout/androidaps/data/OverlappingIntervals.java
+++ b/app/src/main/java/info/nightscout/androidaps/data/OverlappingIntervals.java
@@ -1,7 +1,7 @@
package info.nightscout.androidaps.data;
-import android.support.annotation.Nullable;
+import androidx.annotation.Nullable;
import info.nightscout.androidaps.interfaces.Interval;
diff --git a/app/src/main/java/info/nightscout/androidaps/data/Profile.java b/app/src/main/java/info/nightscout/androidaps/data/Profile.java
index 23a7e62426d..a84fb405376 100644
--- a/app/src/main/java/info/nightscout/androidaps/data/Profile.java
+++ b/app/src/main/java/info/nightscout/androidaps/data/Profile.java
@@ -1,6 +1,6 @@
package info.nightscout.androidaps.data;
-import android.support.v4.util.LongSparseArray;
+import androidx.collection.LongSparseArray;
import org.json.JSONArray;
import org.json.JSONException;
@@ -11,18 +11,22 @@
import java.text.DecimalFormat;
import java.util.TimeZone;
+import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.interfaces.PumpDescription;
import info.nightscout.androidaps.interfaces.PumpInterface;
+import info.nightscout.androidaps.plugins.bus.RxBus;
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin;
+import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions;
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification;
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification;
import info.nightscout.androidaps.utils.DateUtil;
import info.nightscout.androidaps.utils.DecimalFormatter;
import info.nightscout.androidaps.utils.FabricPrivacy;
import info.nightscout.androidaps.utils.MidnightTime;
+import info.nightscout.androidaps.utils.Round;
public class Profile {
private static Logger log = LoggerFactory.getLogger(Profile.class);
@@ -73,6 +77,11 @@ public Profile(JSONObject json, String units) {
}
}
+ // Constructor from profileStore JSON
+ public Profile(JSONObject json) {
+ init(json, 100, 0);
+ }
+
public Profile(JSONObject json, int percentage, int timeshift) {
init(json, percentage, timeshift);
}
@@ -98,8 +107,6 @@ protected void init(JSONObject json, int percentage, int timeshift) {
units = json.getString("units").toLowerCase();
if (json.has("dia"))
dia = json.getDouble("dia");
- if (json.has("dia"))
- dia = json.getDouble("dia");
if (json.has("timezone"))
timeZone = TimeZone.getTimeZone(json.getString("timezone"));
isf = json.getJSONArray("sens");
@@ -147,7 +154,7 @@ public String getUnits() {
return units;
}
- public TimeZone getTimeZone() {
+ TimeZone getTimeZone() {
return timeZone;
}
@@ -160,22 +167,23 @@ private LongSparseArray convertToSparseArray(JSONArray array) {
double multiplier = getMultiplier(array);
LongSparseArray sparse = new LongSparseArray<>();
- for (Integer index = 0; index < array.length(); index++) {
+ for (int index = 0; index < array.length(); index++) {
try {
final JSONObject o = array.getJSONObject(index);
long tas = 0;
try {
- tas = getShitfTimeSecs((int) o.getLong("timeAsSeconds"));
- } catch (JSONException e) {
String time = o.getString("time");
tas = getShitfTimeSecs(DateUtil.toSeconds(time));
+ } catch (JSONException e) {
//log.debug(">>>>>>>>>>>> Used recalculated timeAsSecons: " + time + " " + tas);
+ tas = getShitfTimeSecs((int) o.getLong("timeAsSeconds"));
}
double value = o.getDouble("value") * multiplier;
sparse.put(tas, value);
- } catch (JSONException e) {
+ } catch (Exception e) {
log.error("Unhandled exception", e);
log.error(json.toString());
+ FabricPrivacy.logException(e);
}
}
@@ -226,8 +234,10 @@ public synchronized boolean isValid(String from, boolean notify) {
for (int index = 0; index < basal_v.size(); index++) {
long secondsFromMidnight = basal_v.keyAt(index);
if (notify && secondsFromMidnight % 3600 != 0) {
- Notification notification = new Notification(Notification.BASAL_PROFILE_NOT_ALIGNED_TO_HOURS, String.format(MainApp.gs(R.string.basalprofilenotaligned), from), Notification.NORMAL);
- MainApp.bus().post(new EventNewNotification(notification));
+ if (Config.APS) {
+ Notification notification = new Notification(Notification.BASAL_PROFILE_NOT_ALIGNED_TO_HOURS, String.format(MainApp.gs(R.string.basalprofilenotaligned), from), Notification.NORMAL);
+ RxBus.INSTANCE.send(new EventNewNotification(notification));
+ }
}
}
}
@@ -258,11 +268,11 @@ public synchronized boolean isValid(String from, boolean notify) {
}
protected void sendBelowMinimumNotification(String from) {
- MainApp.bus().post(new EventNewNotification(new Notification(Notification.MINIMAL_BASAL_VALUE_REPLACED, String.format(MainApp.gs(R.string.minimalbasalvaluereplaced), from), Notification.NORMAL)));
+ RxBus.INSTANCE.send(new EventNewNotification(new Notification(Notification.MINIMAL_BASAL_VALUE_REPLACED, String.format(MainApp.gs(R.string.minimalbasalvaluereplaced), from), Notification.NORMAL)));
}
protected void sendAboveMaximumNotification(String from) {
- MainApp.bus().post(new EventNewNotification(new Notification(Notification.MAXIMUM_BASAL_VALUE_REPLACED, String.format(MainApp.gs(R.string.maximumbasalvaluereplaced), from), Notification.NORMAL)));
+ RxBus.INSTANCE.send(new EventNewNotification(new Notification(Notification.MAXIMUM_BASAL_VALUE_REPLACED, String.format(MainApp.gs(R.string.maximumbasalvaluereplaced), from), Notification.NORMAL)));
}
private void validate(LongSparseArray array) {
@@ -380,15 +390,15 @@ private String getValuesList(LongSparseArray array, LongSparseArray max) max = value;
}
return max;
@@ -543,22 +633,39 @@ public static double fromMgdlToUnits(double value, String units) {
else return value * Constants.MGDL_TO_MMOLL;
}
- public static double toUnits(Double valueInMgdl, Double valueInMmol, String units) {
+ public static double fromMmolToUnits(double value, String units) {
+ if (units.equals(Constants.MMOL)) return value;
+ else return value * Constants.MMOLL_TO_MGDL;
+ }
+
+ public static double toUnits(double valueInMgdl, double valueInMmol, String units) {
if (units.equals(Constants.MGDL)) return valueInMgdl;
else return valueInMmol;
}
- public static String toUnitsString(Double valueInMgdl, Double valueInMmol, String units) {
+ public static String toUnitsString(double valueInMgdl, double valueInMmol, String units) {
if (units.equals(Constants.MGDL)) return DecimalFormatter.to0Decimal(valueInMgdl);
else return DecimalFormatter.to1Decimal(valueInMmol);
}
- public static String toSignedUnitsString(Double valueInMgdl, Double valueInMmol, String units) {
+ public static String toSignedUnitsString(double valueInMgdl, double valueInMmol, String units) {
if (units.equals(Constants.MGDL))
return (valueInMgdl > 0 ? "+" : "") + DecimalFormatter.to0Decimal(valueInMgdl);
else return (valueInMmol > 0 ? "+" : "") + DecimalFormatter.to1Decimal(valueInMmol);
}
+ public static double toCurrentUnits(double anyBg) {
+ if (anyBg < 32) return fromMmolToUnits(anyBg, ProfileFunctions.getSystemUnits());
+ else return fromMgdlToUnits(anyBg, ProfileFunctions.getSystemUnits());
+ }
+
+ public static String toCurrentUnitsString(double anyBg) {
+ if (anyBg < 32)
+ return toUnitsString(anyBg * Constants.MMOLL_TO_MGDL, anyBg, ProfileFunctions.getSystemUnits());
+ else
+ return toUnitsString(anyBg, anyBg * Constants.MGDL_TO_MMOLL, ProfileFunctions.getSystemUnits());
+ }
+
// targets are stored in mg/dl but profile vary
public static String toTargetRangeString(double low, double high, String sourceUnits, String units) {
double lowMgdl = toMgdl(low, sourceUnits);
@@ -596,4 +703,133 @@ public int getPercentage() {
public int getTimeshift() {
return timeshift;
}
+
+ public Profile convertToNonCustomizedProfile() {
+ JSONObject o = new JSONObject();
+ try {
+ o.put("units", units);
+ o.put("dia", dia);
+ o.put("timezone", timeZone.getID());
+ // SENS
+ JSONArray sens = new JSONArray();
+ double lastValue = -1d;
+ for (int i = 0; i < 24; i++) {
+ int timeAsSeconds = i * 60 * 60;
+ double value = getIsfTimeFromMidnight(timeAsSeconds);
+ if (value != lastValue) {
+ JSONObject item = new JSONObject();
+ String time;
+ DecimalFormat df = new DecimalFormat("00");
+ time = df.format(i) + ":00";
+ item.put("time", time);
+ item.put("timeAsSeconds", timeAsSeconds);
+ item.put("value", value);
+ lastValue = value;
+ sens.put(item);
+ }
+ }
+ o.put("sens", sens);
+ // CARBRATIO
+ JSONArray carbratio = new JSONArray();
+ lastValue = -1d;
+ for (int i = 0; i < 24; i++) {
+ int timeAsSeconds = i * 60 * 60;
+ double value = getIcTimeFromMidnight(timeAsSeconds);
+ if (value != lastValue) {
+ JSONObject item = new JSONObject();
+ String time;
+ DecimalFormat df = new DecimalFormat("00");
+ time = df.format(i) + ":00";
+ item.put("time", time);
+ item.put("timeAsSeconds", timeAsSeconds);
+ item.put("value", value);
+ lastValue = value;
+ carbratio.put(item);
+ }
+ }
+ o.put("carbratio", carbratio);
+ // BASAL
+ JSONArray basal = new JSONArray();
+ lastValue = -1d;
+ for (int i = 0; i < 24; i++) {
+ int timeAsSeconds = i * 60 * 60;
+ double value = getBasalTimeFromMidnight(timeAsSeconds);
+ if (value != lastValue) {
+ JSONObject item = new JSONObject();
+ String time;
+ DecimalFormat df = new DecimalFormat("00");
+ time = df.format(i) + ":00";
+ item.put("time", time);
+ item.put("timeAsSeconds", timeAsSeconds);
+ item.put("value", value);
+ lastValue = value;
+ basal.put(item);
+ }
+ }
+ o.put("basal", basal);
+ // TARGET_LOW
+ JSONArray target_low = new JSONArray();
+ lastValue = -1d;
+ for (int i = 0; i < 24; i++) {
+ int timeAsSeconds = i * 60 * 60;
+ double value = getTargetLowTimeFromMidnight(timeAsSeconds);
+ if (value != lastValue) {
+ JSONObject item = new JSONObject();
+ String time;
+ DecimalFormat df = new DecimalFormat("00");
+ time = df.format(i) + ":00";
+ item.put("time", time);
+ item.put("timeAsSeconds", timeAsSeconds);
+ item.put("value", value);
+ lastValue = value;
+ target_low.put(item);
+ }
+ }
+ o.put("target_low", target_low);
+ // TARGET_HIGH
+ JSONArray target_high = new JSONArray();
+ lastValue = -1d;
+ for (int i = 0; i < 24; i++) {
+ int timeAsSeconds = i * 60 * 60;
+ double value = getTargetHighTimeFromMidnight(timeAsSeconds);
+ if (value != lastValue) {
+ JSONObject item = new JSONObject();
+ String time;
+ DecimalFormat df = new DecimalFormat("00");
+ time = df.format(i) + ":00";
+ item.put("time", time);
+ item.put("timeAsSeconds", timeAsSeconds);
+ item.put("value", value);
+ lastValue = value;
+ target_high.put(item);
+ }
+ }
+ o.put("target_high", target_high);
+
+ } catch (JSONException e) {
+ log.error("Unhandled exception" + e);
+ }
+ return new Profile(o);
+ }
+
+ public boolean isProfileTheSame(Profile otherProfile) {
+
+ if (!Round.isSame(this.baseBasalSum(), otherProfile.baseBasalSum()))
+ return false;
+
+ ProfileValue[] basalValues = this.getBasalValues();
+ ProfileValue[] otherBasalValues = otherProfile.getBasalValues();
+
+ if (basalValues.length != otherBasalValues.length)
+ return false;
+
+ for (int i = 0; i < basalValues.length; i++) {
+ if (!basalValues[i].equals(otherBasalValues[i])) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
}
diff --git a/app/src/main/java/info/nightscout/androidaps/data/ProfileIntervals.java b/app/src/main/java/info/nightscout/androidaps/data/ProfileIntervals.java
index 8938b539361..37be1dc6e93 100644
--- a/app/src/main/java/info/nightscout/androidaps/data/ProfileIntervals.java
+++ b/app/src/main/java/info/nightscout/androidaps/data/ProfileIntervals.java
@@ -1,7 +1,7 @@
package info.nightscout.androidaps.data;
-import android.support.annotation.Nullable;
-import android.support.v4.util.LongSparseArray;
+import androidx.annotation.Nullable;
+import androidx.collection.LongSparseArray;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -31,7 +31,7 @@ public ProfileIntervals (ProfileIntervals other) {
rawData = other.rawData.clone();
}
- public synchronized ProfileIntervals reset() {
+ public synchronized ProfileIntervals reset() {
rawData = new LongSparseArray<>();
return this;
}
diff --git a/app/src/main/java/info/nightscout/androidaps/data/ProfileStore.java b/app/src/main/java/info/nightscout/androidaps/data/ProfileStore.java
deleted file mode 100644
index f97d8b5e029..00000000000
--- a/app/src/main/java/info/nightscout/androidaps/data/ProfileStore.java
+++ /dev/null
@@ -1,118 +0,0 @@
-package info.nightscout.androidaps.data;
-
-import android.support.annotation.Nullable;
-import android.support.v4.util.ArrayMap;
-
-import org.json.JSONException;
-import org.json.JSONObject;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.ArrayList;
-import java.util.Iterator;
-
-import info.nightscout.androidaps.Constants;
-
-/**
- * Created by mike on 01.06.2017.
- */
-
-public class ProfileStore {
- private static Logger log = LoggerFactory.getLogger(ProfileStore.class);
- private JSONObject json = null;
- private String units = Constants.MGDL;
-
- ArrayMap cachedObjects = new ArrayMap<>();
-
- public ProfileStore(JSONObject json) {
- this.json = json;
- getDefaultProfile(); // initialize units
- }
-
- public JSONObject getData() {
- return json;
- }
-
- @Nullable
- public Profile getDefaultProfile() {
- Profile profile = null;
- try {
- String defaultProfileName = json.getString("defaultProfile");
- JSONObject store = json.getJSONObject("store");
- if (store.has(defaultProfileName)) {
- profile = cachedObjects.get(defaultProfileName);
- if (profile == null) {
- if (store.has("units"))
- units = store.getString("units");
- profile = new Profile(store.getJSONObject(defaultProfileName), units);
- units = profile.getUnits();
- cachedObjects.put(defaultProfileName, profile);
- }
- }
- } catch (JSONException e) {
- log.error("Unhandled exception", e);
- }
- return profile;
- }
-
- @Nullable
- public String getDefaultProfileName() {
- String defaultProfileName = null;
- try {
- defaultProfileName = json.getString("defaultProfile");
- JSONObject store = json.getJSONObject("store");
- if (store.has(defaultProfileName)) {
- return defaultProfileName;
- }
- } catch (JSONException e) {
- log.error("Unhandled exception", e);
- }
- return defaultProfileName;
- }
-
- public String getUnits() {
- return units;
- }
-
- @Nullable
- public Profile getSpecificProfile(String profileName) {
- Profile profile = null;
- try {
- JSONObject store = json.getJSONObject("store");
- if (store.has(profileName)) {
- profile = cachedObjects.get(profileName);
- if (profile == null) {
- if (store.has("units"))
- units = store.getString("units");
- profile = new Profile(store.getJSONObject(profileName), units);
- units = profile.getUnits();
- cachedObjects.put(profileName, profile);
- }
- }
- } catch (JSONException e) {
- log.error("Unhandled exception", e);
- }
- return profile;
- }
-
- public ArrayList getProfileList() {
- ArrayList ret = new ArrayList();
-
- JSONObject store;
- try {
- store = json.getJSONObject("store");
- Iterator> keys = store.keys();
-
- while (keys.hasNext()) {
- String profileName = (String) keys.next();
- ret.add(profileName);
- }
- } catch (JSONException e) {
- log.error("Unhandled exception", e);
- }
-
- return ret;
- }
-
-
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/data/ProfileStore.kt b/app/src/main/java/info/nightscout/androidaps/data/ProfileStore.kt
new file mode 100644
index 00000000000..9415a25f2cb
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/data/ProfileStore.kt
@@ -0,0 +1,60 @@
+package info.nightscout.androidaps.data
+
+import androidx.collection.ArrayMap
+import info.nightscout.androidaps.utils.JsonHelper
+import org.json.JSONException
+import org.json.JSONObject
+import org.slf4j.LoggerFactory
+import java.util.*
+
+class ProfileStore(val data: JSONObject) {
+ private val log = LoggerFactory.getLogger(ProfileStore::class.java)
+
+ private val cachedObjects = ArrayMap()
+
+ private fun getStore(): JSONObject? {
+ try {
+ if (data.has("store")) return data.getJSONObject("store")
+ } catch (e: JSONException) {
+ log.error("Unhandled exception", e)
+ }
+ return null
+ }
+
+ fun getDefaultProfile(): Profile? = getDefaultProfileName()?.let { getSpecificProfile(it) }
+
+ fun getDefaultProfileName(): String? {
+ val defaultProfileName = data.getString("defaultProfile")
+ return getStore()?.has(defaultProfileName)?.let { defaultProfileName }
+ }
+
+ fun getProfileList(): ArrayList {
+ val ret = ArrayList()
+ getStore()?.keys()?.let { keys ->
+ while (keys.hasNext()) {
+ val profileName = keys.next() as String
+ ret.add(profileName)
+ }
+ }
+ return ret
+ }
+
+ fun getSpecificProfile(profileName: String): Profile? {
+ var profile: Profile? = null
+ getStore()?.let { store ->
+ if (store.has(profileName)) {
+ profile = cachedObjects[profileName]
+ if (profile == null) {
+ JsonHelper.safeGetJSONObject(store, profileName, null)?.let { profileObject ->
+ // take units from profile and if N/A from store
+ JsonHelper.safeGetStringAllowNull(profileObject, "units", JsonHelper.safeGetString(data, "units"))?.let { units ->
+ profile = Profile(profileObject, units)
+ cachedObjects[profileName] = profile
+ }
+ }
+ }
+ }
+ }
+ return profile
+ }
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/data/PumpEnactResult.java b/app/src/main/java/info/nightscout/androidaps/data/PumpEnactResult.java
index d38b3556343..461d8faa7bf 100644
--- a/app/src/main/java/info/nightscout/androidaps/data/PumpEnactResult.java
+++ b/app/src/main/java/info/nightscout/androidaps/data/PumpEnactResult.java
@@ -45,6 +45,11 @@ public PumpEnactResult comment(String comment) {
return this;
}
+ public PumpEnactResult comment(int comment) {
+ this.comment = MainApp.gs(comment);
+ return this;
+ }
+
public PumpEnactResult duration(int duration) {
this.duration = duration;
return this;
diff --git a/app/src/main/java/info/nightscout/androidaps/data/QuickWizard.java b/app/src/main/java/info/nightscout/androidaps/data/QuickWizard.java
deleted file mode 100644
index 80a6e1b4578..00000000000
--- a/app/src/main/java/info/nightscout/androidaps/data/QuickWizard.java
+++ /dev/null
@@ -1,86 +0,0 @@
-package info.nightscout.androidaps.data;
-
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import info.nightscout.androidaps.utils.SP;
-
-/**
- * Created by mike on 12.10.2016.
- */
-
-public class QuickWizard {
- private static Logger log = LoggerFactory.getLogger(QuickWizard.class);
-
- private JSONArray storage = new JSONArray();
-
- public void setData(JSONArray newData) {
- storage = newData;
- }
-
- public void save() {
- SP.putString("QuickWizard", storage.toString());
- }
-
- public int size() {
- return storage.length();
- }
-
- public QuickWizardEntry get(int position) {
- try {
- return new QuickWizardEntry((JSONObject) storage.get(position), position);
- } catch (JSONException e) {
- log.error("Unhandled exception", e);
- }
- return null;
- }
-
- public Boolean isActive() {
- for (int i = 0; i < storage.length(); i++) {
- try {
- if (new QuickWizardEntry((JSONObject) storage.get(i), i).isActive()) return true;
- } catch (JSONException e) {
- log.error("Unhandled exception", e);
- }
- }
- return false;
- }
-
- public QuickWizardEntry getActive() {
- for (int i = 0; i < storage.length(); i++) {
- QuickWizardEntry entry;
- try {
- entry = new QuickWizardEntry((JSONObject) storage.get(i), i);
- } catch (JSONException e) {
- continue;
- }
- if (entry.isActive()) return entry;
- }
- return null;
- }
-
- public QuickWizardEntry newEmptyItem() {
- return new QuickWizardEntry();
- }
-
- public void addOrUpdate(QuickWizardEntry newItem) {
- if (newItem.position == -1)
- storage.put(newItem.storage);
- else {
- try {
- storage.put(newItem.position, newItem.storage);
- } catch (JSONException e) {
- log.error("Unhandled exception", e);
- }
- }
- save();
- }
-
- public void remove(int position) {
- storage.remove(position);
- save();
- }
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/data/QuickWizard.kt b/app/src/main/java/info/nightscout/androidaps/data/QuickWizard.kt
new file mode 100644
index 00000000000..f8bca8c450e
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/data/QuickWizard.kt
@@ -0,0 +1,52 @@
+package info.nightscout.androidaps.data
+
+import info.nightscout.androidaps.utils.SP
+import org.json.JSONArray
+import org.json.JSONObject
+
+object QuickWizard {
+ private var storage = JSONArray()
+
+ init {
+ setData(JSONArray(SP.getString("QuickWizard", "[]")))
+ }
+
+ fun getActive(): QuickWizardEntry? {
+ for (i in 0 until storage.length()) {
+ val entry = QuickWizardEntry(storage.get(i) as JSONObject, i)
+ if (entry.isActive) return entry
+ }
+ return null
+ }
+
+ fun setData(newData: JSONArray) {
+ storage = newData
+ }
+
+ fun save() {
+ SP.putString("QuickWizard", storage.toString())
+ }
+
+ fun size(): Int = storage.length()
+
+ operator fun get(position: Int): QuickWizardEntry =
+ QuickWizardEntry(storage.get(position) as JSONObject, position)
+
+
+ fun newEmptyItem(): QuickWizardEntry {
+ return QuickWizardEntry()
+ }
+
+ fun addOrUpdate(newItem: QuickWizardEntry) {
+ if (newItem.position == -1)
+ storage.put(newItem.storage)
+ else
+ storage.put(newItem.position, newItem.storage)
+ save()
+ }
+
+ fun remove(position: Int) {
+ storage.remove(position)
+ save()
+ }
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/data/QuickWizardEntry.java b/app/src/main/java/info/nightscout/androidaps/data/QuickWizardEntry.java
index 0bfcbb1002e..66123e1ce95 100644
--- a/app/src/main/java/info/nightscout/androidaps/data/QuickWizardEntry.java
+++ b/app/src/main/java/info/nightscout/androidaps/data/QuickWizardEntry.java
@@ -11,6 +11,7 @@
import info.nightscout.androidaps.db.BgReading;
import info.nightscout.androidaps.db.TempTarget;
import info.nightscout.androidaps.interfaces.TreatmentsInterface;
+import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.CobInfo;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin;
@@ -50,7 +51,7 @@ public class QuickWizardEntry {
useTemptarget: 0
}
*/
- public QuickWizardEntry() {
+ QuickWizardEntry() {
String emptyData = "{\"buttonText\":\"\",\"carbs\":0,\"validFrom\":0,\"validTo\":86340}";
try {
storage = new JSONObject(emptyData);
@@ -60,22 +61,21 @@ public QuickWizardEntry() {
position = -1;
}
- public QuickWizardEntry(JSONObject entry, int position) {
+ QuickWizardEntry(JSONObject entry, int position) {
storage = entry;
this.position = position;
}
- public Boolean isActive() {
+ Boolean isActive() {
return Profile.secondsFromMidnight() >= validFrom() && Profile.secondsFromMidnight() <= validTo();
}
- public BolusWizard doCalc(Profile profile, TempTarget tempTarget, BgReading lastBG, boolean _synchronized) {
- BolusWizard wizard = new BolusWizard();
-
+ public BolusWizard doCalc(Profile profile, String profileName, BgReading lastBG, boolean _synchronized) {
+ final TempTarget tempTarget = TreatmentsPlugin.getPlugin().getTempTargetFromHistory();
//BG
double bg = 0;
if (lastBG != null && useBG() == YES) {
- bg = lastBG.valueToUnits(profile.getUnits());
+ bg = lastBG.valueToUnits(ProfileFunctions.getSystemUnits());
}
// COB
@@ -86,11 +86,6 @@ public BolusWizard doCalc(Profile profile, TempTarget tempTarget, BgReading last
cob = cobInfo.displayCob;
}
- // Temp target
- if (useTempTarget() == NO) {
- tempTarget = null;
- }
-
// Bolus IOB
boolean bolusIOB = false;
if (useBolusIOB() == YES) {
@@ -130,8 +125,8 @@ public BolusWizard doCalc(Profile profile, TempTarget tempTarget, BgReading last
trend = true;
}
- wizard.doCalc(profile, tempTarget, carbs(), cob, bg, 0d, bolusIOB, basalIOB, superBolus, trend);
- return wizard;
+ double percentage = SP.getDouble(R.string.key_boluswizard_percentage, 100.0);
+ return new BolusWizard(profile, profileName, tempTarget, carbs(), cob, bg, 0d, percentage, true, useCOB() == YES, bolusIOB, basalIOB, superBolus, useTempTarget() == YES, trend, "QuickWizard");
}
public String buttonText() {
diff --git a/app/src/main/java/info/nightscout/androidaps/data/defaultProfile/DefaultProfile.kt b/app/src/main/java/info/nightscout/androidaps/data/defaultProfile/DefaultProfile.kt
new file mode 100644
index 00000000000..b121dbee02b
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/data/defaultProfile/DefaultProfile.kt
@@ -0,0 +1,145 @@
+package info.nightscout.androidaps.data.defaultProfile
+
+import info.nightscout.androidaps.data.Profile
+import info.nightscout.androidaps.utils.Round
+import org.json.JSONArray
+import org.json.JSONObject
+import java.util.*
+
+
+class DefaultProfile {
+ var oneToFive: TreeMap> = TreeMap()
+ var sixToEleven: TreeMap> = TreeMap()
+ var twelveToSeventeen: TreeMap> = TreeMap()
+ var eighteenToTwentyfor: TreeMap> = TreeMap()
+
+ fun profile(age: Double, tdd: Double, weight: Double, units: String): Profile {
+ val profile = JSONObject()
+ if (age >= 1 && age < 6) {
+ val _tdd = if (tdd == 0.0) 0.6 * weight else tdd
+ closest(oneToFive, _tdd * 0.3)?.let { array -> profile.put("basal", arrayToJson(array)) }
+ val ic = Round.roundTo(250.0 / _tdd, 1.0)
+ profile.put("carbratio", singleValueArray(ic, arrayOf( 0.0, -4.0, -1.0, -2.0, -4.0, 0.0, -4.0)))
+ val isf = Round.roundTo(200.0 / _tdd, 0.1)
+ profile.put("sens", singleValueArray(isf, arrayOf( 0.0, -2.0, -0.0, -0.0, -2.0, 0.0, -2.0)))
+ } else if (age >= 6 && age < 12) {
+ val _tdd = if (tdd == 0.0) 0.8 * weight else tdd
+ closest(sixToEleven, _tdd * 0.4)?.let { array -> profile.put("basal", arrayToJson(array)) }
+ val ic = Round.roundTo(375.0 / _tdd, 1.0)
+ profile.put("carbratio", singleValueArray(ic, arrayOf( 0.0, -3.0, 0.0, -1.0, -3.0, 0.0, -2.0)))
+ val isf = Round.roundTo(170.0 / _tdd, 0.1)
+ profile.put("sens", singleValueArray(isf, arrayOf( 0.0, -1.0, -0.0, -0.0, -1.0, 0.0, -1.0)))
+ } else if (age >= 12 && age < 17) {
+ val _tdd = if (tdd == 0.0) 1.0 * weight else tdd
+ closest(twelveToSeventeen, _tdd * 0.5)?.let { array -> profile.put("basal", arrayToJson(array)) }
+ val ic = Round.roundTo(500.0 / _tdd, 1.0)
+ profile.put("carbratio", singleValueArray(ic, arrayOf( 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, -1.0)))
+ val isf = Round.roundTo(100.0 / _tdd, 0.1)
+ profile.put("sens", singleValueArray(isf, arrayOf( 0.2, 0.0, 0.2, 0.2, 0.0, 0.2, 0.2)))
+ } else if (age >= 18) {
+
+ }
+ profile.put("dia", 5.0)
+ profile.put("carbs_hr", 20) // not used
+ profile.put("delay", 5.0) // not used
+ profile.put("timezone", TimeZone.getDefault().getID())
+ profile.put("target_high", JSONArray().put(JSONObject().put("time", "00:00").put("value", Profile.fromMgdlToUnits(108.0, units))))
+ profile.put("target_low", JSONArray().put(JSONObject().put("time", "00:00").put("value", Profile.fromMgdlToUnits(108.0, units))))
+ return Profile(profile, units)
+ }
+
+ init {
+ oneToFive[1.00] = arrayOf(0.050, 0.050, 0.050, 0.050, 0.050, 0.050, 0.075, 0.075, 0.075, 0.050, 0.050, 0.050, 0.050, 0.050, 0.075, 0.075, 0.050, 0.050, 0.050, 0.075, 0.075, 0.075, 0.050, 0.050)
+ oneToFive[1.13] = arrayOf(0.050, 0.050, 0.050, 0.050, 0.050, 0.050, 0.075, 0.075, 0.075, 0.050, 0.050, 0.050, 0.050, 0.050, 0.075, 0.075, 0.050, 0.050, 0.050, 0.075, 0.075, 0.075, 0.050, 0.050)
+ oneToFive[1.25] = arrayOf(0.050, 0.050, 0.050, 0.050, 0.050, 0.050, 0.075, 0.075, 0.075, 0.050, 0.050, 0.050, 0.050, 0.050, 0.075, 0.075, 0.050, 0.050, 0.050, 0.075, 0.075, 0.100, 0.050, 0.050)
+ oneToFive[1.38] = arrayOf(0.050, 0.050, 0.050, 0.050, 0.050, 0.050, 0.075, 0.075, 0.075, 0.050, 0.050, 0.050, 0.050, 0.050, 0.075, 0.075, 0.050, 0.050, 0.050, 0.075, 0.075, 0.100, 0.050, 0.050)
+ oneToFive[1.50] = arrayOf(0.050, 0.050, 0.050, 0.050, 0.050, 0.050, 0.075, 0.075, 0.075, 0.050, 0.050, 0.050, 0.050, 0.050, 0.075, 0.075, 0.050, 0.050, 0.050, 0.075, 0.100, 0.100, 0.050, 0.050)
+ oneToFive[1.75] = arrayOf(0.050, 0.050, 0.050, 0.050, 0.050, 0.050, 0.075, 0.075, 0.100, 0.050, 0.050, 0.050, 0.060, 0.060, 0.075, 0.075, 0.050, 0.050, 0.050, 0.100, 0.125, 0.100, 0.050, 0.050)
+ oneToFive[2.00] = arrayOf(0.050, 0.050, 0.050, 0.050, 0.050, 0.050, 0.075, 0.075, 0.100, 0.075, 0.050, 0.050, 0.065, 0.065, 0.075, 0.075, 0.050, 0.050, 0.050, 0.100, 0.125, 0.100, 0.050, 0.050)
+ oneToFive[2.25] = arrayOf(0.050, 0.050, 0.050, 0.050, 0.075, 0.075, 0.100, 0.100, 0.100, 0.075, 0.060, 0.060, 0.070, 0.070, 0.100, 0.100, 0.050, 0.050, 0.050, 0.125, 0.150, 0.125, 0.065, 0.050)
+ oneToFive[2.50] = arrayOf(0.050, 0.050, 0.050, 0.050, 0.075, 0.075, 0.100, 0.125, 0.125, 0.100, 0.065, 0.065, 0.075, 0.075, 0.125, 0.125, 0.060, 0.060, 0.060, 0.150, 0.150, 0.150, 0.070, 0.060)
+ oneToFive[2.75] = arrayOf(0.075, 0.075, 0.075, 0.100, 0.100, 0.100, 0.125, 0.150, 0.125, 0.100, 0.070, 0.070, 0.080, 0.080, 0.150, 0.150, 0.070, 0.070, 0.070, 0.175, 0.175, 0.175, 0.080, 0.070)
+ oneToFive[3.25] = arrayOf(0.100, 0.100, 0.100, 0.125, 0.125, 0.125, 0.150, 0.150, 0.150, 0.100, 0.080, 0.080, 0.100, 0.100, 0.175, 0.175, 0.075, 0.075, 0.075, 0.200, 0.200, 0.200, 0.090, 0.080)
+ oneToFive[3.75] = arrayOf(0.125, 0.125, 0.125, 0.125, 0.125, 0.125, 0.175, 0.175, 0.175, 0.100, 0.085, 0.085, 0.110, 0.110, 0.185, 0.185, 0.080, 0.080, 0.080, 0.225, 0.225, 0.225, 0.100, 0.090)
+ oneToFive[4.25] = arrayOf(0.125, 0.125, 0.130, 0.140, 0.140, 0.140, 0.200, 0.200, 0.200, 0.125, 0.090, 0.090, 0.120, 0.120, 0.200, 0.200, 0.100, 0.100, 0.100, 0.250, 0.250, 0.250, 0.125, 0.100)
+ oneToFive[4.75] = arrayOf(0.125, 0.130, 0.135, 0.150, 0.150, 0.150, 0.200, 0.225, 0.200, 0.125, 0.100, 0.100, 0.125, 0.125, 0.250, 0.200, 0.110, 0.125, 0.125, 0.275, 0.275, 0.275, 0.130, 0.125)
+ oneToFive[5.25] = arrayOf(0.150, 0.150, 0.150, 0.170, 0.170, 0.170, 0.225, 0.225, 0.225, 0.130, 0.125, 0.125, 0.140, 0.140, 0.250, 0.250, 0.150, 0.150, 0.150, 0.300, 0.300, 0.300, 0.150, 0.150)
+ oneToFive[6.00] = arrayOf(0.170, 0.170, 0.175, 0.200, 0.200, 0.200, 0.250, 0.250, 0.250, 0.150, 0.125, 0.125, 0.150, 0.150, 0.275, 0.275, 0.170, 0.150, 0.150, 0.350, 0.350, 0.350, 0.175, 0.150)
+ oneToFive[6.75] = arrayOf(0.200, 0.200, 0.200, 0.225, 0.225, 0.225, 0.275, 0.275, 0.275, 0.200, 0.130, 0.130, 0.175, 0.175, 0.300, 0.300, 0.170, 0.175, 0.175, 0.375, 0.375, 0.375, 0.200, 0.175)
+ oneToFive[7.50] = arrayOf(0.225, 0.230, 0.235, 0.250, 0.250, 0.250, 0.300, 0.300, 0.300, 0.250, 0.150, 0.150, 0.200, 0.200, 0.325, 0.325, 0.200, 0.200, 0.200, 0.400, 0.450, 0.400, 0.350, 0.200)
+
+ sixToEleven[5.26] = arrayOf(0.18, 0.18, 0.18, 0.20, 0.20, 0.23, 0.25, 0.25, 0.25, 0.18, 0.15, 0.13, 0.15, 0.15, 0.25, 0.25, 0.20, 0.15, 0.18, 0.25, 0.25, 0.25, 0.23, 0.20)
+ sixToEleven[5.61] = arrayOf(0.18, 0.20, 0.20, 0.23, 0.23, 0.25, 0.28, 0.28, 0.25, 0.20, 0.15, 0.13, 0.15, 0.18, 0.25, 0.25, 0.20, 0.15, 0.18, 0.28, 0.25, 0.25, 0.23, 0.20)
+ sixToEleven[5.93] = arrayOf(0.20, 0.20, 0.23, 0.25, 0.25, 0.25, 0.30, 0.30, 0.30, 0.25, 0.15, 0.15, 0.18, 0.18, 0.28, 0.28, 0.20, 0.20, 0.20, 0.28, 0.28, 0.28, 0.25, 0.23)
+ sixToEleven[6.26] = arrayOf(0.20, 0.23, 0.23, 0.25, 0.25, 0.28, 0.33, 0.30, 0.30, 0.25, 0.18, 0.15, 0.18, 0.18, 0.28, 0.28, 0.23, 0.20, 0.20, 0.28, 0.30, 0.28, 0.25, 0.23)
+ sixToEleven[6.60] = arrayOf(0.23, 0.23, 0.25, 0.25, 0.25, 0.28, 0.33, 0.33, 0.33, 0.28, 0.18, 0.15, 0.18, 0.18, 0.30, 0.28, 0.23, 0.23, 0.20, 0.30, 0.30, 0.30, 0.25, 0.25)
+ sixToEleven[7.26] = arrayOf(0.23, 0.25, 0.28, 0.28, 0.30, 0.33, 0.38, 0.35, 0.35, 0.30, 0.18, 0.18, 0.18, 0.19, 0.33, 0.30, 0.25, 0.23, 0.23, 0.33, 0.33, 0.33, 0.30, 0.25)
+ sixToEleven[7.92] = arrayOf(0.25, 0.25, 0.28, 0.30, 0.33, 0.35, 0.38, 0.38, 0.38, 0.35, 0.20, 0.20, 0.23, 0.25, 0.35, 0.33, 0.30, 0.25, 0.25, 0.35, 0.35, 0.35, 0.33, 0.28)
+ sixToEleven[8.57] = arrayOf(0.28, 0.28, 0.30, 0.30, 0.33, 0.38, 0.40, 0.43, 0.40, 0.38, 0.25, 0.25, 0.25, 0.28, 0.38, 0.38, 0.33, 0.28, 0.28, 0.38, 0.40, 0.38, 0.35, 0.30)
+ sixToEleven[9.24] = arrayOf(0.30, 0.33, 0.35, 0.38, 0.40, 0.40, 0.43, 0.45, 0.43, 0.40, 0.30, 0.25, 0.28, 0.28, 0.38, 0.40, 0.33, 0.30, 0.30, 0.40, 0.43, 0.40, 0.38, 0.35)
+ sixToEleven[9.89] = arrayOf(0.35, 0.35, 0.38, 0.40, 0.40, 0.43, 0.45, 0.48, 0.45, 0.40, 0.30, 0.25, 0.28, 0.30, 0.40, 0.43, 0.35, 0.33, 0.33, 0.43, 0.45, 0.43, 0.40, 0.38)
+ sixToEleven[10.56] = arrayOf(0.38, 0.38, 0.40, 0.43, 0.45, 0.45, 0.48, 0.50, 0.48, 0.40, 0.35, 0.25, 0.30, 0.33, 0.43, 0.45, 0.35, 0.35, 0.35, 0.45, 0.48, 0.45, 0.43, 0.40)
+ sixToEleven[11.21] = arrayOf(0.40, 0.43, 0.43, 0.45, 0.48, 0.50, 0.53, 0.55, 0.50, 0.40, 0.35, 0.30, 0.33, 0.33, 0.45, 0.48, 0.38, 0.35, 0.37, 0.50, 0.50, 0.48, 0.45, 0.43)
+ sixToEleven[11.88] = arrayOf(0.43, 0.43, 0.45, 0.45, 0.48, 0.50, 0.55, 0.58, 0.50, 0.40, 0.35, 0.33, 0.33, 0.33, 0.48, 0.50, 0.40, 0.38, 0.38, 0.53, 0.53, 0.50, 0.48, 0.45)
+ sixToEleven[12.53] = arrayOf(0.45, 0.45, 0.48, 0.50, 0.53, 0.55, 0.60, 0.60, 0.60, 0.45, 0.40, 0.35, 0.35, 0.38, 0.50, 0.53, 0.40, 0.38, 0.38, 0.55, 0.58, 0.55, 0.50, 0.48)
+ sixToEleven[13.19] = arrayOf(0.48, 0.48, 0.50, 0.55, 0.58, 0.60, 0.65, 0.65, 0.65, 0.50, 0.45, 0.36, 0.38, 0.40, 0.55, 0.55, 0.45, 0.40, 0.40, 0.60, 0.60, 0.58, 0.55, 0.50)
+ sixToEleven[14.18] = arrayOf(0.53, 0.53, 0.55, 0.60, 0.65, 0.68, 0.70, 0.70, 0.68, 0.60, 0.55, 0.40, 0.40, 0.45, 0.60, 0.60, 0.50, 0.45, 0.45, 0.63, 0.65, 0.63, 0.60, 0.60)
+ sixToEleven[15.17] = arrayOf(0.55, 0.58, 0.60, 0.65, 0.70, 0.70, 0.75, 0.75, 0.70, 0.65, 0.60, 0.42, 0.42, 0.45, 0.65, 0.65, 0.60, 0.50, 0.50, 0.68, 0.68, 0.65, 0.63, 0.63)
+ sixToEleven[16.50] = arrayOf(0.60, 0.63, 0.65, 0.70, 0.70, 0.70, 0.80, 0.80, 0.80, 0.70, 0.60, 0.45, 0.45, 0.50, 0.65, 0.70, 0.60, 0.55, 0.55, 0.75, 0.75, 0.70, 0.65, 0.65)
+
+ twelveToSeventeen[10.70] = arrayOf(0.30, 0.30, 0.30, 0.30, 0.40, 0.40, 0.60, 0.60, 0.60, 0.40, 0.35, 0.30, 0.30, 0.35, 0.45, 0.50, 0.40, 0.30, 0.30, 0.40, 0.50, 0.40, 0.40, 0.30)
+ twelveToSeventeen[11.10] = arrayOf(0.30, 0.30, 0.30, 0.35, 0.40, 0.45, 0.60, 0.60, 0.60, 0.40, 0.40, 0.30, 0.35, 0.40, 0.50, 0.50, 0.30, 0.30, 0.30, 0.50, 0.50, 0.50, 0.30, 0.30)
+ twelveToSeventeen[11.60] = arrayOf(0.30, 0.30, 0.35, 0.45, 0.45, 0.50, 0.65, 0.65, 0.65, 0.45, 0.40, 0.40, 0.40, 0.40, 0.50, 0.55, 0.55, 0.45, 0.45, 0.50, 0.50, 0.50, 0.40, 0.40)
+ twelveToSeventeen[13.00] = arrayOf(0.40, 0.40, 0.40, 0.50, 0.55, 0.60, 0.70, 0.70, 0.70, 0.60, 0.50, 0.40, 0.40, 0.40, 0.50, 0.60, 0.60, 0.50, 0.50, 0.60, 0.60, 0.60, 0.40, 0.30)
+ twelveToSeventeen[15.60] = arrayOf(0.45, 0.50, 0.50, 0.60, 0.65, 0.70, 0.80, 0.80, 0.80, 0.70, 0.60, 0.60, 0.50, 0.50, 0.60, 0.70, 0.70, 0.60, 0.60, 0.60, 0.70, 0.70, 0.50, 0.50)
+ twelveToSeventeen[17.00] = arrayOf(0.50, 0.55, 0.60, 0.70, 0.75, 0.80, 1.00, 1.00, 1.00, 0.80, 0.70, 0.60, 0.60, 0.60, 0.70, 0.80, 0.80, 0.65, 0.65, 0.65, 0.70, 0.70, 0.60, 0.60)
+ twelveToSeventeen[18.00] = arrayOf(0.60, 0.65, 0.70, 0.80, 0.85, 0.90, 1.10, 1.10, 1.10, 0.90, 0.80, 0.60, 0.60, 0.60, 0.70, 0.80, 0.80, 0.70, 0.65, 0.70, 0.75, 0.70, 0.60, 0.60)
+ twelveToSeventeen[20.20] = arrayOf(0.70, 0.75, 0.80, 0.90, 0.95, 1.00, 1.10, 1.10, 1.10, 0.90, 0.80, 0.70, 0.70, 0.70, 0.80, 0.90, 0.90, 0.75, 0.75, 0.75, 0.80, 0.80, 0.70, 0.70)
+ twelveToSeventeen[21.60] = arrayOf(0.75, 0.80, 0.90, 0.90, 1.00, 1.00, 1.20, 1.20, 1.20, 0.90, 0.80, 0.70, 0.70, 0.70, 0.90, 1.00, 1.00, 0.80, 0.80, 0.80, 0.80, 0.80, 0.70, 0.70)
+ twelveToSeventeen[23.80] = arrayOf(0.75, 0.80, 0.90, 1.00, 1.10, 1.10, 1.20, 1.20, 1.20, 1.00, 0.90, 0.80, 0.80, 0.80, 0.90, 1.10, 1.10, 0.90, 0.90, 0.90, 1.00, 1.00, 0.80, 0.80)
+ twelveToSeventeen[26.10] = arrayOf(0.80, 0.80, 0.90, 1.00, 1.20, 1.20, 1.30, 1.30, 1.30, 1.10, 1.00, 0.90, 0.90, 0.90, 1.00, 1.20, 1.10, 0.90, 0.90, 1.00, 1.00, 1.00, 0.90, 0.90)
+ twelveToSeventeen[28.00] = arrayOf(0.90, 0.90, 1.00, 1.10, 1.10, 1.20, 1.30, 1.30, 1.30, 1.20, 1.00, 1.00, 1.00, 1.00, 1.20, 1.20, 1.20, 1.00, 1.00, 1.10, 1.10, 1.10, 0.90, 0.90)
+ twelveToSeventeen[30.10] = arrayOf(1.00, 1.00, 1.10, 1.20, 1.30, 1.40, 1.50, 1.50, 1.50, 1.30, 1.20, 1.00, 1.00, 1.00, 1.30, 1.40, 1.40, 1.00, 1.00, 1.15, 1.15, 1.10, 1.00, 1.00)
+ twelveToSeventeen[32.60] = arrayOf(1.10, 1.10, 1.20, 1.20, 1.40, 1.50, 1.50, 1.50, 1.50, 1.30, 1.20, 1.10, 1.10, 1.10, 1.40, 1.50, 1.40, 1.10, 1.10, 1.20, 1.20, 1.20, 1.10, 1.10)
+ twelveToSeventeen[35.20] = arrayOf(1.20, 1.20, 1.30, 1.40, 1.50, 1.60, 1.70, 1.70, 1.50, 1.40, 1.20, 1.10, 1.10, 1.10, 1.40, 1.50, 1.60, 1.40, 1.20, 1.20, 1.30, 1.30, 1.20, 1.20)
+ twelveToSeventeen[39.00] = arrayOf(1.30, 1.30, 1.40, 1.60, 1.60, 1.60, 1.90, 1.90, 1.90, 1.50, 1.30, 1.20, 1.20, 1.30, 1.50, 1.60, 1.70, 1.80, 1.50, 1.50, 1.60, 1.60, 1.30, 1.30)
+ twelveToSeventeen[42.80] = arrayOf(1.40, 1.40, 1.50, 1.70, 1.80, 1.80, 2.00, 2.00, 2.00, 1.80, 1.80, 1.50, 1.50, 1.50, 1.60, 1.70, 1.80, 1.90, 1.60, 1.60, 1.70, 1.70, 1.50, 1.50)
+ twelveToSeventeen[47.30] = arrayOf(1.50, 1.50, 1.70, 1.70, 2.00, 2.00, 2.20, 2.30, 2.20, 2.00, 1.80, 1.60, 1.60, 1.60, 1.80, 2.00, 2.10, 1.90, 1.80, 1.80, 2.00, 2.00, 1.60, 1.60)
+ }
+
+ private fun closest(map: TreeMap>, key: Double): Array? {
+ val low = map.floorEntry(key)
+ val high = map.ceilingEntry(key)
+ var res: Array? = null
+ if (low != null && high != null) {
+ res = if (Math.abs(key - low.key) < Math.abs(key - high.key))
+ low.value
+ else
+ high.value
+ } else if (low != null || high != null) {
+ res = if (low != null) low.value else high.value
+ }
+ return res
+ }
+
+ fun arrayToJson(b: Array): JSONArray {
+ val basals = JSONArray()
+ for (i in 0..23) {
+ val time = String.format(Locale.ENGLISH, "%02d:00", i)
+ basals.put(JSONObject().put("time", time).put("value", b[i].toString()))
+ }
+ return basals
+ }
+
+ fun singleValueArray(value: Double, sample: Array): JSONArray {
+ val array = JSONArray()
+ array.put(JSONObject().put("time", "00:00").put("value", value + sample[0]))
+ array.put(JSONObject().put("time", "06:00").put("value", value + sample[1]))
+ array.put(JSONObject().put("time", "09:00").put("value", value + sample[2]))
+ array.put(JSONObject().put("time", "11:00").put("value", value + sample[3]))
+ array.put(JSONObject().put("time", "14:00").put("value", value + sample[4]))
+ array.put(JSONObject().put("time", "16:00").put("value", value + sample[5]))
+ array.put(JSONObject().put("time", "19:00").put("value", value + sample[6]))
+ return array
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/db/BgReading.java b/app/src/main/java/info/nightscout/androidaps/db/BgReading.java
index 6fafdc4b6d2..abac9e08c09 100644
--- a/app/src/main/java/info/nightscout/androidaps/db/BgReading.java
+++ b/app/src/main/java/info/nightscout/androidaps/db/BgReading.java
@@ -7,6 +7,7 @@
import org.slf4j.LoggerFactory;
import java.util.Date;
+import java.util.List;
import java.util.Objects;
import info.nightscout.androidaps.Constants;
@@ -19,10 +20,11 @@
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.DataPointWithLabelInterface;
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.PointsWithLabelGraphSeries;
import info.nightscout.androidaps.utils.DecimalFormatter;
+import info.nightscout.androidaps.utils.T;
@DatabaseTable(tableName = DatabaseHelper.DATABASE_BGREADINGS)
public class BgReading implements DataPointWithLabelInterface {
- private static Logger log = LoggerFactory.getLogger(L.DATABASE);
+ private static Logger log = LoggerFactory.getLogger(L.GLUCOSE);
@DatabaseField(id = true)
public long date;
@@ -73,9 +75,10 @@ public String valueToUnitsToString(String units) {
public String directionToSymbol() {
String symbol = "";
- if (direction == null) {
- symbol = "??";
- } else if (direction.compareTo("DoubleDown") == 0) {
+ if (direction == null)
+ direction = calculateDirection();
+
+ if (direction.compareTo("DoubleDown") == 0) {
symbol = "\u21ca";
} else if (direction.compareTo("SingleDown") == 0) {
symbol = "\u2193";
@@ -95,18 +98,13 @@ public String directionToSymbol() {
return symbol;
}
- public static boolean isSlopeNameInvalid(String direction) {
- if (direction.compareTo("NOT_COMPUTABLE") == 0 ||
+ private static boolean isSlopeNameInvalid(String direction) {
+ return direction.compareTo("NOT_COMPUTABLE") == 0 ||
direction.compareTo("NOT COMPUTABLE") == 0 ||
direction.compareTo("OUT_OF_RANGE") == 0 ||
direction.compareTo("OUT OF RANGE") == 0 ||
direction.compareTo("NONE") == 0 ||
- direction.compareTo("NotComputable") == 0
- ) {
- return true;
- } else {
- return false;
- }
+ direction.compareTo("NotComputable") == 0;
}
@@ -123,7 +121,8 @@ public String toString() {
public boolean isDataChanging(BgReading other) {
if (date != other.date) {
- log.error("Comparing different");
+ if (L.isEnabled(L.GLUCOSE))
+ log.error("Comparing different");
return false;
}
if (value != other.value)
@@ -133,7 +132,8 @@ public boolean isDataChanging(BgReading other) {
public boolean isEqual(BgReading other) {
if (date != other.date) {
- log.error("Comparing different");
+ if (L.isEnabled(L.GLUCOSE))
+ log.error("Comparing different");
return false;
}
if (value != other.value)
@@ -149,7 +149,8 @@ public boolean isEqual(BgReading other) {
public void copyFrom(BgReading other) {
if (date != other.date) {
- log.error("Copying different");
+ if (L.isEnabled(L.GLUCOSE))
+ log.error("Copying different");
return;
}
value = other.value;
@@ -181,8 +182,7 @@ public double getX() {
@Override
public double getY() {
- String units = ProfileFunctions.getInstance().getProfileUnits();
- return valueToUnits(units);
+ return valueToUnits(ProfileFunctions.getSystemUnits());
}
@Override
@@ -215,9 +215,9 @@ public float getSize() {
@Override
public int getColor() {
- String units = ProfileFunctions.getInstance().getProfileUnits();
- Double lowLine = OverviewPlugin.getPlugin().determineLowLine(units);
- Double highLine = OverviewPlugin.getPlugin().determineHighLine(units);
+ String units = ProfileFunctions.getSystemUnits();
+ Double lowLine = OverviewPlugin.INSTANCE.determineLowLine();
+ Double highLine = OverviewPlugin.INSTANCE.determineHighLine();
int color = MainApp.gc(R.color.inrange);
if (isPrediction())
return getPredectionColor();
@@ -246,4 +246,53 @@ private boolean isPrediction() {
return isaCOBPrediction || isCOBPrediction || isIOBPrediction || isUAMPrediction || isZTPrediction;
}
+
+ // Copied from xDrip+
+ String calculateDirection() {
+ // Rework to get bgreaings from internal DB and calculate on that base
+
+ List bgReadingsList = MainApp.getDbHelper().getAllBgreadingsDataFromTime(this.date - T.mins(10).msecs(), false);
+ if (bgReadingsList == null || bgReadingsList.size() < 2)
+ return "NONE";
+ BgReading current = bgReadingsList.get(1);
+ BgReading previous = bgReadingsList.get(0);
+
+ if (bgReadingsList.get(1).date < bgReadingsList.get(0).date) {
+ current = bgReadingsList.get(0);
+ previous = bgReadingsList.get(1);
+ }
+
+ double slope;
+
+ // Avoid division by 0
+ if (current.date == previous.date)
+ slope = 0;
+ else
+ slope = (previous.value - current.value) / (previous.date - current.date);
+
+ if (L.isEnabled(L.GLUCOSE))
+ log.debug("Slope is :" + slope + " delta " + (previous.value - current.value) + " date difference " + (current.date - previous.date));
+
+ double slope_by_minute = slope * 60000;
+ String arrow = "NONE";
+
+ if (slope_by_minute <= (-3.5)) {
+ arrow = "DoubleDown";
+ } else if (slope_by_minute <= (-2)) {
+ arrow = "SingleDown";
+ } else if (slope_by_minute <= (-1)) {
+ arrow = "FortyFiveDown";
+ } else if (slope_by_minute <= (1)) {
+ arrow = "Flat";
+ } else if (slope_by_minute <= (2)) {
+ arrow = "FortyFiveUp";
+ } else if (slope_by_minute <= (3.5)) {
+ arrow = "SingleUp";
+ } else if (slope_by_minute <= (40)) {
+ arrow = "DoubleUp";
+ }
+ if (L.isEnabled(L.GLUCOSE))
+ log.debug("Direction set to: " + arrow);
+ return arrow;
+ }
}
diff --git a/app/src/main/java/info/nightscout/androidaps/db/CareportalEvent.java b/app/src/main/java/info/nightscout/androidaps/db/CareportalEvent.java
index f0e70c0a25e..c2dc6f737e6 100644
--- a/app/src/main/java/info/nightscout/androidaps/db/CareportalEvent.java
+++ b/app/src/main/java/info/nightscout/androidaps/db/CareportalEvent.java
@@ -93,12 +93,22 @@ public double getHoursFromStart() {
return (System.currentTimeMillis() - date) / (60 * 60 * 1000.0);
}
- public String age() {
+ public String age(boolean useShortText) {
Map diff = computeDiff(date, System.currentTimeMillis());
- if (OverviewFragment.shorttextmode)
- return diff.get(TimeUnit.DAYS) + "d" + diff.get(TimeUnit.HOURS) + "h";
- else
- return diff.get(TimeUnit.DAYS) + " " + MainApp.gs(R.string.days) + " " + diff.get(TimeUnit.HOURS) + " " + MainApp.gs(R.string.hours);
+
+ String days = " " + MainApp.gs(R.string.days) + " ";
+ String hours = " " + MainApp.gs(R.string.hours) + " ";
+
+ if (useShortText) {
+ days = MainApp.gs(R.string.shortday);
+ hours = MainApp.gs(R.string.shorthour);
+ }
+
+ return diff.get(TimeUnit.DAYS) + days + diff.get(TimeUnit.HOURS) + hours;
+ }
+
+ public String age() {
+ return age(OverviewFragment.shorttextmode);
}
public boolean isOlderThan(double hours) {
@@ -157,7 +167,7 @@ public double getX() {
@Override
public double getY() {
- String units = ProfileFunctions.getInstance().getProfileUnits();
+ String units = ProfileFunctions.getSystemUnits();
if (eventType.equals(MBG)) {
double mbg = 0d;
try {
diff --git a/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelper.java b/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelper.java
index 1f071a2f180..9fe6d615075 100644
--- a/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelper.java
+++ b/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelper.java
@@ -3,7 +3,8 @@
import android.content.Context;
import android.database.DatabaseUtils;
import android.database.sqlite.SQLiteDatabase;
-import android.support.annotation.Nullable;
+
+import androidx.annotation.Nullable;
import com.j256.ormlite.android.apptools.OrmLiteSqliteOpenHelper;
import com.j256.ormlite.dao.CloseableIterator;
@@ -21,6 +22,8 @@
import java.sql.SQLException;
import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.GregorianCalendar;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
@@ -29,7 +32,8 @@
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp;
-import info.nightscout.androidaps.data.OverlappingIntervals;
+import info.nightscout.androidaps.plugins.bus.RxBus;
+import info.nightscout.androidaps.data.NonOverlappingIntervals;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.data.ProfileStore;
import info.nightscout.androidaps.events.EventCareportalEventChange;
@@ -48,11 +52,13 @@
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventNewHistoryData;
+import info.nightscout.androidaps.plugins.pump.combo.ruffyscripter.history.PumpHistory;
import info.nightscout.androidaps.plugins.pump.danaR.activities.DanaRNSHistorySync;
import info.nightscout.androidaps.plugins.pump.danaR.comm.RecordTypes;
import info.nightscout.androidaps.plugins.pump.insight.database.InsightBolusID;
import info.nightscout.androidaps.plugins.pump.insight.database.InsightHistoryOffset;
import info.nightscout.androidaps.plugins.pump.insight.database.InsightPumpID;
+import info.nightscout.androidaps.plugins.pump.omnipod.driver.db.PodHistory;
import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin;
import info.nightscout.androidaps.utils.JsonHelper;
import info.nightscout.androidaps.utils.PercentageSplitter;
@@ -82,8 +88,9 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
public static final String DATABASE_INSIGHT_HISTORY_OFFSETS = "InsightHistoryOffsets";
public static final String DATABASE_INSIGHT_BOLUS_IDS = "InsightBolusIDs";
public static final String DATABASE_INSIGHT_PUMP_IDS = "InsightPumpIDs";
+ public static final String DATABASE_POD_HISTORY = "PodHistory";
- private static final int DATABASE_VERSION = 11;
+ private static final int DATABASE_VERSION = 12;
public static Long earliestDataChange = null;
@@ -131,6 +138,8 @@ public void onCreate(SQLiteDatabase database, ConnectionSource connectionSource)
TableUtils.createTableIfNotExists(connectionSource, InsightHistoryOffset.class);
TableUtils.createTableIfNotExists(connectionSource, InsightBolusID.class);
TableUtils.createTableIfNotExists(connectionSource, InsightPumpID.class);
+ //TableUtils.dropTable(connectionSource, PodHistory.class, true);
+ TableUtils.createTableIfNotExists(connectionSource, PodHistory.class);
database.execSQL("INSERT INTO sqlite_sequence (name, seq) SELECT \"" + DATABASE_INSIGHT_BOLUS_IDS + "\", " + System.currentTimeMillis() + " " +
"WHERE NOT EXISTS (SELECT 1 FROM sqlite_sequence WHERE name = \"" + DATABASE_INSIGHT_BOLUS_IDS + "\")");
database.execSQL("INSERT INTO sqlite_sequence (name, seq) SELECT \"" + DATABASE_INSIGHT_PUMP_IDS + "\", " + System.currentTimeMillis() + " " +
@@ -190,15 +199,6 @@ public int getNewVersion() {
return newVersion;
}
- /**
- * Close the database connections and clear any cached DAOs.
- */
- @Override
- public void close() {
- super.close();
- }
-
-
public long size(String database) {
return DatabaseUtils.queryNumEntries(getReadableDatabase(), database);
}
@@ -216,6 +216,7 @@ public void resetDatabases() {
TableUtils.dropTable(connectionSource, CareportalEvent.class, true);
TableUtils.dropTable(connectionSource, ProfileSwitch.class, true);
TableUtils.dropTable(connectionSource, TDD.class, true);
+ TableUtils.dropTable(connectionSource, PodHistory.class, true);
TableUtils.createTableIfNotExists(connectionSource, TempTarget.class);
TableUtils.createTableIfNotExists(connectionSource, BgReading.class);
TableUtils.createTableIfNotExists(connectionSource, DanaRHistoryRecord.class);
@@ -225,6 +226,7 @@ public void resetDatabases() {
TableUtils.createTableIfNotExists(connectionSource, CareportalEvent.class);
TableUtils.createTableIfNotExists(connectionSource, ProfileSwitch.class);
TableUtils.createTableIfNotExists(connectionSource, TDD.class);
+ TableUtils.createTableIfNotExists(connectionSource, PodHistory.class);
updateEarliestDataChange(0);
} catch (SQLException e) {
log.error("Unhandled exception", e);
@@ -240,7 +242,7 @@ public void resetDatabases() {
new java.util.TimerTask() {
@Override
public void run() {
- MainApp.bus().post(new EventRefreshOverview("resetDatabases"));
+ RxBus.INSTANCE.send(new EventRefreshOverview("resetDatabases"));
}
},
3000
@@ -359,6 +361,10 @@ private Dao getDaoInsightHistoryOffset() throws SQ
return getDao(InsightHistoryOffset.class);
}
+ private Dao getDaoPodHistory() throws SQLException {
+ return getDao(PodHistory.class);
+ }
+
public static long roundDateToSec(long date) {
long rounded = date - date % 1000;
if (rounded != date)
@@ -409,7 +415,7 @@ class PostRunnable implements Runnable {
public void run() {
if (L.isEnabled(L.DATABASE))
log.debug("Firing EventNewBg");
- MainApp.bus().post(new EventNewBG(bgReading));
+ RxBus.INSTANCE.send(new EventNewBG(bgReading));
scheduledBgPost = null;
}
}
@@ -434,7 +440,7 @@ public static BgReading lastBg() {
return null;
for (int i = 0; i < bgList.size(); i++)
- if (bgList.get(i).value > 39)
+ if (bgList.get(i).value >= 39)
return bgList.get(i);
return null;
}
@@ -534,15 +540,29 @@ public List getTDDs() {
return tddList;
}
+ public List getTDDsForLastXDays(int days) {
+ List tddList;
+ GregorianCalendar gc = new GregorianCalendar();
+ gc.add(Calendar.DAY_OF_YEAR, (-1) * days);
- // ------------- DbRequests handling -------------------
-
- public void create(DbRequest dbr) {
try {
- getDaoDbRequest().create(dbr);
+ QueryBuilder queryBuilder = getDaoTDD().queryBuilder();
+ queryBuilder.orderBy("date", false);
+ Where where = queryBuilder.where();
+ where.ge("date", gc.getTimeInMillis());
+ PreparedQuery preparedQuery = queryBuilder.prepare();
+ tddList = getDaoTDD().query(preparedQuery);
} catch (SQLException e) {
log.error("Unhandled exception", e);
+ tddList = new ArrayList<>();
}
+ return tddList;
+ }
+
+ // ------------- DbRequests handling -------------------
+
+ public void create(DbRequest dbr) throws SQLException {
+ getDaoDbRequest().create(dbr);
}
public int delete(DbRequest dbr) {
@@ -596,7 +616,7 @@ public CloseableIterator getDbRequestInterator() {
}
}
- // -------------------- TREATMENT HANDLING -------------------
+ // -------------------- TEMPTARGET HANDLING -------------------
public static void updateEarliestDataChange(long newDate) {
if (earliestDataChange == null) {
@@ -627,6 +647,23 @@ public List getTemptargetsDataFromTime(long mills, boolean ascending
return new ArrayList();
}
+ public List getTemptargetsDataFromTime(long from, long to, boolean ascending) {
+ try {
+ Dao daoTempTargets = getDaoTempTargets();
+ List tempTargets;
+ QueryBuilder queryBuilder = daoTempTargets.queryBuilder();
+ queryBuilder.orderBy("date", ascending);
+ Where where = queryBuilder.where();
+ where.between("date", from, to);
+ PreparedQuery preparedQuery = queryBuilder.prepare();
+ tempTargets = daoTempTargets.query(preparedQuery);
+ return tempTargets;
+ } catch (SQLException e) {
+ log.error("Unhandled exception", e);
+ }
+ return new ArrayList();
+ }
+
public boolean createOrUpdate(TempTarget tempTarget) {
try {
TempTarget old;
@@ -699,7 +736,7 @@ class PostRunnable implements Runnable {
public void run() {
if (L.isEnabled(L.DATABASE))
log.debug("Firing EventTempTargetChange");
- MainApp.bus().post(new EventTempTargetChange());
+ RxBus.INSTANCE.send(new EventTempTargetChange());
scheduledTemTargetPost = null;
}
}
@@ -734,8 +771,8 @@ public void createTemptargetFromJsonIfNotExists(JSONObject trJson) {
TempTarget tempTarget = new TempTarget()
.date(trJson.getLong("mills"))
.duration(JsonHelper.safeGetInt(trJson, "duration"))
- .low(Profile.toMgdl(trJson.getDouble("targetBottom"), units))
- .high(Profile.toMgdl(trJson.getDouble("targetTop"), units))
+ .low(Profile.toMgdl(JsonHelper.safeGetDouble(trJson, "targetBottom"), units))
+ .high(Profile.toMgdl(JsonHelper.safeGetDouble(trJson, "targetTop"), units))
.reason(JsonHelper.safeGetString(trJson, "reason", ""))
._id(trJson.getString("_id"))
.source(Source.NIGHTSCOUT);
@@ -852,6 +889,31 @@ public boolean createOrUpdate(TemporaryBasal tempBasal) {
log.debug("TEMPBASAL: Already exists from: " + Source.getString(tempBasal.source) + " " + tempBasal.toString());
return false;
}
+
+ // search by date (in case its standard record that has become pump record)
+ QueryBuilder queryBuilder2 = getDaoTemporaryBasal().queryBuilder();
+ Where where2 = queryBuilder2.where();
+ where2.eq("date", tempBasal.date);
+ PreparedQuery preparedQuery2 = queryBuilder2.prepare();
+ List trList2 = getDaoTemporaryBasal().query(preparedQuery2);
+
+ if (trList2.size() > 0) {
+ old = trList2.get(0);
+
+ old.copyFromPump(tempBasal);
+ old.source = Source.PUMP;
+
+ if (L.isEnabled(L.DATABASE))
+ log.debug("TEMPBASAL: Updated record with Pump Data : " + Source.getString(tempBasal.source) + " " + tempBasal.toString());
+
+ getDaoTemporaryBasal().update(old);
+
+ updateEarliestDataChange(tempBasal.date);
+ scheduleTemporaryBasalChange();
+
+ return false;
+ }
+
getDaoTemporaryBasal().create(tempBasal);
if (L.isEnabled(L.DATABASE))
log.debug("TEMPBASAL: New record from: " + Source.getString(tempBasal.source) + " " + tempBasal.toString());
@@ -950,15 +1012,31 @@ public List getTemporaryBasalsDataFromTime(long mills, boolean a
return new ArrayList();
}
+ public List getTemporaryBasalsDataFromTime(long from, long to, boolean ascending) {
+ try {
+ List tempbasals;
+ QueryBuilder queryBuilder = getDaoTemporaryBasal().queryBuilder();
+ queryBuilder.orderBy("date", ascending);
+ Where where = queryBuilder.where();
+ where.between("date", from, to);
+ PreparedQuery preparedQuery = queryBuilder.prepare();
+ tempbasals = getDaoTemporaryBasal().query(preparedQuery);
+ return tempbasals;
+ } catch (SQLException e) {
+ log.error("Unhandled exception", e);
+ }
+ return new ArrayList();
+ }
+
private static void scheduleTemporaryBasalChange() {
class PostRunnable implements Runnable {
public void run() {
if (L.isEnabled(L.DATABASE))
log.debug("Firing EventTempBasalChange");
- MainApp.bus().post(new EventReloadTempBasalData());
- MainApp.bus().post(new EventTempBasalChange());
+ RxBus.INSTANCE.send(new EventReloadTempBasalData());
+ RxBus.INSTANCE.send(new EventTempBasalChange());
if (earliestDataChange != null)
- MainApp.bus().post(new EventNewHistoryData(earliestDataChange));
+ RxBus.INSTANCE.send(new EventNewHistoryData(earliestDataChange));
earliestDataChange = null;
scheduledTemBasalsPost = null;
}
@@ -1076,6 +1154,29 @@ public TemporaryBasal findTempBasalById(String _id) {
return null;
}
+
+ public TemporaryBasal findTempBasalByPumpId(Long pumpId) {
+ try {
+ QueryBuilder queryBuilder = null;
+ queryBuilder = getDaoTemporaryBasal().queryBuilder();
+ queryBuilder.orderBy("date", false);
+ Where where = queryBuilder.where();
+ where.eq("pumpId", pumpId);
+ PreparedQuery preparedQuery = queryBuilder.prepare();
+ List list = getDaoTemporaryBasal().query(preparedQuery);
+
+ if (list.size() > 0)
+ return list.get(0);
+ else
+ return null;
+
+ } catch (SQLException e) {
+ log.error("Unhandled exception", e);
+ }
+ return null;
+ }
+
+
// ------------ ExtendedBolus handling ---------------
public boolean createOrUpdate(ExtendedBolus extendedBolus) {
@@ -1268,9 +1369,9 @@ class PostRunnable implements Runnable {
public void run() {
if (L.isEnabled(L.DATABASE))
log.debug("Firing EventExtendedBolusChange");
- MainApp.bus().post(new EventReloadTreatmentData(new EventExtendedBolusChange()));
+ RxBus.INSTANCE.send(new EventReloadTreatmentData(new EventExtendedBolusChange()));
if (earliestDataChange != null)
- MainApp.bus().post(new EventNewHistoryData(earliestDataChange));
+ RxBus.INSTANCE.send(new EventNewHistoryData(earliestDataChange));
earliestDataChange = null;
scheduledExtendedBolusPost = null;
}
@@ -1323,7 +1424,7 @@ public CareportalEvent getLastCareportalEvent(String event) {
QueryBuilder queryBuilder = getDaoCareportalEvents().queryBuilder();
queryBuilder.orderBy("date", false);
Where where = queryBuilder.where();
- where.eq("eventType", event);
+ where.eq("eventType", event).and().isNotNull("json");
queryBuilder.limit(1L);
PreparedQuery preparedQuery = queryBuilder.prepare();
careportalEvents = getDaoCareportalEvents().query(preparedQuery);
@@ -1343,10 +1444,10 @@ public List getCareportalEventsFromTime(long mills, boolean asc
QueryBuilder queryBuilder = getDaoCareportalEvents().queryBuilder();
queryBuilder.orderBy("date", ascending);
Where where = queryBuilder.where();
- where.ge("date", mills);
+ where.ge("date", mills).and().isNotNull("json").and().isNotNull("eventType");
PreparedQuery preparedQuery = queryBuilder.prepare();
careportalEvents = getDaoCareportalEvents().query(preparedQuery);
- preprocessOpenAPSOfflineEvents(careportalEvents);
+ careportalEvents = preprocessOpenAPSOfflineEvents(careportalEvents);
return careportalEvents;
} catch (SQLException e) {
log.error("Unhandled exception", e);
@@ -1354,14 +1455,33 @@ public List getCareportalEventsFromTime(long mills, boolean asc
return new ArrayList<>();
}
- public void preprocessOpenAPSOfflineEvents(List list) {
- OverlappingIntervals offlineEvents = new OverlappingIntervals();
+ public List getCareportalEvents(long start, long end, boolean ascending) {
+ try {
+ List careportalEvents;
+ QueryBuilder queryBuilder = getDaoCareportalEvents().queryBuilder();
+ queryBuilder.orderBy("date", ascending);
+ Where where = queryBuilder.where();
+ where.between("date", start, end).and().isNotNull("json").and().isNotNull("eventType");
+ PreparedQuery preparedQuery = queryBuilder.prepare();
+ careportalEvents = getDaoCareportalEvents().query(preparedQuery);
+ careportalEvents = preprocessOpenAPSOfflineEvents(careportalEvents);
+ return careportalEvents;
+ } catch (SQLException e) {
+ log.error("Unhandled exception", e);
+ }
+ return new ArrayList<>();
+ }
+
+ public List preprocessOpenAPSOfflineEvents(List list) {
+ NonOverlappingIntervals offlineEvents = new NonOverlappingIntervals();
+ List other = new ArrayList<>();
for (int i = 0; i < list.size(); i++) {
CareportalEvent event = list.get(i);
- if (!event.eventType.equals(CareportalEvent.OPENAPSOFFLINE)) continue;
- offlineEvents.add(event);
+ if (event.eventType.equals(CareportalEvent.OPENAPSOFFLINE)) offlineEvents.add(event);
+ else other.add(event);
}
-
+ other.addAll(offlineEvents.getList());
+ return other;
}
public List getCareportalEventsFromTime(long mills, String type, boolean ascending) {
@@ -1370,10 +1490,10 @@ public List getCareportalEventsFromTime(long mills, String type
QueryBuilder queryBuilder = getDaoCareportalEvents().queryBuilder();
queryBuilder.orderBy("date", ascending);
Where where = queryBuilder.where();
- where.ge("date", mills).and().eq("eventType", type);
+ where.ge("date", mills).and().eq("eventType", type).and().isNotNull("json");
PreparedQuery preparedQuery = queryBuilder.prepare();
careportalEvents = getDaoCareportalEvents().query(preparedQuery);
- preprocessOpenAPSOfflineEvents(careportalEvents);
+ careportalEvents = preprocessOpenAPSOfflineEvents(careportalEvents);
return careportalEvents;
} catch (SQLException e) {
log.error("Unhandled exception", e);
@@ -1386,9 +1506,11 @@ public List getCareportalEvents(boolean ascending) {
List careportalEvents;
QueryBuilder queryBuilder = getDaoCareportalEvents().queryBuilder();
queryBuilder.orderBy("date", ascending);
+ Where where = queryBuilder.where();
+ where.isNotNull("json").and().isNotNull("eventType");
PreparedQuery preparedQuery = queryBuilder.prepare();
careportalEvents = getDaoCareportalEvents().query(preparedQuery);
- preprocessOpenAPSOfflineEvents(careportalEvents);
+ careportalEvents = preprocessOpenAPSOfflineEvents(careportalEvents);
return careportalEvents;
} catch (SQLException e) {
log.error("Unhandled exception", e);
@@ -1457,7 +1579,7 @@ class PostRunnable implements Runnable {
public void run() {
if (L.isEnabled(L.DATABASE))
log.debug("Firing scheduleCareportalEventChange");
- MainApp.bus().post(new EventCareportalEventChange());
+ RxBus.INSTANCE.send(new EventCareportalEventChange());
scheduledCareportalEventPost = null;
}
}
@@ -1473,15 +1595,23 @@ public void run() {
// ---------------- ProfileSwitch handling ---------------
- public List getProfileSwitchData(boolean ascending) {
+ public List getProfileSwitchData(long from, boolean ascending) {
try {
Dao daoProfileSwitch = getDaoProfileSwitch();
List profileSwitches;
QueryBuilder queryBuilder = daoProfileSwitch.queryBuilder();
queryBuilder.orderBy("date", ascending);
queryBuilder.limit(100L);
+ Where where = queryBuilder.where();
+ where.ge("date", from);
PreparedQuery preparedQuery = queryBuilder.prepare();
profileSwitches = daoProfileSwitch.query(preparedQuery);
+ //add last one without duration
+ ProfileSwitch last = getLastProfileSwitchWithoutDuration();
+ if (last != null) {
+ if (!profileSwitches.contains(last))
+ profileSwitches.add(last);
+ }
return profileSwitches;
} catch (SQLException e) {
log.error("Unhandled exception", e);
@@ -1489,6 +1619,28 @@ public List getProfileSwitchData(boolean ascending) {
return new ArrayList<>();
}
+ @Nullable
+ private ProfileSwitch getLastProfileSwitchWithoutDuration() {
+ try {
+ Dao daoProfileSwitch = getDaoProfileSwitch();
+ List profileSwitches;
+ QueryBuilder queryBuilder = daoProfileSwitch.queryBuilder();
+ queryBuilder.orderBy("date", false);
+ queryBuilder.limit(1L);
+ Where where = queryBuilder.where();
+ where.eq("durationInMinutes", 0);
+ PreparedQuery preparedQuery = queryBuilder.prepare();
+ profileSwitches = daoProfileSwitch.query(preparedQuery);
+ if (profileSwitches.size() > 0)
+ return profileSwitches.get(0);
+ else
+ return null;
+ } catch (SQLException e) {
+ log.error("Unhandled exception", e);
+ }
+ return null;
+ }
+
public List getProfileSwitchEventsFromTime(long mills, boolean ascending) {
try {
Dao daoProfileSwitch = getDaoProfileSwitch();
@@ -1507,6 +1659,24 @@ public List getProfileSwitchEventsFromTime(long mills, boolean as
return new ArrayList<>();
}
+ public List getProfileSwitchEventsFromTime(long from, long to, boolean ascending) {
+ try {
+ Dao daoProfileSwitch = getDaoProfileSwitch();
+ List profileSwitches;
+ QueryBuilder queryBuilder = daoProfileSwitch.queryBuilder();
+ queryBuilder.orderBy("date", ascending);
+ queryBuilder.limit(100L);
+ Where where = queryBuilder.where();
+ where.between("date", from, to);
+ PreparedQuery preparedQuery = queryBuilder.prepare();
+ profileSwitches = daoProfileSwitch.query(preparedQuery);
+ return profileSwitches;
+ } catch (SQLException e) {
+ log.error("Unhandled exception", e);
+ }
+ return new ArrayList<>();
+ }
+
public boolean createOrUpdate(ProfileSwitch profileSwitch) {
try {
ProfileSwitch old;
@@ -1582,8 +1752,8 @@ class PostRunnable implements Runnable {
public void run() {
if (L.isEnabled(L.DATABASE))
log.debug("Firing EventProfileNeedsUpdate");
- MainApp.bus().post(new EventReloadProfileSwitchData());
- MainApp.bus().post(new EventProfileNeedsUpdate());
+ RxBus.INSTANCE.send(new EventReloadProfileSwitchData());
+ RxBus.INSTANCE.send(new EventProfileNeedsUpdate());
scheduledProfileSwitchEventPost = null;
}
}
@@ -1753,4 +1923,34 @@ public InsightPumpID getPumpStoppedEvent(String pumpSerial, long before) {
}
// ---------------- Food handling ---------------
+
+ // ---------------- PodHistory handling ---------------
+
+ public void createOrUpdate(PodHistory podHistory) {
+ try {
+ getDaoPodHistory().createOrUpdate(podHistory);
+ } catch (SQLException e) {
+ log.error("Unhandled exception", e);
+ }
+ }
+
+
+ public List getPodHistoryFromTime(long from, boolean ascending) {
+ try {
+ Dao daoPodHistory = getDaoPodHistory();
+ List podHistories;
+ QueryBuilder queryBuilder = daoPodHistory.queryBuilder();
+ queryBuilder.orderBy("date", ascending);
+ //queryBuilder.limit(100L);
+ Where where = queryBuilder.where();
+ where.ge("date", from);
+ PreparedQuery preparedQuery = queryBuilder.prepare();
+ podHistories = daoPodHistory.query(preparedQuery);
+ return podHistories;
+ } catch (SQLException e) {
+ log.error("Unhandled exception", e);
+ }
+ return new ArrayList<>();
+ }
+
}
diff --git a/app/src/main/java/info/nightscout/androidaps/db/DbObjectBase.java b/app/src/main/java/info/nightscout/androidaps/db/DbObjectBase.java
new file mode 100644
index 00000000000..a0c7f4bd7b6
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/db/DbObjectBase.java
@@ -0,0 +1,9 @@
+package info.nightscout.androidaps.db;
+
+public interface DbObjectBase {
+
+ long getDate();
+
+ long getPumpId();
+
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/db/DbRequest.java b/app/src/main/java/info/nightscout/androidaps/db/DbRequest.java
index f287e169cef..6cd0491907e 100644
--- a/app/src/main/java/info/nightscout/androidaps/db/DbRequest.java
+++ b/app/src/main/java/info/nightscout/androidaps/db/DbRequest.java
@@ -11,6 +11,7 @@
import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.logging.L;
+import info.nightscout.androidaps.utils.DateUtil;
/**
* Created by mike on 27.02.2016.
@@ -40,66 +41,55 @@ public DbRequest() {
}
// dbAdd
- public DbRequest(String action, String collection, String nsClientID, JSONObject data) {
+ public DbRequest(String action, String collection, JSONObject json) {
this.action = action;
this.collection = collection;
- this.data = data.toString();
- this.nsClientID = nsClientID;
+ this.nsClientID = "" + DateUtil.now();
+ try {
+ json.put("NSCLIENT_ID", nsClientID);
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ this.data = json.toString();
this._id = "";
}
// dbUpdate, dbUpdateUnset
- public DbRequest(String action, String collection, String nsClientID, String _id, JSONObject data) {
+ public DbRequest(String action, String collection, String _id, JSONObject json) {
this.action = action;
this.collection = collection;
- this.data = data.toString();
- this.nsClientID = nsClientID;
+ this.nsClientID = "" + DateUtil.now();
+ try {
+ json.put("NSCLIENT_ID", nsClientID);
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ this.data = json.toString();
this._id = _id;
}
// dbRemove
- public DbRequest(String action, String collection, String nsClientID, String _id) {
+ public DbRequest(String action, String collection,
+ String _id) {
+ JSONObject json = new JSONObject();
this.action = action;
this.collection = collection;
- this.data = new JSONObject().toString();
- this.nsClientID = nsClientID;
- this._id = _id;
- }
-
- public String hash() {
- return Hashing.sha1().hashString(action + collection + _id + data.toString(), Charsets.UTF_8).toString();
- }
-
- public JSONObject toJSON() {
- JSONObject object = new JSONObject();
+ this.nsClientID = "" + DateUtil.now();
try {
- object.put("action", action);
- object.put("collection", collection);
- object.put("data", new JSONObject(data));
- if (_id != null) object.put("_id", _id);
- if (nsClientID != null) object.put("nsClientID", nsClientID);
+ json.put("NSCLIENT_ID", nsClientID);
} catch (JSONException e) {
- log.error("Unhandled exception", e);
+ e.printStackTrace();
}
- return object;
+ this.data = json.toString();
+ this._id = _id;
}
- public static DbRequest fromJSON(JSONObject jsonObject) {
- DbRequest result = new DbRequest();
- try {
- if (jsonObject.has("action"))
- result.action = jsonObject.getString("action");
- if (jsonObject.has("collection"))
- result.collection = jsonObject.getString("collection");
- if (jsonObject.has("data"))
- result.data = jsonObject.getJSONObject("data").toString();
- if (jsonObject.has("_id"))
- result._id = jsonObject.getString("_id");
- if (jsonObject.has("nsClientID"))
- result.nsClientID = jsonObject.getString("nsClientID");
- } catch (JSONException e) {
- log.error("Unhandled exception", e);
- }
- return result;
+ public String log() {
+ return
+ "\nnsClientID:" + nsClientID +
+ "\naction:" + action +
+ "\ncollection:" + collection +
+ "\ndata:" + data +
+ "\n_id:" + _id;
}
}
diff --git a/app/src/main/java/info/nightscout/androidaps/db/ExtendedBolus.java b/app/src/main/java/info/nightscout/androidaps/db/ExtendedBolus.java
index 2f11b752c87..1632751d555 100644
--- a/app/src/main/java/info/nightscout/androidaps/db/ExtendedBolus.java
+++ b/app/src/main/java/info/nightscout/androidaps/db/ExtendedBolus.java
@@ -18,12 +18,14 @@
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.data.Iob;
import info.nightscout.androidaps.data.IobTotal;
+import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.interfaces.InsulinInterface;
import info.nightscout.androidaps.interfaces.Interval;
import info.nightscout.androidaps.logging.L;
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.DataPointWithLabelInterface;
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.PointsWithLabelGraphSeries;
+import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult;
import info.nightscout.androidaps.plugins.treatments.Treatment;
import info.nightscout.androidaps.utils.DateUtil;
import info.nightscout.androidaps.utils.DecimalFormatter;
@@ -219,7 +221,7 @@ public IobTotal iobCalc(long time) {
IobTotal result = new IobTotal(time);
InsulinInterface insulinInterface = ConfigBuilderPlugin.getPlugin().getActiveInsulin();
- int realDuration = getDurationToTime(time);
+ double realDuration = getDurationToTime(time);
if (realDuration > 0) {
double dia_ago = time - dia * 60 * 60 * 1000;
@@ -247,6 +249,56 @@ public IobTotal iobCalc(long time) {
return result;
}
+ public IobTotal iobCalc(long time, Profile profile, AutosensResult lastAutosensResult, boolean exercise_mode, int half_basal_exercise_target, boolean isTempTarget) {
+ IobTotal result = new IobTotal(time);
+ InsulinInterface insulinInterface = ConfigBuilderPlugin.getPlugin().getActiveInsulin();
+
+ double realDuration = getDurationToTime(time);
+ double netBasalAmount = 0d;
+
+ double sensitivityRatio = lastAutosensResult.ratio;
+ double normalTarget = 100;
+
+ if (exercise_mode && isTempTarget && profile.getTargetMgdl() >= normalTarget + 5) {
+ // w/ target 100, temp target 110 = .89, 120 = 0.8, 140 = 0.67, 160 = .57, and 200 = .44
+ // e.g.: Sensitivity ratio set to 0.8 based on temp target of 120; Adjusting basal from 1.65 to 1.35; ISF from 58.9 to 73.6
+ double c = half_basal_exercise_target - normalTarget;
+ sensitivityRatio = c / (c + profile.getTargetMgdl() - normalTarget);
+ }
+
+ if (realDuration > 0) {
+ double netBasalRate;
+ double dia_ago = time - dia * 60 * 60 * 1000;
+ int aboutFiveMinIntervals = (int) Math.ceil(realDuration / 5d);
+ double spacing = realDuration / aboutFiveMinIntervals;
+
+ for (long j = 0L; j < aboutFiveMinIntervals; j++) {
+ // find middle of the interval
+ long calcdate = (long) (date + j * spacing * 60 * 1000 + 0.5d * spacing * 60 * 1000);
+
+ double basalRate = profile.getBasal(calcdate);
+ double basalRateCorrection = basalRate * (sensitivityRatio - 1);
+
+
+ netBasalRate = absoluteRate() - basalRateCorrection;
+
+ if (calcdate > dia_ago && calcdate <= time) {
+ double tempBolusSize = netBasalRate * spacing / 60d;
+
+ Treatment tempBolusPart = new Treatment();
+ tempBolusPart.insulin = tempBolusSize;
+ tempBolusPart.date = calcdate;
+
+ Iob aIOB = insulinInterface.iobCalcForTreatment(tempBolusPart, time, dia);
+ result.iob += aIOB.iobContrib;
+ result.activity += aIOB.activityContrib;
+ result.extendedBolusInsulin += tempBolusPart.insulin;
+ }
+ }
+ }
+ return result;
+ }
+
public int getRealDuration() {
return getDurationToTime(System.currentTimeMillis());
}
@@ -273,8 +325,8 @@ public String toStringShort() {
}
public String toStringMedium() {
- return "E " + DecimalFormatter.to2Decimal(absoluteRate()) + "U/h ("
- + getRealDuration() + "/" + durationInMinutes + ") ";
+ return DecimalFormatter.to2Decimal(absoluteRate()) + "U/h "
+ + getRealDuration() + "/" + durationInMinutes + "'";
}
public String toStringTotal() {
diff --git a/app/src/main/java/info/nightscout/androidaps/db/ProfileSwitch.java b/app/src/main/java/info/nightscout/androidaps/db/ProfileSwitch.java
index 0e589f05958..62b963e9ef8 100644
--- a/app/src/main/java/info/nightscout/androidaps/db/ProfileSwitch.java
+++ b/app/src/main/java/info/nightscout/androidaps/db/ProfileSwitch.java
@@ -1,7 +1,9 @@
package info.nightscout.androidaps.db;
import android.graphics.Color;
-import android.support.annotation.Nullable;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable;
@@ -18,11 +20,13 @@
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.interfaces.Interval;
import info.nightscout.androidaps.logging.L;
+import info.nightscout.androidaps.plugins.bus.RxBus;
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification;
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.DataPointWithLabelInterface;
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.PointsWithLabelGraphSeries;
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification;
import info.nightscout.androidaps.plugins.profile.local.LocalProfilePlugin;
+import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
import info.nightscout.androidaps.utils.DateUtil;
import info.nightscout.androidaps.utils.DecimalFormatter;
import info.nightscout.androidaps.utils.T;
@@ -78,12 +82,12 @@ public ProfileSwitch profile(Profile profile) {
return this;
}
- public ProfileSwitch source(int source) {
+ public ProfileSwitch source(int source) {
this.source = source;
return this;
}
- public ProfileSwitch duration(int duration) {
+ public ProfileSwitch duration(int duration) {
this.durationInMinutes = duration;
return this;
}
@@ -107,7 +111,7 @@ public Profile getProfileObject() {
*/
public String getCustomizedName() {
String name = profileName;
- if(LocalProfilePlugin.LOCAL_PROFILE.equals(name)){
+ if (LocalProfilePlugin.LOCAL_PROFILE.equals(name)) {
name = DecimalFormatter.to2Decimal(getProfileObject().percentageBasalSum()) + "U ";
}
if (isCPP) {
@@ -156,7 +160,7 @@ public void copyFrom(ProfileSwitch t) {
// -------- Interval interface ---------
- Long cuttedEnd = null;
+ private Long cuttedEnd = null;
public long durationInMsec() {
return durationInMinutes * 60 * 1000L;
@@ -212,16 +216,17 @@ public boolean isEndingEvent() {
@Override
public boolean isValid() {
-
boolean isValid = getProfileObject() != null && getProfileObject().isValid(DateUtil.dateAndTimeString(date));
- if (!isValid)
+ ProfileSwitch active = TreatmentsPlugin.getPlugin().getProfileSwitchFromHistory(DateUtil.now());
+ long activeProfileSwitchDate = active != null ? active.date : -1L;
+ if (!isValid && date == activeProfileSwitchDate)
createNotificationInvalidProfile(DateUtil.dateAndTimeString(date));
return isValid;
}
- public void createNotificationInvalidProfile(String detail) {
+ private void createNotificationInvalidProfile(String detail) {
Notification notification = new Notification(Notification.ZERO_VALUE_IN_PROFILE, String.format(MainApp.gs(R.string.zerovalueinprofile), detail), Notification.LOW, 5);
- MainApp.bus().post(new EventNewNotification(notification));
+ RxBus.INSTANCE.send(new EventNewNotification(notification));
}
public static boolean isEvent5minBack(List list, long time, boolean zeroDurationOnly) {
@@ -290,6 +295,7 @@ public int getColor() {
return Color.CYAN;
}
+ @NonNull
public String toString() {
return "ProfileSwitch{" +
"date=" + date +
diff --git a/app/src/main/java/info/nightscout/androidaps/db/TDD.java b/app/src/main/java/info/nightscout/androidaps/db/TDD.java
index 9ca849b7b60..be81e36ba34 100644
--- a/app/src/main/java/info/nightscout/androidaps/db/TDD.java
+++ b/app/src/main/java/info/nightscout/androidaps/db/TDD.java
@@ -6,9 +6,11 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.util.Objects;
-
+import info.nightscout.androidaps.MainApp;
+import info.nightscout.androidaps.R;
import info.nightscout.androidaps.logging.L;
+import info.nightscout.androidaps.plugins.pump.common.utils.DateTimeUtil;
+import info.nightscout.androidaps.utils.DateUtil;
/**
* Created by mike on 20.09.2017.
@@ -45,4 +47,24 @@ public TDD(long date, double bolus, double basal, double total){
this.basal = basal;
this.total = total;
}
+
+
+ @Override
+ public String toString() {
+ return "TDD [" +
+ "date=" + date +
+ "date(str)=" + DateTimeUtil.toStringFromTimeInMillis(date) +
+ ", bolus=" + bolus +
+ ", basal=" + basal +
+ ", total=" + total +
+ ']';
+ }
+
+ public String toText() {
+ return MainApp.gs(R.string.tddformat, DateUtil.dateStringShort(date), total, bolus, basal);
+ }
+
+ public String toText(int days) {
+ return MainApp.gs(R.string.tddformat, String.format("%d ", days) + MainApp.gs(R.string.days), total, bolus, basal);
+ }
}
diff --git a/app/src/main/java/info/nightscout/androidaps/db/TempTarget.java b/app/src/main/java/info/nightscout/androidaps/db/TempTarget.java
index a496af802bd..ef60d029118 100644
--- a/app/src/main/java/info/nightscout/androidaps/db/TempTarget.java
+++ b/app/src/main/java/info/nightscout/androidaps/db/TempTarget.java
@@ -9,6 +9,9 @@
import java.util.Objects;
import info.nightscout.androidaps.Constants;
+import info.nightscout.androidaps.MainApp;
+import info.nightscout.androidaps.R;
+import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.interfaces.Interval;
import info.nightscout.androidaps.logging.L;
import info.nightscout.androidaps.utils.DateUtil;
@@ -191,4 +194,11 @@ public String toString() {
'}';
}
+ public String friendlyDescription(String units) {
+ return Profile.toTargetRangeString(low, high, Constants.MGDL, units) +
+ units +
+ "@" + MainApp.gs(R.string.mins, durationInMinutes) +
+ (reason != null && !reason.equals("") ? "(" + reason + ")" : "");
+ }
+
}
diff --git a/app/src/main/java/info/nightscout/androidaps/db/TemporaryBasal.java b/app/src/main/java/info/nightscout/androidaps/db/TemporaryBasal.java
index 336332790a9..cf0eeab462a 100644
--- a/app/src/main/java/info/nightscout/androidaps/db/TemporaryBasal.java
+++ b/app/src/main/java/info/nightscout/androidaps/db/TemporaryBasal.java
@@ -17,6 +17,7 @@
import info.nightscout.androidaps.logging.L;
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions;
+import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult;
import info.nightscout.androidaps.plugins.treatments.Treatment;
import info.nightscout.androidaps.utils.DateUtil;
import info.nightscout.androidaps.utils.DecimalFormatter;
@@ -27,7 +28,7 @@
*/
@DatabaseTable(tableName = DatabaseHelper.DATABASE_TEMPORARYBASALS)
-public class TemporaryBasal implements Interval {
+public class TemporaryBasal implements Interval, DbObjectBase {
private static Logger log = LoggerFactory.getLogger(L.DATABASE);
@DatabaseField(id = true)
@@ -156,6 +157,14 @@ public void copyFrom(TemporaryBasal t) {
netExtendedRate = t.netExtendedRate;
}
+ public void copyFromPump(TemporaryBasal t) {
+ durationInMinutes = t.durationInMinutes;
+ isAbsolute = t.isAbsolute;
+ percentRate = t.percentRate;
+ absoluteRate = t.absoluteRate;
+ pumpId = t.pumpId;
+ }
+
// -------- Interval interface ---------
Long cuttedEnd = null;
@@ -233,7 +242,7 @@ public IobTotal iobCalc(long time, Profile profile) {
double netBasalAmount = 0d;
if (realDuration > 0) {
- double netBasalRate = 0d;
+ double netBasalRate;
double dia = profile.getDia();
double dia_ago = time - dia * 60 * 60 * 1000;
int aboutFiveMinIntervals = (int) Math.ceil(realDuration / 5d);
@@ -243,10 +252,8 @@ public IobTotal iobCalc(long time, Profile profile) {
// find middle of the interval
long calcdate = (long) (date + j * tempBolusSpacing * 60 * 1000 + 0.5d * tempBolusSpacing * 60 * 1000);
- Double basalRate = profile.getBasal(calcdate);
+ double basalRate = profile.getBasal(calcdate);
- if (basalRate == null)
- continue;
if (isAbsolute) {
netBasalRate = absoluteRate - basalRate;
} else {
@@ -276,6 +283,73 @@ public IobTotal iobCalc(long time, Profile profile) {
return result;
}
+ public IobTotal iobCalc(long time, Profile profile, AutosensResult lastAutosensResult, boolean exercise_mode, int half_basal_exercise_target, boolean isTempTarget) {
+
+ if (isFakeExtended) {
+ log.error("iobCalc should only be called on Extended boluses separately");
+ return new IobTotal(time);
+ }
+
+ IobTotal result = new IobTotal(time);
+ InsulinInterface insulinInterface = ConfigBuilderPlugin.getPlugin().getActiveInsulin();
+
+ double realDuration = getDurationToTime(time);
+ double netBasalAmount = 0d;
+
+ double sensitivityRatio = lastAutosensResult.ratio;
+ double normalTarget = 100;
+
+ if (exercise_mode && isTempTarget && profile.getTargetMgdl() >= normalTarget + 5) {
+ // w/ target 100, temp target 110 = .89, 120 = 0.8, 140 = 0.67, 160 = .57, and 200 = .44
+ // e.g.: Sensitivity ratio set to 0.8 based on temp target of 120; Adjusting basal from 1.65 to 1.35; ISF from 58.9 to 73.6
+ double c = half_basal_exercise_target - normalTarget;
+ sensitivityRatio = c / (c + profile.getTargetMgdl() - normalTarget);
+ }
+
+ if (realDuration > 0) {
+ double netBasalRate;
+ double dia = profile.getDia();
+ double dia_ago = time - dia * 60 * 60 * 1000;
+ int aboutFiveMinIntervals = (int) Math.ceil(realDuration / 5d);
+ double tempBolusSpacing = realDuration / aboutFiveMinIntervals;
+
+ for (long j = 0L; j < aboutFiveMinIntervals; j++) {
+ // find middle of the interval
+ long calcdate = (long) (date + j * tempBolusSpacing * 60 * 1000 + 0.5d * tempBolusSpacing * 60 * 1000);
+
+ double basalRate = profile.getBasal(calcdate);
+ basalRate *= sensitivityRatio;
+
+ if (isAbsolute) {
+ netBasalRate = absoluteRate - basalRate;
+ } else {
+ double abs = percentRate / 100d * profile.getBasal(calcdate);
+ netBasalRate = abs - basalRate;
+ }
+
+ if (calcdate > dia_ago && calcdate <= time) {
+ double tempBolusSize = netBasalRate * tempBolusSpacing / 60d;
+ netBasalAmount += tempBolusSize;
+
+ Treatment tempBolusPart = new Treatment();
+ tempBolusPart.insulin = tempBolusSize;
+ tempBolusPart.date = calcdate;
+
+ Iob aIOB = insulinInterface.iobCalcForTreatment(tempBolusPart, time, dia);
+ result.basaliob += aIOB.iobContrib;
+ result.activity += aIOB.activityContrib;
+ result.netbasalinsulin += tempBolusPart.insulin;
+ if (tempBolusPart.insulin > 0) {
+ result.hightempinsulin += tempBolusPart.insulin;
+ }
+ }
+ result.netRatio = netBasalRate; // ratio at the end of interval
+ }
+ }
+ result.netInsulin = netBasalAmount;
+ return result;
+ }
+
public int getRealDuration() {
return getDurationToTime(System.currentTimeMillis());
}
@@ -331,8 +405,10 @@ public String toStringFull() {
if (isFakeExtended) {
Profile profile = ProfileFunctions.getInstance().getProfile();
+ if (profile == null)
+ return "null";
Double currentBasalRate = profile.getBasal();
- double rate = (currentBasalRate == null) ? 0d : (currentBasalRate + netExtendedRate);
+ double rate = currentBasalRate + netExtendedRate;
return getCalcuatedPercentageIfNeeded() + DecimalFormatter.to2Decimal(rate) + "U/h (" + DecimalFormatter.to2Decimal(netExtendedRate) + "E) @" +
DateUtil.timeString(date) +
" " + getRealDuration() + "/" + durationInMinutes + "'";
@@ -350,12 +426,14 @@ public String toStringFull() {
public String toStringShort() {
if (isAbsolute || isFakeExtended) {
- double rate = 0d;
+ double rate;
if (isFakeExtended) {
Profile profile = ProfileFunctions.getInstance().getProfile();
- Double currentBasalRate = profile.getBasal();
- rate = (currentBasalRate == null) ? 0d : (currentBasalRate + netExtendedRate);
- } else if (isAbsolute) {
+ if (profile == null)
+ return "null";
+ double currentBasalRate = profile.getBasal();
+ rate = currentBasalRate + netExtendedRate;
+ } else {
rate = absoluteRate;
}
@@ -375,24 +453,25 @@ public String toStringShort() {
}
private String getCalcuatedPercentageIfNeeded() {
+ Profile profile = ProfileFunctions.getInstance().getProfile();
+
+ if (profile == null)
+ return "null";
+
if (isAbsolute || isFakeExtended) {
- double rate = 0d;
+ double rate;
if (isFakeExtended) {
- Profile profile = ProfileFunctions.getInstance().getProfile();
- Double currentBasalRate = profile.getBasal();
- rate = (currentBasalRate == null) ? 0d : (currentBasalRate + netExtendedRate);
- } else if (isAbsolute) {
+ double currentBasalRate = profile.getBasal();
+ rate = currentBasalRate + netExtendedRate;
+ } else {
rate = absoluteRate;
}
if (SP.getBoolean(R.string.key_danar_visualizeextendedaspercentage, false) && SP.getBoolean(R.string.key_danar_useextended, false)) {
- Profile profile = ProfileFunctions.getInstance().getProfile();
- if (profile != null) {
- double basal = profile.getBasal();
- if (basal != 0) {
- return Math.round(rate * 100d / basal) + "% ";
- }
+ double basal = profile.getBasal();
+ if (basal != 0) {
+ return Math.round(rate * 100d / basal) + "% ";
}
}
}
@@ -400,14 +479,18 @@ private String getCalcuatedPercentageIfNeeded() {
}
public String toStringVeryShort() {
+ Profile profile = ProfileFunctions.getInstance().getProfile();
+
+ if (profile == null)
+ return "null";
+
if (isAbsolute || isFakeExtended) {
- double rate = 0d;
+ double rate;
if (isFakeExtended) {
- Profile profile = ProfileFunctions.getInstance().getProfile();
- Double currentBasalRate = profile.getBasal();
- rate = (currentBasalRate == null) ? 0d : (currentBasalRate + netExtendedRate);
- } else if (isAbsolute) {
+ double currentBasalRate = profile.getBasal();
+ rate = currentBasalRate + netExtendedRate;
+ } else {
rate = absoluteRate;
}
return DecimalFormatter.to2Decimal(rate) + "U/h ";
@@ -416,4 +499,13 @@ public String toStringVeryShort() {
}
}
+ @Override
+ public long getDate() {
+ return this.date;
+ }
+
+ @Override
+ public long getPumpId() {
+ return this.pumpId;
+ }
}
diff --git a/app/src/main/java/info/nightscout/androidaps/dialogs/BolusProgressDialog.kt b/app/src/main/java/info/nightscout/androidaps/dialogs/BolusProgressDialog.kt
new file mode 100644
index 00000000000..3f629add062
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/dialogs/BolusProgressDialog.kt
@@ -0,0 +1,159 @@
+package info.nightscout.androidaps.dialogs
+
+import android.app.Activity
+import android.os.Bundle
+import android.os.SystemClock
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.view.Window
+import android.view.WindowManager
+import androidx.fragment.app.DialogFragment
+import info.nightscout.androidaps.MainApp
+import info.nightscout.androidaps.R
+import info.nightscout.androidaps.activities.BolusProgressHelperActivity
+import info.nightscout.androidaps.events.EventPumpStatusChanged
+import info.nightscout.androidaps.logging.L
+import info.nightscout.androidaps.plugins.bus.RxBus.toObservable
+import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin
+import info.nightscout.androidaps.plugins.general.overview.events.EventDismissBolusProgressIfRunning
+import info.nightscout.androidaps.plugins.general.overview.events.EventOverviewBolusProgress
+import info.nightscout.androidaps.utils.FabricPrivacy
+import io.reactivex.android.schedulers.AndroidSchedulers
+import io.reactivex.disposables.CompositeDisposable
+import kotlinx.android.synthetic.main.dialog_bolusprogress.*
+import org.slf4j.LoggerFactory
+
+class BolusProgressDialog : DialogFragment() {
+ private val log = LoggerFactory.getLogger(L.UI)
+ private val disposable = CompositeDisposable()
+
+ companion object {
+ private val DEFAULT_STATE = MainApp.gs(R.string.waitingforpump)
+ @JvmField
+ var bolusEnded = false
+ @JvmField
+ var stopPressed = false
+ }
+
+ private var running = true
+ private var amount = 0.0
+ private var state: String? = null
+ private var helpActivity: BolusProgressHelperActivity? = null
+
+ fun setInsulin(amount: Double): BolusProgressDialog {
+ this.amount = amount
+ bolusEnded = false
+ return this
+ }
+
+ fun setHelperActivity(activity: BolusProgressHelperActivity): BolusProgressDialog {
+ helpActivity = activity
+ return this
+ }
+
+ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
+ savedInstanceState: Bundle?): View? {
+ dialog?.window?.requestFeature(Window.FEATURE_NO_TITLE)
+ dialog?.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN)
+ isCancelable = false
+ dialog?.setCanceledOnTouchOutside(false)
+ return inflater.inflate(R.layout.dialog_bolusprogress, container, false)
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ overview_bolusprogress_title.text = String.format(MainApp.gs(R.string.overview_bolusprogress_goingtodeliver), amount)
+ overview_bolusprogress_stop.setOnClickListener {
+ if (L.isEnabled(L.UI)) log.debug("Stop bolus delivery button pressed")
+ stopPressed = true
+ overview_bolusprogress_stoppressed.visibility = View.VISIBLE
+ overview_bolusprogress_stop.visibility = View.INVISIBLE
+ ConfigBuilderPlugin.getPlugin().commandQueue.cancelAllBoluses()
+ }
+ overview_bolusprogress_progressbar.max = 100
+ state = savedInstanceState?.getString("state", DEFAULT_STATE) ?: DEFAULT_STATE
+ overview_bolusprogress_status.text = state
+ stopPressed = false
+ }
+
+ override fun onStart() {
+ super.onStart()
+ dialog?.window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
+ }
+
+ override fun onResume() {
+ super.onResume()
+ if (L.isEnabled(L.UI)) log.debug("onResume")
+ if (!ConfigBuilderPlugin.getPlugin().commandQueue.bolusInQueue())
+ bolusEnded = true
+
+ if (bolusEnded) dismiss()
+ else running = true
+
+ disposable.add(toObservable(EventPumpStatusChanged::class.java)
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe({ overview_bolusprogress_status.text = it.getStatus() }) { FabricPrivacy.logException(it) }
+ )
+ disposable.add(toObservable(EventDismissBolusProgressIfRunning::class.java)
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe({ if (running) dismiss() }) { FabricPrivacy.logException(it) }
+ )
+ disposable.add(toObservable(EventOverviewBolusProgress::class.java)
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe({
+ if (L.isEnabled(L.UI)) log.debug("Status: " + it.status + " Percent: " + it.percent)
+ overview_bolusprogress_status.text = it.status
+ overview_bolusprogress_progressbar.progress = it.percent
+ if (it.percent == 100) {
+ overview_bolusprogress_stop.visibility = View.INVISIBLE
+ scheduleDismiss()
+ }
+ state = it.status
+ }) { FabricPrivacy.logException(it) }
+ )
+ }
+
+ override fun dismiss() {
+ if (L.isEnabled(L.UI)) log.debug("dismiss")
+ try {
+ super.dismiss()
+ } catch (e: IllegalStateException) {
+ // dialog not running yet. onResume will try again. Set bolusEnded to make extra
+ // sure onResume will catch this
+ bolusEnded = true
+ log.error("Unhandled exception", e)
+ }
+ helpActivity?.finish()
+ }
+
+ override fun onPause() {
+ super.onPause()
+ if (L.isEnabled(L.UI)) log.debug("onPause")
+ running = false
+ disposable.clear()
+ }
+
+ override fun onSaveInstanceState(outState: Bundle) {
+ super.onSaveInstanceState(outState)
+ outState.putString("state", state)
+ }
+
+ private fun scheduleDismiss() {
+ if (L.isEnabled(L.UI)) log.debug("scheduleDismiss")
+ Thread(Runnable {
+ SystemClock.sleep(5000)
+ bolusEnded = true
+ val activity: Activity? = activity
+ activity?.runOnUiThread {
+ if (running) {
+ if (L.isEnabled(L.UI)) log.debug("executing")
+ try {
+ dismiss()
+ } catch (e: Exception) {
+ log.error("Unhandled exception", e)
+ }
+ }
+ }
+ }).start()
+ }
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/dialogs/CalibrationDialog.kt b/app/src/main/java/info/nightscout/androidaps/dialogs/CalibrationDialog.kt
new file mode 100644
index 00000000000..9503988dce7
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/dialogs/CalibrationDialog.kt
@@ -0,0 +1,69 @@
+package info.nightscout.androidaps.dialogs
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import com.google.common.base.Joiner
+import info.nightscout.androidaps.Constants
+import info.nightscout.androidaps.MainApp
+import info.nightscout.androidaps.R
+import info.nightscout.androidaps.data.Profile
+import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions
+import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus
+import info.nightscout.androidaps.utils.HtmlHelper
+import info.nightscout.androidaps.utils.OKDialog
+import info.nightscout.androidaps.utils.XdripCalibrations
+import kotlinx.android.synthetic.main.dialog_calibration.*
+import kotlinx.android.synthetic.main.okcancel.*
+import java.text.DecimalFormat
+import java.util.*
+
+class CalibrationDialog : DialogFragmentWithDate() {
+
+ override fun onSaveInstanceState(savedInstanceState: Bundle) {
+ super.onSaveInstanceState(savedInstanceState)
+ savedInstanceState.putDouble("overview_calibration_bg", overview_calibration_bg.value)
+ }
+
+ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
+ savedInstanceState: Bundle?): View? {
+ onCreateViewGeneral()
+ return inflater.inflate(R.layout.dialog_calibration, container, false)
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+
+ val units = ProfileFunctions.getSystemUnits()
+ val bg = Profile.fromMgdlToUnits(GlucoseStatus.getGlucoseStatusData()?.glucose
+ ?: 0.0, units)
+ if (units == Constants.MMOL)
+ overview_calibration_bg.setParams(savedInstanceState?.getDouble("overview_calibration_bg")
+ ?: bg, 2.0, 30.0, 0.1, DecimalFormat("0.0"), false, ok)
+ else
+ overview_calibration_bg.setParams(savedInstanceState?.getDouble("overview_calibration_bg")
+ ?: bg, 36.0, 500.0, 1.0, DecimalFormat("0"), false, ok)
+ overview_calibration_units.text = if (units == Constants.MMOL) MainApp.gs(R.string.mmol) else MainApp.gs(R.string.mgdl)
+ }
+
+ override fun submit() :Boolean {
+ val units = ProfileFunctions.getSystemUnits()
+ val unitLabel = if (units == Constants.MMOL) MainApp.gs(R.string.mmol) else MainApp.gs(R.string.mgdl)
+ val actions: LinkedList = LinkedList()
+ val bg = overview_calibration_bg.value
+ actions.add(MainApp.gs(R.string.treatments_wizard_bg_label) + ": " + Profile.toCurrentUnitsString(bg) + " " + unitLabel)
+ if (bg > 0) {
+ activity?.let { activity ->
+ OKDialog.showConfirmation(activity, MainApp.gs(R.string.overview_calibration), HtmlHelper.fromHtml(Joiner.on(" ").join(actions)), Runnable {
+ log.debug("USER ENTRY: CALIBRATION $bg")
+ XdripCalibrations.confirmAndSendCalibration(bg, context)
+ })
+ }
+ } else
+ activity?.let { activity ->
+ OKDialog.show(activity, MainApp.gs(R.string.overview_calibration), MainApp.gs(R.string.no_action_selected))
+ }
+ return true
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/dialogs/CarbsDialog.kt b/app/src/main/java/info/nightscout/androidaps/dialogs/CarbsDialog.kt
new file mode 100644
index 00000000000..1f0c6643c19
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/dialogs/CarbsDialog.kt
@@ -0,0 +1,228 @@
+package info.nightscout.androidaps.dialogs
+
+import android.os.Bundle
+import android.text.Editable
+import android.text.TextWatcher
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import com.google.common.base.Joiner
+import info.nightscout.androidaps.Constants
+import info.nightscout.androidaps.MainApp
+import info.nightscout.androidaps.R
+import info.nightscout.androidaps.data.Profile
+import info.nightscout.androidaps.db.CareportalEvent
+import info.nightscout.androidaps.db.DatabaseHelper
+import info.nightscout.androidaps.db.Source
+import info.nightscout.androidaps.db.TempTarget
+import info.nightscout.androidaps.interfaces.Constraint
+import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions
+import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
+import info.nightscout.androidaps.plugins.treatments.CarbsGenerator
+import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
+import info.nightscout.androidaps.utils.*
+import kotlinx.android.synthetic.main.dialog_carbs.*
+import kotlinx.android.synthetic.main.notes.*
+import kotlinx.android.synthetic.main.okcancel.*
+import java.text.DecimalFormat
+import java.util.*
+import kotlin.math.max
+
+class CarbsDialog : DialogFragmentWithDate() {
+
+ companion object {
+ private const val FAV1_DEFAULT = 5
+ private const val FAV2_DEFAULT = 10
+ private const val FAV3_DEFAULT = 20
+ }
+
+ private val maxCarbs = MainApp.getConstraintChecker().maxCarbsAllowed.value().toDouble()
+
+ private val textWatcher: TextWatcher = object : TextWatcher {
+ override fun afterTextChanged(s: Editable) {
+ validateInputs()
+ }
+
+ override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
+ override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {}
+ }
+
+ private fun validateInputs() {
+ val time = overview_carbs_time.value.toInt()
+ if (time > 12 * 60 || time < -12 * 60) {
+ overview_carbs_time.value = 0.0
+ ToastUtils.showToastInUiThread(MainApp.instance().applicationContext, MainApp.gs(R.string.constraintapllied))
+ }
+ if (overview_carbs_duration.value > 10) {
+ overview_carbs_duration.value = 0.0
+ ToastUtils.showToastInUiThread(MainApp.instance().applicationContext, MainApp.gs(R.string.constraintapllied))
+ }
+ if (overview_carbs_carbs.value.toInt() > maxCarbs) {
+ overview_carbs_carbs.value = 0.0
+ ToastUtils.showToastInUiThread(MainApp.instance().applicationContext, MainApp.gs(R.string.carbsconstraintapplied))
+ }
+ }
+
+ override fun onSaveInstanceState(savedInstanceState: Bundle) {
+ super.onSaveInstanceState(savedInstanceState)
+ savedInstanceState.putDouble("overview_carbs_time", overview_carbs_time.value)
+ savedInstanceState.putDouble("overview_carbs_duration", overview_carbs_duration.value)
+ savedInstanceState.putDouble("overview_carbs_carbs", overview_carbs_carbs.value)
+ }
+
+ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
+ savedInstanceState: Bundle?): View? {
+ onCreateViewGeneral()
+ return inflater.inflate(R.layout.dialog_carbs, container, false)
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+
+ overview_carbs_time.setParams(savedInstanceState?.getDouble("overview_carbs_time")
+ ?: 0.0, -12 * 60.0, 12 * 60.0, 5.0, DecimalFormat("0"), false, ok, textWatcher)
+
+ overview_carbs_duration.setParams(savedInstanceState?.getDouble("overview_carbs_duration")
+ ?: 0.0, 0.0, 10.0, 1.0, DecimalFormat("0"), false, ok, textWatcher)
+
+ overview_carbs_carbs.setParams(savedInstanceState?.getDouble("overview_carbs_carbs")
+ ?: 0.0, 0.0, maxCarbs, 1.0, DecimalFormat("0"), false, ok, textWatcher)
+
+ overview_carbs_plus1.text = toSignedString(SP.getInt(R.string.key_carbs_button_increment_1, FAV1_DEFAULT))
+ overview_carbs_plus1.setOnClickListener {
+ overview_carbs_carbs.value = max(0.0, overview_carbs_carbs.value
+ + SP.getInt(R.string.key_carbs_button_increment_1, FAV1_DEFAULT))
+ validateInputs()
+ }
+
+ overview_carbs_plus2.text = toSignedString(SP.getInt(R.string.key_carbs_button_increment_2, FAV2_DEFAULT))
+ overview_carbs_plus2.setOnClickListener {
+ overview_carbs_carbs.value = max(0.0, overview_carbs_carbs.value
+ + SP.getInt(R.string.key_carbs_button_increment_2, FAV2_DEFAULT))
+ validateInputs()
+ }
+
+ overview_carbs_plus3.text = toSignedString(SP.getInt(R.string.key_carbs_button_increment_3, FAV3_DEFAULT))
+ overview_carbs_plus3.setOnClickListener {
+ overview_carbs_carbs.value = max(0.0, overview_carbs_carbs.value
+ + SP.getInt(R.string.key_carbs_button_increment_3, FAV3_DEFAULT))
+ validateInputs()
+ }
+
+ DatabaseHelper.actualBg()?.let { bgReading ->
+ if (bgReading.value < 72)
+ overview_carbs_hypo_tt.setChecked(true)
+ }
+ overview_carbs_hypo_tt.setOnClickListener {
+ overview_carbs_activity_tt.isChecked = false
+ overview_carbs_eating_soon_tt.isChecked = false
+ }
+ overview_carbs_activity_tt.setOnClickListener {
+ overview_carbs_hypo_tt.isChecked = false
+ overview_carbs_eating_soon_tt.isChecked = false
+ }
+ overview_carbs_eating_soon_tt.setOnClickListener {
+ overview_carbs_hypo_tt.isChecked = false
+ overview_carbs_activity_tt.isChecked = false
+ }
+ }
+
+ private fun toSignedString(value: Int): String {
+ return if (value > 0) "+$value" else value.toString()
+ }
+
+ override fun submit(): Boolean {
+ val carbs = overview_carbs_carbs.value.toInt()
+ val carbsAfterConstraints = MainApp.getConstraintChecker().applyCarbsConstraints(Constraint(carbs)).value()
+ val units = ProfileFunctions.getSystemUnits()
+ val activityTTDuration = DefaultValueHelper.determineActivityTTDuration()
+ val activityTT = DefaultValueHelper.determineActivityTT()
+ val eatingSoonTTDuration = DefaultValueHelper.determineEatingSoonTTDuration()
+ val eatingSoonTT = DefaultValueHelper.determineEatingSoonTT()
+ val hypoTTDuration = DefaultValueHelper.determineHypoTTDuration()
+ val hypoTT = DefaultValueHelper.determineHypoTT()
+ val actions: LinkedList = LinkedList()
+ val unitLabel = if (units == Constants.MMOL) MainApp.gs(R.string.mmol) else MainApp.gs(R.string.mgdl)
+
+ val activitySelected = overview_carbs_activity_tt.isChecked
+ if (activitySelected)
+ actions.add(MainApp.gs(R.string.temptargetshort) + ": " + "" + DecimalFormatter.to1Decimal(activityTT) + " " + unitLabel + " (" + activityTTDuration + " " + MainApp.gs(R.string.unit_minute_short) + ") ")
+ val eatingSoonSelected = overview_carbs_eating_soon_tt.isChecked
+ if (eatingSoonSelected)
+ actions.add(MainApp.gs(R.string.temptargetshort) + ": " + "" + DecimalFormatter.to1Decimal(eatingSoonTT) + " " + unitLabel + " (" + eatingSoonTTDuration + " " + MainApp.gs(R.string.unit_minute_short) + ") ")
+ val hypoSelected = overview_carbs_hypo_tt.isChecked
+ if (hypoSelected)
+ actions.add(MainApp.gs(R.string.temptargetshort) + ": " + "" + DecimalFormatter.to1Decimal(hypoTT) + " " + unitLabel + " (" + hypoTTDuration + " " + MainApp.gs(R.string.unit_minute_short) + ") ")
+
+ val timeOffset = overview_carbs_time.value.toInt()
+ val time = eventTime + timeOffset * 1000 * 60
+ if (timeOffset != 0)
+ actions.add(MainApp.gs(R.string.time) + ": " + DateUtil.dateAndTimeString(time))
+ val duration = overview_carbs_duration.value.toInt()
+ if (duration > 0)
+ actions.add(MainApp.gs(R.string.duration) + ": " + duration + MainApp.gs(R.string.shorthour))
+ if (carbsAfterConstraints > 0) {
+ actions.add(MainApp.gs(R.string.carbs) + ": " + "" + MainApp.gs(R.string.format_carbs, carbsAfterConstraints) + " ")
+ if (carbsAfterConstraints != carbs)
+ actions.add("" + MainApp.gs(R.string.carbsconstraintapplied) + " ")
+ }
+ val notes = notes.text.toString()
+ if (notes.isNotEmpty())
+ actions.add(MainApp.gs(R.string.careportal_newnstreatment_notes_label) + ": " + notes)
+
+ if (eventTimeChanged)
+ actions.add(MainApp.gs(R.string.time) + ": " + DateUtil.dateAndTimeString(eventTime))
+
+ if (carbsAfterConstraints > 0 || activitySelected || eatingSoonSelected || hypoSelected) {
+ activity?.let { activity ->
+ OKDialog.showConfirmation(activity, MainApp.gs(R.string.carbs), HtmlHelper.fromHtml(Joiner.on(" ").join(actions)), Runnable {
+ if (activitySelected) {
+ log.debug("USER ENTRY: TEMPTARGET ACTIVITY $activityTT duration: $activityTTDuration")
+ val tempTarget = TempTarget()
+ .date(eventTime)
+ .duration(activityTTDuration)
+ .reason(MainApp.gs(R.string.activity))
+ .source(Source.USER)
+ .low(Profile.toMgdl(activityTT, ProfileFunctions.getSystemUnits()))
+ .high(Profile.toMgdl(activityTT, ProfileFunctions.getSystemUnits()))
+ TreatmentsPlugin.getPlugin().addToHistoryTempTarget(tempTarget)
+ } else if (eatingSoonSelected) {
+ log.debug("USER ENTRY: TEMPTARGET EATING SOON $eatingSoonTT duration: $eatingSoonTTDuration")
+ val tempTarget = TempTarget()
+ .date(eventTime)
+ .duration(eatingSoonTTDuration)
+ .reason(MainApp.gs(R.string.eatingsoon))
+ .source(Source.USER)
+ .low(Profile.toMgdl(eatingSoonTT, ProfileFunctions.getSystemUnits()))
+ .high(Profile.toMgdl(eatingSoonTT, ProfileFunctions.getSystemUnits()))
+ TreatmentsPlugin.getPlugin().addToHistoryTempTarget(tempTarget)
+ } else if (hypoSelected) {
+ log.debug("USER ENTRY: TEMPTARGET HYPO $hypoTT duration: $hypoTTDuration")
+ val tempTarget = TempTarget()
+ .date(eventTime)
+ .duration(hypoTTDuration)
+ .reason(MainApp.gs(R.string.hypo))
+ .source(Source.USER)
+ .low(Profile.toMgdl(hypoTT, ProfileFunctions.getSystemUnits()))
+ .high(Profile.toMgdl(hypoTT, ProfileFunctions.getSystemUnits()))
+ TreatmentsPlugin.getPlugin().addToHistoryTempTarget(tempTarget)
+ }
+ if (carbsAfterConstraints > 0) {
+ if (duration == 0) {
+ log.debug("USER ENTRY: CARBS $carbsAfterConstraints time: $time")
+ CarbsGenerator.createCarb(carbsAfterConstraints, time, CareportalEvent.CARBCORRECTION, notes)
+ } else {
+ log.debug("USER ENTRY: CARBS $carbsAfterConstraints time: $time duration: $duration")
+ CarbsGenerator.generateCarbs(carbsAfterConstraints, time, duration, notes)
+ NSUpload.uploadEvent(CareportalEvent.NOTE, time - 2000, MainApp.gs(R.string.generated_ecarbs_note, carbsAfterConstraints, duration, timeOffset))
+ }
+ }
+ }, null)
+ }
+ } else
+ activity?.let { activity ->
+ OKDialog.show(activity, MainApp.gs(R.string.carbs), MainApp.gs(R.string.no_action_selected))
+ }
+ return true
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/dialogs/CareDialog.kt b/app/src/main/java/info/nightscout/androidaps/dialogs/CareDialog.kt
new file mode 100644
index 00000000000..da4a091b1d7
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/dialogs/CareDialog.kt
@@ -0,0 +1,190 @@
+package info.nightscout.androidaps.dialogs
+
+import android.os.Bundle
+import android.text.Editable
+import android.text.TextWatcher
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.Button
+import androidx.annotation.StringRes
+import com.google.common.base.Joiner
+import info.nightscout.androidaps.Constants
+import info.nightscout.androidaps.MainApp
+import info.nightscout.androidaps.R
+import info.nightscout.androidaps.data.Profile
+import info.nightscout.androidaps.db.CareportalEvent
+import info.nightscout.androidaps.db.Source
+import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions
+import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
+import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus
+import info.nightscout.androidaps.utils.DateUtil
+import info.nightscout.androidaps.utils.HtmlHelper
+import info.nightscout.androidaps.utils.OKDialog
+import info.nightscout.androidaps.utils.SP
+import info.nightscout.androidaps.utils.Translator
+import kotlinx.android.synthetic.main.dialog_care.*
+import kotlinx.android.synthetic.main.notes.*
+import kotlinx.android.synthetic.main.okcancel.*
+import org.json.JSONObject
+import java.text.DecimalFormat
+import java.util.*
+
+class CareDialog : DialogFragmentWithDate() {
+
+ enum class EventType {
+ BGCHECK,
+ SENSOR_INSERT,
+ BATTERY_CHANGE,
+ NOTE,
+ EXERCISE
+ }
+
+ private var options: EventType = EventType.BGCHECK
+ @StringRes
+ private var event: Int = R.string.none
+
+ fun setOptions(options: EventType, @StringRes event: Int): CareDialog {
+ this.options = options
+ this.event = event
+ return this
+ }
+
+ override fun onSaveInstanceState(savedInstanceState: Bundle) {
+ super.onSaveInstanceState(savedInstanceState)
+ savedInstanceState.putDouble("actions_care_bg", actions_care_bg.value)
+ savedInstanceState.putDouble("actions_care_duration", actions_care_duration.value)
+ }
+
+ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
+ savedInstanceState: Bundle?): View? {
+ onCreateViewGeneral()
+ return inflater.inflate(R.layout.dialog_care, container, false)
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+
+ actions_care_icon.setImageResource(when (options) {
+ EventType.BGCHECK -> R.drawable.icon_cp_bgcheck
+ EventType.SENSOR_INSERT -> R.drawable.icon_cp_cgm_insert
+ EventType.BATTERY_CHANGE -> R.drawable.icon_cp_pump_battery
+ EventType.NOTE -> R.drawable.icon_cp_note
+ EventType.EXERCISE -> R.drawable.icon_cp_exercise
+ })
+ actions_care_title.text = MainApp.gs(when (options) {
+ EventType.BGCHECK -> R.string.careportal_bgcheck
+ EventType.SENSOR_INSERT -> R.string.careportal_cgmsensorinsert
+ EventType.BATTERY_CHANGE -> R.string.careportal_pumpbatterychange
+ EventType.NOTE -> R.string.careportal_note
+ EventType.EXERCISE -> R.string.careportal_exercise
+ })
+
+ when (options) {
+ EventType.BGCHECK -> {
+ action_care_duration_layout.visibility = View.GONE
+ }
+ EventType.SENSOR_INSERT,
+ EventType.BATTERY_CHANGE -> {
+ action_care_bg_layout.visibility = View.GONE
+ actions_care_bgsource.visibility = View.GONE
+ action_care_duration_layout.visibility = View.GONE
+ }
+ EventType.NOTE,
+ EventType.EXERCISE -> {
+ action_care_bg_layout.visibility = View.GONE
+ actions_care_bgsource.visibility = View.GONE
+ }
+ }
+
+ val bg = Profile.fromMgdlToUnits(GlucoseStatus.getGlucoseStatusData()?.glucose
+ ?: 0.0, ProfileFunctions.getSystemUnits())
+ val bgTextWatcher: TextWatcher = object : TextWatcher {
+ override fun afterTextChanged(s: Editable) {}
+ override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
+ override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
+ if (actions_care_sensor.isChecked) actions_care_meter.isChecked = true
+ }
+ }
+
+ if (ProfileFunctions.getSystemUnits() == Constants.MMOL) {
+ actions_care_bgunits.text = MainApp.gs(R.string.mmol)
+ actions_care_bg.setParams(savedInstanceState?.getDouble("actions_care_bg")
+ ?: bg, 2.0, 30.0, 0.1, DecimalFormat("0.0"), false, ok, bgTextWatcher)
+ } else {
+ actions_care_bgunits.text = MainApp.gs(R.string.mgdl)
+ actions_care_bg.setParams(savedInstanceState?.getDouble("actions_care_bg")
+ ?: bg, 36.0, 500.0, 1.0, DecimalFormat("0"), false, ok, bgTextWatcher)
+ }
+ actions_care_duration.setParams(savedInstanceState?.getDouble("actions_care_duration")
+ ?: 0.0, 0.0, Constants.MAX_PROFILE_SWITCH_DURATION, 10.0, DecimalFormat("0"), false, ok)
+ if (options == EventType.NOTE)
+ notes_layout?.visibility = View.VISIBLE // independent to preferences
+ }
+
+ override fun submit(): Boolean {
+ val enteredBy = SP.getString("careportal_enteredby", "")
+ val unitResId = if (ProfileFunctions.getSystemUnits() == Constants.MGDL) R.string.mgdl else R.string.mmol
+
+ val json = JSONObject()
+ val actions: LinkedList = LinkedList()
+ if (options == EventType.BGCHECK) {
+ val type =
+ when {
+ actions_care_meter.isChecked -> "Finger"
+ actions_care_sensor.isChecked -> "Sensor"
+ else -> "Manual"
+ }
+ actions.add(MainApp.gs(R.string.careportal_newnstreatment_glucosetype) + ": " + Translator.translate(type))
+ actions.add(MainApp.gs(R.string.treatments_wizard_bg_label) + ": " + Profile.toCurrentUnitsString(actions_care_bg.value) + " " + MainApp.gs(unitResId))
+ json.put("glucose", actions_care_bg.value)
+ json.put("glucoseType", type)
+ }
+ if (options == EventType.NOTE || options == EventType.EXERCISE) {
+ actions.add(MainApp.gs(R.string.careportal_newnstreatment_duration_label) + ": " + MainApp.gs(R.string.format_mins, actions_care_duration.value.toInt()))
+ json.put("duration", actions_care_duration.value.toInt())
+ }
+ val notes = notes.text.toString()
+ if (notes.isNotEmpty()) {
+ actions.add(MainApp.gs(R.string.careportal_newnstreatment_notes_label) + ": " + notes)
+ json.put("notes", notes)
+ }
+ eventTime -= eventTime % 1000
+
+ if (eventTimeChanged)
+ actions.add(MainApp.gs(R.string.time) + ": " + DateUtil.dateAndTimeString(eventTime))
+
+ json.put("created_at", DateUtil.toISOString(eventTime))
+ json.put("mills", eventTime)
+ json.put("eventType", when (options) {
+ EventType.BGCHECK -> CareportalEvent.BGCHECK
+ EventType.SENSOR_INSERT -> CareportalEvent.SENSORCHANGE
+ EventType.BATTERY_CHANGE -> CareportalEvent.PUMPBATTERYCHANGE
+ EventType.NOTE -> CareportalEvent.NOTE
+ EventType.EXERCISE -> CareportalEvent.EXERCISE
+ })
+ json.put("units", ProfileFunctions.getSystemUnits())
+ if (enteredBy.isNotEmpty())
+ json.put("enteredBy", enteredBy)
+
+ activity?.let { activity ->
+ OKDialog.showConfirmation(activity, MainApp.gs(event), HtmlHelper.fromHtml(Joiner.on(" ").join(actions)), Runnable {
+ val careportalEvent = CareportalEvent()
+ careportalEvent.date = eventTime
+ careportalEvent.source = Source.USER
+ careportalEvent.eventType = when (options) {
+ EventType.BGCHECK -> CareportalEvent.BGCHECK
+ EventType.SENSOR_INSERT -> CareportalEvent.SENSORCHANGE
+ EventType.BATTERY_CHANGE -> CareportalEvent.PUMPBATTERYCHANGE
+ EventType.NOTE -> CareportalEvent.NOTE
+ EventType.EXERCISE -> CareportalEvent.EXERCISE
+ }
+ careportalEvent.json = json.toString()
+ log.debug("USER ENTRY: CAREPORTAL ${careportalEvent.eventType} json: ${careportalEvent.json}")
+ MainApp.getDbHelper().createOrUpdate(careportalEvent)
+ NSUpload.uploadCareportalEntryToNS(json)
+ }, null)
+ }
+ return true
+ }
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/dialogs/DialogFragmentWithDate.kt b/app/src/main/java/info/nightscout/androidaps/dialogs/DialogFragmentWithDate.kt
new file mode 100644
index 00000000000..ecaea0bc819
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/dialogs/DialogFragmentWithDate.kt
@@ -0,0 +1,124 @@
+package info.nightscout.androidaps.dialogs
+
+import android.app.DatePickerDialog
+import android.app.TimePickerDialog
+import android.os.Bundle
+import android.text.format.DateFormat
+import android.view.View
+import android.view.ViewGroup
+import android.view.Window
+import android.view.WindowManager
+import androidx.fragment.app.DialogFragment
+import info.nightscout.androidaps.R
+import info.nightscout.androidaps.utils.DateUtil
+import info.nightscout.androidaps.utils.SP
+import info.nightscout.androidaps.utils.toVisibility
+import kotlinx.android.synthetic.main.datetime.*
+import kotlinx.android.synthetic.main.notes.*
+import kotlinx.android.synthetic.main.okcancel.*
+import org.slf4j.LoggerFactory
+import java.util.*
+
+abstract class DialogFragmentWithDate : DialogFragment() {
+ val log = LoggerFactory.getLogger(DialogFragmentWithDate::class.java)
+
+ var eventTime = DateUtil.now()
+ var eventTimeChanged = false
+
+ //one shot guards
+ private var okClicked: Boolean = false
+
+ companion object {
+ private var seconds: Int = (Math.random() * 59.0).toInt()
+ }
+
+ override fun onStart() {
+ super.onStart()
+ dialog?.window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
+ }
+
+ override fun onSaveInstanceState(savedInstanceState: Bundle) {
+ super.onSaveInstanceState(savedInstanceState)
+ savedInstanceState.putLong("eventTime", eventTime)
+ savedInstanceState.putBoolean("eventTimeChanged", eventTimeChanged)
+ }
+
+ fun onCreateViewGeneral() {
+ dialog?.window?.requestFeature(Window.FEATURE_NO_TITLE)
+ dialog?.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN)
+ isCancelable = true
+ dialog?.setCanceledOnTouchOutside(false)
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ eventTime = savedInstanceState?.getLong("eventTime") ?: DateUtil.now()
+ eventTimeChanged = savedInstanceState?.getBoolean("eventTimeChanged") ?: false
+ overview_eventdate?.text = DateUtil.dateString(eventTime)
+ overview_eventtime?.text = DateUtil.timeString(eventTime)
+
+ // create an OnDateSetListener
+ val dateSetListener = DatePickerDialog.OnDateSetListener { _, year, monthOfYear, dayOfMonth ->
+ val cal = Calendar.getInstance()
+ cal.timeInMillis = eventTime
+ cal.set(Calendar.YEAR, year)
+ cal.set(Calendar.MONTH, monthOfYear)
+ cal.set(Calendar.DAY_OF_MONTH, dayOfMonth)
+ eventTime = cal.timeInMillis
+ eventTimeChanged = true
+ overview_eventdate?.text = DateUtil.dateString(eventTime)
+ }
+
+ overview_eventdate?.setOnClickListener {
+ context?.let {
+ val cal = Calendar.getInstance()
+ cal.timeInMillis = eventTime
+ DatePickerDialog(it, dateSetListener,
+ cal.get(Calendar.YEAR),
+ cal.get(Calendar.MONTH),
+ cal.get(Calendar.DAY_OF_MONTH)
+ ).show()
+ }
+ }
+
+ // create an OnTimeSetListener
+ val timeSetListener = TimePickerDialog.OnTimeSetListener { _, hour, minute ->
+ val cal = Calendar.getInstance()
+ cal.timeInMillis = eventTime
+ cal.set(Calendar.HOUR_OF_DAY, hour)
+ cal.set(Calendar.MINUTE, minute)
+ cal.set(Calendar.SECOND, seconds++) // randomize seconds to prevent creating record of the same time, if user choose time manually
+ eventTime = cal.timeInMillis
+ eventTimeChanged = true
+ overview_eventtime?.text = DateUtil.timeString(eventTime)
+ }
+
+ overview_eventtime?.setOnClickListener {
+ context?.let {
+ val cal = Calendar.getInstance()
+ cal.timeInMillis = eventTime
+ TimePickerDialog(it, timeSetListener,
+ cal.get(Calendar.HOUR_OF_DAY),
+ cal.get(Calendar.MINUTE),
+ DateFormat.is24HourFormat(context)
+ ).show()
+ }
+ }
+
+ notes_layout?.visibility = SP.getBoolean(R.string.key_show_notes_entry_dialogs, false).toVisibility()
+
+ ok.setOnClickListener {
+ synchronized(okClicked) {
+ if (okClicked) {
+ log.debug("guarding: ok already clicked")
+ } else {
+ okClicked = true
+ if (submit()) dismiss()
+ else okClicked = false
+ }
+ }
+ }
+ cancel.setOnClickListener { dismiss() }
+ }
+
+ abstract fun submit(): Boolean
+}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/dialogs/ErrorDialog.kt b/app/src/main/java/info/nightscout/androidaps/dialogs/ErrorDialog.kt
new file mode 100644
index 00000000000..f3f71003dce
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/dialogs/ErrorDialog.kt
@@ -0,0 +1,109 @@
+package info.nightscout.androidaps.dialogs
+
+import android.content.ClipData
+import android.content.ClipboardManager
+import android.content.Context
+import android.content.Intent
+import android.os.Build
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.view.Window
+import android.view.WindowManager
+import androidx.fragment.app.DialogFragment
+import info.nightscout.androidaps.MainApp
+import info.nightscout.androidaps.R
+import info.nightscout.androidaps.activities.ErrorHelperActivity
+import info.nightscout.androidaps.services.AlarmSoundService
+import kotlinx.android.synthetic.main.dialog_error.*
+import org.slf4j.LoggerFactory
+import java.util.*
+
+class ErrorDialog : DialogFragment() {
+ private val log = LoggerFactory.getLogger(ErrorDialog::class.java)
+
+ var helperActivity: ErrorHelperActivity? = null
+ var status: String = ""
+ var title: String = ""
+ var sound: Int = 0
+ var clipboardContent: String = ""
+
+ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
+ savedInstanceState: Bundle?): View? {
+ dialog?.window?.requestFeature(Window.FEATURE_NO_TITLE)
+ dialog?.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN)
+ isCancelable = true
+ dialog?.setCanceledOnTouchOutside(false)
+
+ savedInstanceState?.let { bundle ->
+ bundle.getString("status")?.let { status = it }
+ bundle.getString("title")?.let { title = it }
+ sound = bundle.getInt("sound", R.raw.error)
+ }
+ log.debug("Error dialog displayed")
+ return inflater.inflate(R.layout.dialog_error, container, false)
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+
+ error_title.text = title
+ overview_error_ok.setOnClickListener {
+ log.debug("USER ENTRY: Error dialog ok button pressed")
+ dismiss()
+ }
+ overview_error_mute.setOnClickListener {
+ log.debug("USER ENTRY: Error dialog mute button pressed")
+ stopAlarm()
+ }
+ copyToClipboard()
+ startAlarm()
+ }
+
+ private fun copyToClipboard() {
+ if (clipboardContent.length > 0) {
+ val clipboard = MainApp.instance().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
+ val clip = ClipData.newPlainText(UUID.randomUUID().toString(), clipboardContent)
+ clipboard.primaryClip = clip
+ }
+ }
+
+ override fun onSaveInstanceState(bundle: Bundle) {
+ super.onSaveInstanceState(bundle)
+ bundle.putString("status", status)
+ bundle.putString("title", title)
+ bundle.putInt("sound", sound)
+ }
+
+ override fun onStart() {
+ super.onStart()
+ dialog?.window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
+ }
+
+ override fun onResume() {
+ super.onResume()
+ overview_error_status.text = status
+ }
+
+ override fun dismiss() {
+ super.dismissAllowingStateLoss()
+ helperActivity?.finish()
+ stopAlarm()
+ }
+
+ private fun startAlarm() {
+ if (sound != 0) {
+ val alarm = Intent(MainApp.instance().applicationContext, AlarmSoundService::class.java)
+ alarm.putExtra("soundid", sound)
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ MainApp.instance().startForegroundService(alarm)
+ } else {
+ MainApp.instance().startService(alarm)
+ }
+ }
+ }
+
+ private fun stopAlarm() =
+ MainApp.instance().stopService(Intent(MainApp.instance().applicationContext, AlarmSoundService::class.java))
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/dialogs/ExtendedBolusDialog.kt b/app/src/main/java/info/nightscout/androidaps/dialogs/ExtendedBolusDialog.kt
new file mode 100644
index 00000000000..dee77051fd9
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/dialogs/ExtendedBolusDialog.kt
@@ -0,0 +1,83 @@
+package info.nightscout.androidaps.dialogs
+
+import android.content.Intent
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import com.google.common.base.Joiner
+import info.nightscout.androidaps.MainApp
+import info.nightscout.androidaps.R
+import info.nightscout.androidaps.activities.ErrorHelperActivity
+import info.nightscout.androidaps.interfaces.Constraint
+import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin
+import info.nightscout.androidaps.queue.Callback
+import info.nightscout.androidaps.utils.HtmlHelper
+import info.nightscout.androidaps.utils.OKDialog
+import info.nightscout.androidaps.utils.SafeParse
+import kotlinx.android.synthetic.main.dialog_extendedbolus.*
+import kotlinx.android.synthetic.main.okcancel.*
+import java.text.DecimalFormat
+import java.util.*
+import kotlin.math.abs
+
+class ExtendedBolusDialog : DialogFragmentWithDate() {
+
+ override fun onSaveInstanceState(savedInstanceState: Bundle) {
+ super.onSaveInstanceState(savedInstanceState)
+ savedInstanceState.putDouble("actions_extendedbolus_insulin", actions_extendedbolus_insulin.value)
+ savedInstanceState.putDouble("actions_extendedbolus_duration", actions_extendedbolus_duration.value)
+ }
+
+ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
+ savedInstanceState: Bundle?): View? {
+ onCreateViewGeneral()
+ return inflater.inflate(R.layout.dialog_extendedbolus, container, false)
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+
+ val pumpDescription = ConfigBuilderPlugin.getPlugin().activePump?.pumpDescription ?: return
+
+ val maxInsulin = MainApp.getConstraintChecker().maxExtendedBolusAllowed.value()
+ val extendedStep = pumpDescription.extendedBolusStep
+ actions_extendedbolus_insulin.setParams(savedInstanceState?.getDouble("actions_extendedbolus_insulin")
+ ?: extendedStep, extendedStep, maxInsulin, extendedStep, DecimalFormat("0.00"), false, ok)
+
+ val extendedDurationStep = pumpDescription.extendedBolusDurationStep
+ val extendedMaxDuration = pumpDescription.extendedBolusMaxDuration
+ actions_extendedbolus_duration.setParams(savedInstanceState?.getDouble("actions_extendedbolus_duration")
+ ?: extendedDurationStep, extendedDurationStep, extendedMaxDuration, extendedDurationStep, DecimalFormat("0"), false, ok)
+ }
+
+ override fun submit(): Boolean {
+ val insulin = SafeParse.stringToDouble(actions_extendedbolus_insulin.text)
+ val durationInMinutes = SafeParse.stringToInt(actions_extendedbolus_duration.text)
+ val actions: LinkedList = LinkedList()
+ val insulinAfterConstraint = MainApp.getConstraintChecker().applyExtendedBolusConstraints(Constraint(insulin)).value()
+ actions.add(MainApp.gs(R.string.formatinsulinunits, insulinAfterConstraint))
+ actions.add(MainApp.gs(R.string.duration) + ": " + MainApp.gs(R.string.format_mins, durationInMinutes))
+ if (abs(insulinAfterConstraint - insulin) > 0.01)
+ actions.add("" + MainApp.gs(R.string.constraintapllied) + " ")
+
+ activity?.let { activity ->
+ OKDialog.showConfirmation(activity, MainApp.gs(R.string.extended_bolus), HtmlHelper.fromHtml(Joiner.on(" ").join(actions)), Runnable {
+ log.debug("USER ENTRY: EXTENDED BOLUS $insulinAfterConstraint duration: $durationInMinutes")
+ ConfigBuilderPlugin.getPlugin().commandQueue.extendedBolus(insulinAfterConstraint, durationInMinutes, object : Callback() {
+ override fun run() {
+ if (!result.success) {
+ val i = Intent(MainApp.instance(), ErrorHelperActivity::class.java)
+ i.putExtra("soundid", R.raw.boluserror)
+ i.putExtra("status", result.comment)
+ i.putExtra("title", MainApp.gs(R.string.treatmentdeliveryerror))
+ i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ MainApp.instance().startActivity(i)
+ }
+ }
+ })
+ }, null)
+ }
+ return true
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/dialogs/FillDialog.kt b/app/src/main/java/info/nightscout/androidaps/dialogs/FillDialog.kt
new file mode 100644
index 00000000000..a840384de04
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/dialogs/FillDialog.kt
@@ -0,0 +1,172 @@
+package info.nightscout.androidaps.dialogs
+
+import android.content.Intent
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import com.google.common.base.Joiner
+import info.nightscout.androidaps.MainApp
+import info.nightscout.androidaps.R
+import info.nightscout.androidaps.activities.ErrorHelperActivity
+import info.nightscout.androidaps.data.DetailedBolusInfo
+import info.nightscout.androidaps.db.CareportalEvent
+import info.nightscout.androidaps.db.Source
+import info.nightscout.androidaps.interfaces.Constraint
+import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin
+import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
+import info.nightscout.androidaps.queue.Callback
+import info.nightscout.androidaps.utils.*
+import kotlinx.android.synthetic.main.dialog_fill.*
+import kotlinx.android.synthetic.main.notes.*
+import kotlinx.android.synthetic.main.okcancel.*
+import org.json.JSONException
+import org.json.JSONObject
+import java.util.*
+import kotlin.math.abs
+
+class FillDialog : DialogFragmentWithDate() {
+
+ override fun onSaveInstanceState(savedInstanceState: Bundle) {
+ super.onSaveInstanceState(savedInstanceState)
+ savedInstanceState.putDouble("fill_insulinamount", fill_insulinamount.value)
+ }
+
+ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
+ savedInstanceState: Bundle?): View? {
+ onCreateViewGeneral()
+ return inflater.inflate(R.layout.dialog_fill, container, false)
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+
+ val maxInsulin = MainApp.getConstraintChecker().maxBolusAllowed.value()
+ val bolusStep = ConfigBuilderPlugin.getPlugin().activePump!!.pumpDescription.bolusStep
+ fill_insulinamount.setParams(savedInstanceState?.getDouble("fill_insulinamount")
+ ?: 0.0, 0.0, maxInsulin, bolusStep, DecimalFormatter.pumpSupportedBolusFormat(), true, ok)
+ val amount1 = SP.getDouble("fill_button1", 0.3)
+ if (amount1 > 0) {
+ fill_preset_button1.visibility = View.VISIBLE
+ fill_preset_button1.text = DecimalFormatter.toPumpSupportedBolus(amount1) // + "U");
+ fill_preset_button1.setOnClickListener { fill_insulinamount.value = amount1 }
+ } else {
+ fill_preset_button1.visibility = View.GONE
+ }
+ val amount2 = SP.getDouble("fill_button2", 0.0)
+ if (amount2 > 0) {
+ fill_preset_button2.visibility = View.VISIBLE
+ fill_preset_button2.text = DecimalFormatter.toPumpSupportedBolus(amount2) // + "U");
+ fill_preset_button2.setOnClickListener { fill_insulinamount.value = amount2 }
+ } else {
+ fill_preset_button2.visibility = View.GONE
+ }
+ val amount3 = SP.getDouble("fill_button3", 0.0)
+ if (amount3 > 0) {
+ fill_preset_button3.visibility = View.VISIBLE
+ fill_preset_button3.text = DecimalFormatter.toPumpSupportedBolus(amount3) // + "U");
+ fill_preset_button3.setOnClickListener { fill_insulinamount.value = amount3 }
+ } else {
+ fill_preset_button3.visibility = View.GONE
+ }
+
+ }
+
+ override fun submit(): Boolean {
+ val insulin = SafeParse.stringToDouble(fill_insulinamount.text)
+ val actions: LinkedList = LinkedList()
+
+ val insulinAfterConstraints = MainApp.getConstraintChecker().applyBolusConstraints(Constraint(insulin)).value()
+ if (insulinAfterConstraints > 0) {
+ actions.add(MainApp.gs(R.string.fillwarning))
+ actions.add("")
+ actions.add(MainApp.gs(R.string.bolus) + ": " + "" + DecimalFormatter.toPumpSupportedBolus(insulinAfterConstraints) + MainApp.gs(R.string.insulin_unit_shortname) + " ")
+ if (abs(insulinAfterConstraints - insulin) > 0.01)
+ actions.add(MainApp.gs(R.string.bolusconstraintappliedwarning, MainApp.gc(R.color.warning), insulin, insulinAfterConstraints))
+ }
+ val siteChange = fill_catheter_change.isChecked
+ if (siteChange)
+ actions.add("" + "" + MainApp.gs(R.string.record_pump_site_change) + " ")
+ val insulinChange = fill_cartridge_change.isChecked
+ if (insulinChange)
+ actions.add("" + "" + MainApp.gs(R.string.record_insulin_cartridge_change) + " ")
+ val notes = notes.text.toString()
+ if (notes.isNotEmpty())
+ actions.add(MainApp.gs(R.string.careportal_newnstreatment_notes_label) + ": " + notes)
+ eventTime -= eventTime % 1000
+
+ if (eventTimeChanged)
+ actions.add(MainApp.gs(R.string.time) + ": " + DateUtil.dateAndTimeString(eventTime))
+
+ if (insulinAfterConstraints > 0 || fill_catheter_change.isChecked || fill_cartridge_change.isChecked) {
+ activity?.let { activity ->
+ OKDialog.showConfirmation(activity, MainApp.gs(R.string.primefill), HtmlHelper.fromHtml(Joiner.on(" ").join(actions)), Runnable {
+ if (insulinAfterConstraints > 0) {
+ log.debug("USER ENTRY: PRIME BOLUS $insulinAfterConstraints")
+ requestPrimeBolus(insulinAfterConstraints, notes)
+ }
+ if (siteChange) {
+ log.debug("USER ENTRY: SITE CHANGE")
+ generateCareportalEvent(CareportalEvent.SITECHANGE, eventTime, notes)
+ }
+ if (insulinChange) {
+ // add a second for case of both checked
+ log.debug("USER ENTRY: INSULIN CHANGE")
+ generateCareportalEvent(CareportalEvent.INSULINCHANGE, eventTime + 1000, notes)
+ }
+ }, null)
+ }
+ } else {
+ activity?.let { activity ->
+ OKDialog.show(activity, MainApp.gs(R.string.primefill), MainApp.gs(R.string.no_action_selected))
+ }
+ }
+ dismiss()
+ return true
+ }
+
+ private fun requestPrimeBolus(insulin: Double, notes: String) {
+ val detailedBolusInfo = DetailedBolusInfo()
+ detailedBolusInfo.insulin = insulin
+ detailedBolusInfo.context = context
+ detailedBolusInfo.source = Source.USER
+ detailedBolusInfo.isValid = false // do not count it in IOB (for pump history)
+ detailedBolusInfo.notes = notes
+ ConfigBuilderPlugin.getPlugin().commandQueue.bolus(detailedBolusInfo, object : Callback() {
+ override fun run() {
+ if (!result.success) {
+ val i = Intent(MainApp.instance(), ErrorHelperActivity::class.java)
+ i.putExtra("soundid", R.raw.boluserror)
+ i.putExtra("status", result.comment)
+ i.putExtra("title", MainApp.gs(R.string.treatmentdeliveryerror))
+ i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ MainApp.instance().startActivity(i)
+ }
+ }
+ })
+ }
+
+ private fun generateCareportalEvent(eventType: String, time: Long, notes: String) {
+ val careportalEvent = CareportalEvent()
+ careportalEvent.source = Source.USER
+ careportalEvent.date = time
+ careportalEvent.json = generateJson(eventType, time, notes).toString()
+ careportalEvent.eventType = eventType
+ MainApp.getDbHelper().createOrUpdate(careportalEvent)
+ NSUpload.uploadEvent(eventType, time, notes)
+ }
+
+ private fun generateJson(careportalEvent: String, time: Long, notes: String): JSONObject {
+ val data = JSONObject()
+ try {
+ data.put("eventType", careportalEvent)
+ data.put("created_at", DateUtil.toISOString(time))
+ data.put("mills", time)
+ data.put("enteredBy", SP.getString("careportal_enteredby", MainApp.gs(R.string.app_name)))
+ if (notes.isNotEmpty()) data.put("notes", notes)
+ } catch (ignored: JSONException) {
+ }
+ return data
+ }
+
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/dialogs/InsulinDialog.kt b/app/src/main/java/info/nightscout/androidaps/dialogs/InsulinDialog.kt
new file mode 100644
index 00000000000..42bc395b8b2
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/dialogs/InsulinDialog.kt
@@ -0,0 +1,196 @@
+package info.nightscout.androidaps.dialogs
+
+import android.content.Intent
+import android.os.Bundle
+import android.text.Editable
+import android.text.TextWatcher
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import com.google.common.base.Joiner
+import info.nightscout.androidaps.Constants
+import info.nightscout.androidaps.MainApp
+import info.nightscout.androidaps.R
+import info.nightscout.androidaps.activities.ErrorHelperActivity
+import info.nightscout.androidaps.data.DetailedBolusInfo
+import info.nightscout.androidaps.data.Profile
+import info.nightscout.androidaps.db.CareportalEvent
+import info.nightscout.androidaps.db.Source
+import info.nightscout.androidaps.db.TempTarget
+import info.nightscout.androidaps.interfaces.Constraint
+import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin
+import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions
+import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
+import info.nightscout.androidaps.queue.Callback
+import info.nightscout.androidaps.utils.*
+import kotlinx.android.synthetic.main.dialog_insulin.*
+import kotlinx.android.synthetic.main.notes.*
+import kotlinx.android.synthetic.main.okcancel.*
+import java.text.DecimalFormat
+import java.util.*
+import kotlin.math.abs
+import kotlin.math.max
+
+class InsulinDialog : DialogFragmentWithDate() {
+
+ companion object {
+ private const val PLUS1_DEFAULT = 0.5
+ private const val PLUS2_DEFAULT = 1.0
+ private const val PLUS3_DEFAULT = 2.0
+ }
+
+ private val maxInsulin = MainApp.getConstraintChecker().maxBolusAllowed.value()
+
+ private val textWatcher: TextWatcher = object : TextWatcher {
+ override fun afterTextChanged(s: Editable) {
+ validateInputs()
+ }
+
+ override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
+ override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {}
+ }
+
+ private fun validateInputs() {
+ if (abs(overview_insulin_time.value.toInt()) > 12 * 60) {
+ overview_insulin_time.value = 0.0
+ ToastUtils.showToastInUiThread(MainApp.instance().applicationContext, MainApp.gs(R.string.constraintapllied))
+ }
+ if (overview_insulin_amount.value > maxInsulin) {
+ overview_insulin_amount.value = 0.0
+ ToastUtils.showToastInUiThread(MainApp.instance().applicationContext, MainApp.gs(R.string.bolusconstraintapplied))
+ }
+ }
+
+ override fun onSaveInstanceState(savedInstanceState: Bundle) {
+ super.onSaveInstanceState(savedInstanceState)
+ savedInstanceState.putDouble("overview_insulin_time", overview_insulin_time.value)
+ savedInstanceState.putDouble("overview_insulin_amount", overview_insulin_amount.value)
+ }
+
+ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
+ savedInstanceState: Bundle?): View? {
+ onCreateViewGeneral()
+ return inflater.inflate(R.layout.dialog_insulin, container, false)
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+
+ overview_insulin_time.setParams(savedInstanceState?.getDouble("overview_insulin_time")
+ ?: 0.0, -12 * 60.0, 12 * 60.0, 5.0, DecimalFormat("0"), false, ok, textWatcher)
+ overview_insulin_amount.setParams(savedInstanceState?.getDouble("overview_insulin_amount")
+ ?: 0.0, 0.0, maxInsulin, ConfigBuilderPlugin.getPlugin().activePump!!.pumpDescription.bolusStep, DecimalFormatter.pumpSupportedBolusFormat(), false, ok, textWatcher)
+
+ overview_insulin_plus05.text = toSignedString(SP.getDouble(MainApp.gs(R.string.key_insulin_button_increment_1), PLUS1_DEFAULT))
+ overview_insulin_plus05.setOnClickListener {
+ overview_insulin_amount.value = max(0.0, overview_insulin_amount.value
+ + SP.getDouble(MainApp.gs(R.string.key_insulin_button_increment_1), PLUS1_DEFAULT))
+ validateInputs()
+ }
+ overview_insulin_plus10.text = toSignedString(SP.getDouble(MainApp.gs(R.string.key_insulin_button_increment_2), PLUS2_DEFAULT))
+ overview_insulin_plus10.setOnClickListener {
+ overview_insulin_amount.value = max(0.0, overview_insulin_amount.value
+ + SP.getDouble(MainApp.gs(R.string.key_insulin_button_increment_2), PLUS2_DEFAULT))
+ validateInputs()
+ }
+ overview_insulin_plus20.text = toSignedString(SP.getDouble(MainApp.gs(R.string.key_insulin_button_increment_3), PLUS3_DEFAULT))
+ overview_insulin_plus20.setOnClickListener {
+ overview_insulin_amount.value = Math.max(0.0, overview_insulin_amount.value
+ + SP.getDouble(MainApp.gs(R.string.key_insulin_button_increment_3), PLUS3_DEFAULT))
+ validateInputs()
+ }
+
+ overview_insulin_time_layout.visibility = View.GONE
+ overview_insulin_record_only.setOnCheckedChangeListener { _, isChecked: Boolean ->
+ overview_insulin_time_layout.visibility = isChecked.toVisibility()
+ }
+ }
+
+ private fun toSignedString(value: Double): String {
+ val formatted = DecimalFormatter.toPumpSupportedBolus(value)
+ return if (value > 0) "+$formatted" else formatted
+ }
+
+ override fun submit(): Boolean {
+ val pumpDescription = ConfigBuilderPlugin.getPlugin().activePump?.pumpDescription
+ ?: return false
+ val insulin = SafeParse.stringToDouble(overview_insulin_amount.text)
+ val insulinAfterConstraints = MainApp.getConstraintChecker().applyBolusConstraints(Constraint(insulin)).value()
+ val actions: LinkedList = LinkedList()
+ val units = ProfileFunctions.getSystemUnits()
+ val unitLabel = if (units == Constants.MMOL) MainApp.gs(R.string.mmol) else MainApp.gs(R.string.mgdl)
+ val recordOnlyChecked = overview_insulin_record_only.isChecked
+ val eatingSoonChecked = overview_insulin_start_eating_soon_tt.isChecked
+
+ if (insulinAfterConstraints > 0) {
+ actions.add(MainApp.gs(R.string.bolus) + ": " + "" + DecimalFormatter.toPumpSupportedBolus(insulinAfterConstraints) + MainApp.gs(R.string.insulin_unit_shortname) + " ")
+ if (recordOnlyChecked)
+ actions.add("" + MainApp.gs(R.string.bolusrecordedonly) + " ")
+ if (abs(insulinAfterConstraints - insulin) > pumpDescription.pumpType.determineCorrectBolusStepSize(insulinAfterConstraints))
+ actions.add(MainApp.gs(R.string.bolusconstraintappliedwarning, MainApp.gc(R.color.warning), insulin, insulinAfterConstraints))
+ }
+ val eatingSoonTTDuration = DefaultValueHelper.determineEatingSoonTTDuration()
+ val eatingSoonTT = DefaultValueHelper.determineEatingSoonTT()
+ if (eatingSoonChecked)
+ actions.add(MainApp.gs(R.string.temptargetshort) + ": " + "" + DecimalFormatter.to1Decimal(eatingSoonTT) + " " + unitLabel + " (" + eatingSoonTTDuration + " " + MainApp.gs(R.string.unit_minute_short) + ") ")
+
+ val timeOffset = overview_insulin_time.value.toInt()
+ val time = DateUtil.now() + T.mins(timeOffset.toLong()).msecs()
+ if (timeOffset != 0)
+ actions.add(MainApp.gs(R.string.time) + ": " + DateUtil.dateAndTimeString(time))
+
+ val notes = notes.text.toString()
+ if (notes.isNotEmpty())
+ actions.add(MainApp.gs(R.string.careportal_newnstreatment_notes_label) + ": " + notes)
+
+ if (insulinAfterConstraints > 0 || eatingSoonChecked) {
+ activity?.let { activity ->
+ OKDialog.showConfirmation(activity, MainApp.gs(R.string.bolus), HtmlHelper.fromHtml(Joiner.on(" ").join(actions)), Runnable {
+ if (eatingSoonChecked) {
+ log.debug("USER ENTRY: TEMPTARGET EATING SOON $eatingSoonTT duration: $eatingSoonTTDuration")
+ val tempTarget = TempTarget()
+ .date(System.currentTimeMillis())
+ .duration(eatingSoonTTDuration)
+ .reason(MainApp.gs(R.string.eatingsoon))
+ .source(Source.USER)
+ .low(Profile.toMgdl(eatingSoonTT, ProfileFunctions.getSystemUnits()))
+ .high(Profile.toMgdl(eatingSoonTT, ProfileFunctions.getSystemUnits()))
+ TreatmentsPlugin.getPlugin().addToHistoryTempTarget(tempTarget)
+ }
+ if (insulinAfterConstraints > 0) {
+ val detailedBolusInfo = DetailedBolusInfo()
+ detailedBolusInfo.eventType = CareportalEvent.CORRECTIONBOLUS
+ detailedBolusInfo.insulin = insulinAfterConstraints
+ detailedBolusInfo.context = context
+ detailedBolusInfo.source = Source.USER
+ detailedBolusInfo.notes = notes
+ if (recordOnlyChecked) {
+ log.debug("USER ENTRY: BOLUS RECORD ONLY $insulinAfterConstraints")
+ detailedBolusInfo.date = time
+ TreatmentsPlugin.getPlugin().addToHistoryTreatment(detailedBolusInfo, false)
+ } else {
+ log.debug("USER ENTRY: BOLUS $insulinAfterConstraints")
+ detailedBolusInfo.date = DateUtil.now()
+ ConfigBuilderPlugin.getPlugin().commandQueue.bolus(detailedBolusInfo, object : Callback() {
+ override fun run() {
+ if (!result.success) {
+ val i = Intent(MainApp.instance(), ErrorHelperActivity::class.java)
+ i.putExtra("soundid", R.raw.boluserror)
+ i.putExtra("status", result.comment)
+ i.putExtra("title", MainApp.gs(R.string.treatmentdeliveryerror))
+ i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ MainApp.instance().startActivity(i)
+ }
+ }
+ })
+ }
+ }
+ })
+ }
+ } else
+ activity?.let { activity ->
+ OKDialog.show(activity, MainApp.gs(R.string.bolus), MainApp.gs(R.string.no_action_selected))
+ }
+ return true
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/dialogs/ProfileSwitchDialog.kt b/app/src/main/java/info/nightscout/androidaps/dialogs/ProfileSwitchDialog.kt
new file mode 100644
index 00000000000..f594564a781
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/dialogs/ProfileSwitchDialog.kt
@@ -0,0 +1,106 @@
+package info.nightscout.androidaps.dialogs
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.ArrayAdapter
+import com.google.common.base.Joiner
+import info.nightscout.androidaps.Constants
+import info.nightscout.androidaps.MainApp
+import info.nightscout.androidaps.R
+import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin
+import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions
+import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
+import info.nightscout.androidaps.utils.DateUtil
+import info.nightscout.androidaps.utils.HtmlHelper
+import info.nightscout.androidaps.utils.OKDialog
+import kotlinx.android.synthetic.main.dialog_profileswitch.*
+import kotlinx.android.synthetic.main.notes.*
+import kotlinx.android.synthetic.main.okcancel.*
+import java.text.DecimalFormat
+import java.util.*
+
+class ProfileSwitchDialog : DialogFragmentWithDate() {
+
+ override fun onSaveInstanceState(savedInstanceState: Bundle) {
+ super.onSaveInstanceState(savedInstanceState)
+ savedInstanceState.putDouble("overview_profileswitch_duration", overview_profileswitch_duration.value)
+ savedInstanceState.putDouble("overview_profileswitch_percentage", overview_profileswitch_percentage.value)
+ savedInstanceState.putDouble("overview_profileswitch_timeshift", overview_profileswitch_timeshift.value)
+ }
+
+ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
+ savedInstanceState: Bundle?): View? {
+ onCreateViewGeneral()
+ return inflater.inflate(R.layout.dialog_profileswitch, container, false)
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+
+ overview_profileswitch_duration.setParams(savedInstanceState?.getDouble("overview_profileswitch_duration")
+ ?: 0.0, 0.0, Constants.MAX_PROFILE_SWITCH_DURATION, 10.0, DecimalFormat("0"), false, ok)
+ overview_profileswitch_percentage.setParams(savedInstanceState?.getDouble("overview_profileswitch_percentage")
+ ?: 100.0, Constants.CPP_MIN_PERCENTAGE.toDouble(), Constants.CPP_MAX_PERCENTAGE.toDouble(), 1.0, DecimalFormat("0"), false, ok)
+ overview_profileswitch_timeshift.setParams(savedInstanceState?.getDouble("overview_profileswitch_timeshift")
+ ?: 0.0, Constants.CPP_MIN_TIMESHIFT.toDouble(), Constants.CPP_MAX_TIMESHIFT.toDouble(), 1.0, DecimalFormat("0"), false, ok)
+
+ // profile
+ context?.let { context ->
+ val profileStore = ConfigBuilderPlugin.getPlugin().activeProfileInterface?.profile
+ ?: return
+ val profileList = profileStore.getProfileList()
+ val adapter = ArrayAdapter(context, R.layout.spinner_centered, profileList)
+ overview_profileswitch_profile.adapter = adapter
+ // set selected to actual profile
+ for (p in profileList.indices)
+ if (profileList[p] == ProfileFunctions.getInstance().getProfileName(false))
+ overview_profileswitch_profile.setSelection(p)
+ } ?: return
+
+ TreatmentsPlugin.getPlugin().getProfileSwitchFromHistory(DateUtil.now())?.let { ps ->
+ if (ps.isCPP) {
+ overview_profileswitch_reuselayout.visibility = View.VISIBLE
+ overview_profileswitch_reusebutton.text = MainApp.gs(R.string.reuse) + " " + ps.percentage + "% " + ps.timeshift + "h"
+ overview_profileswitch_reusebutton.setOnClickListener {
+ overview_profileswitch_percentage.value = ps.percentage.toDouble()
+ overview_profileswitch_timeshift.value = ps.timeshift.toDouble()
+ }
+ } else {
+ overview_profileswitch_reuselayout.visibility = View.GONE
+ }
+ }
+ }
+
+ override fun submit(): Boolean {
+ val profileStore = ConfigBuilderPlugin.getPlugin().activeProfileInterface?.profile
+ ?: return false
+
+ val actions: LinkedList = LinkedList()
+ val duration = overview_profileswitch_duration.value
+ if (duration > 0)
+ actions.add(MainApp.gs(R.string.duration) + ": " + MainApp.gs(R.string.format_hours, duration))
+ val profile = overview_profileswitch_profile.selectedItem.toString()
+ actions.add(MainApp.gs(R.string.profile) + ": " + profile)
+ val percent = overview_profileswitch_percentage.value.toInt()
+ if (percent != 100)
+ actions.add(MainApp.gs(R.string.percent) + ": " + percent + "%")
+ val timeShift = overview_profileswitch_timeshift.value.toInt()
+ if (timeShift != 0)
+ actions.add(MainApp.gs(R.string.careportal_newnstreatment_timeshift_label) + ": " + MainApp.gs(R.string.format_hours, timeShift.toDouble()))
+ val notes = notes.text.toString()
+ if (notes.isNotEmpty())
+ actions.add(MainApp.gs(R.string.careportal_newnstreatment_notes_label) + ": " + notes)
+ if (eventTimeChanged)
+ actions.add(MainApp.gs(R.string.time) + ": " + DateUtil.dateAndTimeString(eventTime))
+
+ activity?.let { activity ->
+ OKDialog.showConfirmation(activity, MainApp.gs(R.string.careportal_profileswitch), HtmlHelper.fromHtml(Joiner.on(" ").join(actions)), Runnable {
+ log.debug("USER ENTRY: PROFILE SWITCH $profile percent: $percent timeshift: $timeShift duration: $duration")
+ ProfileFunctions.doProfileSwitch(profileStore, profile, duration.toInt(), percent, timeShift, eventTime)
+ })
+ }
+ return true
+ }
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/dialogs/ProfileViewerDialog.kt b/app/src/main/java/info/nightscout/androidaps/dialogs/ProfileViewerDialog.kt
new file mode 100644
index 00000000000..ef3b19d4d82
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/dialogs/ProfileViewerDialog.kt
@@ -0,0 +1,108 @@
+package info.nightscout.androidaps.dialogs
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.view.Window
+import android.view.WindowManager
+import androidx.fragment.app.DialogFragment
+import info.nightscout.androidaps.Constants
+import info.nightscout.androidaps.MainApp
+import info.nightscout.androidaps.R
+import info.nightscout.androidaps.data.Profile
+import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
+import info.nightscout.androidaps.utils.DateUtil
+import kotlinx.android.synthetic.main.close.*
+import kotlinx.android.synthetic.main.dialog_profileviewer.*
+import org.json.JSONObject
+
+class ProfileViewerDialog : DialogFragment() {
+ private var time: Long = 0
+
+ enum class Mode(val i: Int) {
+ RUNNING_PROFILE(1),
+ CUSTOM_PROFILE(2)
+ }
+
+ private var mode: Mode = Mode.RUNNING_PROFILE
+ private var customProfileJson: String = ""
+ private var customProfileName: String = ""
+ private var customProfileUnits: String = Constants.MGDL
+
+ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
+ savedInstanceState: Bundle?): View? {
+ // load data from bundle
+ (savedInstanceState ?: arguments)?.let { bundle ->
+ time = bundle.getLong("time", 0)
+ mode = Mode.values()[bundle.getInt("mode", Mode.RUNNING_PROFILE.ordinal)]
+ customProfileJson = bundle.getString("customProfile", "")
+ customProfileUnits = bundle.getString("customProfileUnits", Constants.MGDL)
+ customProfileName = bundle.getString("customProfileName", "")
+ }
+
+ dialog?.window?.requestFeature(Window.FEATURE_NO_TITLE)
+ dialog?.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN)
+ isCancelable = true
+ dialog?.setCanceledOnTouchOutside(false)
+
+ return inflater.inflate(R.layout.dialog_profileviewer, container, false)
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+
+ close.setOnClickListener { dismiss() }
+
+ val profile: Profile?
+ val profileName: String?
+ val date: String?
+ when (mode) {
+ Mode.RUNNING_PROFILE -> {
+ profile = TreatmentsPlugin.getPlugin().getProfileSwitchFromHistory(time)?.profileObject
+ profileName = TreatmentsPlugin.getPlugin().getProfileSwitchFromHistory(time)?.customizedName
+ date = DateUtil.dateAndTimeString(TreatmentsPlugin.getPlugin().getProfileSwitchFromHistory(time)?.date
+ ?: 0)
+ profileview_datelayout.visibility = View.VISIBLE
+ }
+
+ Mode.CUSTOM_PROFILE -> {
+ profile = Profile(JSONObject(customProfileJson), customProfileUnits)
+ profileName = customProfileName
+ date = ""
+ profileview_datelayout.visibility = View.GONE
+ }
+ }
+ profileview_noprofile.visibility = View.VISIBLE
+
+ profile?.let {
+ profileview_units.text = it.units
+ profileview_dia.text = MainApp.gs(R.string.format_hours, it.dia)
+ profileview_activeprofile.text = profileName
+ profileview_date.text = date
+ profileview_ic.text = it.icList
+ profileview_isf.text = it.isfList
+ profileview_basal.text = it.basalList
+ profileview_target.text = it.targetList
+ basal_graph.show(it)
+
+ profileview_noprofile.visibility = View.GONE
+ profileview_invalidprofile.visibility = if (it.isValid("ProfileViewDialog")) View.GONE else View.VISIBLE
+ }
+ }
+
+ override fun onStart() {
+ super.onStart()
+ dialog?.window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)
+ }
+
+ override fun onSaveInstanceState(bundle: Bundle) {
+ super.onSaveInstanceState(bundle)
+ bundle.putLong("time", time)
+ bundle.putInt("mode", mode.ordinal)
+ bundle.putString("customProfile", customProfileJson)
+ bundle.putString("customProfileName", customProfileName)
+ bundle.putString("customProfileUnits", customProfileUnits)
+ }
+
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/dialogs/TempBasalDialog.kt b/app/src/main/java/info/nightscout/androidaps/dialogs/TempBasalDialog.kt
new file mode 100644
index 00000000000..d821aec56b4
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/dialogs/TempBasalDialog.kt
@@ -0,0 +1,117 @@
+package info.nightscout.androidaps.dialogs
+
+import android.content.Intent
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import com.google.common.base.Joiner
+import info.nightscout.androidaps.MainApp
+import info.nightscout.androidaps.R
+import info.nightscout.androidaps.activities.ErrorHelperActivity
+import info.nightscout.androidaps.interfaces.Constraint
+import info.nightscout.androidaps.interfaces.PumpDescription
+import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin
+import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions
+import info.nightscout.androidaps.queue.Callback
+import info.nightscout.androidaps.utils.HtmlHelper
+import info.nightscout.androidaps.utils.OKDialog
+import info.nightscout.androidaps.utils.SafeParse
+import kotlinx.android.synthetic.main.dialog_tempbasal.*
+import kotlinx.android.synthetic.main.okcancel.*
+import java.text.DecimalFormat
+import java.util.*
+import kotlin.math.abs
+
+class TempBasalDialog : DialogFragmentWithDate() {
+ private var isPercentPump = true
+
+ override fun onSaveInstanceState(savedInstanceState: Bundle) {
+ super.onSaveInstanceState(savedInstanceState)
+ savedInstanceState.putDouble("actions_tempbasal_duration", actions_tempbasal_duration.value)
+ savedInstanceState.putDouble("actions_tempbasal_basalpercentinput", actions_tempbasal_basalpercentinput.value)
+ savedInstanceState.putDouble("actions_tempbasal_basalabsoluteinput", actions_tempbasal_basalabsoluteinput.value)
+ }
+
+ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
+ savedInstanceState: Bundle?): View? {
+ onCreateViewGeneral()
+ return inflater.inflate(R.layout.dialog_tempbasal, container, false)
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+
+ val pumpDescription = ConfigBuilderPlugin.getPlugin().activePump?.pumpDescription ?: return
+ val profile = ProfileFunctions.getInstance().profile ?: return
+
+ val maxTempPercent = pumpDescription.maxTempPercent.toDouble()
+ val tempPercentStep = pumpDescription.tempPercentStep.toDouble()
+
+ actions_tempbasal_basalpercentinput.setParams(savedInstanceState?.getDouble("actions_tempbasal_basalpercentinput")
+ ?: 100.0, 0.0, maxTempPercent, tempPercentStep, DecimalFormat("0"), true, ok)
+
+ actions_tempbasal_basalabsoluteinput.setParams(savedInstanceState?.getDouble("actions_tempbasal_basalabsoluteinput")
+ ?: profile.basal, 0.0, pumpDescription.maxTempAbsolute, pumpDescription.tempAbsoluteStep, DecimalFormat("0.00"), true, ok)
+
+ val tempDurationStep = pumpDescription.tempDurationStep.toDouble()
+ val tempMaxDuration = pumpDescription.tempMaxDuration.toDouble()
+ actions_tempbasal_duration.setParams(savedInstanceState?.getDouble("actions_tempbasal_duration")
+ ?: tempDurationStep, tempDurationStep, tempMaxDuration, tempDurationStep, DecimalFormat("0"), false, ok)
+
+ isPercentPump = pumpDescription.tempBasalStyle and PumpDescription.PERCENT == PumpDescription.PERCENT
+ if (isPercentPump) {
+ actions_tempbasal_percent_layout.visibility = View.VISIBLE
+ actions_tempbasal_absolute_layout.visibility = View.GONE
+ } else {
+ actions_tempbasal_percent_layout.visibility = View.GONE
+ actions_tempbasal_absolute_layout.visibility = View.VISIBLE
+ }
+ }
+
+ override fun submit(): Boolean {
+ var percent = 0
+ var absolute = 0.0
+ val durationInMinutes = SafeParse.stringToInt(actions_tempbasal_duration.text)
+ val profile = ProfileFunctions.getInstance().profile ?: return false
+ val actions: LinkedList = LinkedList()
+ if (isPercentPump) {
+ val basalPercentInput = SafeParse.stringToInt(actions_tempbasal_basalpercentinput.text)
+ percent = MainApp.getConstraintChecker().applyBasalPercentConstraints(Constraint(basalPercentInput), profile).value()
+ actions.add(MainApp.gs(R.string.pump_tempbasal_label)+ ": $percent%")
+ actions.add(MainApp.gs(R.string.duration) + ": " + MainApp.gs(R.string.format_mins, durationInMinutes))
+ if (percent != basalPercentInput) actions.add(MainApp.gs(R.string.constraintapllied))
+ } else {
+ val basalAbsoluteInput = SafeParse.stringToDouble(actions_tempbasal_basalabsoluteinput.text)
+ absolute = MainApp.getConstraintChecker().applyBasalConstraints(Constraint(basalAbsoluteInput), profile).value()
+ actions.add(MainApp.gs(R.string.pump_tempbasal_label)+ ": " + MainApp.gs(R.string.pump_basebasalrate, absolute))
+ actions.add(MainApp.gs(R.string.duration) + ": " + MainApp.gs(R.string.format_mins, durationInMinutes))
+ if (abs(absolute - basalAbsoluteInput) > 0.01)
+ actions.add("" + MainApp.gs(R.string.constraintapllied) + " ")
+ }
+ activity?.let { activity ->
+ OKDialog.showConfirmation(activity, MainApp.gs(R.string.pump_tempbasal_label), HtmlHelper.fromHtml(Joiner.on(" ").join(actions)), Runnable {
+ val callback: Callback = object : Callback() {
+ override fun run() {
+ if (!result.success) {
+ val i = Intent(MainApp.instance(), ErrorHelperActivity::class.java)
+ i.putExtra("soundid", R.raw.boluserror)
+ i.putExtra("status", result.comment)
+ i.putExtra("title", MainApp.gs(R.string.tempbasaldeliveryerror))
+ i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ MainApp.instance().startActivity(i)
+ }
+ }
+ }
+ if (isPercentPump) {
+ log.debug("USER ENTRY: TEMP BASAL $percent% duration: $durationInMinutes")
+ ConfigBuilderPlugin.getPlugin().commandQueue.tempBasalPercent(percent, durationInMinutes, true, profile, callback)
+ } else {
+ log.debug("USER ENTRY: TEMP BASAL $absolute duration: $durationInMinutes")
+ ConfigBuilderPlugin.getPlugin().commandQueue.tempBasalAbsolute(absolute, durationInMinutes, true, profile, callback)
+ }
+ })
+ }
+ return true
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/dialogs/TempTargetDialog.kt b/app/src/main/java/info/nightscout/androidaps/dialogs/TempTargetDialog.kt
new file mode 100644
index 00000000000..5b1dd486921
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/dialogs/TempTargetDialog.kt
@@ -0,0 +1,153 @@
+package info.nightscout.androidaps.dialogs
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.AdapterView
+import android.widget.ArrayAdapter
+import com.google.common.base.Joiner
+import com.google.common.collect.Lists
+import info.nightscout.androidaps.Constants
+import info.nightscout.androidaps.MainApp
+import info.nightscout.androidaps.R
+import info.nightscout.androidaps.data.Profile
+import info.nightscout.androidaps.db.Source
+import info.nightscout.androidaps.db.TempTarget
+import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions
+import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
+import info.nightscout.androidaps.utils.DateUtil
+import info.nightscout.androidaps.utils.DefaultValueHelper
+import info.nightscout.androidaps.utils.HtmlHelper
+import info.nightscout.androidaps.utils.OKDialog
+import info.nightscout.androidaps.utils.SP
+import kotlinx.android.synthetic.main.dialog_temptarget.*
+import kotlinx.android.synthetic.main.okcancel.*
+import java.text.DecimalFormat
+import java.util.*
+
+class TempTargetDialog : DialogFragmentWithDate() {
+
+ override fun onSaveInstanceState(savedInstanceState: Bundle) {
+ super.onSaveInstanceState(savedInstanceState)
+ savedInstanceState.putDouble("overview_temptarget_duration", overview_temptarget_duration.value)
+ savedInstanceState.putDouble("overview_temptarget_temptarget", overview_temptarget_temptarget.value)
+ }
+
+ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
+ savedInstanceState: Bundle?): View? {
+ onCreateViewGeneral()
+ return inflater.inflate(R.layout.dialog_temptarget, container, false)
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+
+ overview_temptarget_duration.setParams(savedInstanceState?.getDouble("overview_temptarget_duration")
+ ?: 0.0, 0.0, Constants.MAX_PROFILE_SWITCH_DURATION, 10.0, DecimalFormat("0"), false, ok)
+
+ if (ProfileFunctions.getSystemUnits() == Constants.MMOL)
+ overview_temptarget_temptarget.setParams(
+ savedInstanceState?.getDouble("overview_temptarget_temptarget")
+ ?: Constants.MIN_TT_MMOL,
+ Constants.MIN_TT_MMOL, Constants.MAX_TT_MMOL, 0.1, DecimalFormat("0.0"), false, ok)
+ else
+ overview_temptarget_temptarget.setParams(
+ savedInstanceState?.getDouble("overview_temptarget_temptarget")
+ ?: Constants.MIN_TT_MGDL,
+ Constants.MIN_TT_MGDL, Constants.MAX_TT_MGDL, 1.0, DecimalFormat("0"), false, ok)
+
+ val units = ProfileFunctions.getSystemUnits()
+ overview_temptarget_units.text = if (units == Constants.MMOL) MainApp.gs(R.string.mmol) else MainApp.gs(R.string.mgdl)
+ // temp target
+ context?.let { context ->
+ val reasonList: List = Lists.newArrayList(
+ MainApp.gs(R.string.manual),
+ MainApp.gs(R.string.cancel),
+ MainApp.gs(R.string.eatingsoon),
+ MainApp.gs(R.string.activity),
+ MainApp.gs(R.string.hypo)
+ )
+ val adapterReason = ArrayAdapter(context, R.layout.spinner_centered, reasonList)
+ overview_temptarget_reason.adapter = adapterReason
+ overview_temptarget_reason.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
+ override fun onItemSelected(parent: AdapterView<*>?, view: View, position: Int, id: Long) {
+ val defaultDuration: Double
+ val defaultTarget: Double
+ when (reasonList[position]) {
+ MainApp.gs(R.string.eatingsoon) -> {
+ defaultDuration = DefaultValueHelper.determineEatingSoonTTDuration().toDouble()
+ defaultTarget = DefaultValueHelper.determineEatingSoonTT()
+ }
+
+ MainApp.gs(R.string.activity) -> {
+ defaultDuration = DefaultValueHelper.determineActivityTTDuration().toDouble()
+ defaultTarget = DefaultValueHelper.determineActivityTT()
+ }
+
+ MainApp.gs(R.string.hypo) -> {
+ defaultDuration = DefaultValueHelper.determineHypoTTDuration().toDouble()
+ defaultTarget = DefaultValueHelper.determineHypoTT()
+ }
+
+ MainApp.gs(R.string.cancel) -> {
+ defaultDuration = 0.0
+ defaultTarget = 0.0
+ }
+
+ else -> {
+ defaultDuration = overview_temptarget_duration.value
+ defaultTarget = overview_temptarget_temptarget.value
+ }
+ }
+ overview_temptarget_temptarget.value = defaultTarget
+ overview_temptarget_duration.value = defaultDuration
+ }
+
+ override fun onNothingSelected(parent: AdapterView<*>?) {}
+ }
+ }
+ }
+
+ override fun submit(): Boolean {
+ val actions: LinkedList = LinkedList()
+ val reason = overview_temptarget_reason.selectedItem.toString()
+ val unitResId = if (ProfileFunctions.getSystemUnits() == Constants.MGDL) R.string.mgdl else R.string.mmol
+ val target = overview_temptarget_temptarget.value
+ val duration = overview_temptarget_duration.value.toInt()
+ if (target != 0.0 && duration != 0) {
+ actions.add(MainApp.gs(R.string.reason) + ": " + reason)
+ actions.add(MainApp.gs(R.string.nsprofileview_target_label) + ": " + Profile.toCurrentUnitsString(target) + " " + MainApp.gs(unitResId))
+ actions.add(MainApp.gs(R.string.duration) + ": " + MainApp.gs(R.string.format_mins, duration))
+ } else {
+ actions.add(MainApp.gs(R.string.stoptemptarget))
+ }
+ if (eventTimeChanged)
+ actions.add(MainApp.gs(R.string.time) + ": " + DateUtil.dateAndTimeString(eventTime))
+
+ activity?.let { activity ->
+ OKDialog.showConfirmation(activity, MainApp.gs(R.string.careportal_temporarytarget), HtmlHelper.fromHtml(Joiner.on(" ").join(actions)), Runnable {
+ log.debug("USER ENTRY: TEMP TARGET $target duration: $duration")
+ if (target == 0.0 || duration == 0) {
+ val tempTarget = TempTarget()
+ .date(eventTime)
+ .duration(0)
+ .low(0.0).high(0.0)
+ .source(Source.USER)
+ TreatmentsPlugin.getPlugin().addToHistoryTempTarget(tempTarget)
+ } else {
+ val tempTarget = TempTarget()
+ .date(eventTime)
+ .duration(duration.toInt())
+ .reason(reason)
+ .source(Source.USER)
+ .low(Profile.toMgdl(target, ProfileFunctions.getSystemUnits()))
+ .high(Profile.toMgdl(target, ProfileFunctions.getSystemUnits()))
+ TreatmentsPlugin.getPlugin().addToHistoryTempTarget(tempTarget)
+ }
+ if (duration == 10) SP.putBoolean(R.string.key_objectiveusetemptarget, true)
+ })
+ }
+ return true
+ }
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/dialogs/TreatmentDialog.kt b/app/src/main/java/info/nightscout/androidaps/dialogs/TreatmentDialog.kt
new file mode 100644
index 00000000000..565a65f54f2
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/dialogs/TreatmentDialog.kt
@@ -0,0 +1,133 @@
+package info.nightscout.androidaps.dialogs
+
+import android.content.Intent
+import android.os.Bundle
+import android.text.Editable
+import android.text.TextWatcher
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import com.google.common.base.Joiner
+import info.nightscout.androidaps.MainApp
+import info.nightscout.androidaps.R
+import info.nightscout.androidaps.activities.ErrorHelperActivity
+import info.nightscout.androidaps.data.DetailedBolusInfo
+import info.nightscout.androidaps.db.CareportalEvent
+import info.nightscout.androidaps.db.Source
+import info.nightscout.androidaps.interfaces.Constraint
+import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin
+import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
+import info.nightscout.androidaps.queue.Callback
+import info.nightscout.androidaps.utils.DecimalFormatter
+import info.nightscout.androidaps.utils.HtmlHelper
+import info.nightscout.androidaps.utils.OKDialog
+import info.nightscout.androidaps.utils.SafeParse
+import info.nightscout.androidaps.utils.ToastUtils
+import kotlinx.android.synthetic.main.dialog_treatment.*
+import kotlinx.android.synthetic.main.okcancel.*
+import java.text.DecimalFormat
+import java.util.*
+import kotlin.math.abs
+
+class TreatmentDialog : DialogFragmentWithDate() {
+ private var maxCarbs = MainApp.getConstraintChecker().maxCarbsAllowed.value().toDouble()
+ private var maxInsulin = MainApp.getConstraintChecker().maxBolusAllowed.value()
+
+ private val textWatcher: TextWatcher = object : TextWatcher {
+ override fun afterTextChanged(s: Editable) {}
+ override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
+ override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
+ validateInputs()
+ }
+ }
+
+ private fun validateInputs() {
+ if (SafeParse.stringToInt(overview_treatment_carbs.text) > maxCarbs) {
+ overview_treatment_carbs.value = 0.0
+ ToastUtils.showToastInUiThread(MainApp.instance().applicationContext, MainApp.gs(R.string.carbsconstraintapplied))
+ }
+ if (SafeParse.stringToDouble(overview_treatment_insulin.text) > maxInsulin) {
+ overview_treatment_insulin.value = 0.0
+ ToastUtils.showToastInUiThread(MainApp.instance().applicationContext, MainApp.gs(R.string.bolusconstraintapplied))
+ }
+ }
+
+ override fun onSaveInstanceState(savedInstanceState: Bundle) {
+ super.onSaveInstanceState(savedInstanceState)
+ savedInstanceState.putDouble("overview_treatment_carbs", overview_treatment_carbs.value)
+ savedInstanceState.putDouble("overview_treatment_insulin", overview_treatment_insulin.value)
+ }
+
+ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
+ savedInstanceState: Bundle?): View? {
+ onCreateViewGeneral()
+ return inflater.inflate(R.layout.dialog_treatment, container, false)
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+
+ val pumpDescription = ConfigBuilderPlugin.getPlugin().activePump?.pumpDescription ?: return
+ overview_treatment_carbs.setParams(savedInstanceState?.getDouble("overview_treatment_carbs")
+ ?: 0.0, 0.0, maxCarbs, 1.0, DecimalFormat("0"), false, ok, textWatcher)
+ overview_treatment_insulin.setParams(savedInstanceState?.getDouble("overview_treatment_insulin")
+ ?: 0.0, 0.0, maxInsulin, pumpDescription.bolusStep, DecimalFormatter.pumpSupportedBolusFormat(), false, ok, textWatcher)
+ }
+
+ override fun submit(): Boolean {
+ val pumpDescription = ConfigBuilderPlugin.getPlugin().activePump?.pumpDescription
+ ?: return false
+ val insulin = SafeParse.stringToDouble(overview_treatment_insulin.text)
+ val carbs = SafeParse.stringToInt(overview_treatment_carbs.text)
+ val recordOnlyChecked = overview_treatment_record_only.isChecked
+ val actions: LinkedList = LinkedList()
+ val insulinAfterConstraints = MainApp.getConstraintChecker().applyBolusConstraints(Constraint(insulin)).value()
+ val carbsAfterConstraints = MainApp.getConstraintChecker().applyCarbsConstraints(Constraint(carbs)).value()
+
+ if (insulinAfterConstraints > 0) {
+ actions.add(MainApp.gs(R.string.bolus) + ": " + "" + DecimalFormatter.toPumpSupportedBolus(insulinAfterConstraints) + MainApp.gs(R.string.insulin_unit_shortname) + " ")
+ if (recordOnlyChecked)
+ actions.add("" + MainApp.gs(R.string.bolusrecordedonly) + " ")
+ if (abs(insulinAfterConstraints - insulin) > pumpDescription.pumpType.determineCorrectBolusStepSize(insulinAfterConstraints))
+ actions.add(MainApp.gs(R.string.bolusconstraintappliedwarning, MainApp.gc(R.color.warning), insulin, insulinAfterConstraints))
+ }
+ if (carbsAfterConstraints > 0) {
+ actions.add(MainApp.gs(R.string.carbs) + ": " + "" + MainApp.gs(R.string.format_carbs, carbsAfterConstraints) + " ")
+ if (carbsAfterConstraints != carbs)
+ actions.add("" + MainApp.gs(R.string.carbsconstraintapplied) + " ")
+ }
+ if (insulinAfterConstraints > 0 || carbsAfterConstraints > 0) {
+ activity?.let { activity ->
+ OKDialog.showConfirmation(activity, MainApp.gs(R.string.overview_treatment_label), HtmlHelper.fromHtml(Joiner.on(" ").join(actions)), Runnable {
+ log.debug("USER ENTRY: BOLUS insulin $insulin carbs: $carbs")
+ val detailedBolusInfo = DetailedBolusInfo()
+ if (insulinAfterConstraints == 0.0) detailedBolusInfo.eventType = CareportalEvent.CARBCORRECTION
+ if (carbsAfterConstraints == 0) detailedBolusInfo.eventType = CareportalEvent.CORRECTIONBOLUS
+ detailedBolusInfo.insulin = insulinAfterConstraints
+ detailedBolusInfo.carbs = carbsAfterConstraints.toDouble()
+ detailedBolusInfo.context = context
+ detailedBolusInfo.source = Source.USER
+ if (!(recordOnlyChecked && (detailedBolusInfo.insulin > 0 || pumpDescription.storesCarbInfo))) {
+ ConfigBuilderPlugin.getPlugin().commandQueue.bolus(detailedBolusInfo, object : Callback() {
+ override fun run() {
+ if (!result.success) {
+ val i = Intent(MainApp.instance(), ErrorHelperActivity::class.java)
+ i.putExtra("soundid", R.raw.boluserror)
+ i.putExtra("status", result.comment)
+ i.putExtra("title", MainApp.gs(R.string.treatmentdeliveryerror))
+ i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ MainApp.instance().startActivity(i)
+ }
+ }
+ })
+ } else
+ TreatmentsPlugin.getPlugin().addToHistoryTreatment(detailedBolusInfo, false)
+ })
+ }
+ } else
+ activity?.let { activity ->
+ OKDialog.show(activity, MainApp.gs(R.string.overview_treatment_label), MainApp.gs(R.string.no_action_selected))
+ }
+ return true
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/dialogs/WizardDialog.kt b/app/src/main/java/info/nightscout/androidaps/dialogs/WizardDialog.kt
new file mode 100644
index 00000000000..c84bd4a0b67
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/dialogs/WizardDialog.kt
@@ -0,0 +1,340 @@
+package info.nightscout.androidaps.dialogs
+
+import android.os.Bundle
+import android.text.Editable
+import android.text.TextWatcher
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.view.Window
+import android.view.WindowManager
+import android.widget.AdapterView
+import android.widget.AdapterView.OnItemSelectedListener
+import android.widget.ArrayAdapter
+import android.widget.CompoundButton
+import androidx.fragment.app.DialogFragment
+import info.nightscout.androidaps.Constants
+import info.nightscout.androidaps.MainApp
+import info.nightscout.androidaps.R
+import info.nightscout.androidaps.data.Profile
+import info.nightscout.androidaps.db.BgReading
+import info.nightscout.androidaps.db.DatabaseHelper
+import info.nightscout.androidaps.interfaces.Constraint
+import info.nightscout.androidaps.plugins.bus.RxBus
+import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin
+import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions
+import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
+import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventAutosensCalculationFinished
+import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
+import info.nightscout.androidaps.utils.*
+import io.reactivex.android.schedulers.AndroidSchedulers
+import io.reactivex.disposables.CompositeDisposable
+import kotlinx.android.synthetic.main.dialog_wizard.*
+import org.slf4j.LoggerFactory
+import java.text.DecimalFormat
+import java.util.*
+import kotlin.math.abs
+
+class WizardDialog : DialogFragment() {
+ private val log = LoggerFactory.getLogger(WizardDialog::class.java)
+
+ private var wizard: BolusWizard? = null
+
+ //one shot guards
+ private var okClicked: Boolean = false
+
+ private val textWatcher = object : TextWatcher {
+ override fun afterTextChanged(s: Editable) {}
+ override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
+ override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
+ calculateInsulin()
+ }
+ }
+
+ private var disposable: CompositeDisposable = CompositeDisposable()
+
+ override fun onStart() {
+ super.onStart()
+ dialog?.window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
+ }
+
+ override fun onSaveInstanceState(savedInstanceState: Bundle) {
+ super.onSaveInstanceState(savedInstanceState)
+ savedInstanceState.putDouble("treatments_wizard_bg_input", treatments_wizard_bg_input.value)
+ savedInstanceState.putDouble("treatments_wizard_carbs_input", treatments_wizard_carbs_input.value)
+ savedInstanceState.putDouble("treatments_wizard_correction_input", treatments_wizard_correction_input.value)
+ savedInstanceState.putDouble("treatments_wizard_carb_time_input", treatments_wizard_carb_time_input.value)
+ }
+
+ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
+ savedInstanceState: Bundle?): View? {
+ dialog?.window?.requestFeature(Window.FEATURE_NO_TITLE)
+ dialog?.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN)
+ isCancelable = true
+ dialog?.setCanceledOnTouchOutside(false)
+
+ return inflater.inflate(R.layout.dialog_wizard, container, false)
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ loadCheckedStates()
+ processCobCheckBox()
+ treatments_wizard_sbcheckbox.visibility = SP.getBoolean(R.string.key_usesuperbolus, false).toVisibility()
+ treatments_wizard_notes_layout.visibility = SP.getBoolean(R.string.key_show_notes_entry_dialogs, false).toVisibility()
+
+ val maxCarbs = MainApp.getConstraintChecker().maxCarbsAllowed.value()
+ val maxCorrection = MainApp.getConstraintChecker().maxBolusAllowed.value()
+
+ treatments_wizard_bg_input.setParams(savedInstanceState?.getDouble("treatments_wizard_bg_input")
+ ?: 0.0, 0.0, 500.0, 0.1, DecimalFormat("0.0"), false, ok, textWatcher)
+ treatments_wizard_carbs_input.setParams(savedInstanceState?.getDouble("treatments_wizard_carbs_input")
+ ?: 0.0, 0.0, maxCarbs.toDouble(), 1.0, DecimalFormat("0"), false, ok, textWatcher)
+ val bolusStep = ConfigBuilderPlugin.getPlugin().activePump?.pumpDescription?.bolusStep
+ ?: 0.1
+ treatments_wizard_correction_input.setParams(savedInstanceState?.getDouble("treatments_wizard_correction_input")
+ ?: 0.0, -maxCorrection, maxCorrection, bolusStep, DecimalFormatter.pumpSupportedBolusFormat(), false, ok, textWatcher)
+ treatments_wizard_carb_time_input.setParams(savedInstanceState?.getDouble("treatments_wizard_carb_time_input")
+ ?: 0.0, -60.0, 60.0, 5.0, DecimalFormat("0"), false, ok, textWatcher)
+ initDialog()
+
+ treatments_wizard_percent_used.text = MainApp.gs(R.string.format_percent, SP.getInt(R.string.key_boluswizard_percentage, 100))
+ // ok button
+ ok.setOnClickListener {
+ if (okClicked) {
+ log.debug("guarding: ok already clicked")
+ } else {
+ okClicked = true
+ calculateInsulin()
+ context?.let { context ->
+ wizard?.confirmAndExecute(context)
+ }
+ }
+ dismiss()
+ }
+ // cancel button
+ cancel.setOnClickListener { dismiss() }
+ // checkboxes
+ treatments_wizard_bgcheckbox.setOnCheckedChangeListener(::onCheckedChanged)
+ treatments_wizard_ttcheckbox.setOnCheckedChangeListener(::onCheckedChanged)
+ treatments_wizard_cobcheckbox.setOnCheckedChangeListener(::onCheckedChanged)
+ treatments_wizard_basaliobcheckbox.setOnCheckedChangeListener(::onCheckedChanged)
+ treatments_wizard_bolusiobcheckbox.setOnCheckedChangeListener(::onCheckedChanged)
+ treatments_wizard_bgtrendcheckbox.setOnCheckedChangeListener(::onCheckedChanged)
+ treatments_wizard_sbcheckbox.setOnCheckedChangeListener(::onCheckedChanged)
+
+ val showCalc = SP.getBoolean(MainApp.gs(R.string.key_wizard_calculation_visible), false)
+ treatments_wizard_delimiter.visibility = showCalc.toVisibility()
+ treatments_wizard_resulttable.visibility = showCalc.toVisibility()
+ treatments_wizard_calculationcheckbox.isChecked = showCalc
+ treatments_wizard_calculationcheckbox.setOnCheckedChangeListener { _, isChecked ->
+ run {
+ SP.putBoolean(MainApp.gs(R.string.key_wizard_calculation_visible), isChecked)
+ treatments_wizard_delimiter.visibility = isChecked.toVisibility()
+ treatments_wizard_resulttable.visibility = isChecked.toVisibility()
+ }
+ }
+ // profile spinner
+ treatments_wizard_profile.onItemSelectedListener = object : OnItemSelectedListener {
+ override fun onNothingSelected(parent: AdapterView<*>?) {
+ ToastUtils.showToastInUiThread(MainApp.instance().applicationContext, MainApp.gs(R.string.noprofileselected))
+ ok.visibility = View.GONE
+ }
+
+ override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
+ calculateInsulin()
+ ok.visibility = View.VISIBLE
+ }
+ }
+ // bus
+ disposable.add(RxBus
+ .toObservable(EventAutosensCalculationFinished::class.java)
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe({
+ activity?.runOnUiThread { calculateInsulin() }
+ }, {
+ FabricPrivacy.logException(it)
+ })
+ )
+
+ }
+
+ override fun onDestroyView() {
+ super.onDestroyView()
+ disposable.clear()
+ }
+
+ private fun onCheckedChanged(buttonView: CompoundButton, @Suppress("UNUSED_PARAMETER") state: Boolean) {
+ saveCheckedStates()
+ treatments_wizard_ttcheckbox.isEnabled = treatments_wizard_bgcheckbox.isChecked && TreatmentsPlugin.getPlugin().tempTargetFromHistory != null
+ if (buttonView.id == treatments_wizard_cobcheckbox.id)
+ processCobCheckBox()
+ calculateInsulin()
+ }
+
+ private fun processCobCheckBox() {
+ if (treatments_wizard_cobcheckbox.isChecked) {
+ treatments_wizard_bolusiobcheckbox.isEnabled = false
+ treatments_wizard_basaliobcheckbox.isEnabled = false
+ treatments_wizard_bolusiobcheckbox.isChecked = true
+ treatments_wizard_basaliobcheckbox.isChecked = true
+ } else {
+ treatments_wizard_bolusiobcheckbox.isEnabled = true
+ treatments_wizard_basaliobcheckbox.isEnabled = true
+ }
+ }
+
+ private fun saveCheckedStates() {
+ SP.putBoolean(MainApp.gs(R.string.key_wizard_include_cob), treatments_wizard_cobcheckbox.isChecked)
+ SP.putBoolean(MainApp.gs(R.string.key_wizard_include_trend_bg), treatments_wizard_bgtrendcheckbox.isChecked)
+ }
+
+ private fun loadCheckedStates() {
+ treatments_wizard_bgtrendcheckbox.isChecked = SP.getBoolean(MainApp.gs(R.string.key_wizard_include_trend_bg), false)
+ treatments_wizard_cobcheckbox.isChecked = SP.getBoolean(MainApp.gs(R.string.key_wizard_include_cob), false)
+ }
+
+ private fun initDialog() {
+ val profile = ProfileFunctions.getInstance().profile
+ val profileStore = ConfigBuilderPlugin.getPlugin().activeProfileInterface?.profile
+
+ if (profile == null || profileStore == null) {
+ ToastUtils.showToastInUiThread(MainApp.instance().applicationContext, MainApp.gs(R.string.noprofile))
+ dismiss()
+ return
+ }
+
+ val profileList: ArrayList
+ profileList = profileStore.getProfileList()
+ profileList.add(0, MainApp.gs(R.string.active))
+ context?.let { context ->
+ val adapter = ArrayAdapter(context, R.layout.spinner_centered, profileList)
+ treatments_wizard_profile.adapter = adapter
+ } ?: return
+
+ val units = ProfileFunctions.getSystemUnits()
+ treatments_wizard_bgunits.text = units
+ if (units == Constants.MGDL)
+ treatments_wizard_bg_input.setStep(1.0)
+ else
+ treatments_wizard_bg_input.setStep(0.1)
+
+ // Set BG if not old
+ val lastBg = DatabaseHelper.actualBg()
+
+ if (lastBg != null) {
+ treatments_wizard_bg_input.value = lastBg.valueToUnits(units)
+ } else {
+ treatments_wizard_bg_input.value = 0.0
+ }
+ treatments_wizard_ttcheckbox.isEnabled = TreatmentsPlugin.getPlugin().tempTargetFromHistory != null
+
+ // IOB calculation
+ TreatmentsPlugin.getPlugin().updateTotalIOBTreatments()
+ val bolusIob = TreatmentsPlugin.getPlugin().lastCalculationTreatments.round()
+ TreatmentsPlugin.getPlugin().updateTotalIOBTempBasals()
+ val basalIob = TreatmentsPlugin.getPlugin().lastCalculationTempBasals.round()
+
+ treatments_wizard_bolusiobinsulin.text = StringUtils.formatInsulin(-bolusIob.iob)
+ treatments_wizard_basaliobinsulin.text = StringUtils.formatInsulin(-basalIob.basaliob)
+
+ calculateInsulin()
+
+ treatments_wizard_percent_used.visibility = (SP.getInt(R.string.key_boluswizard_percentage, 100) != 100).toVisibility()
+ }
+
+ private fun calculateInsulin() {
+ val profileStore = ConfigBuilderPlugin.getPlugin().activeProfileInterface?.profile
+ if (treatments_wizard_profile.selectedItem == null || profileStore == null)
+ return // not initialized yet
+ var profileName = treatments_wizard_profile.selectedItem.toString()
+ val specificProfile: Profile?
+ if (profileName == MainApp.gs(R.string.active)) {
+ specificProfile = ProfileFunctions.getInstance().profile
+ profileName = ProfileFunctions.getInstance().profileName
+ } else
+ specificProfile = profileStore.getSpecificProfile(profileName)
+
+ if (specificProfile == null) return
+
+ // Entered values
+ var bg = SafeParse.stringToDouble(treatments_wizard_bg_input.text)
+ val carbs = SafeParse.stringToInt(treatments_wizard_carbs_input.text)
+ val correction = SafeParse.stringToDouble(treatments_wizard_correction_input.text)
+ val carbsAfterConstraint = MainApp.getConstraintChecker().applyCarbsConstraints(Constraint(carbs)).value()
+ if (abs(carbs - carbsAfterConstraint) > 0.01) {
+ treatments_wizard_carbs_input.value = 0.0
+ ToastUtils.showToastInUiThread(MainApp.instance().applicationContext, MainApp.gs(R.string.carbsconstraintapplied))
+ return
+ }
+
+ bg = if (treatments_wizard_bgcheckbox.isChecked) bg else 0.0
+ val tempTarget = if (treatments_wizard_ttcheckbox.isChecked) TreatmentsPlugin.getPlugin().tempTargetFromHistory else null
+
+ // COB
+ var cob = 0.0
+ if (treatments_wizard_cobcheckbox.isChecked) {
+ val cobInfo = IobCobCalculatorPlugin.getPlugin().getCobInfo(false, "Wizard COB")
+ cobInfo.displayCob?.let { cob = it }
+ }
+
+ val carbTime = SafeParse.stringToInt(treatments_wizard_carb_time_input.text)
+
+ wizard = BolusWizard(specificProfile, profileName, tempTarget, carbsAfterConstraint, cob, bg, correction,
+ SP.getInt(R.string.key_boluswizard_percentage, 100).toDouble(),
+ treatments_wizard_bgcheckbox.isChecked,
+ treatments_wizard_cobcheckbox.isChecked,
+ treatments_wizard_bolusiobcheckbox.isChecked,
+ treatments_wizard_basaliobcheckbox.isChecked,
+ treatments_wizard_sbcheckbox.isChecked,
+ treatments_wizard_ttcheckbox.isChecked,
+ treatments_wizard_bgtrendcheckbox.isChecked,
+ treatment_wizard_notes.text.toString(), carbTime)
+
+ wizard?.let { wizard ->
+ treatments_wizard_bg.text = String.format(MainApp.gs(R.string.format_bg_isf), BgReading().value(Profile.toMgdl(bg, ProfileFunctions.getSystemUnits())).valueToUnitsToString(ProfileFunctions.getSystemUnits()), wizard.sens)
+ treatments_wizard_bginsulin.text = StringUtils.formatInsulin(wizard.insulinFromBG)
+
+ treatments_wizard_carbs.text = String.format(MainApp.gs(R.string.format_carbs_ic), carbs.toDouble(), wizard.ic)
+ treatments_wizard_carbsinsulin.text = StringUtils.formatInsulin(wizard.insulinFromCarbs)
+
+ treatments_wizard_bolusiobinsulin.text = StringUtils.formatInsulin(wizard.insulinFromBolusIOB)
+ treatments_wizard_basaliobinsulin.text = StringUtils.formatInsulin(wizard.insulinFromBasalsIOB)
+
+ treatments_wizard_correctioninsulin.text = StringUtils.formatInsulin(wizard.insulinFromCorrection)
+
+ // Superbolus
+ treatments_wizard_sb.text = if (treatments_wizard_sbcheckbox.isChecked) MainApp.gs(R.string.twohours) else ""
+ treatments_wizard_sbinsulin.text = StringUtils.formatInsulin(wizard.insulinFromSuperBolus)
+
+ // Trend
+ if (treatments_wizard_bgtrendcheckbox.isChecked && wizard.glucoseStatus != null) {
+ treatments_wizard_bgtrend.text = ((if (wizard.trend > 0) "+" else "")
+ + Profile.toUnitsString(wizard.trend * 3, wizard.trend * 3 / Constants.MMOLL_TO_MGDL, ProfileFunctions.getSystemUnits())
+ + " " + ProfileFunctions.getSystemUnits())
+ } else {
+ treatments_wizard_bgtrend.text = ""
+ }
+ treatments_wizard_bgtrendinsulin.text = StringUtils.formatInsulin(wizard.insulinFromTrend)
+
+ // COB
+ if (treatments_wizard_cobcheckbox.isChecked) {
+ treatments_wizard_cob.text = String.format(MainApp.gs(R.string.format_cob_ic), cob, wizard.ic)
+ treatments_wizard_cobinsulin.text = StringUtils.formatInsulin(wizard.insulinFromCOB)
+ } else {
+ treatments_wizard_cob.text = ""
+ treatments_wizard_cobinsulin.text = ""
+ }
+
+ if (wizard.calculatedTotalInsulin > 0.0 || carbsAfterConstraint > 0.0) {
+ val insulinText = if (wizard.calculatedTotalInsulin > 0.0) MainApp.gs(R.string.formatinsulinunits, wizard.calculatedTotalInsulin) else ""
+ val carbsText = if (carbsAfterConstraint > 0.0) MainApp.gs(R.string.format_carbs, carbsAfterConstraint) else ""
+ treatments_wizard_total.text = MainApp.gs(R.string.result_insulin_carbs, insulinText, carbsText)
+ ok.visibility = View.VISIBLE
+ } else {
+ treatments_wizard_total.text = MainApp.gs(R.string.missing_carbs, wizard.carbsEquivalent.toInt())
+ ok.visibility = View.INVISIBLE
+ }
+ }
+
+ }
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/events/Event.java b/app/src/main/java/info/nightscout/androidaps/events/Event.java
deleted file mode 100644
index 864d55d6f74..00000000000
--- a/app/src/main/java/info/nightscout/androidaps/events/Event.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package info.nightscout.androidaps.events;
-
-import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-
-/** Base class for all events posted on the event bus. */
-public abstract class Event {
- static {
- ReflectionToStringBuilder.setDefaultStyle(ToStringStyle.SHORT_PREFIX_STYLE);
- }
-
- @Override
- public String toString() {
- return ReflectionToStringBuilder.toString(this);
- }
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/events/Event.kt b/app/src/main/java/info/nightscout/androidaps/events/Event.kt
new file mode 100644
index 00000000000..a44f65e8368
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/events/Event.kt
@@ -0,0 +1,18 @@
+package info.nightscout.androidaps.events
+
+import org.apache.commons.lang3.builder.ReflectionToStringBuilder
+import org.apache.commons.lang3.builder.ToStringStyle
+
+/** Base class for all events posted on the event bus. */
+abstract class Event {
+
+ override fun toString(): String {
+ return ReflectionToStringBuilder.toString(this)
+ }
+
+ companion object {
+ init {
+ ReflectionToStringBuilder.setDefaultStyle(ToStringStyle.SHORT_PREFIX_STYLE)
+ }
+ }
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventAcceptOpenLoopChange.java b/app/src/main/java/info/nightscout/androidaps/events/EventAcceptOpenLoopChange.java
deleted file mode 100644
index 2dfbf9ae354..00000000000
--- a/app/src/main/java/info/nightscout/androidaps/events/EventAcceptOpenLoopChange.java
+++ /dev/null
@@ -1,5 +0,0 @@
-package info.nightscout.androidaps.events;
-
-/** Base class for events to update the UI, mostly a specific tab. */
-public class EventAcceptOpenLoopChange extends Event {
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventAcceptOpenLoopChange.kt b/app/src/main/java/info/nightscout/androidaps/events/EventAcceptOpenLoopChange.kt
new file mode 100644
index 00000000000..552564edfc7
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/events/EventAcceptOpenLoopChange.kt
@@ -0,0 +1,3 @@
+package info.nightscout.androidaps.events
+
+class EventAcceptOpenLoopChange : Event()
diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventAppExit.java b/app/src/main/java/info/nightscout/androidaps/events/EventAppExit.java
deleted file mode 100644
index 9ce91a9a397..00000000000
--- a/app/src/main/java/info/nightscout/androidaps/events/EventAppExit.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package info.nightscout.androidaps.events;
-
-/**
- * Created by mike on 07.07.2016.
- */
-public class EventAppExit extends Event {
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventAppExit.kt b/app/src/main/java/info/nightscout/androidaps/events/EventAppExit.kt
new file mode 100644
index 00000000000..640b586f5fa
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/events/EventAppExit.kt
@@ -0,0 +1,3 @@
+package info.nightscout.androidaps.events
+
+class EventAppExit : Event()
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventAppInitialized.java b/app/src/main/java/info/nightscout/androidaps/events/EventAppInitialized.java
deleted file mode 100644
index 17262cfb851..00000000000
--- a/app/src/main/java/info/nightscout/androidaps/events/EventAppInitialized.java
+++ /dev/null
@@ -1,8 +0,0 @@
-package info.nightscout.androidaps.events;
-
-/**
- * Created by mike on 23.01.2018.
- */
-
-public class EventAppInitialized extends Event {
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventAppInitialized.kt b/app/src/main/java/info/nightscout/androidaps/events/EventAppInitialized.kt
new file mode 100644
index 00000000000..293f9698f25
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/events/EventAppInitialized.kt
@@ -0,0 +1,3 @@
+package info.nightscout.androidaps.events
+
+class EventAppInitialized : Event()
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventBolusRequested.java b/app/src/main/java/info/nightscout/androidaps/events/EventBolusRequested.java
deleted file mode 100644
index cb727758bba..00000000000
--- a/app/src/main/java/info/nightscout/androidaps/events/EventBolusRequested.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package info.nightscout.androidaps.events;
-
-/**
- * Created by adrian on 07/02/17.
- */
-
-public class EventBolusRequested extends Event {
- private double amount;
-
- public EventBolusRequested (double amount){
- this.amount = amount;
- }
-
- public double getAmount() {
- return amount;
- }
-
- public void setAmount(double amount) {
- this.amount = amount;
- }
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventBolusRequested.kt b/app/src/main/java/info/nightscout/androidaps/events/EventBolusRequested.kt
new file mode 100644
index 00000000000..a528ef1656f
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/events/EventBolusRequested.kt
@@ -0,0 +1,3 @@
+package info.nightscout.androidaps.events
+
+class EventBolusRequested(var amount: Double) : Event()
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventCareportalEventChange.java b/app/src/main/java/info/nightscout/androidaps/events/EventCareportalEventChange.java
deleted file mode 100644
index 9b47ed39cbb..00000000000
--- a/app/src/main/java/info/nightscout/androidaps/events/EventCareportalEventChange.java
+++ /dev/null
@@ -1,8 +0,0 @@
-package info.nightscout.androidaps.events;
-
-/**
- * Created by mike on 25.05.2017.
- */
-
-public class EventCareportalEventChange extends Event {
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventCareportalEventChange.kt b/app/src/main/java/info/nightscout/androidaps/events/EventCareportalEventChange.kt
new file mode 100644
index 00000000000..e7d52d86c01
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/events/EventCareportalEventChange.kt
@@ -0,0 +1,3 @@
+package info.nightscout.androidaps.events
+
+class EventCareportalEventChange : Event()
diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventChargingState.java b/app/src/main/java/info/nightscout/androidaps/events/EventChargingState.java
deleted file mode 100644
index bcd9061133d..00000000000
--- a/app/src/main/java/info/nightscout/androidaps/events/EventChargingState.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package info.nightscout.androidaps.events;
-
-public class EventChargingState {
-
- public boolean isCharging = false;
-
- public EventChargingState() {}
-
- public EventChargingState(boolean isCharging) {
- this.isCharging = isCharging;
- }
-
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventChargingState.kt b/app/src/main/java/info/nightscout/androidaps/events/EventChargingState.kt
new file mode 100644
index 00000000000..f9ff60a71de
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/events/EventChargingState.kt
@@ -0,0 +1,3 @@
+package info.nightscout.androidaps.events
+
+class EventChargingState(val isCharging: Boolean) : Event()
diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventConfigBuilderChange.java b/app/src/main/java/info/nightscout/androidaps/events/EventConfigBuilderChange.java
deleted file mode 100644
index ad5f558fe85..00000000000
--- a/app/src/main/java/info/nightscout/androidaps/events/EventConfigBuilderChange.java
+++ /dev/null
@@ -1,8 +0,0 @@
-package info.nightscout.androidaps.events;
-
-/**
- * Created by mike on 17.02.2017.
- */
-
-public class EventConfigBuilderChange extends Event {
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventConfigBuilderChange.kt b/app/src/main/java/info/nightscout/androidaps/events/EventConfigBuilderChange.kt
new file mode 100644
index 00000000000..b674374fad5
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/events/EventConfigBuilderChange.kt
@@ -0,0 +1,3 @@
+package info.nightscout.androidaps.events
+
+class EventConfigBuilderChange : Event()
diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventCustomActionsChanged.kt b/app/src/main/java/info/nightscout/androidaps/events/EventCustomActionsChanged.kt
new file mode 100644
index 00000000000..d75bf612ce5
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/events/EventCustomActionsChanged.kt
@@ -0,0 +1,3 @@
+package info.nightscout.androidaps.events
+
+class EventCustomActionsChanged : Event()
diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventCustomCalculationFinished.java b/app/src/main/java/info/nightscout/androidaps/events/EventCustomCalculationFinished.java
deleted file mode 100644
index e52761dc583..00000000000
--- a/app/src/main/java/info/nightscout/androidaps/events/EventCustomCalculationFinished.java
+++ /dev/null
@@ -1,8 +0,0 @@
-package info.nightscout.androidaps.events;
-
-/**
- * Created by mike on 13.02.2018.
- */
-
-public class EventCustomCalculationFinished extends Event {
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventCustomCalculationFinished.kt b/app/src/main/java/info/nightscout/androidaps/events/EventCustomCalculationFinished.kt
new file mode 100644
index 00000000000..f6092b395d0
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/events/EventCustomCalculationFinished.kt
@@ -0,0 +1,3 @@
+package info.nightscout.androidaps.events
+
+class EventCustomCalculationFinished : Event()
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventExtendedBolusChange.java b/app/src/main/java/info/nightscout/androidaps/events/EventExtendedBolusChange.java
deleted file mode 100644
index 8881b0ecc14..00000000000
--- a/app/src/main/java/info/nightscout/androidaps/events/EventExtendedBolusChange.java
+++ /dev/null
@@ -1,8 +0,0 @@
-package info.nightscout.androidaps.events;
-
-/**
- * Created by mike on 15.05.2017.
- */
-
-public class EventExtendedBolusChange extends Event {
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventExtendedBolusChange.kt b/app/src/main/java/info/nightscout/androidaps/events/EventExtendedBolusChange.kt
new file mode 100644
index 00000000000..4ed0ca5ffe3
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/events/EventExtendedBolusChange.kt
@@ -0,0 +1,3 @@
+package info.nightscout.androidaps.events
+
+class EventExtendedBolusChange : EventLoop()
diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventFeatureRunning.java b/app/src/main/java/info/nightscout/androidaps/events/EventFeatureRunning.java
deleted file mode 100644
index 0d07cd6c61e..00000000000
--- a/app/src/main/java/info/nightscout/androidaps/events/EventFeatureRunning.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package info.nightscout.androidaps.events;
-
-/**
- * Created by jamorham on 07/02/2018.
- *
- * Event to indicate that an app feature is being used, for example bolus wizard being opened
- *
- * The purpose this has been created for is to enable opportunistic connection to the pump
- * so that it is already connected before the user wishes to enact a pump function
- *
- */
-
-public class EventFeatureRunning extends Event {
-
- private Feature feature = Feature.UNKNOWN;
-
- public EventFeatureRunning() {
- }
-
- public EventFeatureRunning(Feature feature) {
- this.feature = feature;
- }
-
- public Feature getFeature() {
- return feature;
- }
-
- public enum Feature {
- UNKNOWN,
- MAIN,
- WIZARD,
-
- JUST_ADD_MORE_HERE
- }
-
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventFoodDatabaseChanged.java b/app/src/main/java/info/nightscout/androidaps/events/EventFoodDatabaseChanged.java
deleted file mode 100644
index 48e6be3a14c..00000000000
--- a/app/src/main/java/info/nightscout/androidaps/events/EventFoodDatabaseChanged.java
+++ /dev/null
@@ -1,8 +0,0 @@
-package info.nightscout.androidaps.events;
-
-/**
- * Created by mike on 20.09.2017.
- */
-
-public class EventFoodDatabaseChanged extends Event {
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventFoodDatabaseChanged.kt b/app/src/main/java/info/nightscout/androidaps/events/EventFoodDatabaseChanged.kt
new file mode 100644
index 00000000000..83402c3cb61
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/events/EventFoodDatabaseChanged.kt
@@ -0,0 +1,3 @@
+package info.nightscout.androidaps.events
+
+class EventFoodDatabaseChanged : Event()
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventInitializationChanged.java b/app/src/main/java/info/nightscout/androidaps/events/EventInitializationChanged.java
deleted file mode 100644
index f2bef1d3d07..00000000000
--- a/app/src/main/java/info/nightscout/androidaps/events/EventInitializationChanged.java
+++ /dev/null
@@ -1,8 +0,0 @@
-package info.nightscout.androidaps.events;
-
-/**
- * Created by mike on 13.12.2016.
- */
-
-public class EventInitializationChanged extends Event {
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventInitializationChanged.kt b/app/src/main/java/info/nightscout/androidaps/events/EventInitializationChanged.kt
new file mode 100644
index 00000000000..33ab0062c5c
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/events/EventInitializationChanged.kt
@@ -0,0 +1,3 @@
+package info.nightscout.androidaps.events
+
+class EventInitializationChanged : Event()
diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventLocationChange.kt b/app/src/main/java/info/nightscout/androidaps/events/EventLocationChange.kt
new file mode 100644
index 00000000000..fee6c9f800d
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/events/EventLocationChange.kt
@@ -0,0 +1,5 @@
+package info.nightscout.androidaps.events
+
+import android.location.Location
+
+class EventLocationChange(var location: Location) : Event()
diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventLoop.java b/app/src/main/java/info/nightscout/androidaps/events/EventLoop.java
deleted file mode 100644
index d694d52537e..00000000000
--- a/app/src/main/java/info/nightscout/androidaps/events/EventLoop.java
+++ /dev/null
@@ -1,5 +0,0 @@
-package info.nightscout.androidaps.events;
-
-/** Supeclass for all events concerned with input or output into or from the LoopPlugin. */
-public abstract class EventLoop extends Event {
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventLoop.kt b/app/src/main/java/info/nightscout/androidaps/events/EventLoop.kt
new file mode 100644
index 00000000000..dd28e2323b0
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/events/EventLoop.kt
@@ -0,0 +1,4 @@
+package info.nightscout.androidaps.events
+
+/** Supeclass for all events concerned with input or output into or from the LoopPlugin. */
+abstract class EventLoop : Event()
diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventNetworkChange.java b/app/src/main/java/info/nightscout/androidaps/events/EventNetworkChange.java
deleted file mode 100644
index 546d6f86247..00000000000
--- a/app/src/main/java/info/nightscout/androidaps/events/EventNetworkChange.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package info.nightscout.androidaps.events;
-
-
-import info.nightscout.androidaps.utils.StringUtils;
-
-public class EventNetworkChange extends Event {
-
- public boolean mobileConnected = false;
- public boolean wifiConnected = false;
-
- public String ssid = "";
- public boolean roaming = false;
-
- public String getSsid() {
- return StringUtils.removeSurroundingQuotes(ssid);
- }
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventNetworkChange.kt b/app/src/main/java/info/nightscout/androidaps/events/EventNetworkChange.kt
new file mode 100644
index 00000000000..62c8bdd13e8
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/events/EventNetworkChange.kt
@@ -0,0 +1,16 @@
+package info.nightscout.androidaps.events
+
+import info.nightscout.androidaps.utils.StringUtils
+
+class EventNetworkChange : Event() {
+
+ var mobileConnected = false
+ var wifiConnected = false
+
+ var ssid = ""
+ var roaming = false
+
+ fun connectedSsid(): String {
+ return StringUtils.removeSurroundingQuotes(ssid)
+ }
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventNewBG.java b/app/src/main/java/info/nightscout/androidaps/events/EventNewBG.java
deleted file mode 100644
index dc4d434e0ab..00000000000
--- a/app/src/main/java/info/nightscout/androidaps/events/EventNewBG.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package info.nightscout.androidaps.events;
-
-import android.support.annotation.Nullable;
-
-import info.nightscout.androidaps.db.BgReading;
-
-/**
- * Created by mike on 05.06.2016.
- */
-public class EventNewBG extends EventLoop {
- @Nullable
- public final BgReading bgReading;
-
- public EventNewBG(BgReading bgReading) {
- this.bgReading = bgReading;
- }
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventNewBG.kt b/app/src/main/java/info/nightscout/androidaps/events/EventNewBG.kt
new file mode 100644
index 00000000000..08c05407c93
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/events/EventNewBG.kt
@@ -0,0 +1,5 @@
+package info.nightscout.androidaps.events
+
+import info.nightscout.androidaps.db.BgReading
+
+class EventNewBG(val bgReading: BgReading?) : EventLoop()
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventNewBasalProfile.java b/app/src/main/java/info/nightscout/androidaps/events/EventNewBasalProfile.java
deleted file mode 100644
index f26a310b6b3..00000000000
--- a/app/src/main/java/info/nightscout/androidaps/events/EventNewBasalProfile.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package info.nightscout.androidaps.events;
-
-/**
- * Created by mike on 04.06.2016.
- */
-public class EventNewBasalProfile extends Event {
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventNewBasalProfile.kt b/app/src/main/java/info/nightscout/androidaps/events/EventNewBasalProfile.kt
new file mode 100644
index 00000000000..2ffa5a97244
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/events/EventNewBasalProfile.kt
@@ -0,0 +1,3 @@
+package info.nightscout.androidaps.events
+
+class EventNewBasalProfile : Event()
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventNsFood.java b/app/src/main/java/info/nightscout/androidaps/events/EventNsFood.java
deleted file mode 100644
index 90b6f5681b6..00000000000
--- a/app/src/main/java/info/nightscout/androidaps/events/EventNsFood.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package info.nightscout.androidaps.events;
-
-import android.os.Bundle;
-
-/**
- * Event which is published with data fetched from NightScout specific for the
- * Food-class.
- *
- * Payload is the from NS retrieved JSON-String which should be handled by all
- * subscriber.
- */
-
-public class EventNsFood extends Event {
-
- public static final int ADD = 0;
- public static final int UPDATE = 1;
- public static final int REMOVE = 2;
-
- private final int mode;
-
- private final Bundle payload;
-
- public EventNsFood(int mode, Bundle payload) {
- this.mode = mode;
- this.payload = payload;
- }
-
- public int getMode() {
- return mode;
- }
-
- public Bundle getPayload() {
- return payload;
- }
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventNsFood.kt b/app/src/main/java/info/nightscout/androidaps/events/EventNsFood.kt
new file mode 100644
index 00000000000..2f34e76c85f
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/events/EventNsFood.kt
@@ -0,0 +1,19 @@
+package info.nightscout.androidaps.events
+
+import android.os.Bundle
+
+/**
+ * Event which is published with data fetched from NightScout specific for the
+ * Food-class.
+ *
+ * Payload is the from NS retrieved JSON-String which should be handled by all
+ * subscriber.
+ */
+
+class EventNsFood(val mode: Int, val payload: Bundle) : Event() {
+ companion object {
+ val ADD = 0
+ val UPDATE = 1
+ val REMOVE = 2
+ }
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventNsTreatment.java b/app/src/main/java/info/nightscout/androidaps/events/EventNsTreatment.java
deleted file mode 100644
index 2c5ba6c9c07..00000000000
--- a/app/src/main/java/info/nightscout/androidaps/events/EventNsTreatment.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package info.nightscout.androidaps.events;
-
-import org.json.JSONObject;
-
-
-/**
- * Event which is published with data fetched from NightScout specific for the
- * Treatment-class.
- *
- * Payload is the from NS retrieved JSON-String which should be handled by all
- * subscriber.
- */
-
-public class EventNsTreatment extends Event {
-
- public static final int ADD = 0;
- public static final int UPDATE = 1;
- public static final int REMOVE = 2;
-
- private final int mode;
-
- private final JSONObject payload;
-
- public EventNsTreatment(int mode, JSONObject payload) {
- this.mode = mode;
- this.payload = payload;
- }
-
- public int getMode() {
- return mode;
- }
-
- public JSONObject getPayload() {
- return payload;
- }
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventNsTreatment.kt b/app/src/main/java/info/nightscout/androidaps/events/EventNsTreatment.kt
new file mode 100644
index 00000000000..149894c2218
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/events/EventNsTreatment.kt
@@ -0,0 +1,21 @@
+package info.nightscout.androidaps.events
+
+import org.json.JSONObject
+
+
+/**
+ * Event which is published with data fetched from NightScout specific for the
+ * Treatment-class.
+ *
+ *
+ * Payload is the from NS retrieved JSON-String which should be handled by all
+ * subscriber.
+ */
+
+class EventNsTreatment(val mode: Int, val payload: JSONObject) : Event() {
+ companion object {
+ val ADD = 0
+ val UPDATE = 1
+ val REMOVE = 2
+ }
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventPreferenceChange.java b/app/src/main/java/info/nightscout/androidaps/events/EventPreferenceChange.java
deleted file mode 100644
index f23d4e802a8..00000000000
--- a/app/src/main/java/info/nightscout/androidaps/events/EventPreferenceChange.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package info.nightscout.androidaps.events;
-
-import info.nightscout.androidaps.MainApp;
-
-/**
- * Created by mike on 19.06.2016.
- */
-public class EventPreferenceChange extends Event {
- public String changedKey;
- public EventPreferenceChange(String key) {
- changedKey = key;
- }
-
- public EventPreferenceChange(int resourceID) {
- changedKey = MainApp.gs(resourceID);
- }
-
- public boolean isChanged(int id) {
- return changedKey.equals(MainApp.gs(id));
- }
-
- public boolean isChanged(String id) {
- return changedKey.equals(id);
- }
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventPreferenceChange.kt b/app/src/main/java/info/nightscout/androidaps/events/EventPreferenceChange.kt
new file mode 100644
index 00000000000..d224d75df1e
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/events/EventPreferenceChange.kt
@@ -0,0 +1,19 @@
+package info.nightscout.androidaps.events
+
+import info.nightscout.androidaps.MainApp
+
+class EventPreferenceChange : Event {
+ private var changedKey: String? = null
+
+ constructor(key: String) {
+ changedKey = key
+ }
+
+ constructor(resourceID: Int) {
+ changedKey = MainApp.gs(resourceID)
+ }
+
+ fun isChanged(id: Int): Boolean {
+ return changedKey == MainApp.gs(id)
+ }
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventProfileNeedsUpdate.java b/app/src/main/java/info/nightscout/androidaps/events/EventProfileNeedsUpdate.java
deleted file mode 100644
index 9e3f3b08c75..00000000000
--- a/app/src/main/java/info/nightscout/androidaps/events/EventProfileNeedsUpdate.java
+++ /dev/null
@@ -1,8 +0,0 @@
-package info.nightscout.androidaps.events;
-
-/**
- * Created by mike on 02.06.2017.
- */
-
-public class EventProfileNeedsUpdate extends Event {
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventProfileNeedsUpdate.kt b/app/src/main/java/info/nightscout/androidaps/events/EventProfileNeedsUpdate.kt
new file mode 100644
index 00000000000..2baf1db9452
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/events/EventProfileNeedsUpdate.kt
@@ -0,0 +1,3 @@
+package info.nightscout.androidaps.events
+
+class EventProfileNeedsUpdate : Event()
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventProfileStoreChanged.java b/app/src/main/java/info/nightscout/androidaps/events/EventProfileStoreChanged.java
deleted file mode 100644
index 0b2d933c12b..00000000000
--- a/app/src/main/java/info/nightscout/androidaps/events/EventProfileStoreChanged.java
+++ /dev/null
@@ -1,4 +0,0 @@
-package info.nightscout.androidaps.events;
-
-public class EventProfileStoreChanged extends Event {
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventProfileStoreChanged.kt b/app/src/main/java/info/nightscout/androidaps/events/EventProfileStoreChanged.kt
new file mode 100644
index 00000000000..0e839ca2d35
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/events/EventProfileStoreChanged.kt
@@ -0,0 +1,3 @@
+package info.nightscout.androidaps.events
+
+class EventProfileStoreChanged : Event()
diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventPumpStatusChanged.java b/app/src/main/java/info/nightscout/androidaps/events/EventPumpStatusChanged.java
deleted file mode 100644
index 6729a4e7031..00000000000
--- a/app/src/main/java/info/nightscout/androidaps/events/EventPumpStatusChanged.java
+++ /dev/null
@@ -1,63 +0,0 @@
-package info.nightscout.androidaps.events;
-
-import info.nightscout.androidaps.MainApp;
-import info.nightscout.androidaps.R;
-
-/**
- * Created by mike on 19.02.2017.
- */
-
-public class EventPumpStatusChanged extends Event {
- public static final int CONNECTING = 0;
- public static final int CONNECTED = 1;
- public static final int HANDSHAKING = 2;
- public static final int PERFORMING = 3;
- public static final int DISCONNECTING = 4;
- public static final int DISCONNECTED = 5;
-
- public int sStatus = DISCONNECTED;
- public int sSecondsElapsed = 0;
- public String sPerfomingAction = "";
-
- public static String error = "";
-
- public EventPumpStatusChanged(int status) {
- sStatus = status;
- sSecondsElapsed = 0;
- error = "";
- }
-
- public EventPumpStatusChanged(int status, int secondsElapsed) {
- sStatus = status;
- sSecondsElapsed = secondsElapsed;
- error = "";
- }
-
- public EventPumpStatusChanged(int status, String error) {
- sStatus = status;
- sSecondsElapsed = 0;
- this.error = error;
- }
-
- public EventPumpStatusChanged(String action) {
- sStatus = PERFORMING;
- sSecondsElapsed = 0;
- sPerfomingAction = action;
- }
-
- public String textStatus() {
- if (sStatus == CONNECTING)
- return String.format(MainApp.gs(R.string.danar_history_connectingfor), sSecondsElapsed);
- else if (sStatus == HANDSHAKING)
- return MainApp.gs(R.string.handshaking);
- else if (sStatus == CONNECTED)
- return MainApp.gs(R.string.connected);
- else if (sStatus == PERFORMING)
- return sPerfomingAction;
- else if (sStatus == DISCONNECTING)
- return MainApp.gs(R.string.disconnecting);
- else if (sStatus == DISCONNECTED)
- return "";
- return "";
- }
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventPumpStatusChanged.kt b/app/src/main/java/info/nightscout/androidaps/events/EventPumpStatusChanged.kt
new file mode 100644
index 00000000000..3d25bc1ca55
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/events/EventPumpStatusChanged.kt
@@ -0,0 +1,62 @@
+package info.nightscout.androidaps.events
+
+import info.nightscout.androidaps.MainApp
+import info.nightscout.androidaps.R
+
+class EventPumpStatusChanged : EventStatus {
+
+ enum class Status {
+ CONNECTING,
+ CONNECTED,
+ HANDSHAKING,
+ PERFORMING,
+ DISCONNECTING,
+ DISCONNECTED
+ }
+
+ var sStatus: Status = Status.DISCONNECTED
+ var sSecondsElapsed = 0
+ var sPerfomingAction = ""
+ var error = ""
+
+ constructor(status: Status) {
+ sStatus = status
+ sSecondsElapsed = 0
+ error = ""
+ }
+
+ constructor(status: Status, secondsElapsed: Int) {
+ sStatus = status
+ sSecondsElapsed = secondsElapsed
+ error = ""
+ }
+
+ constructor(status: Status, error: String) {
+ sStatus = status
+ sSecondsElapsed = 0
+ this.error = error
+ }
+
+ constructor(action: String) {
+ sStatus = Status.PERFORMING
+ sSecondsElapsed = 0
+ sPerfomingAction = action
+ }
+
+ // status for startup wizard
+ override fun getStatus(): String {
+ if (sStatus == Status.CONNECTING)
+ return String.format(MainApp.gs(R.string.danar_history_connectingfor), sSecondsElapsed)
+ else if (sStatus == Status.HANDSHAKING)
+ return MainApp.gs(R.string.handshaking)
+ else if (sStatus == Status.CONNECTED)
+ return MainApp.gs(R.string.connected)
+ else if (sStatus == Status.PERFORMING)
+ return sPerfomingAction
+ else if (sStatus == Status.DISCONNECTING)
+ return MainApp.gs(R.string.disconnecting)
+ else if (sStatus == Status.DISCONNECTED)
+ return ""
+ return ""
+ }
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventRebuildTabs.kt b/app/src/main/java/info/nightscout/androidaps/events/EventRebuildTabs.kt
new file mode 100644
index 00000000000..aa0db3467ab
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/events/EventRebuildTabs.kt
@@ -0,0 +1,3 @@
+package info.nightscout.androidaps.events
+
+class EventRebuildTabs @JvmOverloads constructor(var recreate: Boolean = false) : Event()
diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventRefreshGui.java b/app/src/main/java/info/nightscout/androidaps/events/EventRefreshGui.java
deleted file mode 100644
index 390ad8ea4ff..00000000000
--- a/app/src/main/java/info/nightscout/androidaps/events/EventRefreshGui.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package info.nightscout.androidaps.events;
-
-/**
- * Created by mike on 13.06.2016.
- */
-public class EventRefreshGui extends Event {
- public boolean recreate = false;
- public EventRefreshGui(boolean recreate) {
- this.recreate = recreate;
- }
- public EventRefreshGui(){
- this(false);
- }
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventRefreshOverview.java b/app/src/main/java/info/nightscout/androidaps/events/EventRefreshOverview.java
deleted file mode 100644
index 2ba78fa9ec3..00000000000
--- a/app/src/main/java/info/nightscout/androidaps/events/EventRefreshOverview.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package info.nightscout.androidaps.events;
-
-/**
- * Created by mike on 16.06.2017.
- */
-
-public class EventRefreshOverview extends Event {
- public String from;
-
- public EventRefreshOverview(String from) {
- this.from = from;
- }
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventRefreshOverview.kt b/app/src/main/java/info/nightscout/androidaps/events/EventRefreshOverview.kt
new file mode 100644
index 00000000000..533a25dd40f
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/events/EventRefreshOverview.kt
@@ -0,0 +1,3 @@
+package info.nightscout.androidaps.events
+
+class EventRefreshOverview(var from: String) : Event()
diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventReloadProfileSwitchData.java b/app/src/main/java/info/nightscout/androidaps/events/EventReloadProfileSwitchData.java
deleted file mode 100644
index 212e8856d95..00000000000
--- a/app/src/main/java/info/nightscout/androidaps/events/EventReloadProfileSwitchData.java
+++ /dev/null
@@ -1,8 +0,0 @@
-package info.nightscout.androidaps.events;
-
-/**
- * Created by mike on 12.06.2017.
- */
-
-public class EventReloadProfileSwitchData extends Event {
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventReloadProfileSwitchData.kt b/app/src/main/java/info/nightscout/androidaps/events/EventReloadProfileSwitchData.kt
new file mode 100644
index 00000000000..6f6d848b5ec
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/events/EventReloadProfileSwitchData.kt
@@ -0,0 +1,3 @@
+package info.nightscout.androidaps.events
+
+class EventReloadProfileSwitchData : Event()
diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventReloadTempBasalData.java b/app/src/main/java/info/nightscout/androidaps/events/EventReloadTempBasalData.java
deleted file mode 100644
index 80125cbb4a3..00000000000
--- a/app/src/main/java/info/nightscout/androidaps/events/EventReloadTempBasalData.java
+++ /dev/null
@@ -1,8 +0,0 @@
-package info.nightscout.androidaps.events;
-
-/**
- * Created by mike on 29.05.2017.
- */
-
-public class EventReloadTempBasalData extends Event {
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventReloadTempBasalData.kt b/app/src/main/java/info/nightscout/androidaps/events/EventReloadTempBasalData.kt
new file mode 100644
index 00000000000..fa8f7208963
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/events/EventReloadTempBasalData.kt
@@ -0,0 +1,3 @@
+package info.nightscout.androidaps.events
+
+class EventReloadTempBasalData : Event()
diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventReloadTreatmentData.java b/app/src/main/java/info/nightscout/androidaps/events/EventReloadTreatmentData.java
deleted file mode 100644
index 0ba9b95ad76..00000000000
--- a/app/src/main/java/info/nightscout/androidaps/events/EventReloadTreatmentData.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package info.nightscout.androidaps.events;
-
-/**
- * Created by mike on 29.05.2017.
- */
-
-public class EventReloadTreatmentData extends Event {
- public Object next;
-
- public EventReloadTreatmentData(Object next) {
- this.next = next;
- }
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventReloadTreatmentData.kt b/app/src/main/java/info/nightscout/androidaps/events/EventReloadTreatmentData.kt
new file mode 100644
index 00000000000..1f8b2938b9b
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/events/EventReloadTreatmentData.kt
@@ -0,0 +1,3 @@
+package info.nightscout.androidaps.events
+
+class EventReloadTreatmentData(var next: Event) : Event()
diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventStatus.kt b/app/src/main/java/info/nightscout/androidaps/events/EventStatus.kt
new file mode 100644
index 00000000000..193c3b1fdb4
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/events/EventStatus.kt
@@ -0,0 +1,6 @@
+package info.nightscout.androidaps.events
+
+// pass string to startup wizard
+abstract class EventStatus :Event() {
+ abstract fun getStatus() : String
+}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventTempBasalChange.java b/app/src/main/java/info/nightscout/androidaps/events/EventTempBasalChange.java
deleted file mode 100644
index 73660bb00ec..00000000000
--- a/app/src/main/java/info/nightscout/androidaps/events/EventTempBasalChange.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package info.nightscout.androidaps.events;
-
-/**
- * Created by mike on 05.06.2016.
- */
-public class EventTempBasalChange extends EventLoop {
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventTempBasalChange.kt b/app/src/main/java/info/nightscout/androidaps/events/EventTempBasalChange.kt
new file mode 100644
index 00000000000..3f3ecf732e6
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/events/EventTempBasalChange.kt
@@ -0,0 +1,3 @@
+package info.nightscout.androidaps.events
+
+class EventTempBasalChange : EventLoop()
diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventTempTargetChange.java b/app/src/main/java/info/nightscout/androidaps/events/EventTempTargetChange.java
deleted file mode 100644
index 4e3bf5c5f81..00000000000
--- a/app/src/main/java/info/nightscout/androidaps/events/EventTempTargetChange.java
+++ /dev/null
@@ -1,8 +0,0 @@
-package info.nightscout.androidaps.events;
-
-/**
- * Created by mike on 13.01.2017.
- */
-
-public class EventTempTargetChange extends Event {
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventTempTargetChange.kt b/app/src/main/java/info/nightscout/androidaps/events/EventTempTargetChange.kt
new file mode 100644
index 00000000000..c108d6589c5
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/events/EventTempTargetChange.kt
@@ -0,0 +1,3 @@
+package info.nightscout.androidaps.events
+
+class EventTempTargetChange : Event()
diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventTreatmentChange.java b/app/src/main/java/info/nightscout/androidaps/events/EventTreatmentChange.java
deleted file mode 100644
index 990f28a388c..00000000000
--- a/app/src/main/java/info/nightscout/androidaps/events/EventTreatmentChange.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package info.nightscout.androidaps.events;
-
-import android.support.annotation.Nullable;
-
-import info.nightscout.androidaps.plugins.treatments.Treatment;
-
-/**
- * Created by mike on 04.06.2016.
- */
-public class EventTreatmentChange extends EventLoop {
- @Nullable
- public final Treatment treatment;
-
- public EventTreatmentChange(Treatment treatment) {
- this.treatment = treatment;
- }
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventTreatmentChange.kt b/app/src/main/java/info/nightscout/androidaps/events/EventTreatmentChange.kt
new file mode 100644
index 00000000000..9cbc9d15632
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/events/EventTreatmentChange.kt
@@ -0,0 +1,5 @@
+package info.nightscout.androidaps.events
+
+import info.nightscout.androidaps.plugins.treatments.Treatment
+
+class EventTreatmentChange(val treatment: Treatment?) : EventLoop()
diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventUpdateGui.java b/app/src/main/java/info/nightscout/androidaps/events/EventUpdateGui.java
deleted file mode 100644
index 3471d2e851d..00000000000
--- a/app/src/main/java/info/nightscout/androidaps/events/EventUpdateGui.java
+++ /dev/null
@@ -1,5 +0,0 @@
-package info.nightscout.androidaps.events;
-
-/** Base class for events to update the UI, mostly a specific tab. */
-public abstract class EventUpdateGui extends Event {
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventUpdateGui.kt b/app/src/main/java/info/nightscout/androidaps/events/EventUpdateGui.kt
new file mode 100644
index 00000000000..cc21e784b98
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/events/EventUpdateGui.kt
@@ -0,0 +1,4 @@
+package info.nightscout.androidaps.events
+
+/** Base class for events to update the UI, mostly a specific tab. */
+abstract class EventUpdateGui : Event()
diff --git a/app/src/main/java/info/nightscout/androidaps/interfaces/APSInterface.java b/app/src/main/java/info/nightscout/androidaps/interfaces/APSInterface.java
index e2f3460701e..7d32e37ff09 100644
--- a/app/src/main/java/info/nightscout/androidaps/interfaces/APSInterface.java
+++ b/app/src/main/java/info/nightscout/androidaps/interfaces/APSInterface.java
@@ -6,8 +6,9 @@
* Created by mike on 10.06.2016.
*/
public interface APSInterface {
- public APSResult getLastAPSResult();
- public long getLastAPSRun();
+ APSResult getLastAPSResult();
- public void invoke(String initiator, boolean tempBasalFallback);
+ long getLastAPSRun();
+
+ void invoke(String initiator, boolean tempBasalFallback);
}
diff --git a/app/src/main/java/info/nightscout/androidaps/interfaces/ConstraintsInterface.java b/app/src/main/java/info/nightscout/androidaps/interfaces/ConstraintsInterface.java
index f1c79dd5cbe..14b2d549af1 100644
--- a/app/src/main/java/info/nightscout/androidaps/interfaces/ConstraintsInterface.java
+++ b/app/src/main/java/info/nightscout/androidaps/interfaces/ConstraintsInterface.java
@@ -61,6 +61,6 @@ default Constraint applyCarbsConstraints(Constraint carbs) {
default Constraint applyMaxIOBConstraints(Constraint maxIob) {
return maxIob;
- };
+ }
}
diff --git a/app/src/main/java/info/nightscout/androidaps/interfaces/PluginBase.java b/app/src/main/java/info/nightscout/androidaps/interfaces/PluginBase.java
index 01be2965390..5d4ec01fd99 100644
--- a/app/src/main/java/info/nightscout/androidaps/interfaces/PluginBase.java
+++ b/app/src/main/java/info/nightscout/androidaps/interfaces/PluginBase.java
@@ -1,16 +1,26 @@
package info.nightscout.androidaps.interfaces;
import android.os.SystemClock;
-import android.support.v4.app.FragmentActivity;
+import android.preference.Preference;
+import android.preference.PreferenceFragment;
+import androidx.fragment.app.FragmentActivity;
+
+import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.MainApp;
+import info.nightscout.androidaps.R;
+import info.nightscout.androidaps.events.EventConfigBuilderChange;
+import info.nightscout.androidaps.events.EventRebuildTabs;
import info.nightscout.androidaps.logging.L;
-import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderFragment;
+import info.nightscout.androidaps.plugins.bus.RxBus;
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin;
+import info.nightscout.androidaps.plugins.configBuilder.EventConfigBuilderUpdateGui;
import info.nightscout.androidaps.queue.CommandQueue;
+import info.nightscout.androidaps.utils.OKDialog;
+import info.nightscout.androidaps.utils.SP;
/**
* Created by mike on 09.06.2016.
@@ -38,17 +48,42 @@ public PluginBase(PluginDescription pluginDescription) {
// Default always calls invoke
// Plugins that have special constraints if they get switched to may override this method
- public void switchAllowed(ConfigBuilderFragment.PluginViewHolder.PluginSwitcher pluginSwitcher, FragmentActivity activity) {
- pluginSwitcher.invoke();
+ public void switchAllowed(boolean newState, FragmentActivity activity, PluginType type) {
+ performPluginSwitch(newState, type);
+ }
+
+ protected void confirmPumpPluginActivation(boolean newState, FragmentActivity activity, PluginType type) {
+ if (type == PluginType.PUMP) {
+ boolean allowHardwarePump = SP.getBoolean("allow_hardware_pump", false);
+ if (allowHardwarePump || activity == null) {
+ performPluginSwitch(newState, type);
+ } else {
+ OKDialog.showConfirmation(activity, MainApp.gs(R.string.allow_hardware_pump_text), () -> {
+ performPluginSwitch(newState, type);
+ SP.putBoolean("allow_hardware_pump", true);
+ if (L.isEnabled(L.PUMP))
+ log.debug("First time HW pump allowed!");
+ }, () -> {
+ RxBus.INSTANCE.send(new EventConfigBuilderUpdateGui());
+ if (L.isEnabled(L.PUMP))
+ log.debug("User does not allow switching to HW pump!");
+ });
+ }
+ } else {
+ performPluginSwitch(newState, type);
+ }
}
-// public PluginType getType() {
-// return mainType;
-// }
-
-// public String getFragmentClass() {
-// return fragmentClass;
-// }
+ public void performPluginSwitch(boolean enabled, PluginType type) {
+ setPluginEnabled(type, enabled);
+ setFragmentVisible(type, enabled);
+ ConfigBuilderPlugin.getPlugin().processOnEnabledCategoryChanged(this, getType());
+ ConfigBuilderPlugin.getPlugin().storeSettings("CheckedCheckboxEnabled");
+ RxBus.INSTANCE.send(new EventRebuildTabs());
+ RxBus.INSTANCE.send(new EventConfigBuilderChange());
+ RxBus.INSTANCE.send(new EventConfigBuilderUpdateGui());
+ ConfigBuilderPlugin.getPlugin().logPluginStatus();
+ }
public String getName() {
if (pluginDescription.pluginName == -1)
@@ -80,10 +115,6 @@ public int getPreferencesId() {
return pluginDescription.preferencesId;
}
- public int getAdvancedPreferencesId() {
- return pluginDescription.advancedPreferencesId;
- }
-
public boolean isEnabled(PluginType type) {
if (pluginDescription.alwaysEnabled && type == pluginDescription.mainType)
return true;
@@ -143,7 +174,7 @@ public void setFragmentVisible(PluginType type, boolean fragmentVisible) {
}
public boolean isFragmentVisible() {
- if (pluginDescription.alwayVisible)
+ if (pluginDescription.alwaysVisible)
return true;
if (pluginDescription.neverVisible)
return false;
@@ -183,4 +214,10 @@ protected void onStop() {
protected void onStateChange(PluginType type, State oldState, State newState) {
}
+
+ public void preprocessPreferences(@NotNull final PreferenceFragment preferenceFragment) {
+ }
+
+ public void updatePreferenceSummary(@NotNull final Preference pref) {
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/interfaces/PluginDescription.java b/app/src/main/java/info/nightscout/androidaps/interfaces/PluginDescription.java
index 1634fc672db..2929d3f21b1 100644
--- a/app/src/main/java/info/nightscout/androidaps/interfaces/PluginDescription.java
+++ b/app/src/main/java/info/nightscout/androidaps/interfaces/PluginDescription.java
@@ -3,7 +3,7 @@
public class PluginDescription {
PluginType mainType = PluginType.GENERAL;
String fragmentClass = null;
- public boolean alwayVisible = false;
+ public boolean alwaysVisible = false;
public boolean neverVisible = false;
public boolean alwaysEnabled = false;
boolean showInList = true;
@@ -11,7 +11,6 @@ public class PluginDescription {
int shortName = -1;
int description = -1;
int preferencesId = -1;
- int advancedPreferencesId = -1;
public boolean enableByDefault = false;
public boolean visibleByDefault = false;
@@ -30,8 +29,8 @@ public PluginDescription alwaysEnabled(boolean alwaysEnabled) {
return this;
}
- public PluginDescription alwayVisible(boolean alwayVisible) {
- this.alwayVisible = alwayVisible;
+ public PluginDescription alwaysVisible(boolean alwaysVisible) {
+ this.alwaysVisible = alwaysVisible;
return this;
}
@@ -60,11 +59,6 @@ public PluginDescription preferencesId(int preferencesId) {
return this;
}
- public PluginDescription advancedPreferencesId(int advancedPreferencesId) {
- this.advancedPreferencesId = advancedPreferencesId;
- return this;
- }
-
public PluginDescription enableByDefault(boolean enableByDefault) {
this.enableByDefault = enableByDefault;
return this;
diff --git a/app/src/main/java/info/nightscout/androidaps/interfaces/ProfileInterface.java b/app/src/main/java/info/nightscout/androidaps/interfaces/ProfileInterface.java
index e3b368fe866..5fb3b459b62 100644
--- a/app/src/main/java/info/nightscout/androidaps/interfaces/ProfileInterface.java
+++ b/app/src/main/java/info/nightscout/androidaps/interfaces/ProfileInterface.java
@@ -1,6 +1,6 @@
package info.nightscout.androidaps.interfaces;
-import android.support.annotation.Nullable;
+import androidx.annotation.Nullable;
import info.nightscout.androidaps.data.ProfileStore;
@@ -10,6 +10,5 @@
public interface ProfileInterface {
@Nullable
ProfileStore getProfile();
- String getUnits();
String getProfileName();
}
diff --git a/app/src/main/java/info/nightscout/androidaps/interfaces/PumpDescription.java b/app/src/main/java/info/nightscout/androidaps/interfaces/PumpDescription.java
index e4a02883e85..0b83944d946 100644
--- a/app/src/main/java/info/nightscout/androidaps/interfaces/PumpDescription.java
+++ b/app/src/main/java/info/nightscout/androidaps/interfaces/PumpDescription.java
@@ -55,6 +55,8 @@ public PumpDescription () {
public boolean supportsTDDs;
public boolean needsManualTDDLoad;
+ public boolean hasFixedUnreachableAlert;
+ public boolean hasCustomUnreachableAlertCheck;
public void resetSettings() {
isBolusCapable = true;
@@ -87,6 +89,9 @@ public void resetSettings() {
supportsTDDs = false;
needsManualTDDLoad = true;
+
+ hasFixedUnreachableAlert = false;
+ hasCustomUnreachableAlertCheck = false;
}
public void setPumpDescription(PumpType pumpType) {
@@ -134,6 +139,9 @@ public void setPumpDescription(PumpType pumpType) {
needsManualTDDLoad = pumpCapability.hasCapability(PumpCapability.ManualTDDLoad);
is30minBasalRatesCapable = pumpCapability.hasCapability(PumpCapability.BasalRate30min);
+
+ hasFixedUnreachableAlert = pumpType.getHasFixedUnreachableAlert();
+ hasCustomUnreachableAlertCheck = pumpType.getHasCustomUnreachableAlertCheck();
}
}
diff --git a/app/src/main/java/info/nightscout/androidaps/interfaces/PumpInterface.java b/app/src/main/java/info/nightscout/androidaps/interfaces/PumpInterface.java
index 3690312cf8f..3b17aef1f3e 100644
--- a/app/src/main/java/info/nightscout/androidaps/interfaces/PumpInterface.java
+++ b/app/src/main/java/info/nightscout/androidaps/interfaces/PumpInterface.java
@@ -7,8 +7,11 @@
import info.nightscout.androidaps.data.DetailedBolusInfo;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.data.PumpEnactResult;
+import info.nightscout.androidaps.plugins.common.ManufacturerType;
import info.nightscout.androidaps.plugins.general.actions.defs.CustomAction;
import info.nightscout.androidaps.plugins.general.actions.defs.CustomActionType;
+import info.nightscout.androidaps.plugins.pump.common.defs.PumpType;
+import info.nightscout.androidaps.utils.TimeChangeType;
/**
* Created by mike on 04.06.2016.
@@ -16,21 +19,30 @@
public interface PumpInterface {
boolean isInitialized(); // true if pump status has been read and is ready to accept commands
+
boolean isSuspended(); // true if suspended (not delivering insulin)
+
boolean isBusy(); // if true pump is not ready to accept commands right now
+
boolean isConnected(); // true if BT connection is established
+
boolean isConnecting(); // true if BT connection is in progress
+
boolean isHandshakeInProgress(); // true if BT is connected but initial handshake is still in progress
+
void finishHandshaking(); // set initial handshake completed
void connect(String reason);
+
void disconnect(String reason);
+
void stopConnecting();
void getPumpStatus();
// Upload to pump new basal profile
PumpEnactResult setNewBasalProfile(Profile profile);
+
boolean isThisProfileSet(Profile profile);
long lastDataTime();
@@ -42,18 +54,29 @@ public interface PumpInterface {
int getBatteryLevel(); // in percent as integer
PumpEnactResult deliverTreatment(DetailedBolusInfo detailedBolusInfo);
+
void stopBolusDelivering();
+
PumpEnactResult setTempBasalAbsolute(Double absoluteRate, Integer durationInMinutes, Profile profile, boolean enforceNew);
+
PumpEnactResult setTempBasalPercent(Integer percent, Integer durationInMinutes, Profile profile, boolean enforceNew);
+
PumpEnactResult setExtendedBolus(Double insulin, Integer durationInMinutes);
+
//some pumps might set a very short temp close to 100% as cancelling a temp can be noisy
//when the cancel request is requested by the user (forced), the pump should always do a real cancel
PumpEnactResult cancelTempBasal(boolean enforceNew);
+
PumpEnactResult cancelExtendedBolus();
// Status to be passed to NS
JSONObject getJSONStatus(Profile profile, String profileName);
- String deviceID();
+
+ ManufacturerType manufacturer();
+
+ PumpType model();
+
+ String serialNumber();
// Pump capabilities
PumpDescription getPumpDescription();
@@ -65,10 +88,22 @@ public interface PumpInterface {
PumpEnactResult loadTDDs();
- public boolean canHandleDST();
+ boolean canHandleDST();
List getCustomActions();
void executeCustomAction(CustomActionType customActionType);
+ /**
+ * This method will be called when time or Timezone changes, and pump driver can then do a specific action (for
+ * example update clock on pump).
+ * @param timeChangeType
+ */
+ void timezoneOrDSTChanged(TimeChangeType timeChangeType);
+
+ /* Only used for pump types where hasCustomUnreachableAlertCheck=true */
+ default boolean isUnreachableAlertTimeoutExceeded(long alertTimeoutMilliseconds) {
+ return false;
+ }
+
}
diff --git a/app/src/main/java/info/nightscout/androidaps/interfaces/TreatmentsInterface.java b/app/src/main/java/info/nightscout/androidaps/interfaces/TreatmentsInterface.java
index 0ef71dac2a7..cbdd5d696a3 100644
--- a/app/src/main/java/info/nightscout/androidaps/interfaces/TreatmentsInterface.java
+++ b/app/src/main/java/info/nightscout/androidaps/interfaces/TreatmentsInterface.java
@@ -5,6 +5,7 @@
import info.nightscout.androidaps.data.DetailedBolusInfo;
import info.nightscout.androidaps.data.IobTotal;
import info.nightscout.androidaps.data.MealData;
+import info.nightscout.androidaps.data.NonOverlappingIntervals;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.db.ExtendedBolus;
import info.nightscout.androidaps.db.ProfileSwitch;
@@ -25,12 +26,13 @@ public interface TreatmentsInterface {
IobTotal getLastCalculationTreatments();
IobTotal getCalculationToTimeTreatments(long time);
IobTotal getLastCalculationTempBasals();
- IobTotal getCalculationToTimeTempBasals(long time, Profile profile);
+ IobTotal getCalculationToTimeTempBasals(long time);
MealData getMealData();
List getTreatmentsFromHistory();
- List getTreatments5MinBackFromHistory(long time);
+ List getCarbTreatments5MinBackFromHistory(long time);
+ List getTreatmentsFromHistoryAfterTimestamp(long timestamp);
long getLastBolusTime();
// real basals (not faked by extended bolus)
@@ -42,7 +44,7 @@ public interface TreatmentsInterface {
// basal that can be faked by extended boluses
boolean isTempBasalInProgress();
TemporaryBasal getTempBasalFromHistory(long time);
- Intervals getTemporaryBasalsFromHistory();
+ NonOverlappingIntervals getTemporaryBasalsFromHistory();
boolean isInHistoryExtendedBoluslInProgress();
ExtendedBolus getExtendedBolusFromHistory(long time);
@@ -63,4 +65,4 @@ public interface TreatmentsInterface {
long oldestDataAvailable();
-}
+}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/logging/L.java b/app/src/main/java/info/nightscout/androidaps/logging/L.java
index f685bbd4247..25b6750844f 100644
--- a/app/src/main/java/info/nightscout/androidaps/logging/L.java
+++ b/app/src/main/java/info/nightscout/androidaps/logging/L.java
@@ -77,6 +77,7 @@ public static void resetToDefaults() {
public static final String CORE = "CORE";
public static final String AUTOSENS = "AUTOSENS";
+ public static final String AUTOMATION = "AUTOMATION";
public static final String EVENTS = "EVENTS";
public static final String GLUCOSE = "GLUCOSE";
public static final String BGSOURCE = "BGSOURCE";
@@ -87,6 +88,7 @@ public static void resetToDefaults() {
public static final String DATAFOOD = "DATAFOOD";
public static final String DATATREATMENTS = "DATATREATMENTS";
public static final String NSCLIENT = "NSCLIENT";
+ public static final String TIDEPOOL = "TIDEPOOL";
public static final String CONSTRAINTS = "CONSTRAINTS";
public static final String PUMP = "PUMP";
public static final String PUMPQUEUE = "PUMPQUEUE";
@@ -96,11 +98,13 @@ public static void resetToDefaults() {
public static final String PROFILE = "PROFILE";
public static final String CONFIGBUILDER = "CONFIGBUILDER";
public static final String UI = "UI";
+ public static final String LOCATION = "LOCATION";
public static final String SMS = "SMS";
private static void initialize() {
logElements = new ArrayList<>();
logElements.add(new LogElement(APS, true));
+ logElements.add(new LogElement(AUTOMATION, true));
logElements.add(new LogElement(AUTOSENS, false));
logElements.add(new LogElement(BGSOURCE, true));
logElements.add(new LogElement(GLUCOSE, false));
@@ -112,8 +116,10 @@ private static void initialize() {
logElements.add(new LogElement(DATASERVICE, true));
logElements.add(new LogElement(DATATREATMENTS, true));
logElements.add(new LogElement(EVENTS, false, true));
+ logElements.add(new LogElement(LOCATION, true));
logElements.add(new LogElement(NOTIFICATION, true));
logElements.add(new LogElement(NSCLIENT, true));
+ logElements.add(new LogElement(TIDEPOOL, true));
logElements.add(new LogElement(OVERVIEW, true));
logElements.add(new LogElement(PROFILE, true));
logElements.add(new LogElement(PUMP, true));
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/APSResult.java b/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/APSResult.java
index b3b0c091d56..7e568af2d9c 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/APSResult.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/APSResult.java
@@ -247,7 +247,7 @@ public List getPredictions() {
}
}
} catch (JSONException e) {
- e.printStackTrace();
+ log.error("Unhandled exception", e);
}
return array;
}
@@ -280,7 +280,7 @@ public long getLatestPredictionsTime() {
}
}
} catch (JSONException e) {
- e.printStackTrace();
+ log.error("Unhandled exception", e);
}
return latest;
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/DeviceStatus.java b/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/DeviceStatus.java
index 69afe3d8e76..26d7359efef 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/DeviceStatus.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/DeviceStatus.java
@@ -381,13 +381,11 @@ public JSONObject mongoRecord() {
try {
if (device != null) record.put("device", device);
if (pump != null) record.put("pump", pump);
- if (suggested != null) {
- JSONObject openaps = new JSONObject();
- if (enacted != null) openaps.put("enacted", enacted);
- if (suggested != null) openaps.put("suggested", suggested);
- if (iob != null) openaps.put("iob", iob);
- record.put("openaps", openaps);
- }
+ JSONObject openaps = new JSONObject();
+ if (enacted != null) openaps.put("enacted", enacted);
+ if (suggested != null) openaps.put("suggested", suggested);
+ if (iob != null) openaps.put("iob", iob);
+ record.put("openaps", openaps);
if (uploaderBattery != 0) record.put("uploaderBattery", uploaderBattery);
if (created_at != null) record.put("created_at", created_at);
} catch (JSONException e) {
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/LoopFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/LoopFragment.java
deleted file mode 100644
index 951631eb0c5..00000000000
--- a/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/LoopFragment.java
+++ /dev/null
@@ -1,145 +0,0 @@
-package info.nightscout.androidaps.plugins.aps.loop;
-
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.text.Html;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.Button;
-import android.widget.TextView;
-
-import com.squareup.otto.Subscribe;
-
-import butterknife.BindView;
-import butterknife.ButterKnife;
-import butterknife.OnClick;
-import info.nightscout.androidaps.MainApp;
-import info.nightscout.androidaps.R;
-import info.nightscout.androidaps.interfaces.Constraint;
-import info.nightscout.androidaps.plugins.aps.loop.events.EventLoopSetLastRunGui;
-import info.nightscout.androidaps.plugins.aps.loop.events.EventLoopUpdateGui;
-import info.nightscout.androidaps.plugins.common.SubscriberFragment;
-import info.nightscout.androidaps.utils.FabricPrivacy;
-
-public class LoopFragment extends SubscriberFragment {
- @BindView(R.id.loop_run)
- Button runNowButton;
- @BindView(R.id.loop_lastrun)
- TextView lastRunView;
- @BindView(R.id.loop_lastenact)
- TextView lastEnactView;
- @BindView(R.id.loop_source)
- TextView sourceView;
- @BindView(R.id.loop_request)
- TextView requestView;
- @BindView(R.id.loop_constraintsprocessed)
- TextView constraintsProcessedView;
- @BindView(R.id.loop_constraints)
- TextView constraintsView;
- @BindView(R.id.loop_tbrsetbypump)
- TextView tbrSetByPumpView;
- @BindView(R.id.loop_smbsetbypump)
- TextView smbSetByPumpView;
-
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- try {
- View view = inflater.inflate(R.layout.loop_fragment, container, false);
- unbinder = ButterKnife.bind(this, view);
- return view;
- } catch (Exception e) {
- FabricPrivacy.logException(e);
- }
- return null;
- }
-
- @OnClick(R.id.loop_run)
- void onRunClick() {
- lastRunView.setText(MainApp.gs(R.string.executing));
- new Thread(() -> LoopPlugin.getPlugin().invoke("Loop button", true)).start();
- }
-
- @Subscribe
- public void onStatusEvent(final EventLoopUpdateGui ev) {
- updateGUI();
- }
-
- @Subscribe
- public void onStatusEvent(final EventLoopSetLastRunGui ev) {
- clearGUI();
- final Activity activity = getActivity();
- if (activity != null)
- activity.runOnUiThread(() -> {
- synchronized (LoopFragment.this) {
- if (lastRunView != null) lastRunView.setText(ev.text);
- }
- });
- }
-
-
- @Override
- protected void updateGUI() {
- Activity activity = getActivity();
- if (activity != null)
- activity.runOnUiThread(() -> {
- synchronized (LoopFragment.this) {
- if (!isBound()) return;
- LoopPlugin.LastRun lastRun = LoopPlugin.lastRun;
- if (lastRun != null) {
- requestView.setText(lastRun.request != null ? lastRun.request.toSpanned() : "");
- constraintsProcessedView.setText(lastRun.constraintsProcessed != null ? lastRun.constraintsProcessed.toSpanned() : "");
- sourceView.setText(lastRun.source != null ? lastRun.source : "");
- lastRunView.setText(lastRun.lastAPSRun != null && lastRun.lastAPSRun.getTime() != 0 ? lastRun.lastAPSRun.toLocaleString() : "");
- lastEnactView.setText(lastRun.lastEnact != null && lastRun.lastEnact.getTime() != 0 ? lastRun.lastEnact.toLocaleString() : "");
- tbrSetByPumpView.setText(lastRun.tbrSetByPump != null ? Html.fromHtml(lastRun.tbrSetByPump.toHtml()) : "");
- smbSetByPumpView.setText(lastRun.smbSetByPump != null ? Html.fromHtml(lastRun.smbSetByPump.toHtml()) : "");
-
- String constraints = "";
- if (lastRun.constraintsProcessed != null) {
- Constraint allConstraints = new Constraint<>(0d);
- if (lastRun.constraintsProcessed.rateConstraint != null)
- allConstraints.copyReasons(lastRun.constraintsProcessed.rateConstraint);
- if (lastRun.constraintsProcessed.smbConstraint != null)
- allConstraints.copyReasons(lastRun.constraintsProcessed.smbConstraint);
- constraints = allConstraints.getMostLimitedReasons();
- }
- constraintsView.setText(constraints);
- }
- }
- });
- }
-
- void clearGUI() {
- Activity activity = getActivity();
- if (activity != null)
- activity.runOnUiThread(() -> {
- synchronized (LoopFragment.this) {
- if (isBound()) {
- requestView.setText("");
- constraintsProcessedView.setText("");
- sourceView.setText("");
- lastRunView.setText("");
- lastEnactView.setText("");
- tbrSetByPumpView.setText("");
- smbSetByPumpView.setText("");
- }
- }
- });
- }
-
- boolean isBound() {
- return requestView != null
- && constraintsProcessedView != null
- && sourceView != null
- && lastRunView != null
- && lastEnactView != null
- && tbrSetByPumpView != null
- && smbSetByPumpView != null
- && constraintsView != null
- && runNowButton != null;
- }
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/LoopFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/LoopFragment.kt
new file mode 100644
index 00000000000..5625fd978fd
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/LoopFragment.kt
@@ -0,0 +1,115 @@
+package info.nightscout.androidaps.plugins.aps.loop
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.fragment.app.Fragment
+import info.nightscout.androidaps.MainApp
+import info.nightscout.androidaps.R
+import info.nightscout.androidaps.interfaces.Constraint
+import info.nightscout.androidaps.plugins.aps.loop.events.EventLoopSetLastRunGui
+import info.nightscout.androidaps.plugins.aps.loop.events.EventLoopUpdateGui
+import info.nightscout.androidaps.plugins.bus.RxBus
+import info.nightscout.androidaps.utils.DateUtil
+import info.nightscout.androidaps.utils.FabricPrivacy
+import info.nightscout.androidaps.utils.HtmlHelper
+import info.nightscout.androidaps.utils.SP
+import info.nightscout.androidaps.utils.plusAssign
+import io.reactivex.android.schedulers.AndroidSchedulers
+import io.reactivex.disposables.CompositeDisposable
+import kotlinx.android.synthetic.main.loop_fragment.*
+
+class LoopFragment : Fragment() {
+
+ private var disposable: CompositeDisposable = CompositeDisposable()
+
+ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
+ savedInstanceState: Bundle?): View? {
+ return inflater.inflate(R.layout.loop_fragment, container, false)
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+
+ loop_run.setOnClickListener {
+ loop_lastrun.text = MainApp.gs(R.string.executing)
+ Thread { LoopPlugin.getPlugin().invoke("Loop button", true) }.start()
+ }
+ }
+
+ @Synchronized
+ override fun onResume() {
+ super.onResume()
+ disposable += RxBus
+ .toObservable(EventLoopUpdateGui::class.java)
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe({
+ updateGUI()
+ }, {
+ FabricPrivacy.logException(it)
+ })
+
+ disposable += RxBus
+ .toObservable(EventLoopSetLastRunGui::class.java)
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe({
+ clearGUI()
+ loop_lastrun?.text = it.text
+ }, { FabricPrivacy.logException(it) })
+
+ updateGUI()
+ SP.putBoolean(R.string.key_objectiveuseloop, true)
+ }
+
+ @Synchronized
+ override fun onPause() {
+ super.onPause()
+ disposable.clear()
+ }
+
+ @Synchronized
+ fun updateGUI() {
+ if (loop_request == null) return
+ LoopPlugin.lastRun?.let {
+ loop_request?.text = it.request?.toSpanned() ?: ""
+ loop_constraintsprocessed?.text = it.constraintsProcessed?.toSpanned() ?: ""
+ loop_source?.text = it.source ?: ""
+ loop_lastrun?.text = it.lastAPSRun?.let { lastRun -> DateUtil.dateAndTimeString(lastRun.time) }
+ ?: ""
+ loop_smbrequest_time?.text = DateUtil.dateAndTimeAndSecondsString(it.lastSMBRequest)
+ loop_smbexecution_time?.text = DateUtil.dateAndTimeAndSecondsString(it.lastSMBEnact)
+ loop_tbrrequest_time?.text = DateUtil.dateAndTimeAndSecondsString(it.lastTBRRequest)
+ loop_tbrexecution_time?.text = DateUtil.dateAndTimeAndSecondsString(it.lastTBREnact)
+
+ loop_tbrsetbypump?.text = it.tbrSetByPump?.let { tbrSetByPump -> HtmlHelper.fromHtml(tbrSetByPump.toHtml()) }
+ ?: ""
+ loop_smbsetbypump?.text = it.smbSetByPump?.let { smbSetByPump -> HtmlHelper.fromHtml(smbSetByPump.toHtml()) }
+ ?: ""
+
+ val constraints =
+ it.constraintsProcessed?.let { constraintsProcessed ->
+ val allConstraints = Constraint(0.0)
+ constraintsProcessed.rateConstraint?.let { rateConstraint -> allConstraints.copyReasons(rateConstraint) }
+ constraintsProcessed.smbConstraint?.let { smbConstraint -> allConstraints.copyReasons(smbConstraint) }
+ allConstraints.mostLimitedReasons
+ } ?: ""
+ loop_constraints?.text = constraints
+ }
+ }
+
+ @Synchronized
+ private fun clearGUI() {
+ loop_request?.text = ""
+ loop_constraints?.text = ""
+ loop_constraintsprocessed?.text = ""
+ loop_source?.text = ""
+ loop_lastrun?.text = ""
+ loop_smbrequest_time?.text = ""
+ loop_smbexecution_time?.text = ""
+ loop_tbrrequest_time?.text = ""
+ loop_tbrexecution_time?.text = ""
+ loop_tbrsetbypump?.text = ""
+ loop_smbsetbypump?.text = ""
+ }
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/LoopPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/LoopPlugin.java
index 92378a1d6b5..4710cf9b642 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/LoopPlugin.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/LoopPlugin.java
@@ -10,11 +10,12 @@
import android.content.Intent;
import android.os.Build;
import android.os.SystemClock;
-import android.support.annotation.NonNull;
-import android.support.v4.app.NotificationCompat;
-import com.squareup.otto.Subscribe;
+import androidx.annotation.NonNull;
+import androidx.core.app.NotificationCompat;
+import org.json.JSONException;
+import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -47,26 +48,30 @@
import info.nightscout.androidaps.plugins.aps.loop.events.EventLoopSetLastRunGui;
import info.nightscout.androidaps.plugins.aps.loop.events.EventLoopUpdateGui;
import info.nightscout.androidaps.plugins.aps.loop.events.EventNewOpenLoopNotification;
+import info.nightscout.androidaps.plugins.bus.RxBus;
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions;
-import info.nightscout.androidaps.plugins.constraints.objectives.ObjectivesPlugin;
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload;
+import info.nightscout.androidaps.activities.ErrorHelperActivity;
import info.nightscout.androidaps.plugins.general.wear.ActionStringHandler;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventAutosensCalculationFinished;
import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin;
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
import info.nightscout.androidaps.queue.Callback;
import info.nightscout.androidaps.queue.commands.Command;
+import info.nightscout.androidaps.utils.DateUtil;
import info.nightscout.androidaps.utils.FabricPrivacy;
import info.nightscout.androidaps.utils.SP;
import info.nightscout.androidaps.utils.T;
-import info.nightscout.androidaps.utils.ToastUtils;
+import io.reactivex.disposables.CompositeDisposable;
+import io.reactivex.schedulers.Schedulers;
/**
* Created by mike on 05.08.2016.
*/
public class LoopPlugin extends PluginBase {
private static Logger log = LoggerFactory.getLogger(L.APS);
+ private CompositeDisposable disposable = new CompositeDisposable();
private static final String CHANNEL_ID = "AndroidAPS-Openloop";
@@ -82,9 +87,9 @@ public static LoopPlugin getPlugin() {
return loopPlugin;
}
- private long loopSuspendedTill = 0L; // end of manual loop suspend
- private boolean isSuperBolus = false;
- private boolean isDisconnected = false;
+ private long loopSuspendedTill; // end of manual loop suspend
+ private boolean isSuperBolus;
+ private boolean isDisconnected;
public class LastRun {
public APSResult request = null;
@@ -93,8 +98,11 @@ public class LastRun {
public PumpEnactResult smbSetByPump = null;
public String source = null;
public Date lastAPSRun = null;
- public Date lastEnact = null;
- public Date lastOpenModeAccept;
+ public long lastTBREnact = 0;
+ public long lastSMBEnact = 0;
+ public long lastTBRRequest = 0;
+ public long lastSMBRequest = 0;
+ public long lastOpenModeAccept;
}
static public LastRun lastRun = null;
@@ -115,9 +123,39 @@ public LoopPlugin() {
@Override
protected void onStart() {
- MainApp.bus().register(this);
createNotificationChannel();
super.onStart();
+ disposable.add(RxBus.INSTANCE
+ .toObservable(EventTempTargetChange.class)
+ .observeOn(Schedulers.io())
+ .subscribe(event -> {
+ invoke("EventTempTargetChange", true);
+ }, FabricPrivacy::logException)
+ );
+ /**
+ * This method is triggered once autosens calculation has completed, so the LoopPlugin
+ * has current data to work with. However, autosens calculation can be triggered by multiple
+ * sources and currently only a new BG should trigger a loop run. Hence we return early if
+ * the event causing the calculation is not EventNewBg.
+ *
+ */
+ disposable.add(RxBus.INSTANCE
+ .toObservable(EventAutosensCalculationFinished.class)
+ .observeOn(Schedulers.io())
+ .subscribe(event -> {
+ // Autosens calculation not triggered by a new BG
+ if (!(event.getCause() instanceof EventNewBG)) return;
+
+ BgReading bgReading = DatabaseHelper.actualBg();
+ // BG outdated
+ if (bgReading == null) return;
+ // already looped with that value
+ if (bgReading.date <= lastBgTriggeredRun) return;
+
+ lastBgTriggeredRun = bgReading.date;
+ invoke("AutosenseCalculation for " + bgReading, true);
+ }, FabricPrivacy::logException)
+ );
}
private void createNotificationChannel() {
@@ -134,8 +172,8 @@ private void createNotificationChannel() {
@Override
protected void onStop() {
+ disposable.clear();
super.onStop();
- MainApp.bus().unregister(this);
}
@Override
@@ -144,43 +182,10 @@ public boolean specialEnableCondition() {
return pump == null || pump.getPumpDescription().isTempBasalCapable;
}
- /**
- * This method is triggered once autosens calculation has completed, so the LoopPlugin
- * has current data to work with. However, autosens calculation can be triggered by multiple
- * sources and currently only a new BG should trigger a loop run. Hence we return early if
- * the event causing the calculation is not EventNewBg.
- *
- */
- @Subscribe
- public void onStatusEvent(final EventAutosensCalculationFinished ev) {
- if (!(ev.cause instanceof EventNewBG)) {
- // Autosens calculation not triggered by a new BG
- return;
- }
- BgReading bgReading = DatabaseHelper.actualBg();
- if (bgReading == null) {
- // BG outdated
- return;
- }
- if (bgReading.date <= lastBgTriggeredRun) {
- // already looped with that value
- return;
- }
-
- lastBgTriggeredRun = bgReading.date;
- invoke("AutosenseCalculation for " + bgReading, true);
- }
-
public long suspendedTo() {
return loopSuspendedTill;
}
- @Subscribe
- public void onStatusEvent(final EventTempTargetChange ev) {
- new Thread(() -> invoke("EventTempTargetChange", true)).start();
- }
-
-
public void suspendTo(long endTime) {
loopSuspendedTill = endTime;
isSuperBolus = false;
@@ -278,7 +283,7 @@ public synchronized void invoke(String initiator, boolean allowNotification, boo
String message = MainApp.gs(R.string.loopdisabled) + "\n" + loopEnabled.getReasons();
if (L.isEnabled(L.APS))
log.debug(message);
- MainApp.bus().post(new EventLoopSetLastRunGui(message));
+ RxBus.INSTANCE.send(new EventLoopSetLastRunGui(message));
return;
}
final PumpInterface pump = ConfigBuilderPlugin.getPlugin().getActivePump();
@@ -289,10 +294,10 @@ public synchronized void invoke(String initiator, boolean allowNotification, boo
Profile profile = ProfileFunctions.getInstance().getProfile();
- if (!ProfileFunctions.getInstance().isProfileValid("Loop")) {
+ if (profile == null || !ProfileFunctions.getInstance().isProfileValid("Loop")) {
if (L.isEnabled(L.APS))
log.debug(MainApp.gs(R.string.noprofileselected));
- MainApp.bus().post(new EventLoopSetLastRunGui(MainApp.gs(R.string.noprofileselected)));
+ RxBus.INSTANCE.send(new EventLoopSetLastRunGui(MainApp.gs(R.string.noprofileselected)));
return;
}
@@ -307,7 +312,7 @@ public synchronized void invoke(String initiator, boolean allowNotification, boo
// Check if we have any result
if (result == null) {
- MainApp.bus().post(new EventLoopSetLastRunGui(MainApp.gs(R.string.noapsselected)));
+ RxBus.INSTANCE.send(new EventLoopSetLastRunGui(MainApp.gs(R.string.noapsselected)));
return;
}
@@ -343,20 +348,24 @@ public synchronized void invoke(String initiator, boolean allowNotification, boo
lastRun.source = ((PluginBase) usedAPS).getName();
lastRun.tbrSetByPump = null;
lastRun.smbSetByPump = null;
+ lastRun.lastTBREnact = 0;
+ lastRun.lastTBRRequest = 0;
+ lastRun.lastSMBEnact = 0;
+ lastRun.lastSMBRequest = 0;
NSUpload.uploadDeviceStatus();
if (isSuspended()) {
if (L.isEnabled(L.APS))
log.debug(MainApp.gs(R.string.loopsuspended));
- MainApp.bus().post(new EventLoopSetLastRunGui(MainApp.gs(R.string.loopsuspended)));
+ RxBus.INSTANCE.send(new EventLoopSetLastRunGui(MainApp.gs(R.string.loopsuspended)));
return;
}
if (pump.isSuspended()) {
if (L.isEnabled(L.APS))
log.debug(MainApp.gs(R.string.pumpsuspended));
- MainApp.bus().post(new EventLoopSetLastRunGui(MainApp.gs(R.string.pumpsuspended)));
+ RxBus.INSTANCE.send(new EventLoopSetLastRunGui(MainApp.gs(R.string.pumpsuspended)));
return;
}
@@ -372,32 +381,35 @@ public synchronized void invoke(String initiator, boolean allowNotification, boo
lastRun.tbrSetByPump = waiting;
if (resultAfterConstraints.bolusRequested)
lastRun.smbSetByPump = waiting;
- MainApp.bus().post(new EventLoopUpdateGui());
+ RxBus.INSTANCE.send(new EventLoopUpdateGui());
FabricPrivacy.getInstance().logCustom("APSRequest");
applyTBRRequest(resultAfterConstraints, profile, new Callback() {
@Override
public void run() {
if (result.enacted || result.success) {
lastRun.tbrSetByPump = result;
- lastRun.lastEnact = lastRun.lastAPSRun;
+ lastRun.lastTBRRequest = lastRun.lastAPSRun.getTime();
+ lastRun.lastTBREnact = DateUtil.now();
+ RxBus.INSTANCE.send(new EventLoopUpdateGui());
applySMBRequest(resultAfterConstraints, new Callback() {
@Override
public void run() {
//Callback is only called if a bolus was acutally requested
if (result.enacted || result.success) {
lastRun.smbSetByPump = result;
- lastRun.lastEnact = lastRun.lastAPSRun;
+ lastRun.lastSMBRequest = lastRun.lastAPSRun.getTime();
+ lastRun.lastSMBEnact = DateUtil.now();
} else {
new Thread(() -> {
SystemClock.sleep(1000);
LoopPlugin.getPlugin().invoke("tempBasalFallback", allowNotification, true);
}).start();
}
- MainApp.bus().post(new EventLoopUpdateGui());
+ RxBus.INSTANCE.send(new EventLoopUpdateGui());
}
});
}
- MainApp.bus().post(new EventLoopUpdateGui());
+ RxBus.INSTANCE.send(new EventLoopUpdateGui());
}
});
} else {
@@ -414,7 +426,7 @@ public void run() {
.setAutoCancel(true)
.setPriority(Notification.PRIORITY_HIGH)
.setCategory(Notification.CATEGORY_ALARM)
- .setVisibility(Notification.VISIBILITY_PUBLIC);
+ .setVisibility(NotificationCompat.VISIBILITY_PUBLIC);
if (SP.getBoolean("wearcontrol", false)) {
builder.setLocalOnly(true);
}
@@ -438,7 +450,7 @@ public void run() {
(NotificationManager) MainApp.instance().getSystemService(Context.NOTIFICATION_SERVICE);
// mId allows you to update the notification later on.
mNotificationManager.notify(Constants.notificationID, builder.build());
- MainApp.bus().post(new EventNewOpenLoopNotification());
+ RxBus.INSTANCE.send(new EventNewOpenLoopNotification());
// Send to Wear
ActionStringHandler.handleInitiate("changeRequest");
@@ -451,7 +463,7 @@ public void run() {
}
}
- MainApp.bus().post(new EventLoopUpdateGui());
+ RxBus.INSTANCE.send(new EventLoopUpdateGui());
} finally {
if (L.isEnabled(L.APS))
log.debug("invoke end");
@@ -466,16 +478,13 @@ public void acceptChangeRequest() {
public void run() {
if (result.enacted) {
lastRun.tbrSetByPump = result;
- lastRun.lastEnact = new Date();
- lastRun.lastOpenModeAccept = new Date();
+ lastRun.lastTBRRequest = lastRun.lastAPSRun.getTime();
+ lastRun.lastTBREnact = DateUtil.now();
+ lastRun.lastOpenModeAccept = DateUtil.now();
NSUpload.uploadDeviceStatus();
- ObjectivesPlugin objectivesPlugin = MainApp.getSpecificPlugin(ObjectivesPlugin.class);
- if (objectivesPlugin != null) {
- ObjectivesPlugin.getPlugin().manualEnacts++;
- ObjectivesPlugin.getPlugin().saveProgress();
- }
+ SP.incInt(R.string.key_ObjectivesmanualEnacts);
}
- MainApp.bus().post(new EventAcceptOpenLoopChange());
+ RxBus.INSTANCE.send(new EventAcceptOpenLoopChange());
}
});
FabricPrivacy.getInstance().logCustom("AcceptTemp");
@@ -644,25 +653,53 @@ public void disconnectPump(int durationInMinutes, Profile profile) {
TreatmentsInterface activeTreatments = TreatmentsPlugin.getPlugin();
LoopPlugin.getPlugin().disconnectTo(System.currentTimeMillis() + durationInMinutes * 60 * 1000L);
- ConfigBuilderPlugin.getPlugin().getCommandQueue().tempBasalPercent(0, durationInMinutes, true, profile, new Callback() {
- @Override
- public void run() {
- if (!result.success) {
- ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), MainApp.gs(R.string.tempbasaldeliveryerror));
+
+ if (pump.getPumpDescription().tempBasalStyle == PumpDescription.ABSOLUTE) {
+ ConfigBuilderPlugin.getPlugin().getCommandQueue().tempBasalAbsolute(0, durationInMinutes, true, profile, new Callback() {
+ @Override
+ public void run() {
+ if (!result.success) {
+ Intent i = new Intent(MainApp.instance(), ErrorHelperActivity.class);
+ i.putExtra("soundid", R.raw.boluserror);
+ i.putExtra("status", result.comment);
+ i.putExtra("title", MainApp.gs(R.string.tempbasaldeliveryerror));
+ i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ MainApp.instance().startActivity(i);
+ }
}
- }
- });
+ });
+ } else {
+ ConfigBuilderPlugin.getPlugin().getCommandQueue().tempBasalPercent(0, durationInMinutes, true, profile, new Callback() {
+ @Override
+ public void run() {
+ if (!result.success) {
+ Intent i = new Intent(MainApp.instance(), ErrorHelperActivity.class);
+ i.putExtra("soundid", R.raw.boluserror);
+ i.putExtra("status", result.comment);
+ i.putExtra("title", MainApp.gs(R.string.tempbasaldeliveryerror));
+ i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ MainApp.instance().startActivity(i);
+ }
+ }
+ });
+ }
+
if (pump.getPumpDescription().isExtendedBolusCapable && activeTreatments.isInHistoryExtendedBoluslInProgress()) {
ConfigBuilderPlugin.getPlugin().getCommandQueue().cancelExtended(new Callback() {
@Override
public void run() {
if (!result.success) {
- ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), MainApp.gs(R.string.extendedbolusdeliveryerror));
+ Intent i = new Intent(MainApp.instance(), ErrorHelperActivity.class);
+ i.putExtra("soundid", R.raw.boluserror);
+ i.putExtra("status", result.comment);
+ i.putExtra("title", MainApp.gs(R.string.extendedbolusdeliveryerror));
+ i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ MainApp.instance().startActivity(i);
}
}
});
}
- NSUpload.uploadOpenAPSOffline(durationInMinutes);
+ createOfflineEvent(durationInMinutes);
}
public void suspendLoop(int durationInMinutes) {
@@ -671,11 +708,32 @@ public void suspendLoop(int durationInMinutes) {
@Override
public void run() {
if (!result.success) {
- ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), MainApp.gs(R.string.tempbasaldeliveryerror));
+ Intent i = new Intent(MainApp.instance(), ErrorHelperActivity.class);
+ i.putExtra("soundid", R.raw.boluserror);
+ i.putExtra("status", result.comment);
+ i.putExtra("title", MainApp.gs(R.string.tempbasaldeliveryerror));
+ i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ MainApp.instance().startActivity(i);
}
}
});
- NSUpload.uploadOpenAPSOffline(durationInMinutes);
+ createOfflineEvent(durationInMinutes);
}
+ public void createOfflineEvent(int durationInMinutes) {
+ JSONObject data = new JSONObject();
+ try {
+ data.put("eventType", CareportalEvent.OPENAPSOFFLINE);
+ data.put("duration", durationInMinutes);
+ } catch (JSONException e) {
+ log.error("Unhandled exception", e);
+ }
+ CareportalEvent event = new CareportalEvent();
+ event.date = DateUtil.now();
+ event.source = Source.USER;
+ event.eventType = CareportalEvent.OPENAPSOFFLINE;
+ event.json = data.toString();
+ MainApp.getDbHelper().createOrUpdate(event);
+ NSUpload.uploadOpenAPSOffline(event);
+ }
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/events/EventLoopSetLastRunGui.java b/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/events/EventLoopSetLastRunGui.java
deleted file mode 100644
index 0d2a45f5280..00000000000
--- a/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/events/EventLoopSetLastRunGui.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package info.nightscout.androidaps.plugins.aps.loop.events;
-
-import info.nightscout.androidaps.events.EventUpdateGui;
-
-/**
- * Created by mike on 05.08.2016.
- */
-public class EventLoopSetLastRunGui extends EventUpdateGui {
- public String text = null;
-
- public EventLoopSetLastRunGui(String text) {
- this.text = text;
- }
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/events/EventLoopSetLastRunGui.kt b/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/events/EventLoopSetLastRunGui.kt
new file mode 100644
index 00000000000..19c7e92c5ce
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/events/EventLoopSetLastRunGui.kt
@@ -0,0 +1,8 @@
+package info.nightscout.androidaps.plugins.aps.loop.events
+
+import info.nightscout.androidaps.events.EventUpdateGui
+
+/**
+ * Created by mike on 05.08.2016.
+ */
+class EventLoopSetLastRunGui(val text: String) : EventUpdateGui()
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/events/EventLoopUpdateGui.java b/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/events/EventLoopUpdateGui.java
deleted file mode 100644
index f746dfb0a09..00000000000
--- a/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/events/EventLoopUpdateGui.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package info.nightscout.androidaps.plugins.aps.loop.events;
-
-import info.nightscout.androidaps.events.EventUpdateGui;
-
-/**
- * Created by mike on 05.08.2016.
- */
-public class EventLoopUpdateGui extends EventUpdateGui {
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/events/EventLoopUpdateGui.kt b/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/events/EventLoopUpdateGui.kt
new file mode 100644
index 00000000000..89507d85f81
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/events/EventLoopUpdateGui.kt
@@ -0,0 +1,8 @@
+package info.nightscout.androidaps.plugins.aps.loop.events
+
+import info.nightscout.androidaps.events.EventUpdateGui
+
+/**
+ * Created by mike on 05.08.2016.
+ */
+class EventLoopUpdateGui : EventUpdateGui()
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/events/EventNewOpenLoopNotification.java b/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/events/EventNewOpenLoopNotification.java
deleted file mode 100644
index 6a0a4dc0cf9..00000000000
--- a/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/events/EventNewOpenLoopNotification.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package info.nightscout.androidaps.plugins.aps.loop.events;
-
-import info.nightscout.androidaps.events.Event;
-
-/**
- * Created by mike on 07.08.2016.
- */
-public class EventNewOpenLoopNotification extends Event {
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/events/EventNewOpenLoopNotification.kt b/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/events/EventNewOpenLoopNotification.kt
new file mode 100644
index 00000000000..2933318dd62
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/events/EventNewOpenLoopNotification.kt
@@ -0,0 +1,5 @@
+package info.nightscout.androidaps.plugins.aps.loop.events
+
+import info.nightscout.androidaps.events.Event
+
+class EventNewOpenLoopNotification : Event()
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSAMA/DetermineBasalAdapterAMAJS.java b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSAMA/DetermineBasalAdapterAMAJS.java
index 5b5c8cb63d2..9ea2d395671 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSAMA/DetermineBasalAdapterAMAJS.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSAMA/DetermineBasalAdapterAMAJS.java
@@ -16,10 +16,14 @@
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
+import java.nio.charset.StandardCharsets;
+
+import javax.annotation.Nullable;
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
+import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus;
import info.nightscout.androidaps.data.IobTotal;
import info.nightscout.androidaps.data.MealData;
@@ -59,6 +63,7 @@ public DetermineBasalAdapterAMAJS(ScriptReader scriptReader) {
mScriptReader = scriptReader;
}
+ @Nullable
public DetermineBasalResultAMA invoke() {
if (L.isEnabled(L.APS)) {
@@ -190,8 +195,6 @@ public void setData(Profile profile,
double autosensDataRatio,
boolean tempTargetSet) throws JSONException {
- String units = profile.getUnits();
-
mProfile = new JSONObject();
mProfile.put("max_iob", maxIob);
mProfile.put("dia", Math.min(profile.getDia(), 3d));
@@ -202,7 +205,7 @@ public void setData(Profile profile,
mProfile.put("max_bg", maxBg);
mProfile.put("target_bg", targetBg);
mProfile.put("carb_ratio", profile.getIc());
- mProfile.put("sens", Profile.toMgdl(profile.getIsf(), units));
+ mProfile.put("sens", profile.getIsfMgdl());
mProfile.put("max_daily_safety_multiplier", SP.getInt(R.string.key_openapsama_max_daily_safety_multiplier, 3));
mProfile.put("current_basal_safety_multiplier", SP.getDouble(R.string.key_openapsama_current_basal_safety_multiplier, 4d));
mProfile.put("skip_neutral_temps", true);
@@ -216,7 +219,7 @@ public void setData(Profile profile,
mProfile.put("min_5m_carbimpact", SP.getDouble(R.string.key_openapsama_min_5m_carbimpact, SMBDefaults.min_5m_carbimpact));
}
- if (units.equals(Constants.MMOL)) {
+ if (ProfileFunctions.getSystemUnits().equals(Constants.MMOL)) {
mProfile.put("out_units", "mmol/L");
}
@@ -277,7 +280,7 @@ private Object makeParamArray(JSONArray jsonArray, Context rhino, Scriptable sco
private String readFile(String filename) throws IOException {
byte[] bytes = mScriptReader.readFile(filename);
- String string = new String(bytes, "UTF-8");
+ String string = new String(bytes, StandardCharsets.UTF_8);
if (string.startsWith("#!/usr/bin/env node")) {
string = string.substring(20);
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSAMA/OpenAPSAMAFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSAMA/OpenAPSAMAFragment.java
deleted file mode 100644
index 0aadf52cbd2..00000000000
--- a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSAMA/OpenAPSAMAFragment.java
+++ /dev/null
@@ -1,134 +0,0 @@
-package info.nightscout.androidaps.plugins.aps.openAPSAMA;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.Button;
-import android.widget.TextView;
-
-import com.squareup.otto.Subscribe;
-
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import info.nightscout.androidaps.MainApp;
-import info.nightscout.androidaps.R;
-import info.nightscout.androidaps.logging.L;
-import info.nightscout.androidaps.plugins.aps.openAPSMA.events.EventOpenAPSUpdateGui;
-import info.nightscout.androidaps.plugins.aps.openAPSMA.events.EventOpenAPSUpdateResultGui;
-import info.nightscout.androidaps.plugins.common.SubscriberFragment;
-import info.nightscout.androidaps.utils.DateUtil;
-import info.nightscout.androidaps.utils.JSONFormatter;
-
-public class OpenAPSAMAFragment extends SubscriberFragment implements View.OnClickListener {
- private static Logger log = LoggerFactory.getLogger(L.APS);
-
- Button run;
- TextView lastRunView;
- TextView glucoseStatusView;
- TextView currentTempView;
- TextView iobDataView;
- TextView profileView;
- TextView mealDataView;
- TextView autosensDataView;
- TextView resultView;
- TextView scriptdebugView;
- TextView requestView;
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- View view = inflater.inflate(R.layout.openapsama_fragment, container, false);
-
- run = (Button) view.findViewById(R.id.openapsma_run);
- run.setOnClickListener(this);
- lastRunView = (TextView) view.findViewById(R.id.openapsma_lastrun);
- glucoseStatusView = (TextView) view.findViewById(R.id.openapsma_glucosestatus);
- currentTempView = (TextView) view.findViewById(R.id.openapsma_currenttemp);
- iobDataView = (TextView) view.findViewById(R.id.openapsma_iobdata);
- profileView = (TextView) view.findViewById(R.id.openapsma_profile);
- mealDataView = (TextView) view.findViewById(R.id.openapsma_mealdata);
- autosensDataView = (TextView) view.findViewById(R.id.openapsma_autosensdata);
- scriptdebugView = (TextView) view.findViewById(R.id.openapsma_scriptdebugdata);
- resultView = (TextView) view.findViewById(R.id.openapsma_result);
- requestView = (TextView) view.findViewById(R.id.openapsma_request);
-
- updateGUI();
- return view;
- }
-
- @Override
- public void onClick(View view) {
- switch (view.getId()) {
- case R.id.openapsma_run:
- OpenAPSAMAPlugin.getPlugin().invoke("OpenAPSAMA button", false);
- break;
- }
-
- }
-
- @Subscribe
- public void onStatusEvent(final EventOpenAPSUpdateGui ev) {
- updateGUI();
- }
-
- @Subscribe
- public void onStatusEvent(final EventOpenAPSUpdateResultGui ev) {
- updateResultGUI(ev.text);
- }
-
- @Override
- protected void updateGUI() {
- Activity activity = getActivity();
- if (activity != null)
- activity.runOnUiThread(() -> {
- DetermineBasalResultAMA lastAPSResult = OpenAPSAMAPlugin.getPlugin().lastAPSResult;
- if (lastAPSResult != null) {
- resultView.setText(JSONFormatter.format(lastAPSResult.json));
- requestView.setText(lastAPSResult.toSpanned());
- }
- DetermineBasalAdapterAMAJS determineBasalAdapterAMAJS = OpenAPSAMAPlugin.getPlugin().lastDetermineBasalAdapterAMAJS;
- if (determineBasalAdapterAMAJS != null) {
- glucoseStatusView.setText(JSONFormatter.format(determineBasalAdapterAMAJS.getGlucoseStatusParam()));
- currentTempView.setText(JSONFormatter.format(determineBasalAdapterAMAJS.getCurrentTempParam()));
- try {
- JSONArray iobArray = new JSONArray(determineBasalAdapterAMAJS.getIobDataParam());
- iobDataView.setText(String.format(MainApp.gs(R.string.array_of_elements), iobArray.length()) + "\n" + JSONFormatter.format(iobArray.getString(0)));
- } catch (JSONException e) {
- log.error("Unhandled exception", e);
- iobDataView.setText("JSONException");
- }
- profileView.setText(JSONFormatter.format(determineBasalAdapterAMAJS.getProfileParam()));
- mealDataView.setText(JSONFormatter.format(determineBasalAdapterAMAJS.getMealDataParam()));
- scriptdebugView.setText(determineBasalAdapterAMAJS.getScriptDebug());
- }
- if (OpenAPSAMAPlugin.getPlugin().lastAPSRun != 0) {
- lastRunView.setText(DateUtil.dateAndTimeFullString(OpenAPSAMAPlugin.getPlugin().lastAPSRun));
- }
- if (OpenAPSAMAPlugin.getPlugin().lastAutosensResult != null) {
- autosensDataView.setText(JSONFormatter.format(OpenAPSAMAPlugin.getPlugin().lastAutosensResult.json()));
- }
- });
- }
-
- void updateResultGUI(final String text) {
- Activity activity = getActivity();
- if (activity != null)
- activity.runOnUiThread(() -> {
- resultView.setText(text);
- glucoseStatusView.setText("");
- currentTempView.setText("");
- iobDataView.setText("");
- profileView.setText("");
- mealDataView.setText("");
- autosensDataView.setText("");
- scriptdebugView.setText("");
- requestView.setText("");
- lastRunView.setText("");
- });
- }
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSAMA/OpenAPSAMAFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSAMA/OpenAPSAMAFragment.kt
new file mode 100644
index 00000000000..94747a45976
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSAMA/OpenAPSAMAFragment.kt
@@ -0,0 +1,115 @@
+package info.nightscout.androidaps.plugins.aps.openAPSAMA
+
+import android.os.Bundle
+import android.text.TextUtils
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.fragment.app.Fragment
+import info.nightscout.androidaps.MainApp
+import info.nightscout.androidaps.R
+import info.nightscout.androidaps.logging.L
+import info.nightscout.androidaps.plugins.aps.openAPSMA.events.EventOpenAPSUpdateGui
+import info.nightscout.androidaps.plugins.aps.openAPSMA.events.EventOpenAPSUpdateResultGui
+import info.nightscout.androidaps.plugins.bus.RxBus
+import info.nightscout.androidaps.utils.DateUtil
+import info.nightscout.androidaps.utils.FabricPrivacy
+import info.nightscout.androidaps.utils.JSONFormatter
+import info.nightscout.androidaps.utils.plusAssign
+import io.reactivex.android.schedulers.AndroidSchedulers
+import io.reactivex.disposables.CompositeDisposable
+import kotlinx.android.synthetic.main.openapsama_fragment.*
+import org.json.JSONArray
+import org.json.JSONException
+import org.slf4j.LoggerFactory
+
+class OpenAPSAMAFragment : Fragment() {
+ private val log = LoggerFactory.getLogger(L.APS)
+ private var disposable: CompositeDisposable = CompositeDisposable()
+
+ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
+ savedInstanceState: Bundle?): View? {
+ return inflater.inflate(R.layout.openapsama_fragment, container, false)
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+
+ openapsma_run.setOnClickListener {
+ OpenAPSAMAPlugin.getPlugin().invoke("OpenAPSAMA button", false)
+ }
+ }
+
+ @Synchronized
+ override fun onResume() {
+ super.onResume()
+
+ disposable += RxBus
+ .toObservable(EventOpenAPSUpdateGui::class.java)
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe({
+ updateGUI()
+ }, {
+ FabricPrivacy.logException(it)
+ })
+ disposable += RxBus
+ .toObservable(EventOpenAPSUpdateResultGui::class.java)
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe({
+ updateResultGUI(it.text)
+ }, {
+ FabricPrivacy.logException(it)
+ })
+
+ updateGUI()
+ }
+
+ @Synchronized
+ override fun onPause() {
+ super.onPause()
+ disposable.clear()
+ }
+
+ @Synchronized
+ private fun updateGUI() {
+ if (openapsma_result == null) return
+ OpenAPSAMAPlugin.getPlugin().lastAPSResult?.let { lastAPSResult ->
+ openapsma_result.text = JSONFormatter.format(lastAPSResult.json)
+ openapsma_request.text = lastAPSResult.toSpanned()
+ }
+ OpenAPSAMAPlugin.getPlugin().lastDetermineBasalAdapterAMAJS?.let { determineBasalAdapterAMAJS ->
+ openapsma_glucosestatus.text = JSONFormatter.format(determineBasalAdapterAMAJS.glucoseStatusParam)
+ openapsma_currenttemp.text = JSONFormatter.format(determineBasalAdapterAMAJS.currentTempParam)
+ try {
+ val iobArray = JSONArray(determineBasalAdapterAMAJS.iobDataParam)
+ openapsma_iobdata.text = TextUtils.concat(String.format(MainApp.gs(R.string.array_of_elements), iobArray.length()) + "\n", JSONFormatter.format(iobArray.getString(0)))
+ } catch (e: JSONException) {
+ log.error("Unhandled exception", e)
+ openapsma_iobdata.text = "JSONException see log for details"
+ }
+
+ openapsma_profile.text = JSONFormatter.format(determineBasalAdapterAMAJS.profileParam)
+ openapsma_mealdata.text = JSONFormatter.format(determineBasalAdapterAMAJS.mealDataParam)
+ openapsma_scriptdebugdata.text = determineBasalAdapterAMAJS.scriptDebug
+ }
+ if (OpenAPSAMAPlugin.getPlugin().lastAPSRun != 0L) {
+ openapsma_lastrun.text = DateUtil.dateAndTimeFullString(OpenAPSAMAPlugin.getPlugin().lastAPSRun)
+ }
+ OpenAPSAMAPlugin.getPlugin().lastAutosensResult?.let {
+ openapsma_autosensdata.text = JSONFormatter.format(it.json())
+ }
+ }
+
+ private fun updateResultGUI(text: String) {
+ openapsma_result.text = text
+ openapsma_glucosestatus.text = ""
+ openapsma_currenttemp.text = ""
+ openapsma_iobdata.text = ""
+ openapsma_profile.text = ""
+ openapsma_mealdata.text = ""
+ openapsma_autosensdata.text = ""
+ openapsma_scriptdebugdata.text = ""
+ openapsma_request.text = ""
+ openapsma_lastrun.text = ""
+ }
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSAMA/OpenAPSAMAPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSAMA/OpenAPSAMAPlugin.java
index 1f7deebea42..49881c51586 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSAMA/OpenAPSAMAPlugin.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSAMA/OpenAPSAMAPlugin.java
@@ -6,7 +6,6 @@
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
-import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus;
import info.nightscout.androidaps.data.IobTotal;
import info.nightscout.androidaps.data.MealData;
import info.nightscout.androidaps.data.Profile;
@@ -17,17 +16,20 @@
import info.nightscout.androidaps.interfaces.PluginType;
import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.logging.L;
+import info.nightscout.androidaps.plugins.aps.loop.APSResult;
+import info.nightscout.androidaps.plugins.aps.loop.ScriptReader;
+import info.nightscout.androidaps.plugins.aps.openAPSMA.events.EventOpenAPSUpdateGui;
+import info.nightscout.androidaps.plugins.aps.openAPSMA.events.EventOpenAPSUpdateResultGui;
+import info.nightscout.androidaps.plugins.bus.RxBus;
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensData;
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.aps.loop.APSResult;
-import info.nightscout.androidaps.plugins.aps.loop.ScriptReader;
-import info.nightscout.androidaps.plugins.aps.openAPSMA.events.EventOpenAPSUpdateGui;
-import info.nightscout.androidaps.plugins.aps.openAPSMA.events.EventOpenAPSUpdateResultGui;
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;
import info.nightscout.androidaps.utils.Profiler;
import info.nightscout.androidaps.utils.Round;
@@ -99,32 +101,37 @@ public void invoke(String initiator, boolean tempBasalFallback) {
PumpInterface pump = ConfigBuilderPlugin.getPlugin().getActivePump();
if (profile == null) {
- MainApp.bus().post(new EventOpenAPSUpdateResultGui(MainApp.gs(R.string.noprofileselected)));
+ RxBus.INSTANCE.send(new EventOpenAPSUpdateResultGui(MainApp.gs(R.string.noprofileselected)));
if (L.isEnabled(L.APS))
log.debug(MainApp.gs(R.string.noprofileselected));
return;
}
+ if (pump == null) {
+ RxBus.INSTANCE.send(new EventOpenAPSUpdateResultGui(MainApp.gs(R.string.nopumpselected)));
+ if (L.isEnabled(L.APS))
+ log.debug(MainApp.gs(R.string.nopumpselected));
+ return;
+ }
+
if (!isEnabled(PluginType.APS)) {
- MainApp.bus().post(new EventOpenAPSUpdateResultGui(MainApp.gs(R.string.openapsma_disabled)));
+ RxBus.INSTANCE.send(new EventOpenAPSUpdateResultGui(MainApp.gs(R.string.openapsma_disabled)));
if (L.isEnabled(L.APS))
log.debug(MainApp.gs(R.string.openapsma_disabled));
return;
}
if (glucoseStatus == null) {
- MainApp.bus().post(new EventOpenAPSUpdateResultGui(MainApp.gs(R.string.openapsma_noglucosedata)));
+ RxBus.INSTANCE.send(new EventOpenAPSUpdateResultGui(MainApp.gs(R.string.openapsma_noglucosedata)));
if (L.isEnabled(L.APS))
log.debug(MainApp.gs(R.string.openapsma_noglucosedata));
return;
}
- String units = profile.getUnits();
-
double maxBasal = MainApp.getConstraintChecker().getMaxBasalAllowed(profile).value();
- double minBg = Profile.toMgdl(profile.getTargetLow(), units);
- double maxBg = Profile.toMgdl(profile.getTargetHigh(), units);
- double targetBg = Profile.toMgdl(profile.getTarget(), units);
+ double minBg = profile.getTargetLowMgdl();
+ double maxBg = profile.getTargetHighMgdl();
+ double targetBg = profile.getTargetMgdl();
minBg = Round.roundTo(minBg, 0.1d);
maxBg = Round.roundTo(maxBg, 0.1d);
@@ -160,9 +167,9 @@ public void invoke(String initiator, boolean tempBasalFallback) {
return;
if (!HardLimits.checkOnlyHardLimits(profile.getIcTimeFromMidnight(Profile.secondsFromMidnight()), "carbratio", HardLimits.MINIC, HardLimits.MAXIC))
return;
- if (!HardLimits.checkOnlyHardLimits(Profile.toMgdl(profile.getIsf(), units), "sens", HardLimits.MINISF, HardLimits.MAXISF))
+ if (!HardLimits.checkOnlyHardLimits(profile.getIsfMgdl(), "sens", HardLimits.MINISF, HardLimits.MAXISF))
return;
- if (!HardLimits.checkOnlyHardLimits(profile.getMaxDailyBasal(), "max_daily_basal", 0.05, HardLimits.maxBasal()))
+ if (!HardLimits.checkOnlyHardLimits(profile.getMaxDailyBasal(), "max_daily_basal", 0.02, HardLimits.maxBasal()))
return;
if (!HardLimits.checkOnlyHardLimits(pump.getBaseBasalRate(), "current_basal", 0.01, HardLimits.maxBasal()))
return;
@@ -171,7 +178,7 @@ public void invoke(String initiator, boolean tempBasalFallback) {
if (MainApp.getConstraintChecker().isAutosensModeEnabled().value()) {
AutosensData autosensData = IobCobCalculatorPlugin.getPlugin().getLastAutosensDataSynchronized("OpenAPSPlugin");
if (autosensData == null) {
- MainApp.bus().post(new EventOpenAPSUpdateResultGui(MainApp.gs(R.string.openaps_noasdata)));
+ RxBus.INSTANCE.send(new EventOpenAPSUpdateResultGui(MainApp.gs(R.string.openaps_noasdata)));
return;
}
lastAutosensResult = autosensData.autosensResult;
@@ -192,7 +199,8 @@ public void invoke(String initiator, boolean tempBasalFallback) {
isTempTarget
);
} catch (JSONException e) {
- log.error("Unable to set data: " + e.toString());
+ FabricPrivacy.logException(e);
+ return;
}
@@ -200,23 +208,31 @@ public void invoke(String initiator, boolean tempBasalFallback) {
if (L.isEnabled(L.APS))
Profiler.log(log, "AMA calculation", start);
// Fix bug determine basal
- if (determineBasalResultAMA.rate == 0d && determineBasalResultAMA.duration == 0 && !TreatmentsPlugin.getPlugin().isTempBasalInProgress())
- determineBasalResultAMA.tempBasalRequested = false;
+ if (determineBasalResultAMA == null) {
+ if (L.isEnabled(L.APS))
+ log.error("SMB calculation returned null");
+ lastDetermineBasalAdapterAMAJS = null;
+ lastAPSResult = null;
+ lastAPSRun = 0;
+ } else {
+ if (determineBasalResultAMA.rate == 0d && determineBasalResultAMA.duration == 0 && !TreatmentsPlugin.getPlugin().isTempBasalInProgress())
+ determineBasalResultAMA.tempBasalRequested = false;
- determineBasalResultAMA.iob = iobArray[0];
+ determineBasalResultAMA.iob = iobArray[0];
- long now = System.currentTimeMillis();
+ long now = System.currentTimeMillis();
- try {
- determineBasalResultAMA.json.put("timestamp", DateUtil.toISOString(now));
- } catch (JSONException e) {
- log.error("Unhandled exception", e);
- }
+ try {
+ determineBasalResultAMA.json.put("timestamp", DateUtil.toISOString(now));
+ } catch (JSONException e) {
+ log.error("Unhandled exception", e);
+ }
- lastDetermineBasalAdapterAMAJS = determineBasalAdapterAMAJS;
- lastAPSResult = determineBasalResultAMA;
- lastAPSRun = now;
- MainApp.bus().post(new EventOpenAPSUpdateGui());
+ lastDetermineBasalAdapterAMAJS = determineBasalAdapterAMAJS;
+ lastAPSResult = determineBasalResultAMA;
+ lastAPSRun = now;
+ }
+ RxBus.INSTANCE.send(new EventOpenAPSUpdateGui());
//deviceStatus.suggested = determineBasalResultAMA.json;
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSMA/DetermineBasalAdapterMAJS.java b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSMA/DetermineBasalAdapterMAJS.java
index ae1f390dedd..dbc7782ab33 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSMA/DetermineBasalAdapterMAJS.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSMA/DetermineBasalAdapterMAJS.java
@@ -14,9 +14,13 @@
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
+import java.nio.charset.StandardCharsets;
+
+import javax.annotation.Nullable;
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.R;
+import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus;
import info.nightscout.androidaps.data.IobTotal;
import info.nightscout.androidaps.data.MealData;
@@ -47,6 +51,7 @@ public class DetermineBasalAdapterMAJS {
mScriptReader = scriptReader;
}
+ @Nullable
public DetermineBasalResultMA invoke() {
DetermineBasalResultMA determineBasalResultMA = null;
@@ -156,8 +161,6 @@ public void setData(Profile profile,
GlucoseStatus glucoseStatus,
MealData mealData) throws JSONException {
- String units = profile.getUnits();
-
mProfile = new JSONObject();
mProfile.put("max_iob", maxIob);
mProfile.put("dia", Math.min(profile.getDia(), 3d));
@@ -168,11 +171,11 @@ public void setData(Profile profile,
mProfile.put("max_bg", maxBg);
mProfile.put("target_bg", targetBg);
mProfile.put("carb_ratio", profile.getIc());
- mProfile.put("sens", Profile.toMgdl(profile.getIsf(), units));
+ mProfile.put("sens", profile.getIsfMgdl());
mProfile.put("current_basal", basalRate);
- if (units.equals(Constants.MMOL)) {
+ if (ProfileFunctions.getSystemUnits().equals(Constants.MMOL)) {
mProfile.put("out_units", "mmol/L");
}
@@ -207,7 +210,7 @@ public void setData(Profile profile,
private String readFile(String filename) throws IOException {
byte[] bytes = mScriptReader.readFile(filename);
- String string = new String(bytes, "UTF-8");
+ String string = new String(bytes, StandardCharsets.UTF_8);
if (string.startsWith("#!/usr/bin/env node")) {
string = string.substring(20);
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSMA/LoggerCallback.java b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSMA/LoggerCallback.java
index 30ce388f5db..a2596d91740 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSMA/LoggerCallback.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSMA/LoggerCallback.java
@@ -36,16 +36,14 @@ public void jsConstructor() {
public void jsFunction_log(Object obj1) {
if (L.isEnabled(L.APS))
- log.debug(obj1.toString());
+ log.debug(obj1.toString().trim());
logBuffer.append(obj1.toString());
- logBuffer.append(' ');
}
public void jsFunction_error(Object obj1) {
if (L.isEnabled(L.APS))
- log.error(obj1.toString());
+ log.error(obj1.toString().trim());
errorBuffer.append(obj1.toString());
- errorBuffer.append(' ');
}
@@ -60,4 +58,4 @@ public static String getScriptDebug() {
}
return ret;
}
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSMA/OpenAPSMAFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSMA/OpenAPSMAFragment.java
deleted file mode 100644
index 5d632a44fc5..00000000000
--- a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSMA/OpenAPSMAFragment.java
+++ /dev/null
@@ -1,116 +0,0 @@
-package info.nightscout.androidaps.plugins.aps.openAPSMA;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.Button;
-import android.widget.TextView;
-
-import com.squareup.otto.Subscribe;
-
-import info.nightscout.androidaps.R;
-import info.nightscout.androidaps.plugins.aps.openAPSMA.events.EventOpenAPSUpdateGui;
-import info.nightscout.androidaps.plugins.aps.openAPSMA.events.EventOpenAPSUpdateResultGui;
-import info.nightscout.androidaps.plugins.common.SubscriberFragment;
-import info.nightscout.androidaps.utils.DateUtil;
-import info.nightscout.androidaps.utils.FabricPrivacy;
-import info.nightscout.androidaps.utils.JSONFormatter;
-
-public class OpenAPSMAFragment extends SubscriberFragment implements View.OnClickListener {
- Button run;
- TextView lastRunView;
- TextView glucoseStatusView;
- TextView currentTempView;
- TextView iobDataView;
- TextView profileView;
- TextView mealDataView;
- TextView resultView;
- TextView requestView;
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- try {
- View view = inflater.inflate(R.layout.openapsma_fragment, container, false);
-
- run = (Button) view.findViewById(R.id.openapsma_run);
- run.setOnClickListener(this);
- lastRunView = (TextView) view.findViewById(R.id.openapsma_lastrun);
- glucoseStatusView = (TextView) view.findViewById(R.id.openapsma_glucosestatus);
- currentTempView = (TextView) view.findViewById(R.id.openapsma_currenttemp);
- iobDataView = (TextView) view.findViewById(R.id.openapsma_iobdata);
- profileView = (TextView) view.findViewById(R.id.openapsma_profile);
- mealDataView = (TextView) view.findViewById(R.id.openapsma_mealdata);
- resultView = (TextView) view.findViewById(R.id.openapsma_result);
- requestView = (TextView) view.findViewById(R.id.openapsma_request);
-
- updateGUI();
- return view;
- } catch (Exception e) {
- FabricPrivacy.logException(e);
- }
-
- return null;
- }
-
- @Override
- public void onClick(View view) {
- switch (view.getId()) {
- case R.id.openapsma_run:
- OpenAPSMAPlugin.getPlugin().invoke("OpenAPSMA button", false);
- break;
- }
-
- }
-
- @Subscribe
- public void onStatusEvent(final EventOpenAPSUpdateGui ev) {
- updateGUI();
- }
-
- @Subscribe
- public void onStatusEvent(final EventOpenAPSUpdateResultGui ev) {
- updateResultGUI(ev.text);
- }
-
- @Override
- protected void updateGUI() {
- Activity activity = getActivity();
- if (activity != null)
- activity.runOnUiThread(() -> {
- DetermineBasalResultMA lastAPSResult = OpenAPSMAPlugin.getPlugin().lastAPSResult;
- if (lastAPSResult != null) {
- resultView.setText(JSONFormatter.format(lastAPSResult.json));
- requestView.setText(lastAPSResult.toSpanned());
- }
- DetermineBasalAdapterMAJS determineBasalAdapterMAJS = OpenAPSMAPlugin.getPlugin().lastDetermineBasalAdapterMAJS;
- if (determineBasalAdapterMAJS != null) {
- glucoseStatusView.setText(JSONFormatter.format(determineBasalAdapterMAJS.getGlucoseStatusParam()));
- currentTempView.setText(JSONFormatter.format(determineBasalAdapterMAJS.getCurrentTempParam()));
- iobDataView.setText(JSONFormatter.format(determineBasalAdapterMAJS.getIobDataParam()));
- profileView.setText(JSONFormatter.format(determineBasalAdapterMAJS.getProfileParam()));
- mealDataView.setText(JSONFormatter.format(determineBasalAdapterMAJS.getMealDataParam()));
- }
- if (OpenAPSMAPlugin.getPlugin().lastAPSRun != 0) {
- lastRunView.setText(DateUtil.dateAndTimeFullString(OpenAPSMAPlugin.getPlugin().lastAPSRun));
- }
- });
- }
-
- private void updateResultGUI(final String text) {
- Activity activity = getActivity();
- if (activity != null)
- activity.runOnUiThread(() -> {
- resultView.setText(text);
- glucoseStatusView.setText("");
- currentTempView.setText("");
- iobDataView.setText("");
- profileView.setText("");
- mealDataView.setText("");
- requestView.setText("");
- lastRunView.setText("");
- });
- }
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSMA/OpenAPSMAFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSMA/OpenAPSMAFragment.kt
new file mode 100644
index 00000000000..1b72f573651
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSMA/OpenAPSMAFragment.kt
@@ -0,0 +1,100 @@
+package info.nightscout.androidaps.plugins.aps.openAPSMA
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.fragment.app.Fragment
+import info.nightscout.androidaps.R
+import info.nightscout.androidaps.logging.L
+import info.nightscout.androidaps.plugins.aps.openAPSMA.events.EventOpenAPSUpdateGui
+import info.nightscout.androidaps.plugins.aps.openAPSMA.events.EventOpenAPSUpdateResultGui
+import info.nightscout.androidaps.plugins.bus.RxBus
+import info.nightscout.androidaps.utils.DateUtil
+import info.nightscout.androidaps.utils.FabricPrivacy
+import info.nightscout.androidaps.utils.JSONFormatter
+import info.nightscout.androidaps.utils.plusAssign
+import io.reactivex.android.schedulers.AndroidSchedulers
+import io.reactivex.disposables.CompositeDisposable
+import kotlinx.android.synthetic.main.openapsama_fragment.*
+import org.slf4j.LoggerFactory
+
+class OpenAPSMAFragment : Fragment() {
+ private val log = LoggerFactory.getLogger(L.APS)
+ private var disposable: CompositeDisposable = CompositeDisposable()
+
+ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
+ savedInstanceState: Bundle?): View? {
+ return inflater.inflate(R.layout.openapsma_fragment, container, false)
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+
+ openapsma_run.setOnClickListener {
+ OpenAPSMAPlugin.getPlugin().invoke("OpenAPSMA button", false)
+ }
+
+ }
+
+ @Synchronized
+ override fun onResume() {
+ super.onResume()
+
+ disposable += RxBus
+ .toObservable(EventOpenAPSUpdateGui::class.java)
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe({
+ updateGUI()
+ }, {
+ FabricPrivacy.logException(it)
+ })
+ disposable += RxBus
+ .toObservable(EventOpenAPSUpdateResultGui::class.java)
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe({
+ updateResultGUI(it.text)
+ }, {
+ FabricPrivacy.logException(it)
+ })
+ updateGUI()
+ }
+
+ @Synchronized
+ override fun onPause() {
+ super.onPause()
+ disposable.clear()
+ }
+
+ @Synchronized
+ private fun updateGUI() {
+ if (openapsma_result == null) return
+ OpenAPSMAPlugin.getPlugin().lastAPSResult?.let { lastAPSResult ->
+ openapsma_result.text = JSONFormatter.format(lastAPSResult.json)
+ openapsma_request.text = lastAPSResult.toSpanned()
+ }
+ OpenAPSMAPlugin.getPlugin().lastDetermineBasalAdapterMAJS?.let { determineBasalAdapterMAJS ->
+ openapsma_glucosestatus.text = JSONFormatter.format(determineBasalAdapterMAJS.glucoseStatusParam)
+ openapsma_currenttemp.text = JSONFormatter.format(determineBasalAdapterMAJS.currentTempParam)
+ openapsma_iobdata.text = JSONFormatter.format(determineBasalAdapterMAJS.iobDataParam)
+ openapsma_profile.text = JSONFormatter.format(determineBasalAdapterMAJS.profileParam)
+ openapsma_mealdata.text = JSONFormatter.format(determineBasalAdapterMAJS.mealDataParam)
+ }
+ if (OpenAPSMAPlugin.getPlugin().lastAPSRun != 0L) {
+ openapsma_lastrun.text = DateUtil.dateAndTimeString(OpenAPSMAPlugin.getPlugin().lastAPSRun)
+ }
+ }
+
+ @Synchronized
+ private fun updateResultGUI(text: String) {
+ if (openapsma_result == null) return
+ openapsma_result.text = text
+ openapsma_glucosestatus.text = ""
+ openapsma_currenttemp.text = ""
+ openapsma_iobdata.text = ""
+ openapsma_profile.text = ""
+ openapsma_mealdata.text = ""
+ openapsma_request.text = ""
+ openapsma_lastrun.text = ""
+ }
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSMA/OpenAPSMAPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSMA/OpenAPSMAPlugin.java
index 2dd78bdb825..0380156c74d 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSMA/OpenAPSMAPlugin.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSMA/OpenAPSMAPlugin.java
@@ -6,7 +6,6 @@
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
-import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus;
import info.nightscout.androidaps.data.IobTotal;
import info.nightscout.androidaps.data.MealData;
import info.nightscout.androidaps.data.Profile;
@@ -17,14 +16,17 @@
import info.nightscout.androidaps.interfaces.PluginType;
import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.logging.L;
-import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin;
-import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions;
import info.nightscout.androidaps.plugins.aps.loop.APSResult;
import info.nightscout.androidaps.plugins.aps.loop.ScriptReader;
import info.nightscout.androidaps.plugins.aps.openAPSMA.events.EventOpenAPSUpdateGui;
import info.nightscout.androidaps.plugins.aps.openAPSMA.events.EventOpenAPSUpdateResultGui;
+import info.nightscout.androidaps.plugins.bus.RxBus;
+import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin;
+import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions;
+import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus;
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;
import info.nightscout.androidaps.utils.Profiler;
import info.nightscout.androidaps.utils.Round;
@@ -98,33 +100,38 @@ public void invoke(String initiator, boolean tempBasalFallback) {
PumpInterface pump = ConfigBuilderPlugin.getPlugin().getActivePump();
if (profile == null) {
- MainApp.bus().post(new EventOpenAPSUpdateResultGui(MainApp.gs(R.string.noprofileselected)));
+ RxBus.INSTANCE.send(new EventOpenAPSUpdateResultGui(MainApp.gs(R.string.noprofileselected)));
if (L.isEnabled(L.APS))
log.debug(MainApp.gs(R.string.noprofileselected));
return;
}
+ if (pump == null) {
+ RxBus.INSTANCE.send(new EventOpenAPSUpdateResultGui(MainApp.gs(R.string.nopumpselected)));
+ if (L.isEnabled(L.APS))
+ log.debug(MainApp.gs(R.string.nopumpselected));
+ return;
+ }
+
if (!isEnabled(PluginType.APS)) {
- MainApp.bus().post(new EventOpenAPSUpdateResultGui(MainApp.gs(R.string.openapsma_disabled)));
+ RxBus.INSTANCE.send(new EventOpenAPSUpdateResultGui(MainApp.gs(R.string.openapsma_disabled)));
if (L.isEnabled(L.APS))
log.debug(MainApp.gs(R.string.openapsma_disabled));
return;
}
if (glucoseStatus == null) {
- MainApp.bus().post(new EventOpenAPSUpdateResultGui(MainApp.gs(R.string.openapsma_noglucosedata)));
+ RxBus.INSTANCE.send(new EventOpenAPSUpdateResultGui(MainApp.gs(R.string.openapsma_noglucosedata)));
if (L.isEnabled(L.APS))
log.debug(MainApp.gs(R.string.openapsma_noglucosedata));
return;
}
- String units = profile.getUnits();
-
double maxBasal = MainApp.getConstraintChecker().getMaxBasalAllowed(profile).value();
- double minBg = Profile.toMgdl(profile.getTargetLow(), units);
- double maxBg = Profile.toMgdl(profile.getTargetHigh(), units);
- double targetBg = Profile.toMgdl(profile.getTarget(), units);
+ double minBg = profile.getTargetLowMgdl();
+ double maxBg = profile.getTargetHighMgdl();
+ double targetBg = profile.getTargetMgdl();
minBg = Round.roundTo(minBg, 0.1d);
maxBg = Round.roundTo(maxBg, 0.1d);
@@ -158,9 +165,9 @@ public void invoke(String initiator, boolean tempBasalFallback) {
return;
if (!checkOnlyHardLimits(profile.getIcTimeFromMidnight(Profile.secondsFromMidnight()), "carbratio", HardLimits.MINIC, HardLimits.MAXIC))
return;
- if (!checkOnlyHardLimits(Profile.toMgdl(profile.getIsf(), units), "sens", HardLimits.MINISF, HardLimits.MAXISF))
+ if (!checkOnlyHardLimits(profile.getIsfMgdl(), "sens", HardLimits.MINISF, HardLimits.MAXISF))
return;
- if (!checkOnlyHardLimits(profile.getMaxDailyBasal(), "max_daily_basal", 0.05, HardLimits.maxBasal()))
+ if (!checkOnlyHardLimits(profile.getMaxDailyBasal(), "max_daily_basal", 0.02, HardLimits.maxBasal()))
return;
if (!checkOnlyHardLimits(pump.getBaseBasalRate(), "current_basal", 0.01, HardLimits.maxBasal()))
return;
@@ -169,7 +176,8 @@ public void invoke(String initiator, boolean tempBasalFallback) {
try {
determineBasalAdapterMAJS.setData(profile, maxIob, maxBasal, minBg, maxBg, targetBg, ConfigBuilderPlugin.getPlugin().getActivePump().getBaseBasalRate(), iobTotal, glucoseStatus, mealData);
} catch (JSONException e) {
- log.error("Unhandled exception", e);
+ FabricPrivacy.logException(e);
+ return;
}
if (L.isEnabled(L.APS))
Profiler.log(log, "MA calculation", start);
@@ -178,22 +186,30 @@ public void invoke(String initiator, boolean tempBasalFallback) {
long now = System.currentTimeMillis();
DetermineBasalResultMA determineBasalResultMA = determineBasalAdapterMAJS.invoke();
- // Fix bug determinef basal
- if (determineBasalResultMA.rate == 0d && determineBasalResultMA.duration == 0 && !TreatmentsPlugin.getPlugin().isTempBasalInProgress())
- determineBasalResultMA.tempBasalRequested = false;
-
- determineBasalResultMA.iob = iobTotal;
-
- try {
- determineBasalResultMA.json.put("timestamp", DateUtil.toISOString(now));
- } catch (JSONException e) {
- log.error("Unhandled exception", e);
+ if (determineBasalResultMA == null) {
+ if (L.isEnabled(L.APS))
+ log.error("MA calculation returned null");
+ lastDetermineBasalAdapterMAJS = null;
+ lastAPSResult = null;
+ lastAPSRun = 0;
+ } else {
+ // Fix bug determinef basal
+ if (determineBasalResultMA.rate == 0d && determineBasalResultMA.duration == 0 && !TreatmentsPlugin.getPlugin().isTempBasalInProgress())
+ determineBasalResultMA.tempBasalRequested = false;
+
+ determineBasalResultMA.iob = iobTotal;
+
+ try {
+ determineBasalResultMA.json.put("timestamp", DateUtil.toISOString(now));
+ } catch (JSONException e) {
+ log.error("Unhandled exception", e);
+ }
+
+ lastDetermineBasalAdapterMAJS = determineBasalAdapterMAJS;
+ lastAPSResult = determineBasalResultMA;
+ lastAPSRun = now;
}
-
- lastDetermineBasalAdapterMAJS = determineBasalAdapterMAJS;
- lastAPSResult = determineBasalResultMA;
- lastAPSRun = now;
- MainApp.bus().post(new EventOpenAPSUpdateGui());
+ RxBus.INSTANCE.send(new EventOpenAPSUpdateGui());
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSMA/events/EventOpenAPSUpdateGui.java b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSMA/events/EventOpenAPSUpdateGui.java
deleted file mode 100644
index de4292025df..00000000000
--- a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSMA/events/EventOpenAPSUpdateGui.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package info.nightscout.androidaps.plugins.aps.openAPSMA.events;
-
-import info.nightscout.androidaps.events.EventUpdateGui;
-
-/**
- * Created by mike on 05.08.2016.
- */
-public class EventOpenAPSUpdateGui extends EventUpdateGui {
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSMA/events/EventOpenAPSUpdateGui.kt b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSMA/events/EventOpenAPSUpdateGui.kt
new file mode 100644
index 00000000000..2b642c68807
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSMA/events/EventOpenAPSUpdateGui.kt
@@ -0,0 +1,5 @@
+package info.nightscout.androidaps.plugins.aps.openAPSMA.events
+
+import info.nightscout.androidaps.events.EventUpdateGui
+
+class EventOpenAPSUpdateGui : EventUpdateGui()
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSMA/events/EventOpenAPSUpdateResultGui.java b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSMA/events/EventOpenAPSUpdateResultGui.java
deleted file mode 100644
index fb5ea7e78f7..00000000000
--- a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSMA/events/EventOpenAPSUpdateResultGui.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package info.nightscout.androidaps.plugins.aps.openAPSMA.events;
-
-import info.nightscout.androidaps.events.EventUpdateGui;
-
-/**
- * Created by mike on 05.08.2016.
- */
-public class EventOpenAPSUpdateResultGui extends EventUpdateGui {
- public String text;
-
- public EventOpenAPSUpdateResultGui(String text) {
- this.text = text;
- }
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSMA/events/EventOpenAPSUpdateResultGui.kt b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSMA/events/EventOpenAPSUpdateResultGui.kt
new file mode 100644
index 00000000000..4ba02b87559
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSMA/events/EventOpenAPSUpdateResultGui.kt
@@ -0,0 +1,5 @@
+package info.nightscout.androidaps.plugins.aps.openAPSMA.events
+
+import info.nightscout.androidaps.events.EventUpdateGui
+
+class EventOpenAPSUpdateResultGui(val text: String) : EventUpdateGui()
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMB/DetermineBasalAdapterSMBJS.java b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMB/DetermineBasalAdapterSMBJS.java
index bfb75503c19..76571176d30 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMB/DetermineBasalAdapterSMBJS.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMB/DetermineBasalAdapterSMBJS.java
@@ -16,10 +16,14 @@
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
+import java.nio.charset.StandardCharsets;
+
+import javax.annotation.Nullable;
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
+import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus;
import info.nightscout.androidaps.data.IobTotal;
import info.nightscout.androidaps.data.MealData;
@@ -68,6 +72,7 @@ public class DetermineBasalAdapterSMBJS {
}
+ @Nullable
public DetermineBasalResultSMB invoke() {
@@ -215,8 +220,6 @@ public void setData(Profile profile,
boolean advancedFiltering
) throws JSONException {
- String units = profile.getUnits();
-
mProfile = new JSONObject();
mProfile.put("max_iob", maxIob);
@@ -228,7 +231,7 @@ public void setData(Profile profile,
mProfile.put("max_bg", maxBg);
mProfile.put("target_bg", targetBg);
mProfile.put("carb_ratio", profile.getIc());
- mProfile.put("sens", Profile.toMgdl(profile.getIsf(), units));
+ mProfile.put("sens", profile.getIsfMgdl());
mProfile.put("max_daily_safety_multiplier", SP.getInt(R.string.key_openapsama_max_daily_safety_multiplier, 3));
mProfile.put("current_basal_safety_multiplier", SP.getDouble(R.string.key_openapsama_current_basal_safety_multiplier, 4d));
@@ -269,7 +272,7 @@ public void setData(Profile profile,
mProfile.put("temptargetSet", tempTargetSet);
mProfile.put("autosens_max", SafeParse.stringToDouble(SP.getString(R.string.key_openapsama_autosens_max, "1.2")));
- if (units.equals(Constants.MMOL)) {
+ if (ProfileFunctions.getSystemUnits().equals(Constants.MMOL)) {
mProfile.put("out_units", "mmol/L");
}
@@ -340,7 +343,7 @@ private Object makeParamArray(JSONArray jsonArray, Context rhino, Scriptable sco
private String readFile(String filename) throws IOException {
byte[] bytes = mScriptReader.readFile(filename);
- String string = new String(bytes, "UTF-8");
+ String string = new String(bytes, StandardCharsets.UTF_8);
if (string.startsWith("#!/usr/bin/env node")) {
string = string.substring(20);
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMB/OpenAPSSMBFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMB/OpenAPSSMBFragment.java
deleted file mode 100644
index 18828e840e1..00000000000
--- a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMB/OpenAPSSMBFragment.java
+++ /dev/null
@@ -1,157 +0,0 @@
-package info.nightscout.androidaps.plugins.aps.openAPSSMB;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.Button;
-import android.widget.TextView;
-
-import com.squareup.otto.Subscribe;
-
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import butterknife.BindView;
-import butterknife.ButterKnife;
-import butterknife.OnClick;
-import info.nightscout.androidaps.MainApp;
-import info.nightscout.androidaps.R;
-import info.nightscout.androidaps.logging.L;
-import info.nightscout.androidaps.plugins.aps.openAPSMA.events.EventOpenAPSUpdateGui;
-import info.nightscout.androidaps.plugins.aps.openAPSMA.events.EventOpenAPSUpdateResultGui;
-import info.nightscout.androidaps.plugins.common.SubscriberFragment;
-import info.nightscout.androidaps.utils.DateUtil;
-import info.nightscout.androidaps.utils.JSONFormatter;
-
-public class OpenAPSSMBFragment extends SubscriberFragment {
- private static Logger log = LoggerFactory.getLogger(L.APS);
-
- @BindView(R.id.openapsma_run)
- Button run;
- @BindView(R.id.openapsma_lastrun)
- TextView lastRunView;
- @BindView(R.id.openapsma_constraints)
- TextView constraintsView;
- @BindView(R.id.openapsma_glucosestatus)
- TextView glucoseStatusView;
- @BindView(R.id.openapsma_currenttemp)
- TextView currentTempView;
- @BindView(R.id.openapsma_iobdata)
- TextView iobDataView;
- @BindView(R.id.openapsma_profile)
- TextView profileView;
- @BindView(R.id.openapsma_mealdata)
- TextView mealDataView;
- @BindView(R.id.openapsma_autosensdata)
- TextView autosensDataView;
- @BindView(R.id.openapsma_result)
- TextView resultView;
- @BindView(R.id.openapsma_scriptdebugdata)
- TextView scriptdebugView;
- @BindView(R.id.openapsma_request)
- TextView requestView;
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- View view = inflater.inflate(R.layout.openapsama_fragment, container, false);
-
- unbinder = ButterKnife.bind(this, view);
- return view;
- }
-
- @OnClick(R.id.openapsma_run)
- public void onRunClick() {
- OpenAPSSMBPlugin.getPlugin().invoke("OpenAPSSMB button", false);
- }
-
- @Subscribe
- public void onStatusEvent(final EventOpenAPSUpdateGui ev) {
- updateGUI();
- }
-
- @Subscribe
- public void onStatusEvent(final EventOpenAPSUpdateResultGui ev) {
- updateResultGUI(ev.text);
- }
-
- @Override
- protected void updateGUI() {
- Activity activity = getActivity();
- if (activity != null)
- activity.runOnUiThread(() -> {
- synchronized (OpenAPSSMBFragment.this) {
- if (!isBound()) return;
- OpenAPSSMBPlugin plugin = OpenAPSSMBPlugin.getPlugin();
- DetermineBasalResultSMB lastAPSResult = plugin.lastAPSResult;
- if (lastAPSResult != null) {
- resultView.setText(JSONFormatter.format(lastAPSResult.json));
- requestView.setText(lastAPSResult.toSpanned());
- }
- DetermineBasalAdapterSMBJS determineBasalAdapterSMBJS = plugin.lastDetermineBasalAdapterSMBJS;
- if (determineBasalAdapterSMBJS != null) {
- glucoseStatusView.setText(JSONFormatter.format(determineBasalAdapterSMBJS.getGlucoseStatusParam()).toString().trim());
- currentTempView.setText(JSONFormatter.format(determineBasalAdapterSMBJS.getCurrentTempParam()).toString().trim());
- try {
- JSONArray iobArray = new JSONArray(determineBasalAdapterSMBJS.getIobDataParam());
- iobDataView.setText((String.format(MainApp.gs(R.string.array_of_elements), iobArray.length()) + "\n" + JSONFormatter.format(iobArray.getString(0))).trim());
- } catch (JSONException e) {
- log.error("Unhandled exception", e);
- iobDataView.setText("JSONException see log for details");
- }
- profileView.setText(JSONFormatter.format(determineBasalAdapterSMBJS.getProfileParam()).toString().trim());
- mealDataView.setText(JSONFormatter.format(determineBasalAdapterSMBJS.getMealDataParam()).toString().trim());
- scriptdebugView.setText(determineBasalAdapterSMBJS.getScriptDebug().trim());
- if (lastAPSResult != null && lastAPSResult.inputConstraints != null)
- constraintsView.setText(lastAPSResult.inputConstraints.getReasons().trim());
- }
- if (plugin.lastAPSRun != 0) {
- lastRunView.setText(DateUtil.dateAndTimeFullString(plugin.lastAPSRun));
- }
- if (plugin.lastAutosensResult != null) {
- autosensDataView.setText(JSONFormatter.format(plugin.lastAutosensResult.json()).toString().trim());
- }
- }
- });
- }
-
- void updateResultGUI(final String text) {
- Activity activity = getActivity();
- if (activity != null)
- activity.runOnUiThread(() -> {
- synchronized (OpenAPSSMBFragment.this) {
- if (isBound()) {
- resultView.setText(text);
- glucoseStatusView.setText("");
- currentTempView.setText("");
- iobDataView.setText("");
- profileView.setText("");
- mealDataView.setText("");
- autosensDataView.setText("");
- scriptdebugView.setText("");
- requestView.setText("");
- lastRunView.setText("");
- }
- }
- });
- }
-
- private boolean isBound() {
- return run != null
- && lastRunView != null
- && constraintsView != null
- && glucoseStatusView != null
- && currentTempView != null
- && iobDataView != null
- && profileView != null
- && mealDataView != null
- && autosensDataView != null
- && resultView != null
- && scriptdebugView != null
- && requestView != null;
- }
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMB/OpenAPSSMBFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMB/OpenAPSSMBFragment.kt
new file mode 100644
index 00000000000..06ad0d01fd0
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMB/OpenAPSSMBFragment.kt
@@ -0,0 +1,122 @@
+package info.nightscout.androidaps.plugins.aps.openAPSSMB
+
+import android.annotation.SuppressLint
+import android.os.Bundle
+import android.text.TextUtils
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.fragment.app.Fragment
+import info.nightscout.androidaps.MainApp
+import info.nightscout.androidaps.R
+import info.nightscout.androidaps.logging.L
+import info.nightscout.androidaps.plugins.aps.openAPSMA.events.EventOpenAPSUpdateGui
+import info.nightscout.androidaps.plugins.aps.openAPSMA.events.EventOpenAPSUpdateResultGui
+import info.nightscout.androidaps.plugins.bus.RxBus
+import info.nightscout.androidaps.utils.DateUtil
+import info.nightscout.androidaps.utils.FabricPrivacy
+import info.nightscout.androidaps.utils.JSONFormatter
+import info.nightscout.androidaps.utils.plusAssign
+import io.reactivex.android.schedulers.AndroidSchedulers
+import io.reactivex.disposables.CompositeDisposable
+import kotlinx.android.synthetic.main.openapsama_fragment.*
+import org.json.JSONArray
+import org.json.JSONException
+import org.slf4j.LoggerFactory
+
+class OpenAPSSMBFragment : Fragment() {
+ private val log = LoggerFactory.getLogger(L.APS)
+ private var disposable: CompositeDisposable = CompositeDisposable()
+
+ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
+ savedInstanceState: Bundle?): View? {
+ return inflater.inflate(R.layout.openapsama_fragment, container, false)
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+
+ openapsma_run.setOnClickListener {
+ OpenAPSSMBPlugin.getPlugin().invoke("OpenAPSSMB button", false)
+ }
+ }
+
+ @Synchronized
+ override fun onResume() {
+ super.onResume()
+ disposable += RxBus
+ .toObservable(EventOpenAPSUpdateGui::class.java)
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe({
+ updateGUI()
+ }, {
+ FabricPrivacy.logException(it)
+ })
+ disposable += RxBus
+ .toObservable(EventOpenAPSUpdateResultGui::class.java)
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe({
+ updateResultGUI(it.text)
+ }, {
+ FabricPrivacy.logException(it)
+ })
+
+ updateGUI()
+ }
+
+ @Synchronized
+ override fun onPause() {
+ super.onPause()
+ disposable.clear()
+ }
+
+ @Synchronized
+ fun updateGUI() {
+ if (openapsma_result == null) return
+ val plugin = OpenAPSSMBPlugin.getPlugin()
+ plugin.lastAPSResult?.let { lastAPSResult ->
+ openapsma_result.text = JSONFormatter.format(lastAPSResult.json)
+ openapsma_request.text = lastAPSResult.toSpanned()
+ }
+ plugin.lastDetermineBasalAdapterSMBJS?.let { determineBasalAdapterSMBJS ->
+ openapsma_glucosestatus.text = JSONFormatter.format(determineBasalAdapterSMBJS.glucoseStatusParam)
+ openapsma_currenttemp.text = JSONFormatter.format(determineBasalAdapterSMBJS.currentTempParam)
+ try {
+ val iobArray = JSONArray(determineBasalAdapterSMBJS.iobDataParam)
+ openapsma_iobdata.text = TextUtils.concat(String.format(MainApp.gs(R.string.array_of_elements), iobArray.length()) + "\n", JSONFormatter.format(iobArray.getString(0)))
+ } catch (e: JSONException) {
+ log.error("Unhandled exception", e)
+ @SuppressLint("SetTextl18n")
+ openapsma_iobdata.text = "JSONException see log for details"
+ }
+
+ openapsma_profile.text = JSONFormatter.format(determineBasalAdapterSMBJS.profileParam)
+ openapsma_mealdata.text = JSONFormatter.format(determineBasalAdapterSMBJS.mealDataParam)
+ openapsma_scriptdebugdata.text = determineBasalAdapterSMBJS.scriptDebug
+ plugin.lastAPSResult?.inputConstraints?.let {
+ openapsma_constraints.text = it.reasons
+ }
+ }
+ if (plugin.lastAPSRun != 0L) {
+ openapsma_lastrun.text = DateUtil.dateAndTimeFullString(plugin.lastAPSRun)
+ }
+ plugin.lastAutosensResult?.let {
+ openapsma_autosensdata.text = JSONFormatter.format(it.json())
+ }
+ }
+
+ @Synchronized
+ private fun updateResultGUI(text: String) {
+ if (openapsma_result == null) return
+ openapsma_result.text = text
+ openapsma_glucosestatus.text = ""
+ openapsma_currenttemp.text = ""
+ openapsma_iobdata.text = ""
+ openapsma_profile.text = ""
+ openapsma_mealdata.text = ""
+ openapsma_autosensdata.text = ""
+ openapsma_scriptdebugdata.text = ""
+ openapsma_request.text = ""
+ openapsma_lastrun.text = ""
+ }
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMB/OpenAPSSMBPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMB/OpenAPSSMBPlugin.java
index 728e3145d61..426c04090b6 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMB/OpenAPSSMBPlugin.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMB/OpenAPSSMBPlugin.java
@@ -6,7 +6,6 @@
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
-import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus;
import info.nightscout.androidaps.data.IobTotal;
import info.nightscout.androidaps.data.MealData;
import info.nightscout.androidaps.data.Profile;
@@ -19,18 +18,21 @@
import info.nightscout.androidaps.interfaces.PluginType;
import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.logging.L;
+import info.nightscout.androidaps.plugins.aps.loop.APSResult;
+import info.nightscout.androidaps.plugins.aps.loop.ScriptReader;
+import info.nightscout.androidaps.plugins.aps.openAPSMA.events.EventOpenAPSUpdateGui;
+import info.nightscout.androidaps.plugins.aps.openAPSMA.events.EventOpenAPSUpdateResultGui;
+import info.nightscout.androidaps.plugins.bus.RxBus;
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions;
+import info.nightscout.androidaps.plugins.general.nsclient.NSUpload;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensData;
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.aps.loop.APSResult;
-import info.nightscout.androidaps.plugins.aps.loop.ScriptReader;
-import info.nightscout.androidaps.plugins.general.nsclient.NSUpload;
-import info.nightscout.androidaps.plugins.aps.openAPSMA.events.EventOpenAPSUpdateGui;
-import info.nightscout.androidaps.plugins.aps.openAPSMA.events.EventOpenAPSUpdateResultGui;
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;
import info.nightscout.androidaps.utils.Profiler;
import info.nightscout.androidaps.utils.Round;
@@ -103,47 +105,48 @@ public void invoke(String initiator, boolean tempBasalFallback) {
PumpInterface pump = ConfigBuilderPlugin.getPlugin().getActivePump();
if (profile == null) {
- MainApp.bus().post(new EventOpenAPSUpdateResultGui(MainApp.gs(R.string.noprofileselected)));
+ RxBus.INSTANCE.send(new EventOpenAPSUpdateResultGui(MainApp.gs(R.string.noprofileselected)));
if (L.isEnabled(L.APS))
log.debug(MainApp.gs(R.string.noprofileselected));
return;
}
+ if (pump == null) {
+ RxBus.INSTANCE.send(new EventOpenAPSUpdateResultGui(MainApp.gs(R.string.nopumpselected)));
+ if (L.isEnabled(L.APS))
+ log.debug(MainApp.gs(R.string.nopumpselected));
+ return;
+ }
+
if (!isEnabled(PluginType.APS)) {
- MainApp.bus().post(new EventOpenAPSUpdateResultGui(MainApp.gs(R.string.openapsma_disabled)));
+ RxBus.INSTANCE.send(new EventOpenAPSUpdateResultGui(MainApp.gs(R.string.openapsma_disabled)));
if (L.isEnabled(L.APS))
log.debug(MainApp.gs(R.string.openapsma_disabled));
return;
}
if (glucoseStatus == null) {
- MainApp.bus().post(new EventOpenAPSUpdateResultGui(MainApp.gs(R.string.openapsma_noglucosedata)));
+ RxBus.INSTANCE.send(new EventOpenAPSUpdateResultGui(MainApp.gs(R.string.openapsma_noglucosedata)));
if (L.isEnabled(L.APS))
log.debug(MainApp.gs(R.string.openapsma_noglucosedata));
return;
}
- String units = profile.getUnits();
-
Constraint inputConstraints = new Constraint<>(0d); // fake. only for collecting all results
Constraint maxBasalConstraint = MainApp.getConstraintChecker().getMaxBasalAllowed(profile);
inputConstraints.copyReasons(maxBasalConstraint);
double maxBasal = maxBasalConstraint.value();
- double minBg = Profile.toMgdl(profile.getTargetLow(), units);
- double maxBg = Profile.toMgdl(profile.getTargetHigh(), units);
- double targetBg = Profile.toMgdl(profile.getTarget(), units);
+ double minBg = profile.getTargetLowMgdl();
+ double maxBg = profile.getTargetHighMgdl();
+ double targetBg = profile.getTargetMgdl();
minBg = Round.roundTo(minBg, 0.1d);
maxBg = Round.roundTo(maxBg, 0.1d);
long start = System.currentTimeMillis();
long startPart = System.currentTimeMillis();
- IobTotal[] iobArray = IobCobCalculatorPlugin.getPlugin().calculateIobArrayForSMB(profile);
- if (L.isEnabled(L.APS))
- Profiler.log(log, "calculateIobArrayInDia()", startPart);
- startPart = System.currentTimeMillis();
MealData mealData = TreatmentsPlugin.getPlugin().getMealData();
if (L.isEnabled(L.APS))
Profiler.log(log, "getMealData()", startPart);
@@ -170,9 +173,9 @@ public void invoke(String initiator, boolean tempBasalFallback) {
return;
if (!checkOnlyHardLimits(profile.getIcTimeFromMidnight(Profile.secondsFromMidnight()), "carbratio", HardLimits.MINIC, HardLimits.MAXIC))
return;
- if (!checkOnlyHardLimits(Profile.toMgdl(profile.getIsf(), units), "sens", HardLimits.MINISF, HardLimits.MAXISF))
+ if (!checkOnlyHardLimits(profile.getIsfMgdl(), "sens", HardLimits.MINISF, HardLimits.MAXISF))
return;
- if (!checkOnlyHardLimits(profile.getMaxDailyBasal(), "max_daily_basal", 0.05, HardLimits.maxBasal()))
+ if (!checkOnlyHardLimits(profile.getMaxDailyBasal(), "max_daily_basal", 0.02, HardLimits.maxBasal()))
return;
if (!checkOnlyHardLimits(pump.getBaseBasalRate(), "current_basal", 0.01, HardLimits.maxBasal()))
return;
@@ -181,7 +184,7 @@ public void invoke(String initiator, boolean tempBasalFallback) {
if (MainApp.getConstraintChecker().isAutosensModeEnabled().value()) {
AutosensData autosensData = IobCobCalculatorPlugin.getPlugin().getLastAutosensDataSynchronized("OpenAPSPlugin");
if (autosensData == null) {
- MainApp.bus().post(new EventOpenAPSUpdateResultGui(MainApp.gs(R.string.openaps_noasdata)));
+ RxBus.INSTANCE.send(new EventOpenAPSUpdateResultGui(MainApp.gs(R.string.openaps_noasdata)));
return;
}
lastAutosensResult = autosensData.autosensResult;
@@ -190,6 +193,11 @@ public void invoke(String initiator, boolean tempBasalFallback) {
lastAutosensResult.sensResult = "autosens disabled";
}
+ IobTotal[] iobArray = IobCobCalculatorPlugin.getPlugin().calculateIobArrayForSMB(lastAutosensResult, SMBDefaults.exercise_mode, SMBDefaults.half_basal_exercise_target, isTempTarget);
+ if (L.isEnabled(L.APS))
+ Profiler.log(log, "calculateIobArrayInDia()", startPart);
+
+ startPart = System.currentTimeMillis();
Constraint smbAllowed = new Constraint<>(!tempBasalFallback);
MainApp.getConstraintChecker().isSMBModeEnabled(smbAllowed);
inputConstraints.copyReasons(smbAllowed);
@@ -217,7 +225,7 @@ public void invoke(String initiator, boolean tempBasalFallback) {
advancedFiltering.value()
);
} catch (JSONException e) {
- log.error(e.getMessage());
+ FabricPrivacy.logException(e);
return;
}
@@ -226,25 +234,33 @@ public void invoke(String initiator, boolean tempBasalFallback) {
DetermineBasalResultSMB determineBasalResultSMB = determineBasalAdapterSMBJS.invoke();
if (L.isEnabled(L.APS))
Profiler.log(log, "SMB calculation", start);
- // TODO still needed with oref1?
- // Fix bug determine basal
- if (determineBasalResultSMB.rate == 0d && determineBasalResultSMB.duration == 0 && !TreatmentsPlugin.getPlugin().isTempBasalInProgress())
- determineBasalResultSMB.tempBasalRequested = false;
+ if (determineBasalResultSMB == null) {
+ if (L.isEnabled(L.APS))
+ log.error("SMB calculation returned null");
+ lastDetermineBasalAdapterSMBJS = null;
+ lastAPSResult = null;
+ lastAPSRun = 0;
+ } else {
+ // TODO still needed with oref1?
+ // Fix bug determine basal
+ if (determineBasalResultSMB.rate == 0d && determineBasalResultSMB.duration == 0 && !TreatmentsPlugin.getPlugin().isTempBasalInProgress())
+ determineBasalResultSMB.tempBasalRequested = false;
- determineBasalResultSMB.iob = iobArray[0];
+ determineBasalResultSMB.iob = iobArray[0];
- try {
- determineBasalResultSMB.json.put("timestamp", DateUtil.toISOString(now));
- } catch (JSONException e) {
- log.error("Unhandled exception", e);
- }
+ try {
+ determineBasalResultSMB.json.put("timestamp", DateUtil.toISOString(now));
+ } catch (JSONException e) {
+ log.error("Unhandled exception", e);
+ }
- determineBasalResultSMB.inputConstraints = inputConstraints;
+ determineBasalResultSMB.inputConstraints = inputConstraints;
- lastDetermineBasalAdapterSMBJS = determineBasalAdapterSMBJS;
- lastAPSResult = determineBasalResultSMB;
- lastAPSRun = now;
- MainApp.bus().post(new EventOpenAPSUpdateGui());
+ lastDetermineBasalAdapterSMBJS = determineBasalAdapterSMBJS;
+ lastAPSResult = determineBasalResultSMB;
+ lastAPSRun = now;
+ }
+ RxBus.INSTANCE.send(new EventOpenAPSUpdateGui());
//deviceStatus.suggested = determineBasalResultAMA.json;
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/bus/RxBus.kt b/app/src/main/java/info/nightscout/androidaps/plugins/bus/RxBus.kt
new file mode 100644
index 00000000000..1774df14710
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/bus/RxBus.kt
@@ -0,0 +1,23 @@
+package info.nightscout.androidaps.plugins.bus
+
+import info.nightscout.androidaps.events.Event
+import io.reactivex.Observable
+import io.reactivex.schedulers.Schedulers
+import io.reactivex.subjects.PublishSubject
+
+// Use object so we have a singleton instance
+object RxBus {
+
+ private val publisher = PublishSubject.create()
+
+ fun send(event: Event) {
+ publisher.onNext(event)
+ }
+
+ // Listen should return an Observable and not the publisher
+ // Using ofType we filter only events that match that class type
+ fun toObservable(eventType: Class): Observable =
+ publisher
+ .subscribeOn(Schedulers.io())
+ .ofType(eventType)
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/common/ManufacturerType.java b/app/src/main/java/info/nightscout/androidaps/plugins/common/ManufacturerType.java
new file mode 100644
index 00000000000..0f61dd3320a
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/common/ManufacturerType.java
@@ -0,0 +1,27 @@
+package info.nightscout.androidaps.plugins.common;
+
+public enum ManufacturerType {
+
+ AndroidAPS("AndroidAPS"),
+ Medtronic("Medtronic"),
+ Sooil("SOOIL"),
+
+ Tandem("Tandem"),
+ Insulet("Insulet"),
+ Animas("Animas"), Cellnovo("Cellnovo"), Roche("Roche");
+
+
+
+ private String description;
+
+ ManufacturerType(String description) {
+
+ this.description = description;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/common/SubscriberFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/common/SubscriberFragment.java
deleted file mode 100644
index 3ac877b42d3..00000000000
--- a/app/src/main/java/info/nightscout/androidaps/plugins/common/SubscriberFragment.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package info.nightscout.androidaps.plugins.common;
-
-import android.support.v4.app.Fragment;
-
-import butterknife.Unbinder;
-import info.nightscout.androidaps.MainApp;
-
-abstract public class SubscriberFragment extends Fragment {
- protected Unbinder unbinder;
-
- @Override
- public void onPause() {
- super.onPause();
- MainApp.bus().unregister(this);
- }
-
- @Override
- public void onResume() {
- super.onResume();
- MainApp.bus().register(this);
- updateGUI();
- }
-
- @Override public synchronized void onDestroyView() {
- super.onDestroyView();
- if (unbinder != null)
- unbinder.unbind();
- }
-
-
- protected abstract void updateGUI();
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/configBuilder/ConfigBuilderFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/configBuilder/ConfigBuilderFragment.java
deleted file mode 100644
index 47b5d493574..00000000000
--- a/app/src/main/java/info/nightscout/androidaps/plugins/configBuilder/ConfigBuilderFragment.java
+++ /dev/null
@@ -1,283 +0,0 @@
-package info.nightscout.androidaps.plugins.configBuilder;
-
-
-import android.content.Intent;
-import android.os.Bundle;
-import android.support.annotation.NonNull;
-import android.support.annotation.StringRes;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.Button;
-import android.widget.CheckBox;
-import android.widget.ImageButton;
-import android.widget.LinearLayout;
-import android.widget.RadioButton;
-import android.widget.ScrollView;
-import android.widget.TextView;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import butterknife.BindView;
-import butterknife.ButterKnife;
-import butterknife.OnClick;
-import butterknife.Unbinder;
-import info.nightscout.androidaps.MainApp;
-import info.nightscout.androidaps.R;
-import info.nightscout.androidaps.activities.PreferencesActivity;
-import info.nightscout.androidaps.events.EventConfigBuilderChange;
-import info.nightscout.androidaps.events.EventRefreshGui;
-import info.nightscout.androidaps.interfaces.APSInterface;
-import info.nightscout.androidaps.interfaces.BgSourceInterface;
-import info.nightscout.androidaps.interfaces.ConstraintsInterface;
-import info.nightscout.androidaps.interfaces.InsulinInterface;
-import info.nightscout.androidaps.interfaces.PluginBase;
-import info.nightscout.androidaps.interfaces.PluginType;
-import info.nightscout.androidaps.interfaces.ProfileInterface;
-import info.nightscout.androidaps.interfaces.PumpInterface;
-import info.nightscout.androidaps.interfaces.SensitivityInterface;
-import info.nightscout.androidaps.plugins.common.SubscriberFragment;
-import info.nightscout.androidaps.plugins.insulin.InsulinOrefRapidActingPlugin;
-import info.nightscout.androidaps.plugins.profile.ns.NSProfilePlugin;
-import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin;
-import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref0Plugin;
-import info.nightscout.androidaps.utils.FabricPrivacy;
-import info.nightscout.androidaps.utils.PasswordProtection;
-
-
-public class ConfigBuilderFragment extends SubscriberFragment {
-
- private List pluginViewHolders = new ArrayList<>();
-
- @BindView(R.id.categories)
- LinearLayout categories;
-
- @BindView(R.id.main_layout)
- ScrollView mainLayout;
- @BindView(R.id.unlock)
- Button unlock;
-
- @Override
- public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- try {
- View view = inflater.inflate(R.layout.configbuilder_fragment, container, false);
- unbinder = ButterKnife.bind(this, view);
-
- if (PasswordProtection.isLocked("settings_password"))
- mainLayout.setVisibility(View.GONE);
- else unlock.setVisibility(View.GONE);
-
- createViews();
-
- return view;
- } catch (Exception e) {
- FabricPrivacy.logException(e);
- }
-
- return null;
- }
-
- @OnClick(R.id.unlock)
- void onClickUnlock() {
- PasswordProtection.QueryPassword(getContext(), R.string.settings_password, "settings_password", () -> {
- mainLayout.setVisibility(View.VISIBLE);
- unlock.setVisibility(View.GONE);
- }, null);
- }
-
- @Override
- public void onDestroyView() {
- super.onDestroyView();
- for (PluginViewHolder pluginViewHolder : pluginViewHolders) pluginViewHolder.unbind();
- pluginViewHolders.clear();
- }
-
- @Override
- protected void updateGUI() {
- for (PluginViewHolder pluginViewHolder : pluginViewHolders) pluginViewHolder.update();
- }
-
- private void createViews() {
- createViewsForPlugins(R.string.configbuilder_profile, R.string.configbuilder_profile_description, PluginType.PROFILE, MainApp.getSpecificPluginsVisibleInListByInterface(ProfileInterface.class, PluginType.PROFILE));
- createViewsForPlugins(R.string.configbuilder_insulin, R.string.configbuilder_insulin_description, PluginType.INSULIN, MainApp.getSpecificPluginsVisibleInListByInterface(InsulinInterface.class, PluginType.INSULIN));
- createViewsForPlugins(R.string.configbuilder_bgsource, R.string.configbuilder_bgsource_description, PluginType.BGSOURCE, MainApp.getSpecificPluginsVisibleInListByInterface(BgSourceInterface.class, PluginType.BGSOURCE));
- createViewsForPlugins(R.string.configbuilder_pump, R.string.configbuilder_pump_description, PluginType.PUMP, MainApp.getSpecificPluginsVisibleInList(PluginType.PUMP));
- createViewsForPlugins(R.string.configbuilder_sensitivity, R.string.configbuilder_sensitivity_description, PluginType.SENSITIVITY, MainApp.getSpecificPluginsVisibleInListByInterface(SensitivityInterface.class, PluginType.SENSITIVITY));
- createViewsForPlugins(R.string.configbuilder_aps, R.string.configbuilder_aps_description, PluginType.APS, MainApp.getSpecificPluginsVisibleInList(PluginType.APS));
- createViewsForPlugins(R.string.configbuilder_loop, R.string.configbuilder_loop_description, PluginType.LOOP, MainApp.getSpecificPluginsVisibleInList(PluginType.LOOP));
- createViewsForPlugins(R.string.constraints, R.string.configbuilder_constraints_description, PluginType.CONSTRAINTS, MainApp.getSpecificPluginsVisibleInListByInterface(ConstraintsInterface.class, PluginType.CONSTRAINTS));
- createViewsForPlugins(R.string.configbuilder_treatments, R.string.configbuilder_treatments_description, PluginType.TREATMENT, MainApp.getSpecificPluginsVisibleInList(PluginType.TREATMENT));
- createViewsForPlugins(R.string.configbuilder_general, R.string.configbuilder_general_description, PluginType.GENERAL, MainApp.getSpecificPluginsVisibleInList(PluginType.GENERAL));
- }
-
- private void createViewsForPlugins(@StringRes int title, @StringRes int description, PluginType pluginType, List plugins) {
- if (plugins.size() == 0) return;
- LinearLayout parent = (LinearLayout) getLayoutInflater().inflate(R.layout.configbuilder_single_category, null);
- ((TextView) parent.findViewById(R.id.category_title)).setText(MainApp.gs(title));
- ((TextView) parent.findViewById(R.id.category_description)).setText(MainApp.gs(description));
- LinearLayout pluginContainer = parent.findViewById(R.id.category_plugins);
- for (PluginBase plugin: plugins) {
- PluginViewHolder pluginViewHolder = new PluginViewHolder(pluginType, plugin);
- pluginContainer.addView(pluginViewHolder.getBaseView());
- pluginViewHolders.add(pluginViewHolder);
- }
- categories.addView(parent);
- }
-
- private boolean areMultipleSelectionsAllowed(PluginType type) {
- return type == PluginType.GENERAL || type == PluginType.CONSTRAINTS ||type == PluginType.LOOP;
- }
-
- public static void processOnEnabledCategoryChanged(PluginBase changedPlugin, PluginType type) {
- ArrayList pluginsInCategory = null;
- switch (type) {
- // Multiple selection allowed
- case GENERAL:
- case CONSTRAINTS:
- case LOOP:
- break;
- // Single selection allowed
- case INSULIN:
- pluginsInCategory = MainApp.getSpecificPluginsListByInterface(InsulinInterface.class);
- break;
- case SENSITIVITY:
- pluginsInCategory = MainApp.getSpecificPluginsListByInterface(SensitivityInterface.class);
- break;
- case APS:
- pluginsInCategory = MainApp.getSpecificPluginsListByInterface(APSInterface.class);
- break;
- case PROFILE:
- pluginsInCategory = MainApp.getSpecificPluginsListByInterface(ProfileInterface.class);
- break;
- case BGSOURCE:
- pluginsInCategory = MainApp.getSpecificPluginsListByInterface(BgSourceInterface.class);
- break;
- case TREATMENT:
- case PUMP:
- pluginsInCategory = MainApp.getSpecificPluginsListByInterface(PumpInterface.class);
- break;
- }
- if (pluginsInCategory != null) {
- boolean newSelection = changedPlugin.isEnabled(type);
- if (newSelection) { // new plugin selected -> disable others
- for (PluginBase p : pluginsInCategory) {
- if (p.getName().equals(changedPlugin.getName())) {
- // this is new selected
- } else {
- p.setPluginEnabled(type, false);
- p.setFragmentVisible(type, false);
- }
- }
- } else { // enable first plugin in list
- if (type == PluginType.PUMP)
- VirtualPumpPlugin.getPlugin().setPluginEnabled(type, true);
- else if (type == PluginType.INSULIN)
- InsulinOrefRapidActingPlugin.getPlugin().setPluginEnabled(type, true);
- else if (type == PluginType.SENSITIVITY)
- SensitivityOref0Plugin.getPlugin().setPluginEnabled(type, true);
- else if (type == PluginType.PROFILE)
- NSProfilePlugin.getPlugin().setPluginEnabled(type, true);
- else
- pluginsInCategory.get(0).setPluginEnabled(type, true);
- }
- }
- }
-
- public class PluginViewHolder {
-
- private Unbinder unbinder;
- private PluginType pluginType;
- private PluginBase plugin;
-
- LinearLayout baseView;
- @BindView(R.id.plugin_enabled_exclusive)
- RadioButton enabledExclusive;
- @BindView(R.id.plugin_enabled_inclusive)
- CheckBox enabledInclusive;
- @BindView(R.id.plugin_name)
- TextView pluginName;
- @BindView(R.id.plugin_description)
- TextView pluginDescription;
- @BindView(R.id.plugin_preferences)
- ImageButton pluginPreferences;
- @BindView(R.id.plugin_visibility)
- CheckBox pluginVisibility;
-
- public PluginViewHolder(PluginType pluginType, PluginBase plugin) {
- this.pluginType = pluginType;
- this.plugin = plugin;
- baseView = (LinearLayout) getLayoutInflater().inflate(R.layout.configbuilder_single_plugin, null);
- unbinder = ButterKnife.bind(this, baseView);
- update();
- }
-
- public LinearLayout getBaseView() {
- return baseView;
- }
-
- public void update() {
- enabledExclusive.setVisibility(areMultipleSelectionsAllowed(pluginType) ? View.GONE : View.VISIBLE);
- enabledInclusive.setVisibility(areMultipleSelectionsAllowed(pluginType) ? View.VISIBLE : View.GONE);
- enabledExclusive.setChecked(plugin.isEnabled(pluginType));
- enabledInclusive.setChecked(plugin.isEnabled(pluginType));
- enabledInclusive.setEnabled(!plugin.pluginDescription.alwaysEnabled);
- enabledExclusive.setEnabled(!plugin.pluginDescription.alwaysEnabled);
- pluginName.setText(plugin.getName());
- if (plugin.getDescription() == null) pluginDescription.setVisibility(View.GONE);
- else {
- pluginDescription.setVisibility(View.VISIBLE);
- pluginDescription.setText(plugin.getDescription());
- }
- pluginPreferences.setVisibility(plugin.getPreferencesId() == -1 || !plugin.isEnabled(pluginType) ? View.INVISIBLE : View.VISIBLE);
- pluginVisibility.setVisibility(plugin.hasFragment() ? View.VISIBLE : View.INVISIBLE);
- pluginVisibility.setEnabled(!(plugin.pluginDescription.neverVisible || plugin.pluginDescription.alwayVisible) && plugin.isEnabled(pluginType));
- pluginVisibility.setChecked(plugin.isFragmentVisible());
- }
-
- @OnClick(R.id.plugin_visibility)
- void onVisibilityChanged() {
- plugin.setFragmentVisible(pluginType, pluginVisibility.isChecked());
- ConfigBuilderPlugin.getPlugin().storeSettings("CheckedCheckboxVisible");
- MainApp.bus().post(new EventRefreshGui());
- ConfigBuilderPlugin.getPlugin().logPluginStatus();
- }
-
- @OnClick({R.id.plugin_enabled_exclusive, R.id.plugin_enabled_inclusive})
- void onEnabledChanged() {
- plugin.switchAllowed(new PluginSwitcher(), getActivity());
- }
-
- @OnClick(R.id.plugin_preferences)
- void onPluginPreferencesClicked() {
- PasswordProtection.QueryPassword(getContext(), R.string.settings_password, "settings_password", () -> {
- Intent i = new Intent(getContext(), PreferencesActivity.class);
- i.putExtra("id", plugin.getPreferencesId());
- startActivity(i);
- }, null);
- }
-
- public void unbind() {
- unbinder.unbind();
- }
-
- public class PluginSwitcher {
- public void invoke() {
- boolean enabled = enabledExclusive.getVisibility() == View.VISIBLE ? enabledExclusive.isChecked() : enabledInclusive.isChecked();
- plugin.setPluginEnabled(pluginType, enabled);
- plugin.setFragmentVisible(pluginType, enabled);
- processOnEnabledCategoryChanged(plugin, pluginType);
- updateGUI();
- ConfigBuilderPlugin.getPlugin().storeSettings("CheckedCheckboxEnabled");
- MainApp.bus().post(new EventRefreshGui());
- MainApp.bus().post(new EventConfigBuilderChange());
- ConfigBuilderPlugin.getPlugin().logPluginStatus();
- }
-
- public void cancel(){
- updateGUI();
- }
- }
- }
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/configBuilder/ConfigBuilderFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/configBuilder/ConfigBuilderFragment.kt
new file mode 100644
index 00000000000..059bec14441
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/configBuilder/ConfigBuilderFragment.kt
@@ -0,0 +1,98 @@
+package info.nightscout.androidaps.plugins.configBuilder
+
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.LinearLayout
+import android.widget.TextView
+import androidx.annotation.StringRes
+import androidx.fragment.app.Fragment
+import info.nightscout.androidaps.MainApp
+import info.nightscout.androidaps.R
+import info.nightscout.androidaps.interfaces.*
+import info.nightscout.androidaps.plugins.bus.RxBus
+import info.nightscout.androidaps.utils.FabricPrivacy
+import info.nightscout.androidaps.utils.PasswordProtection
+import io.reactivex.android.schedulers.AndroidSchedulers
+import io.reactivex.disposables.CompositeDisposable
+import kotlinx.android.synthetic.main.configbuilder_fragment.*
+import java.util.*
+
+class ConfigBuilderFragment : Fragment() {
+
+ private var disposable: CompositeDisposable = CompositeDisposable()
+ private val pluginViewHolders = ArrayList()
+
+ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
+ savedInstanceState: Bundle?): View? {
+ return inflater.inflate(R.layout.configbuilder_fragment, container, false)
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+
+ if (PasswordProtection.isLocked("settings_password"))
+ configbuilder_main_layout.visibility = View.GONE
+ else
+ unlock.visibility = View.GONE
+
+ unlock.setOnClickListener {
+ PasswordProtection.QueryPassword(context, R.string.settings_password, "settings_password", {
+ configbuilder_main_layout.visibility = View.VISIBLE
+ unlock.visibility = View.GONE
+ }, null)
+ }
+ }
+
+ @Synchronized
+ override fun onResume() {
+ super.onResume()
+ disposable.add(RxBus
+ .toObservable(EventConfigBuilderUpdateGui::class.java)
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe({
+ for (pluginViewHolder in pluginViewHolders) pluginViewHolder.update()
+ }, {
+ FabricPrivacy.logException(it)
+ }))
+ updateGUI()
+ }
+
+ @Synchronized
+ override fun onPause() {
+ super.onPause()
+ disposable.clear()
+ }
+
+ @Synchronized
+ private fun updateGUI() {
+ configbuilder_categories.removeAllViews()
+ createViewsForPlugins(R.string.configbuilder_profile, R.string.configbuilder_profile_description, PluginType.PROFILE, MainApp.getSpecificPluginsVisibleInListByInterface(ProfileInterface::class.java, PluginType.PROFILE))
+ createViewsForPlugins(R.string.configbuilder_insulin, R.string.configbuilder_insulin_description, PluginType.INSULIN, MainApp.getSpecificPluginsVisibleInListByInterface(InsulinInterface::class.java, PluginType.INSULIN))
+ createViewsForPlugins(R.string.configbuilder_bgsource, R.string.configbuilder_bgsource_description, PluginType.BGSOURCE, MainApp.getSpecificPluginsVisibleInListByInterface(BgSourceInterface::class.java, PluginType.BGSOURCE))
+ createViewsForPlugins(R.string.configbuilder_pump, R.string.configbuilder_pump_description, PluginType.PUMP, MainApp.getSpecificPluginsVisibleInList(PluginType.PUMP))
+ createViewsForPlugins(R.string.configbuilder_sensitivity, R.string.configbuilder_sensitivity_description, PluginType.SENSITIVITY, MainApp.getSpecificPluginsVisibleInListByInterface(SensitivityInterface::class.java, PluginType.SENSITIVITY))
+ createViewsForPlugins(R.string.configbuilder_aps, R.string.configbuilder_aps_description, PluginType.APS, MainApp.getSpecificPluginsVisibleInList(PluginType.APS))
+ createViewsForPlugins(R.string.configbuilder_loop, R.string.configbuilder_loop_description, PluginType.LOOP, MainApp.getSpecificPluginsVisibleInList(PluginType.LOOP))
+ createViewsForPlugins(R.string.constraints, R.string.configbuilder_constraints_description, PluginType.CONSTRAINTS, MainApp.getSpecificPluginsVisibleInListByInterface(ConstraintsInterface::class.java, PluginType.CONSTRAINTS))
+ createViewsForPlugins(R.string.configbuilder_treatments, R.string.configbuilder_treatments_description, PluginType.TREATMENT, MainApp.getSpecificPluginsVisibleInList(PluginType.TREATMENT))
+ createViewsForPlugins(R.string.configbuilder_general, R.string.configbuilder_general_description, PluginType.GENERAL, MainApp.getSpecificPluginsVisibleInList(PluginType.GENERAL))
+ }
+
+ private fun createViewsForPlugins(@StringRes title: Int, @StringRes description: Int, pluginType: PluginType, plugins: List) {
+ if (plugins.size == 0) return
+ val parent = layoutInflater.inflate(R.layout.configbuilder_single_category, null) as LinearLayout
+ (parent.findViewById(R.id.category_title) as TextView).text = MainApp.gs(title)
+ (parent.findViewById(R.id.category_description) as TextView).text = MainApp.gs(description)
+ val pluginContainer = parent.findViewById(R.id.category_plugins)
+ for (plugin in plugins) {
+ val pluginViewHolder = PluginViewHolder(this, pluginType, plugin)
+ pluginContainer.addView(pluginViewHolder.baseView)
+ pluginViewHolders.add(pluginViewHolder)
+ }
+ configbuilder_categories.addView(parent)
+ }
+
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/configBuilder/ConfigBuilderPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/configBuilder/ConfigBuilderPlugin.java
index 3c3531da865..f43513fbf5c 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/configBuilder/ConfigBuilderPlugin.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/configBuilder/ConfigBuilderPlugin.java
@@ -1,6 +1,6 @@
package info.nightscout.androidaps.plugins.configBuilder;
-import android.support.annotation.Nullable;
+import androidx.annotation.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -20,7 +20,9 @@
import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.interfaces.SensitivityInterface;
import info.nightscout.androidaps.logging.L;
+import info.nightscout.androidaps.plugins.bus.RxBus;
import info.nightscout.androidaps.plugins.insulin.InsulinOrefRapidActingPlugin;
+import info.nightscout.androidaps.plugins.profile.ns.NSProfilePlugin;
import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin;
import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref0Plugin;
import info.nightscout.androidaps.queue.CommandQueue;
@@ -57,7 +59,7 @@ public ConfigBuilderPlugin() {
.fragmentClass(ConfigBuilderFragment.class.getName())
.showInList(true)
.alwaysEnabled(true)
- .alwayVisible(false)
+ .alwaysVisible(false)
.pluginName(R.string.configbuilder)
.shortName(R.string.configbuilder_shortname)
.description(R.string.description_config_builder)
@@ -66,14 +68,12 @@ public ConfigBuilderPlugin() {
@Override
protected void onStart() {
- MainApp.bus().register(this);
super.onStart();
}
@Override
protected void onStop() {
super.onStop();
- MainApp.bus().unregister(this);
}
@@ -82,7 +82,7 @@ public void initialize() {
upgradeSettings();
loadSettings();
setAlwaysEnabledPluginsEnabled();
- MainApp.bus().post(new EventAppInitialized());
+ RxBus.INSTANCE.send(new EventAppInitialized());
}
private void setAlwaysEnabledPluginsEnabled() {
@@ -102,7 +102,7 @@ public void storeSettings(String from) {
for (PluginBase p : pluginList) {
PluginType type = p.getType();
- if (p.pluginDescription.alwaysEnabled && p.pluginDescription.alwayVisible)
+ if (p.pluginDescription.alwaysEnabled && p.pluginDescription.alwaysVisible)
continue;
if (p.pluginDescription.alwaysEnabled && p.pluginDescription.neverVisible)
continue;
@@ -232,31 +232,37 @@ public CommandQueue getCommandQueue() {
return commandQueue;
}
+ @Nullable
public BgSourceInterface getActiveBgSource() {
return activeBgSource;
}
+ @Nullable
public ProfileInterface getActiveProfileInterface() {
return activeProfile;
}
+ @Nullable
public InsulinInterface getActiveInsulin() {
return activeInsulin;
}
+ @Nullable
public APSInterface getActiveAPS() {
return activeAPS;
}
+ @Nullable
public PumpInterface getActivePump() {
return activePump;
}
+ @Nullable
public SensitivityInterface getActiveSensitivity() {
return activeSensitivity;
}
- void logPluginStatus() {
+ public void logPluginStatus() {
if (L.isEnabled(L.CONFIGBUILDER))
for (PluginBase p : pluginList) {
log.debug(p.getName() + ":" +
@@ -399,4 +405,58 @@ private PluginBase getTheOneEnabledInArray(ArrayList pluginsInCatego
return found;
}
+ public void processOnEnabledCategoryChanged(PluginBase changedPlugin, PluginType type) {
+ ArrayList pluginsInCategory = null;
+ switch (type) {
+ // Multiple selection allowed
+ case GENERAL:
+ case CONSTRAINTS:
+ case LOOP:
+ break;
+ // Single selection allowed
+ case INSULIN:
+ pluginsInCategory = MainApp.getSpecificPluginsListByInterface(InsulinInterface.class);
+ break;
+ case SENSITIVITY:
+ pluginsInCategory = MainApp.getSpecificPluginsListByInterface(SensitivityInterface.class);
+ break;
+ case APS:
+ pluginsInCategory = MainApp.getSpecificPluginsListByInterface(APSInterface.class);
+ break;
+ case PROFILE:
+ pluginsInCategory = MainApp.getSpecificPluginsListByInterface(ProfileInterface.class);
+ break;
+ case BGSOURCE:
+ pluginsInCategory = MainApp.getSpecificPluginsListByInterface(BgSourceInterface.class);
+ break;
+ case TREATMENT:
+ case PUMP:
+ pluginsInCategory = MainApp.getSpecificPluginsListByInterface(PumpInterface.class);
+ break;
+ }
+ if (pluginsInCategory != null) {
+ boolean newSelection = changedPlugin.isEnabled(type);
+ if (newSelection) { // new plugin selected -> disable others
+ for (PluginBase p : pluginsInCategory) {
+ if (p.getName().equals(changedPlugin.getName())) {
+ // this is new selected
+ } else {
+ p.setPluginEnabled(type, false);
+ p.setFragmentVisible(type, false);
+ }
+ }
+ } else { // enable first plugin in list
+ if (type == PluginType.PUMP)
+ VirtualPumpPlugin.getPlugin().setPluginEnabled(type, true);
+ else if (type == PluginType.INSULIN)
+ InsulinOrefRapidActingPlugin.getPlugin().setPluginEnabled(type, true);
+ else if (type == PluginType.SENSITIVITY)
+ SensitivityOref0Plugin.getPlugin().setPluginEnabled(type, true);
+ else if (type == PluginType.PROFILE)
+ NSProfilePlugin.getPlugin().setPluginEnabled(type, true);
+ else
+ pluginsInCategory.get(0).setPluginEnabled(type, true);
+ }
+ }
+ }
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/configBuilder/DetailedBolusInfoStorage.java b/app/src/main/java/info/nightscout/androidaps/plugins/configBuilder/DetailedBolusInfoStorage.java
deleted file mode 100644
index b19948fc5ea..00000000000
--- a/app/src/main/java/info/nightscout/androidaps/plugins/configBuilder/DetailedBolusInfoStorage.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package info.nightscout.androidaps.plugins.configBuilder;
-
-import android.support.annotation.Nullable;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import info.nightscout.androidaps.data.DetailedBolusInfo;
-import info.nightscout.androidaps.logging.L;
-
-/**
- * Created by mike on 08.08.2017.
- */
-
-public class DetailedBolusInfoStorage {
- private static Logger log = LoggerFactory.getLogger(L.PUMP);
- private static List store = new ArrayList<>();
-
- public static synchronized void add(DetailedBolusInfo detailedBolusInfo) {
- log.debug("Stored bolus info: " + detailedBolusInfo);
- store.add(detailedBolusInfo);
- }
-
- @Nullable
- public static synchronized DetailedBolusInfo findDetailedBolusInfo(long bolustime) {
- DetailedBolusInfo found = null;
- for (int i = 0; i < store.size(); i++) {
- long infoTime = store.get(i).date;
- if (L.isEnabled(L.PUMP))
- log.debug("Existing bolus info: " + store.get(i));
- if (bolustime > infoTime - 60 * 1000 && bolustime < infoTime + 60 * 1000) {
- found = store.get(i);
- if (L.isEnabled(L.PUMP))
- log.debug("Using & removing bolus info: " + store.get(i));
- store.remove(i);
- break;
- }
- }
- return found;
- }
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/configBuilder/EventConfigBuilderUpdateGui.kt b/app/src/main/java/info/nightscout/androidaps/plugins/configBuilder/EventConfigBuilderUpdateGui.kt
new file mode 100644
index 00000000000..e57fd79983d
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/configBuilder/EventConfigBuilderUpdateGui.kt
@@ -0,0 +1,6 @@
+package info.nightscout.androidaps.plugins.configBuilder
+
+import info.nightscout.androidaps.events.EventUpdateGui
+
+class EventConfigBuilderUpdateGui : EventUpdateGui() {
+}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/configBuilder/PluginViewHolder.kt b/app/src/main/java/info/nightscout/androidaps/plugins/configBuilder/PluginViewHolder.kt
new file mode 100644
index 00000000000..2670e786336
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/configBuilder/PluginViewHolder.kt
@@ -0,0 +1,87 @@
+package info.nightscout.androidaps.plugins.configBuilder
+
+import android.content.Intent
+import android.view.View
+import android.widget.CheckBox
+import android.widget.ImageButton
+import android.widget.LinearLayout
+import android.widget.RadioButton
+import android.widget.TextView
+import info.nightscout.androidaps.R
+import info.nightscout.androidaps.activities.PreferencesActivity
+import info.nightscout.androidaps.events.EventRebuildTabs
+import info.nightscout.androidaps.interfaces.PluginBase
+import info.nightscout.androidaps.interfaces.PluginType
+import info.nightscout.androidaps.plugins.bus.RxBus
+import info.nightscout.androidaps.utils.PasswordProtection
+import info.nightscout.androidaps.utils.toVisibility
+
+class PluginViewHolder internal constructor(private val fragment: ConfigBuilderFragment,
+ private val pluginType: PluginType,
+ private val plugin: PluginBase) {
+
+ val baseView: LinearLayout = fragment.layoutInflater.inflate(R.layout.configbuilder_single_plugin, null) as LinearLayout
+ private val enabledExclusive: RadioButton
+ private val enabledInclusive: CheckBox
+ private val pluginName: TextView
+ private val pluginDescription: TextView
+ private val pluginPreferences: ImageButton
+ private val pluginVisibility: CheckBox
+
+ init {
+ enabledExclusive = baseView.findViewById(R.id.plugin_enabled_exclusive)
+ enabledInclusive = baseView.findViewById(R.id.plugin_enabled_inclusive)
+ pluginName = baseView.findViewById(R.id.plugin_name)
+ pluginDescription = baseView.findViewById(R.id.plugin_description)
+ pluginPreferences = baseView.findViewById(R.id.plugin_preferences)
+ pluginVisibility = baseView.findViewById(R.id.plugin_visibility)
+
+ pluginVisibility.setOnClickListener {
+ plugin.setFragmentVisible(pluginType, pluginVisibility.isChecked)
+ ConfigBuilderPlugin.getPlugin().storeSettings("CheckedCheckboxVisible")
+ RxBus.send(EventRebuildTabs())
+ ConfigBuilderPlugin.getPlugin().logPluginStatus()
+ }
+
+ enabledExclusive.setOnClickListener {
+ plugin.switchAllowed(if (enabledExclusive.visibility == View.VISIBLE) enabledExclusive.isChecked else enabledInclusive.isChecked, fragment.activity, pluginType)
+ }
+ enabledInclusive.setOnClickListener {
+ plugin.switchAllowed(if (enabledExclusive.visibility == View.VISIBLE) enabledExclusive.isChecked else enabledInclusive.isChecked, fragment.activity, pluginType)
+ }
+
+ pluginPreferences.setOnClickListener {
+ PasswordProtection.QueryPassword(fragment.context, R.string.settings_password, "settings_password", {
+ val i = Intent(fragment.context, PreferencesActivity::class.java)
+ i.putExtra("id", plugin.preferencesId)
+ fragment.startActivity(i)
+ }, null)
+ }
+ update()
+ }
+
+ fun update() {
+ enabledExclusive.visibility = areMultipleSelectionsAllowed(pluginType).not().toVisibility()
+ enabledInclusive.visibility = areMultipleSelectionsAllowed(pluginType).toVisibility()
+ enabledExclusive.isChecked = plugin.isEnabled(pluginType)
+ enabledInclusive.isChecked = plugin.isEnabled(pluginType)
+ enabledInclusive.isEnabled = !plugin.pluginDescription.alwaysEnabled
+ enabledExclusive.isEnabled = !plugin.pluginDescription.alwaysEnabled
+ pluginName.text = plugin.name
+ if (plugin.description == null)
+ pluginDescription.visibility = View.GONE
+ else {
+ pluginDescription.visibility = View.VISIBLE
+ pluginDescription.text = plugin.description
+ }
+ pluginPreferences.visibility = if (plugin.preferencesId == -1 || !plugin.isEnabled(pluginType)) View.INVISIBLE else View.VISIBLE
+ pluginVisibility.visibility = plugin.hasFragment().toVisibility()
+ pluginVisibility.isEnabled = !(plugin.pluginDescription.neverVisible || plugin.pluginDescription.alwaysVisible) && plugin.isEnabled(pluginType)
+ pluginVisibility.isChecked = plugin.isFragmentVisible
+ }
+
+ private fun areMultipleSelectionsAllowed(type: PluginType): Boolean {
+ return type == PluginType.GENERAL || type == PluginType.CONSTRAINTS || type == PluginType.LOOP
+ }
+
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/configBuilder/ProfileFunctions.java b/app/src/main/java/info/nightscout/androidaps/plugins/configBuilder/ProfileFunctions.java
index 0360ba4a680..bdde6606bb8 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/configBuilder/ProfileFunctions.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/configBuilder/ProfileFunctions.java
@@ -2,10 +2,10 @@
import android.content.Intent;
import android.os.Bundle;
-import android.support.annotation.Nullable;
+
+import androidx.annotation.Nullable;
import com.google.firebase.analytics.FirebaseAnalytics;
-import com.squareup.otto.Subscribe;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -23,13 +23,19 @@
import info.nightscout.androidaps.interfaces.ProfileInterface;
import info.nightscout.androidaps.interfaces.TreatmentsInterface;
import info.nightscout.androidaps.logging.L;
-import info.nightscout.androidaps.plugins.general.overview.dialogs.ErrorHelperActivity;
+import info.nightscout.androidaps.plugins.bus.RxBus;
+import info.nightscout.androidaps.activities.ErrorHelperActivity;
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
import info.nightscout.androidaps.queue.Callback;
+import info.nightscout.androidaps.utils.DateUtil;
import info.nightscout.androidaps.utils.FabricPrivacy;
+import info.nightscout.androidaps.utils.SP;
+import io.reactivex.disposables.CompositeDisposable;
+import io.reactivex.schedulers.Schedulers;
public class ProfileFunctions {
private static Logger log = LoggerFactory.getLogger(L.PROFILE);
+ private CompositeDisposable disposable = new CompositeDisposable();
private static ProfileFunctions profileFunctions = null;
@@ -43,65 +49,74 @@ public static ProfileFunctions getInstance() {
ProfileFunctions.getInstance(); // register to bus at start
}
- ProfileFunctions() {
- MainApp.bus().register(this);
- }
-
- @Subscribe
- public void onProfileSwitch(EventProfileNeedsUpdate ignored) {
- if (L.isEnabled(L.PROFILE))
- log.debug("onProfileSwitch");
- ConfigBuilderPlugin.getPlugin().getCommandQueue().setProfile(getProfile(), new Callback() {
- @Override
- public void run() {
- if (!result.success) {
- Intent i = new Intent(MainApp.instance(), ErrorHelperActivity.class);
- i.putExtra("soundid", R.raw.boluserror);
- i.putExtra("status", result.comment);
- i.putExtra("title", MainApp.gs(R.string.failedupdatebasalprofile));
- i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- MainApp.instance().startActivity(i);
- }
- if (result.enacted)
- MainApp.bus().post(new EventNewBasalProfile());
- }
- });
+ private ProfileFunctions() {
+ disposable.add(RxBus.INSTANCE
+ .toObservable(EventProfileNeedsUpdate.class)
+ .observeOn(Schedulers.io())
+ .subscribe(event -> {
+ if (L.isEnabled(L.PROFILE))
+ log.debug("onProfileSwitch");
+ ConfigBuilderPlugin.getPlugin().getCommandQueue().setProfile(getProfile(), new Callback() {
+ @Override
+ public void run() {
+ if (!result.success) {
+ Intent i = new Intent(MainApp.instance(), ErrorHelperActivity.class);
+ i.putExtra("soundid", R.raw.boluserror);
+ i.putExtra("status", result.comment);
+ i.putExtra("title", MainApp.gs(R.string.failedupdatebasalprofile));
+ i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ MainApp.instance().startActivity(i);
+ }
+ if (result.enacted)
+ RxBus.INSTANCE.send(new EventNewBasalProfile());
+ }
+ });
+ }, FabricPrivacy::logException)
+ );
}
public String getProfileName() {
- return getProfileName(System.currentTimeMillis());
+ return getProfileName(System.currentTimeMillis(), true, false);
}
public String getProfileName(boolean customized) {
- return getProfileName(System.currentTimeMillis(), customized);
+ return getProfileName(System.currentTimeMillis(), customized, false);
}
- public String getProfileName(long time) {
- return getProfileName(time, true);
+ public String getProfileNameWithDuration() {
+ return getProfileName(System.currentTimeMillis(), true, true);
}
- public String getProfileName(long time, boolean customized) {
+ public String getProfileName(long time, boolean customized, boolean showRemainingTime) {
+ String profileName = MainApp.gs(R.string.noprofileselected);
+
TreatmentsInterface activeTreatments = TreatmentsPlugin.getPlugin();
ProfileInterface activeProfile = ConfigBuilderPlugin.getPlugin().getActiveProfileInterface();
ProfileSwitch profileSwitch = activeTreatments.getProfileSwitchFromHistory(time);
if (profileSwitch != null) {
if (profileSwitch.profileJson != null) {
- return customized ? profileSwitch.getCustomizedName() : profileSwitch.profileName;
+ profileName = customized ? profileSwitch.getCustomizedName() : profileSwitch.profileName;
} else {
ProfileStore profileStore = activeProfile.getProfile();
if (profileStore != null) {
Profile profile = profileStore.getSpecificProfile(profileSwitch.profileName);
if (profile != null)
- return profileSwitch.profileName;
+ profileName = profileSwitch.profileName;
}
}
+
+ if (showRemainingTime && profileSwitch.durationInMinutes != 0) {
+ profileName += DateUtil.untilString(profileSwitch.originalEnd());
+ }
+ return profileName;
}
- return MainApp.gs(R.string.noprofileselected);
+ return profileName;
}
public boolean isProfileValid(String from) {
- return getProfile() != null && getProfile().isValid(from);
+ Profile profile = getProfile();
+ return profile != null && profile.isValid(from);
}
@Nullable
@@ -109,9 +124,8 @@ public Profile getProfile() {
return getProfile(System.currentTimeMillis());
}
- public String getProfileUnits() {
- Profile profile = getProfile();
- return profile != null ? profile.getUnits() : Constants.MGDL;
+ public static String getSystemUnits() {
+ return SP.getString(R.string.key_units, Constants.MGDL);
}
@Nullable
@@ -156,9 +170,11 @@ public static ProfileSwitch prepareProfileSwitch(final ProfileStore profileStore
return profileSwitch;
}
- public static void doProfileSwitch(final ProfileStore profileStore, final String profileName, final int duration, final int percentage, final int timeshift) {
- ProfileSwitch profileSwitch = prepareProfileSwitch(profileStore, profileName, duration, percentage, timeshift, System.currentTimeMillis());
+ public static void doProfileSwitch(final ProfileStore profileStore, final String profileName, final int duration, final int percentage, final int timeshift, final long date) {
+ ProfileSwitch profileSwitch = prepareProfileSwitch(profileStore, profileName, duration, percentage, timeshift, date);
TreatmentsPlugin.getPlugin().addToHistoryProfileSwitch(profileSwitch);
+ if (percentage == 90 && duration == 10)
+ SP.putBoolean(R.string.key_objectiveuseprofileswitch, true);
}
public static void doProfileSwitch(final int duration, final int percentage, final int timeshift) {
@@ -167,7 +183,7 @@ public static void doProfileSwitch(final int duration, final int percentage, fin
profileSwitch = new ProfileSwitch();
profileSwitch.date = System.currentTimeMillis();
profileSwitch.source = Source.USER;
- profileSwitch.profileName = getInstance().getProfileName(System.currentTimeMillis(), false);
+ profileSwitch.profileName = getInstance().getProfileName(System.currentTimeMillis(), false, false);
profileSwitch.profileJson = getInstance().getProfile().getData().toString();
profileSwitch.profilePlugin = ConfigBuilderPlugin.getPlugin().getActiveProfileInterface().getClass().getName();
profileSwitch.durationInMinutes = duration;
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/dstHelper/DstHelperPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/dstHelper/DstHelperPlugin.java
index ec3ef448815..828fa1b86f0 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/dstHelper/DstHelperPlugin.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/dstHelper/DstHelperPlugin.java
@@ -15,13 +15,14 @@
import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.logging.L;
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin;
+import info.nightscout.androidaps.plugins.bus.RxBus;
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification;
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification;
public class DstHelperPlugin extends PluginBase implements ConstraintsInterface {
public static final int DISABLE_TIMEFRAME_HOURS = -3;
- public static final int WARN_PRIOR_TIMEFRAME_HOURS = 24;
+ public static final int WARN_PRIOR_TIMEFRAME_HOURS = 12;
private static Logger log = LoggerFactory.getLogger(L.CONSTRAINTS);
static DstHelperPlugin plugin = null;
@@ -89,6 +90,6 @@ public Constraint isLoopInvocationAllowed(Constraint value) {
private void warnUser(int id, String warningText) {
Notification notification = new Notification(id, warningText, Notification.LOW);
- MainApp.bus().post(new EventNewNotification(notification));
+ RxBus.INSTANCE.send(new EventNewNotification(notification));
}
}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/ObjectivesFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/ObjectivesFragment.java
deleted file mode 100644
index b9435710894..00000000000
--- a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/ObjectivesFragment.java
+++ /dev/null
@@ -1,229 +0,0 @@
-package info.nightscout.androidaps.plugins.constraints.objectives;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Looper;
-import android.support.annotation.NonNull;
-import android.support.v7.widget.CardView;
-import android.support.v7.widget.LinearLayoutManager;
-import android.support.v7.widget.LinearSmoothScroller;
-import android.support.v7.widget.RecyclerView;
-import android.text.Html;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.Button;
-import android.widget.CheckBox;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-import java.util.Date;
-
-import info.nightscout.androidaps.MainApp;
-import info.nightscout.androidaps.R;
-import info.nightscout.androidaps.plugins.common.SubscriberFragment;
-import info.nightscout.androidaps.plugins.constraints.objectives.objectives.Objective;
-import info.nightscout.androidaps.utils.FabricPrivacy;
-
-public class ObjectivesFragment extends SubscriberFragment {
- RecyclerView recyclerView;
- CheckBox enableFake;
- TextView reset;
- ObjectivesAdapter objectivesAdapter = new ObjectivesAdapter();
- Handler handler = new Handler(Looper.getMainLooper());
-
- private Runnable objectiveUpdater = new Runnable() {
- @Override
- public void run() {
- handler.postDelayed(this, 60 * 1000);
- updateGUI();
- }
- };
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- try {
- View view = inflater.inflate(R.layout.objectives_fragment, container, false);
-
- recyclerView = view.findViewById(R.id.objectives_recyclerview);
- recyclerView.setLayoutManager(new LinearLayoutManager(view.getContext()));
- recyclerView.setAdapter(objectivesAdapter);
- enableFake = view.findViewById(R.id.objectives_fake);
- reset = view.findViewById(R.id.objectives_reset);
- enableFake.setOnClickListener(v -> updateGUI());
- reset.setOnClickListener(v -> {
- ObjectivesPlugin.getPlugin().reset();
- ObjectivesPlugin.getPlugin().saveProgress();
- recyclerView.getAdapter().notifyDataSetChanged();
- scrollToCurrentObjective();
- });
- scrollToCurrentObjective();
- startUpdateTimer();
- return view;
- } catch (Exception e) {
- FabricPrivacy.logException(e);
- }
-
- return null;
- }
-
- @Override
- public synchronized void onDestroyView() {
- super.onDestroyView();
- handler.removeCallbacks(objectiveUpdater);
- }
-
- private void startUpdateTimer() {
- handler.removeCallbacks(objectiveUpdater);
- for (Objective objective : ObjectivesPlugin.getPlugin().getObjectives()) {
- if (objective.isStarted() && !objective.isAccomplished()) {
- long timeTillNextMinute = (System.currentTimeMillis() - objective.getStartedOn().getTime()) % (60 * 1000);
- handler.postDelayed(objectiveUpdater, timeTillNextMinute);
- break;
- }
- }
- }
-
- private void scrollToCurrentObjective() {
- for (int i = 0; i < ObjectivesPlugin.getPlugin().getObjectives().size(); i++) {
- Objective objective = ObjectivesPlugin.getPlugin().getObjectives().get(i);
- if (!objective.isStarted() || !objective.isAccomplished()) {
- RecyclerView.SmoothScroller smoothScroller = new LinearSmoothScroller(getContext()) {
- @Override
- protected int getVerticalSnapPreference() {
- return LinearSmoothScroller.SNAP_TO_START;
- }
-
- @Override
- protected int calculateTimeForScrolling(int dx) {
- return super.calculateTimeForScrolling(dx) * 4;
- }
- };
- smoothScroller.setTargetPosition(i);
- recyclerView.getLayoutManager().startSmoothScroll(smoothScroller);
- break;
- }
- }
- }
-
- private class ObjectivesAdapter extends RecyclerView.Adapter {
-
- @NonNull
- @Override
- public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
- return new ViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.objectives_item, parent, false));
- }
-
- @Override
- public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
- Objective objective = ObjectivesPlugin.getPlugin().getObjectives().get(position);
- holder.title.setText(MainApp.gs(R.string.nth_objective, position + 1));
- holder.revert.setVisibility(View.INVISIBLE);
- if (objective.getObjective() != 0) {
- holder.objective.setVisibility(View.VISIBLE);
- holder.objective.setText(MainApp.gs(objective.getObjective()));
- } else holder.objective.setVisibility(View.GONE);
- if (objective.getGate() != 0) {
- holder.gate.setVisibility(View.VISIBLE);
- holder.gate.setText(MainApp.gs(objective.getGate()));
- } else holder.gate.setVisibility(View.GONE);
- if (!objective.isStarted()) {
- holder.gate.setTextColor(0xFFFFFFFF);
- holder.verify.setVisibility(View.GONE);
- holder.progress.setVisibility(View.GONE);
- if (position == 0 || ObjectivesPlugin.getPlugin().getObjectives().get(position - 1).isAccomplished())
- holder.start.setVisibility(View.VISIBLE);
- else holder.start.setVisibility(View.GONE);
- } else if (objective.isAccomplished()) {
- holder.gate.setTextColor(0xFF4CAF50);
- holder.verify.setVisibility(View.GONE);
- holder.progress.setVisibility(View.GONE);
- holder.start.setVisibility(View.GONE);
- } else if (objective.isStarted()) {
- holder.gate.setTextColor(0xFFFFFFFF);
- holder.verify.setVisibility(View.VISIBLE);
- holder.verify.setEnabled(objective.isCompleted() || enableFake.isChecked());
- holder.start.setVisibility(View.GONE);
- if(objective.isRevertable()) {
- holder.revert.setVisibility(View.VISIBLE);
- }
- holder.progress.setVisibility(View.VISIBLE);
- holder.progress.removeAllViews();
- for (Objective.Task task : objective.getTasks()) {
- if (task.shouldBeIgnored()) continue;
- TextView textView = new TextView(holder.progress.getContext());
- textView.setTextColor(0xFFFFFFFF);
- String basicHTML = "%2$s: %3$s ";
- String formattedHTML = String.format(basicHTML, task.isCompleted() ? "#4CAF50" : "#FF9800", MainApp.gs(task.getTask()), task.getProgress());
- textView.setText(Html.fromHtml(formattedHTML));
- holder.progress.addView(textView, LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
- }
- }
- holder.verify.setOnClickListener((view) -> {
- objective.setAccomplishedOn(new Date());
- notifyDataSetChanged();
- scrollToCurrentObjective();
- startUpdateTimer();
- });
- holder.start.setOnClickListener((view) -> {
- objective.setStartedOn(new Date());
- notifyDataSetChanged();
- scrollToCurrentObjective();
- startUpdateTimer();
- });
- holder.revert.setOnClickListener((view) -> {
- objective.setAccomplishedOn(null);
- objective.setStartedOn(null);
- if (position > 0) {
- Objective prevObj = ObjectivesPlugin.getPlugin().getObjectives().get(position - 1);
- prevObj.setAccomplishedOn(null);
- }
- notifyDataSetChanged();
- scrollToCurrentObjective();
- });
- }
-
-
-
- @Override
- public int getItemCount() {
- return ObjectivesPlugin.getPlugin().getObjectives().size();
- }
-
- public class ViewHolder extends RecyclerView.ViewHolder {
-
- public CardView cardView;
- public TextView title;
- public TextView objective;
- public TextView gate;
- public LinearLayout progress;
- public Button verify;
- public Button start;
- public Button revert;
-
- public ViewHolder(View itemView) {
- super(itemView);
- cardView = (CardView) itemView;
- title = itemView.findViewById(R.id.objective_title);
- objective = itemView.findViewById(R.id.objective_objective);
- gate = itemView.findViewById(R.id.objective_gate);
- progress = itemView.findViewById(R.id.objective_progress);
- verify = itemView.findViewById(R.id.objective_verify);
- start = itemView.findViewById(R.id.objective_start);
- revert = itemView.findViewById(R.id.objective_back);
- }
- }
- }
-
- @Override
- public void updateGUI() {
- Activity activity = getActivity();
- if (activity != null)
- activity.runOnUiThread(() -> {
- objectivesAdapter.notifyDataSetChanged();
- });
- }
-
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/ObjectivesFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/ObjectivesFragment.kt
new file mode 100644
index 00000000000..7f004b7f02f
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/ObjectivesFragment.kt
@@ -0,0 +1,349 @@
+package info.nightscout.androidaps.plugins.constraints.objectives
+
+import android.graphics.Color
+import android.os.Bundle
+import android.os.Handler
+import android.os.Looper
+import android.os.SystemClock
+import android.view.Gravity
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.Button
+import android.widget.EditText
+import android.widget.LinearLayout
+import android.widget.TextView
+import androidx.appcompat.app.AppCompatActivity
+import androidx.fragment.app.Fragment
+import androidx.recyclerview.widget.LinearLayoutManager
+import androidx.recyclerview.widget.LinearSmoothScroller
+import androidx.recyclerview.widget.RecyclerView
+import info.nightscout.androidaps.MainApp
+import info.nightscout.androidaps.R
+import info.nightscout.androidaps.logging.L
+import info.nightscout.androidaps.plugins.bus.RxBus
+import info.nightscout.androidaps.plugins.constraints.objectives.activities.ObjectivesExamDialog
+import info.nightscout.androidaps.plugins.constraints.objectives.dialogs.NtpProgressDialog
+import info.nightscout.androidaps.plugins.constraints.objectives.events.EventNtpStatus
+import info.nightscout.androidaps.plugins.constraints.objectives.events.EventObjectivesUpdateGui
+import info.nightscout.androidaps.plugins.constraints.objectives.objectives.Objective.ExamTask
+import info.nightscout.androidaps.receivers.NetworkChangeReceiver
+import info.nightscout.androidaps.setupwizard.events.EventSWUpdate
+import info.nightscout.androidaps.utils.*
+import io.reactivex.android.schedulers.AndroidSchedulers
+import io.reactivex.disposables.CompositeDisposable
+import kotlinx.android.synthetic.main.objectives_fragment.*
+import org.slf4j.LoggerFactory
+
+class ObjectivesFragment : Fragment() {
+ private val log = LoggerFactory.getLogger(L.CONSTRAINTS)
+ private val objectivesAdapter = ObjectivesAdapter()
+ private val handler = Handler(Looper.getMainLooper())
+
+ private var disposable: CompositeDisposable = CompositeDisposable()
+
+ private val objectiveUpdater = object : Runnable {
+ override fun run() {
+ handler.postDelayed(this, (60 * 1000).toLong())
+ updateGUI()
+ }
+ }
+
+ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
+ savedInstanceState: Bundle?): View? {
+ return inflater.inflate(R.layout.objectives_fragment, container, false)
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ objectives_recyclerview.layoutManager = LinearLayoutManager(view.context)
+ objectives_recyclerview.adapter = objectivesAdapter
+ objectives_fake.setOnClickListener { updateGUI() }
+ objectives_reset.setOnClickListener {
+ ObjectivesPlugin.reset()
+ objectives_recyclerview.adapter?.notifyDataSetChanged()
+ scrollToCurrentObjective()
+ }
+ scrollToCurrentObjective()
+ startUpdateTimer()
+ }
+
+ @Synchronized
+ override fun onResume() {
+ super.onResume()
+ disposable.add(RxBus
+ .toObservable(EventObjectivesUpdateGui::class.java)
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe({
+ objectives_recyclerview.adapter?.notifyDataSetChanged()
+ }, {
+ FabricPrivacy.logException(it)
+ })
+ )
+ }
+
+ @Synchronized
+ override fun onPause() {
+ super.onPause()
+ disposable.clear()
+ }
+
+ @Synchronized
+ override fun onDestroyView() {
+ super.onDestroyView()
+ handler.removeCallbacks(objectiveUpdater)
+ }
+
+ private fun startUpdateTimer() {
+ handler.removeCallbacks(objectiveUpdater)
+ for (objective in ObjectivesPlugin.objectives) {
+ if (objective.isStarted && !objective.isAccomplished) {
+ val timeTillNextMinute = (System.currentTimeMillis() - objective.startedOn) % (60 * 1000)
+ handler.postDelayed(objectiveUpdater, timeTillNextMinute)
+ break
+ }
+ }
+ }
+
+ private fun scrollToCurrentObjective() {
+ activity?.runOnUiThread {
+ for (i in 0 until ObjectivesPlugin.objectives.size) {
+ val objective = ObjectivesPlugin.objectives[i]
+ if (!objective.isStarted || !objective.isAccomplished) {
+ context?.let {
+ val smoothScroller = object : LinearSmoothScroller(it) {
+ override fun getVerticalSnapPreference(): Int = SNAP_TO_START
+ override fun calculateTimeForScrolling(dx: Int): Int = super.calculateTimeForScrolling(dx) * 4
+ }
+ smoothScroller.targetPosition = i
+ objectives_recyclerview.layoutManager?.startSmoothScroll(smoothScroller)
+ }
+ break
+ }
+ }
+ }
+ }
+
+ private inner class ObjectivesAdapter : RecyclerView.Adapter() {
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
+ return ViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.objectives_item, parent, false))
+ }
+
+ override fun onBindViewHolder(holder: ViewHolder, position: Int) {
+ val objective = ObjectivesPlugin.objectives[position]
+ holder.title.text = MainApp.gs(R.string.nth_objective, position + 1)
+ if (objective.objective != 0) {
+ holder.objective.visibility = View.VISIBLE
+ holder.objective.text = MainApp.gs(objective.objective)
+ } else
+ holder.objective.visibility = View.GONE
+ if (objective.gate != 0) {
+ holder.gate.visibility = View.VISIBLE
+ holder.gate.text = MainApp.gs(objective.gate)
+ } else
+ holder.gate.visibility = View.GONE
+ if (!objective.isStarted) {
+ holder.gate.setTextColor(-0x1)
+ holder.verify.visibility = View.GONE
+ holder.progress.visibility = View.GONE
+ holder.accomplished.visibility = View.GONE
+ holder.unFinish.visibility = View.GONE
+ holder.unStart.visibility = View.GONE
+ if (position == 0 || ObjectivesPlugin.objectives[position - 1].isAccomplished)
+ holder.start.visibility = View.VISIBLE
+ else
+ holder.start.visibility = View.GONE
+ } else if (objective.isAccomplished) {
+ holder.gate.setTextColor(-0xb350b0)
+ holder.verify.visibility = View.GONE
+ holder.progress.visibility = View.GONE
+ holder.start.visibility = View.GONE
+ holder.accomplished.visibility = View.VISIBLE
+ holder.unFinish.visibility = View.VISIBLE
+ holder.unStart.visibility = View.GONE
+ } else if (objective.isStarted) {
+ holder.gate.setTextColor(-0x1)
+ holder.verify.visibility = View.VISIBLE
+ holder.verify.isEnabled = objective.isCompleted || objectives_fake.isChecked
+ holder.start.visibility = View.GONE
+ holder.accomplished.visibility = View.GONE
+ holder.unFinish.visibility = View.GONE
+ holder.unStart.visibility = View.VISIBLE
+ holder.progress.visibility = View.VISIBLE
+ holder.progress.removeAllViews()
+ for (task in objective.tasks) {
+ if (task.shouldBeIgnored()) continue
+ // name
+ val name = TextView(holder.progress.context)
+ name.text = MainApp.gs(task.task) + ":"
+ name.setTextColor(-0x1)
+ holder.progress.addView(name, LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT)
+ // hint
+ task.hints.forEach { h ->
+ if (!task.isCompleted)
+ holder.progress.addView(h.generate(context))
+ }
+ // state
+ val state = TextView(holder.progress.context)
+ state.setTextColor(-0x1)
+ val basicHTML = "%2\$s "
+ val formattedHTML = String.format(basicHTML, if (task.isCompleted) "#4CAF50" else "#FF9800", task.progress)
+ state.text = HtmlHelper.fromHtml(formattedHTML)
+ state.gravity = Gravity.END
+ holder.progress.addView(state, LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT)
+ if (task is ExamTask) {
+ state.setOnClickListener {
+ val dialog = ObjectivesExamDialog()
+ val bundle = Bundle()
+ val taskPosition = objective.tasks.indexOf(task)
+ bundle.putInt("currentTask", taskPosition)
+ dialog.arguments = bundle
+ ObjectivesExamDialog.objective = objective
+ fragmentManager?.let { dialog.show(it, "ObjectivesFragment") }
+ }
+ }
+ // horizontal line
+ val separator = View(holder.progress.context)
+ separator.setBackgroundColor(Color.DKGRAY)
+ holder.progress.addView(separator, LinearLayout.LayoutParams.MATCH_PARENT, 2)
+ }
+ }
+ holder.accomplished.text = MainApp.gs(R.string.accomplished, DateUtil.dateAndTimeString(objective.accomplishedOn))
+ holder.accomplished.setTextColor(-0x3e3e3f)
+ holder.verify.setOnClickListener {
+ NetworkChangeReceiver.grabNetworkStatus(context)
+ if (objectives_fake.isChecked) {
+ objective.accomplishedOn = DateUtil.now()
+ scrollToCurrentObjective()
+ startUpdateTimer()
+ RxBus.send(EventObjectivesUpdateGui())
+ RxBus.send(EventSWUpdate(false))
+ } else {
+ // move out of UI thread
+ Thread {
+ NtpProgressDialog().show((context as AppCompatActivity).supportFragmentManager, "NtpCheck")
+ RxBus.send(EventNtpStatus(MainApp.gs(R.string.timedetection), 0))
+ SntpClient.ntpTime(object : SntpClient.Callback() {
+ override fun run() {
+ log.debug("NTP time: $time System time: ${DateUtil.now()}")
+ SystemClock.sleep(300)
+ if (!networkConnected) {
+ RxBus.send(EventNtpStatus(MainApp.gs(R.string.notconnected), 99))
+ } else if (success) {
+ if (objective.isCompleted(time)) {
+ objective.accomplishedOn = time
+ RxBus.send(EventNtpStatus(MainApp.gs(R.string.success), 100))
+ SystemClock.sleep(1000)
+ RxBus.send(EventObjectivesUpdateGui())
+ RxBus.send(EventSWUpdate(false))
+ SystemClock.sleep(100)
+ scrollToCurrentObjective()
+ } else {
+ RxBus.send(EventNtpStatus(MainApp.gs(R.string.requirementnotmet), 99))
+ }
+ } else {
+ RxBus.send(EventNtpStatus(MainApp.gs(R.string.failedretrievetime), 99))
+ }
+ }
+ }, NetworkChangeReceiver.isConnected())
+ }.start()
+ }
+ }
+ holder.start.setOnClickListener {
+ NetworkChangeReceiver.grabNetworkStatus(context)
+ if (objectives_fake.isChecked) {
+ objective.startedOn = DateUtil.now()
+ scrollToCurrentObjective()
+ startUpdateTimer()
+ RxBus.send(EventObjectivesUpdateGui())
+ RxBus.send(EventSWUpdate(false))
+ } else
+ // move out of UI thread
+ Thread {
+ NtpProgressDialog().show((context as AppCompatActivity).supportFragmentManager, "NtpCheck")
+ RxBus.send(EventNtpStatus(MainApp.gs(R.string.timedetection), 0))
+ SntpClient.ntpTime(object : SntpClient.Callback() {
+ override fun run() {
+ log.debug("NTP time: $time System time: ${DateUtil.now()}")
+ SystemClock.sleep(300)
+ if (!networkConnected) {
+ RxBus.send(EventNtpStatus(MainApp.gs(R.string.notconnected), 99))
+ } else if (success) {
+ objective.startedOn = time
+ RxBus.send(EventNtpStatus(MainApp.gs(R.string.success), 100))
+ SystemClock.sleep(1000)
+ RxBus.send(EventObjectivesUpdateGui())
+ RxBus.send(EventSWUpdate(false))
+ SystemClock.sleep(100)
+ scrollToCurrentObjective()
+ } else {
+ RxBus.send(EventNtpStatus(MainApp.gs(R.string.failedretrievetime), 99))
+ }
+ }
+ }, NetworkChangeReceiver.isConnected())
+ }.start()
+ }
+ holder.unStart.setOnClickListener {
+ activity?.let { activity ->
+ OKDialog.showConfirmation(activity, MainApp.gs(R.string.objectives), MainApp.gs(R.string.doyouwantresetstart), Runnable {
+ objective.startedOn = 0
+ scrollToCurrentObjective()
+ RxBus.send(EventObjectivesUpdateGui())
+ RxBus.send(EventSWUpdate(false))
+ })
+ }
+ }
+ holder.unFinish.setOnClickListener {
+ objective.accomplishedOn = 0
+ scrollToCurrentObjective()
+ RxBus.send(EventObjectivesUpdateGui())
+ RxBus.send(EventSWUpdate(false))
+ }
+ if (objective.hasSpecialInput && !objective.isAccomplished && objective.isStarted && objective.specialActionEnabled()) {
+ // generate random request code if none exists
+ val request = SP.getString(R.string.key_objectives_request_code, String.format("%1$05d", (Math.random() * 99999).toInt()))
+ SP.putString(R.string.key_objectives_request_code, request)
+ holder.requestCode.text = MainApp.gs(R.string.requestcode, request)
+ holder.requestCode.visibility = View.VISIBLE
+ holder.enterButton.visibility = View.VISIBLE
+ holder.input.visibility = View.VISIBLE
+ holder.inputHint.visibility = View.VISIBLE
+ holder.enterButton.setOnClickListener {
+ val input = holder.input.text.toString()
+ objective.specialAction(activity, input)
+ RxBus.send(EventObjectivesUpdateGui())
+ }
+ } else {
+ holder.enterButton.visibility = View.GONE
+ holder.input.visibility = View.GONE
+ holder.inputHint.visibility = View.GONE
+ holder.requestCode.visibility = View.GONE
+ }
+ }
+
+ override fun getItemCount(): Int {
+ return ObjectivesPlugin.objectives.size
+ }
+
+ inner class ViewHolder internal constructor(itemView: View) : RecyclerView.ViewHolder(itemView) {
+ val title: TextView = itemView.findViewById(R.id.objective_title)
+ val objective: TextView = itemView.findViewById(R.id.objective_objective)
+ val gate: TextView = itemView.findViewById(R.id.objective_gate)
+ val accomplished: TextView = itemView.findViewById(R.id.objective_accomplished)
+ val progress: LinearLayout = itemView.findViewById(R.id.objective_progress)
+ val verify: Button = itemView.findViewById(R.id.objective_verify)
+ val start: Button = itemView.findViewById(R.id.objective_start)
+ val unFinish: Button = itemView.findViewById(R.id.objective_unfinish)
+ val unStart: Button = itemView.findViewById(R.id.objective_unstart)
+ val inputHint: TextView = itemView.findViewById(R.id.objective_inputhint)
+ val input: EditText = itemView.findViewById(R.id.objective_input)
+ val enterButton: Button = itemView.findViewById(R.id.objective_enterbutton)
+ val requestCode: TextView = itemView.findViewById(R.id.objective_requestcode)
+ }
+ }
+
+ fun updateGUI() {
+ activity?.runOnUiThread { objectivesAdapter.notifyDataSetChanged() }
+ }
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/ObjectivesPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/ObjectivesPlugin.java
deleted file mode 100644
index 1d18cd14b48..00000000000
--- a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/ObjectivesPlugin.java
+++ /dev/null
@@ -1,164 +0,0 @@
-package info.nightscout.androidaps.plugins.constraints.objectives;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import info.nightscout.androidaps.Config;
-import info.nightscout.androidaps.MainApp;
-import info.nightscout.androidaps.R;
-import info.nightscout.androidaps.interfaces.Constraint;
-import info.nightscout.androidaps.interfaces.ConstraintsInterface;
-import info.nightscout.androidaps.interfaces.PluginBase;
-import info.nightscout.androidaps.interfaces.PluginDescription;
-import info.nightscout.androidaps.interfaces.PluginType;
-import info.nightscout.androidaps.interfaces.PumpInterface;
-import info.nightscout.androidaps.logging.L;
-import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin;
-import info.nightscout.androidaps.plugins.constraints.objectives.events.EventObjectivesSaved;
-import info.nightscout.androidaps.plugins.constraints.objectives.objectives.Objective;
-import info.nightscout.androidaps.plugins.constraints.objectives.objectives.Objective1;
-import info.nightscout.androidaps.plugins.constraints.objectives.objectives.Objective2;
-import info.nightscout.androidaps.plugins.constraints.objectives.objectives.Objective3;
-import info.nightscout.androidaps.plugins.constraints.objectives.objectives.Objective4;
-import info.nightscout.androidaps.plugins.constraints.objectives.objectives.Objective5;
-import info.nightscout.androidaps.plugins.constraints.objectives.objectives.Objective6;
-import info.nightscout.androidaps.plugins.constraints.objectives.objectives.Objective7;
-import info.nightscout.androidaps.plugins.constraints.objectives.objectives.Objective8;
-import info.nightscout.androidaps.utils.SP;
-
-/**
- * Created by mike on 05.08.2016.
- */
-public class ObjectivesPlugin extends PluginBase implements ConstraintsInterface {
- private static Logger log = LoggerFactory.getLogger(L.CONSTRAINTS);
-
- private static ObjectivesPlugin objectivesPlugin;
-
- public List objectives = new ArrayList<>();
- public boolean bgIsAvailableInNS = false;
- public boolean pumpStatusIsAvailableInNS = false;
- public Integer manualEnacts = 0;
-
- public static ObjectivesPlugin getPlugin() {
- if (objectivesPlugin == null) {
- objectivesPlugin = new ObjectivesPlugin();
- }
- return objectivesPlugin;
- }
-
- private ObjectivesPlugin() {
- super(new PluginDescription()
- .mainType(PluginType.CONSTRAINTS)
- .fragmentClass(ObjectivesFragment.class.getName())
- .alwaysEnabled(!Config.NSCLIENT)
- .showInList(!Config.NSCLIENT)
- .pluginName(R.string.objectives)
- .shortName(R.string.objectives_shortname)
- .description(R.string.description_objectives)
- );
- setupObjectives();
- loadProgress();
- }
-
- @Override
- public boolean specialEnableCondition() {
- PumpInterface pump = ConfigBuilderPlugin.getPlugin().getActivePump();
- return pump == null || pump.getPumpDescription().isTempBasalCapable;
- }
-
- private void setupObjectives() {
- objectives.add(new Objective1());
- objectives.add(new Objective2());
- objectives.add(new Objective3());
- objectives.add(new Objective4());
- objectives.add(new Objective5());
- objectives.add(new Objective6());
- objectives.add(new Objective7());
- objectives.add(new Objective8());
- }
-
- public void reset() {
- for (Objective objective : objectives) {
- objective.setStartedOn(null);
- objective.setAccomplishedOn(null);
- }
- bgIsAvailableInNS = false;
- pumpStatusIsAvailableInNS = false;
- manualEnacts = 0;
- saveProgress();
- }
-
- public void saveProgress() {
- SP.putBoolean("Objectives" + "bgIsAvailableInNS", bgIsAvailableInNS);
- SP.putBoolean("Objectives" + "pumpStatusIsAvailableInNS", pumpStatusIsAvailableInNS);
- SP.putString("Objectives" + "manualEnacts", Integer.toString(manualEnacts));
- if (L.isEnabled(L.CONSTRAINTS))
- log.debug("Objectives stored");
- MainApp.bus().post(new EventObjectivesSaved());
- }
-
- private void loadProgress() {
- bgIsAvailableInNS = SP.getBoolean("Objectives" + "bgIsAvailableInNS", false);
- pumpStatusIsAvailableInNS = SP.getBoolean("Objectives" + "pumpStatusIsAvailableInNS", false);
- try {
- manualEnacts = SP.getInt("Objectives" + "manualEnacts", 0);
- } catch (Exception e) {
- log.error("Unhandled exception", e);
- }
- if (L.isEnabled(L.CONSTRAINTS))
- log.debug("Objectives loaded");
- }
-
- public List getObjectives() {
- return objectives;
- }
-
- /**
- * Constraints interface
- **/
- @Override
- public Constraint isLoopInvocationAllowed(Constraint value) {
- if (!objectives.get(0).isStarted())
- value.set(false, String.format(MainApp.gs(R.string.objectivenotstarted), 1), this);
- return value;
- }
-
- @Override
- public Constraint isClosedLoopAllowed(Constraint value) {
- if (!objectives.get(3).isStarted())
- value.set(false, String.format(MainApp.gs(R.string.objectivenotstarted), 4), this);
- return value;
- }
-
- @Override
- public Constraint isAutosensModeEnabled(Constraint value) {
- if (!objectives.get(5).isStarted())
- value.set(false, String.format(MainApp.gs(R.string.objectivenotstarted), 6), this);
- return value;
- }
-
- @Override
- public Constraint isAMAModeEnabled(Constraint value) {
- if (!objectives.get(6).isStarted())
- value.set(false, String.format(MainApp.gs(R.string.objectivenotstarted), 7), this);
- return value;
- }
-
- @Override
- public Constraint isSMBModeEnabled(Constraint value) {
- if (!objectives.get(7).isStarted())
- value.set(false, String.format(MainApp.gs(R.string.objectivenotstarted), 8), this);
- return value;
- }
-
- @Override
- public Constraint applyMaxIOBConstraints(Constraint maxIob) {
- if (objectives.get(3).isStarted() && !objectives.get(3).isAccomplished())
- maxIob.set(0d, String.format(MainApp.gs(R.string.objectivenotfinished), 4), this);
- return maxIob;
- }
-
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/ObjectivesPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/ObjectivesPlugin.kt
new file mode 100644
index 00000000000..ebae80150cc
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/ObjectivesPlugin.kt
@@ -0,0 +1,170 @@
+package info.nightscout.androidaps.plugins.constraints.objectives
+
+import android.app.Activity
+import com.google.common.base.Charsets
+import com.google.common.hash.Hashing
+import info.nightscout.androidaps.BuildConfig
+import info.nightscout.androidaps.Config
+import info.nightscout.androidaps.MainApp
+import info.nightscout.androidaps.R
+import info.nightscout.androidaps.interfaces.*
+import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin
+import info.nightscout.androidaps.plugins.constraints.objectives.objectives.*
+import info.nightscout.androidaps.utils.DateUtil
+import info.nightscout.androidaps.utils.OKDialog
+import info.nightscout.androidaps.utils.SP
+import java.util.*
+
+/**
+ * Created by mike on 05.08.2016.
+ */
+object ObjectivesPlugin : PluginBase(PluginDescription()
+ .mainType(PluginType.CONSTRAINTS)
+ .fragmentClass(ObjectivesFragment::class.qualifiedName)
+ .alwaysEnabled(Config.APS)
+ .showInList(Config.APS)
+ .pluginName(R.string.objectives)
+ .shortName(R.string.objectives_shortname)
+ .description(R.string.description_objectives)), ConstraintsInterface {
+
+ var objectives: MutableList = ArrayList()
+
+ val FIRST_OBJECTIVE = 0
+ val USAGE_OBJECTIVE = 1
+ val EXAM_OBJECTIVE = 2
+ val OPENLOOP_OBJECTIVE = 3
+ val MAXBASAL_OBJECTIVE = 4
+ val MAXIOB_ZERO_CL_OBJECTIVE = 5
+ val MAXIOB_OBJECTIVE = 6
+ val AUTOSENS_OBJECTIVE = 7
+ val AMA_OBJECTIVE = 8
+ val SMB_OBJECTIVE = 9
+
+ init {
+ convertSP()
+ setupObjectives()
+ }
+
+ override fun specialEnableCondition(): Boolean {
+ val pump = ConfigBuilderPlugin.getPlugin().activePump
+ return pump == null || pump.pumpDescription.isTempBasalCapable
+ }
+
+ // convert 2.3 SP version
+ private fun convertSP() {
+ doConvertSP(0, "config")
+ doConvertSP(1, "openloop")
+ doConvertSP(2, "maxbasal")
+ doConvertSP(3, "maxiobzero")
+ doConvertSP(4, "maxiob")
+ doConvertSP(5, "autosens")
+ doConvertSP(6, "ama")
+ doConvertSP(7, "smb")
+ }
+
+ private fun doConvertSP(number: Int, name: String) {
+ if (!SP.contains("Objectives_" + name + "_started")) {
+ SP.putLong("Objectives_" + name + "_started", SP.getLong("Objectives" + number + "started", 0L))
+ SP.putLong("Objectives_" + name + "_accomplished", SP.getLong("Objectives" + number + "accomplished", 0L))
+ }
+ // TODO: we can remove Objectives1accomplished sometimes later
+ }
+
+ private fun setupObjectives() {
+ objectives.clear()
+ objectives.add(Objective0())
+ objectives.add(Objective1())
+ objectives.add(Objective2())
+ objectives.add(Objective3())
+ objectives.add(Objective4())
+ objectives.add(Objective5())
+ objectives.add(Objective6())
+ objectives.add(Objective7())
+ objectives.add(Objective8())
+ objectives.add(Objective9())
+ }
+
+ fun reset() {
+ for (objective in objectives) {
+ objective.startedOn = 0
+ objective.accomplishedOn = 0
+ }
+ SP.putBoolean(R.string.key_ObjectivesbgIsAvailableInNS, false)
+ SP.putBoolean(R.string.key_ObjectivespumpStatusIsAvailableInNS, false)
+ SP.putInt(R.string.key_ObjectivesmanualEnacts, 0)
+ SP.putBoolean(R.string.key_objectiveuseprofileswitch, false)
+ SP.putBoolean(R.string.key_objectiveusedisconnect, false)
+ SP.putBoolean(R.string.key_objectiveusereconnect, false)
+ SP.putBoolean(R.string.key_objectiveusetemptarget, false)
+ SP.putBoolean(R.string.key_objectiveuseactions, false)
+ SP.putBoolean(R.string.key_objectiveuseloop, false)
+ SP.putBoolean(R.string.key_objectiveusescale, false)
+ }
+
+ fun completeObjectives(activity: Activity, request: String) {
+ val requestCode = SP.getString(R.string.key_objectives_request_code, "")
+ var url = SP.getString(R.string.key_nsclientinternal_url, "").toLowerCase()
+ if (!url.endsWith("/")) url = "$url/"
+ @Suppress("DEPRECATION") val hashNS = Hashing.sha1().hashString(url + BuildConfig.APPLICATION_ID + "/" + requestCode, Charsets.UTF_8).toString()
+ if (request.equals(hashNS.substring(0, 10), ignoreCase = true)) {
+ SP.putLong("Objectives_" + "openloop" + "_started", DateUtil.now())
+ SP.putLong("Objectives_" + "openloop" + "_accomplished", DateUtil.now())
+ SP.putLong("Objectives_" + "maxbasal" + "_started", DateUtil.now())
+ SP.putLong("Objectives_" + "maxbasal" + "_accomplished", DateUtil.now())
+ SP.putLong("Objectives_" + "maxiobzero" + "_started", DateUtil.now())
+ SP.putLong("Objectives_" + "maxiobzero" + "_accomplished", DateUtil.now())
+ SP.putLong("Objectives_" + "maxiob" + "_started", DateUtil.now())
+ SP.putLong("Objectives_" + "maxiob" + "_accomplished", DateUtil.now())
+ SP.putLong("Objectives_" + "autosens" + "_started", DateUtil.now())
+ SP.putLong("Objectives_" + "autosens" + "_accomplished", DateUtil.now())
+ SP.putLong("Objectives_" + "ama" + "_started", DateUtil.now())
+ SP.putLong("Objectives_" + "ama" + "_accomplished", DateUtil.now())
+ SP.putLong("Objectives_" + "smb" + "_started", DateUtil.now())
+ SP.putLong("Objectives_" + "smb" + "_accomplished", DateUtil.now())
+ setupObjectives()
+ OKDialog.show(activity, MainApp.gs(R.string.objectives), MainApp.gs(R.string.codeaccepted))
+ } else {
+ OKDialog.show(activity, MainApp.gs(R.string.objectives), MainApp.gs(R.string.codeinvalid))
+ }
+ }
+
+ /**
+ * Constraints interface
+ */
+ override fun isLoopInvocationAllowed(value: Constraint): Constraint {
+ if (!objectives[FIRST_OBJECTIVE].isStarted)
+ value.set(false, String.format(MainApp.gs(R.string.objectivenotstarted), FIRST_OBJECTIVE + 1), this)
+ return value
+ }
+
+ override fun isClosedLoopAllowed(value: Constraint): Constraint {
+ if (!objectives[MAXIOB_ZERO_CL_OBJECTIVE].isStarted)
+ value.set(false, String.format(MainApp.gs(R.string.objectivenotstarted), MAXIOB_ZERO_CL_OBJECTIVE + 1), this)
+ return value
+ }
+
+ override fun isAutosensModeEnabled(value: Constraint): Constraint {
+ if (!objectives[AUTOSENS_OBJECTIVE].isStarted)
+ value.set(false, String.format(MainApp.gs(R.string.objectivenotstarted), AUTOSENS_OBJECTIVE + 1), this)
+ return value
+ }
+
+ override fun isAMAModeEnabled(value: Constraint): Constraint {
+ if (!objectives[AMA_OBJECTIVE].isStarted)
+ value.set(false, String.format(MainApp.gs(R.string.objectivenotstarted), AMA_OBJECTIVE + 1), this)
+ return value
+ }
+
+ override fun isSMBModeEnabled(value: Constraint): Constraint {
+ if (!objectives[SMB_OBJECTIVE].isStarted)
+ value.set(false, String.format(MainApp.gs(R.string.objectivenotstarted), SMB_OBJECTIVE + 1), this)
+ return value
+ }
+
+ override fun applyMaxIOBConstraints(maxIob: Constraint): Constraint {
+ if (objectives[MAXIOB_ZERO_CL_OBJECTIVE].isStarted && !objectives[MAXIOB_ZERO_CL_OBJECTIVE].isAccomplished)
+ maxIob.set(0.0, String.format(MainApp.gs(R.string.objectivenotfinished), MAXIOB_ZERO_CL_OBJECTIVE + 1), this)
+ return maxIob
+ }
+
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/activities/ObjectivesExamDialog.kt b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/activities/ObjectivesExamDialog.kt
new file mode 100644
index 00000000000..1428652be51
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/activities/ObjectivesExamDialog.kt
@@ -0,0 +1,130 @@
+package info.nightscout.androidaps.plugins.constraints.objectives.activities
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.fragment.app.DialogFragment
+import info.nightscout.androidaps.MainApp
+import info.nightscout.androidaps.R
+import info.nightscout.androidaps.plugins.bus.RxBus
+import info.nightscout.androidaps.plugins.constraints.objectives.events.EventObjectivesUpdateGui
+import info.nightscout.androidaps.plugins.constraints.objectives.objectives.Objective
+import info.nightscout.androidaps.plugins.constraints.objectives.objectives.Objective.*
+import info.nightscout.androidaps.utils.DateUtil
+import info.nightscout.androidaps.utils.OKDialog
+import info.nightscout.androidaps.utils.T
+import info.nightscout.androidaps.utils.ToastUtils
+import kotlinx.android.synthetic.main.objectives_exam_fragment.*
+
+class ObjectivesExamDialog : DialogFragment() {
+ companion object {
+ var objective: Objective? = null
+ }
+
+ var currentTask = 0
+
+ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
+ savedInstanceState: Bundle?): View? {
+ // load data from bundle
+ (savedInstanceState ?: arguments)?.let { bundle ->
+ currentTask = bundle.getInt("currentTask", 0)
+ }
+
+ return inflater.inflate(R.layout.objectives_exam_fragment, container, false)
+ }
+
+ override fun onStart() {
+ super.onStart()
+ dialog?.setCanceledOnTouchOutside(false)
+ dialog?.window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
+ }
+
+ override fun onResume() {
+ super.onResume()
+ updateGui()
+ }
+
+ override fun onSaveInstanceState(bundle: Bundle) {
+ super.onSaveInstanceState(bundle)
+ bundle.putInt("currentTask", currentTask)
+ }
+
+ fun updateGui() {
+ objective?.let { objective ->
+ val task: ExamTask = objective.tasks[currentTask] as ExamTask
+ objectives_exam_name.setText(task.task)
+ objectives_exam_question.setText(task.question)
+ // Options
+ objectives_exam_options.removeAllViews()
+ task.options.forEach {
+ val cb = it.generate(context)
+ if (task.answered) {
+ cb.isEnabled = false
+ if (it.isCorrect)
+ cb.isChecked = true
+ }
+ objectives_exam_options.addView(cb)
+ }
+ // Hints
+ objectives_exam_hints.removeAllViews()
+ for (h in task.hints) {
+ objectives_exam_hints.addView(h.generate(context))
+ }
+ // Disabled to
+ objectives_exam_disabledto.text = MainApp.gs(R.string.answerdisabledto, DateUtil.timeString(task.disabledTo))
+ objectives_exam_disabledto.visibility = if (task.isEnabledAnswer) View.GONE else View.VISIBLE
+ // Buttons
+ objectives_exam_verify.isEnabled = !task.answered && task.isEnabledAnswer
+ objectives_exam_verify.setOnClickListener {
+ var result = true
+ for (o in task.options) {
+ val option: Option = o as Option;
+ result = result && option.evaluate()
+ }
+ task.setAnswered(result);
+ if (!result) {
+ task.disabledTo = DateUtil.now() + T.hours(1).msecs()
+ ToastUtils.showToastInUiThread(context, R.string.wronganswer)
+ } else task.disabledTo = 0
+ updateGui()
+ RxBus.send(EventObjectivesUpdateGui())
+ }
+ close.setOnClickListener { dismiss() }
+ objectives_exam_reset.setOnClickListener {
+ task.answered = false
+ //task.disabledTo = 0
+ updateGui()
+ RxBus.send(EventObjectivesUpdateGui())
+ }
+ objectives_back_button.isEnabled = currentTask != 0
+ objectives_back_button.setOnClickListener {
+ currentTask--
+ updateGui()
+ }
+ objectives_next_button.isEnabled = currentTask != objective.tasks.size - 1
+ objectives_next_button.setOnClickListener {
+ currentTask++
+ updateGui()
+ }
+
+ objectives_next_unanswered_button.isEnabled = !objective.isCompleted
+ objectives_next_unanswered_button.setOnClickListener {
+ for (i in (currentTask + 1)..(objective.tasks.size - 1)) {
+ if (!objective.tasks[i].isCompleted) {
+ currentTask = i
+ updateGui()
+ return@setOnClickListener
+ }
+ }
+ for (i in 0..currentTask) {
+ if (!objective.tasks[i].isCompleted) {
+ currentTask = i
+ updateGui()
+ return@setOnClickListener
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/dialogs/NtpProgressDialog.kt b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/dialogs/NtpProgressDialog.kt
new file mode 100644
index 00000000000..77e6f22b436
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/dialogs/NtpProgressDialog.kt
@@ -0,0 +1,85 @@
+package info.nightscout.androidaps.plugins.constraints.objectives.dialogs
+
+import android.os.Bundle
+import android.os.SystemClock
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.fragment.app.DialogFragment
+import info.nightscout.androidaps.MainApp
+import info.nightscout.androidaps.R
+import info.nightscout.androidaps.logging.L
+import info.nightscout.androidaps.plugins.bus.RxBus.toObservable
+import info.nightscout.androidaps.plugins.constraints.objectives.events.EventNtpStatus
+import info.nightscout.androidaps.utils.FabricPrivacy
+import io.reactivex.android.schedulers.AndroidSchedulers
+import io.reactivex.disposables.CompositeDisposable
+import kotlinx.android.synthetic.main.dialog_bolusprogress.*
+import org.slf4j.LoggerFactory
+
+class NtpProgressDialog : DialogFragment() {
+ private val log = LoggerFactory.getLogger(L.UI)
+ private val disposable = CompositeDisposable()
+
+ private val DEFAULT_STATE = MainApp.gs(R.string.timedetection)
+ private var state: String = DEFAULT_STATE
+ private var percent = 0
+
+ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
+ savedInstanceState: Bundle?): View? {
+ dialog?.setTitle(String.format(MainApp.gs(R.string.objectives)))
+ isCancelable = false
+
+ state = savedInstanceState?.getString("state", DEFAULT_STATE) ?: DEFAULT_STATE
+ percent = savedInstanceState?.getInt("percent", 0) ?: 0
+
+ return inflater.inflate(R.layout.dialog_bolusprogress, container, false)
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ overview_bolusprogress_stop.setOnClickListener { dismiss() }
+ overview_bolusprogress_status.text = state
+ overview_bolusprogress_progressbar.max = 100
+ overview_bolusprogress_progressbar.progress = percent
+ overview_bolusprogress_stop.text = MainApp.gs(R.string.close)
+ overview_bolusprogress_title.text = MainApp.gs(R.string.please_wait)
+ }
+
+ override fun onResume() {
+ super.onResume()
+ if (L.isEnabled(L.UI)) log.debug("onResume")
+ if (percent == 100) {
+ dismiss()
+ return
+ } else
+ dialog?.window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
+
+ disposable.add(toObservable(EventNtpStatus::class.java)
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe({ event: EventNtpStatus ->
+ if (L.isEnabled(L.UI)) log.debug("Status: " + event.status + " Percent: " + event.percent)
+ overview_bolusprogress_status?.text = event.status
+ overview_bolusprogress_progressbar?.progress = event.percent
+ if (event.percent == 100) {
+ SystemClock.sleep(100)
+ dismiss()
+ }
+ state = event.status
+ percent = event.percent
+ }) { FabricPrivacy.logException(it) }
+ )
+ }
+
+ override fun onPause() {
+ if (L.isEnabled(L.UI)) log.debug("onPause")
+ super.onPause()
+ disposable.clear()
+ }
+
+ override fun onSaveInstanceState(outState: Bundle) {
+ outState.putString("state", state)
+ outState.putInt("percent", percent)
+ super.onSaveInstanceState(outState)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/events/EventNtpStatus.kt b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/events/EventNtpStatus.kt
new file mode 100644
index 00000000000..fc4e5cb8e91
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/events/EventNtpStatus.kt
@@ -0,0 +1,5 @@
+package info.nightscout.androidaps.plugins.constraints.objectives.events
+
+import info.nightscout.androidaps.events.Event
+
+class EventNtpStatus(val status: String, val percent: Int) : Event()
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/events/EventObjectivesSaved.java b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/events/EventObjectivesSaved.java
deleted file mode 100644
index d4dbb0251de..00000000000
--- a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/events/EventObjectivesSaved.java
+++ /dev/null
@@ -1,6 +0,0 @@
-package info.nightscout.androidaps.plugins.constraints.objectives.events;
-
-import info.nightscout.androidaps.events.Event;
-
-public class EventObjectivesSaved extends Event {
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/events/EventObjectivesUpdateGui.kt b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/events/EventObjectivesUpdateGui.kt
new file mode 100644
index 00000000000..fd59db7d9fe
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/events/EventObjectivesUpdateGui.kt
@@ -0,0 +1,5 @@
+package info.nightscout.androidaps.plugins.constraints.objectives.events
+
+import info.nightscout.androidaps.events.EventUpdateGui
+
+class EventObjectivesUpdateGui : EventUpdateGui()
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective.java b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective.java
index 83abe156882..7082c7e7bce 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective.java
@@ -1,35 +1,46 @@
package info.nightscout.androidaps.plugins.constraints.objectives.objectives;
-import android.support.annotation.StringRes;
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Color;
+import android.text.util.Linkify;
+import android.view.View;
+import android.widget.CheckBox;
+import android.widget.TextView;
+
+import androidx.annotation.StringRes;
import java.util.ArrayList;
-import java.util.Date;
import java.util.List;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
+import info.nightscout.androidaps.utils.DateUtil;
import info.nightscout.androidaps.utils.SP;
import info.nightscout.androidaps.utils.T;
public abstract class Objective {
- private int number;
+ private String spName;
@StringRes
private int objective;
@StringRes
private int gate;
- private Date startedOn;
- private Date accomplishedOn;
- private List tasks = new ArrayList<>();
+ private long startedOn;
+ private long accomplishedOn;
+ List tasks = new ArrayList<>();
+ public boolean hasSpecialInput = false;
- public Objective(int number, @StringRes int objective, @StringRes int gate) {
- this.number = number;
+ public Objective(String spName, @StringRes int objective, @StringRes int gate) {
+ this.spName = spName;
this.objective = objective;
this.gate = gate;
- startedOn = new Date(SP.getLong("Objectives" + number + "started", 0L));
- if (startedOn.getTime() == 0L) startedOn = null;
- accomplishedOn = new Date(SP.getLong("Objectives" + number + "accomplished", 0L));
- if (accomplishedOn.getTime() == 0L) accomplishedOn = null;
+ startedOn = SP.getLong("Objectives_" + spName + "_started", 0L);
+ accomplishedOn = SP.getLong("Objectives_" + spName + "_accomplished", 0L);
+ if ((accomplishedOn - DateUtil.now()) > T.hours(3).msecs() || (startedOn - DateUtil.now()) > T.hours(3).msecs()) { // more than 3 hours in the future
+ startedOn = 0;
+ accomplishedOn = 0;
+ }
setupTasks(tasks);
for (Task task : tasks) task.objective = this;
}
@@ -42,19 +53,23 @@ public boolean isCompleted() {
return true;
}
- public boolean isRevertable() {
- return false;
+ public boolean isCompleted(long trueTime) {
+ for (Task task : tasks) {
+ if (!task.shouldBeIgnored() && !task.isCompleted(trueTime))
+ return false;
+ }
+ return true;
}
public boolean isAccomplished() {
- return accomplishedOn != null;
+ return accomplishedOn != 0 && accomplishedOn < DateUtil.now();
}
public boolean isStarted() {
- return startedOn != null;
+ return startedOn != 0;
}
- public Date getStartedOn() {
+ public long getStartedOn() {
return startedOn;
}
@@ -66,14 +81,18 @@ public int getGate() {
return gate;
}
- public void setStartedOn(Date startedOn) {
+ public void setStartedOn(long startedOn) {
this.startedOn = startedOn;
- SP.putLong("Objectives" + number + "started", startedOn == null ? 0 : startedOn.getTime());
+ SP.putLong("Objectives_" + spName + "_started", startedOn);
}
- public void setAccomplishedOn(Date accomplishedOn) {
+ public void setAccomplishedOn(long accomplishedOn) {
this.accomplishedOn = accomplishedOn;
- SP.putLong("Objectives" + number + "accomplished", accomplishedOn == null ? 0 : accomplishedOn.getTime());
+ SP.putLong("Objectives_" + spName + "_accomplished", accomplishedOn);
+ }
+
+ public long getAccomplishedOn() {
+ return accomplishedOn;
}
protected void setupTasks(List tasks) {
@@ -84,16 +103,21 @@ public List getTasks() {
return tasks;
}
+ public boolean specialActionEnabled() { return true; }
+
+ public void specialAction(Activity activity, String input) {}
+
public abstract class Task {
@StringRes
private int task;
private Objective objective;
+ ArrayList hints = new ArrayList<>();
public Task(@StringRes int task) {
this.task = task;
}
- public int getTask() {
+ public @StringRes int getTask() {
return task;
}
@@ -102,11 +126,21 @@ protected Objective getObjective() {
}
public abstract boolean isCompleted();
+ public boolean isCompleted(long trueTime) { return isCompleted(); };
public String getProgress() {
return MainApp.gs(isCompleted() ? R.string.completed_well_done : R.string.not_completed_yet);
}
+ Task hint(Hint hint) {
+ hints.add(hint);
+ return this;
+ }
+
+ public ArrayList getHints() {
+ return hints;
+ }
+
public boolean shouldBeIgnored() {
return false;
}
@@ -116,19 +150,24 @@ public class MinimumDurationTask extends Task {
private long minimumDuration;
- public MinimumDurationTask(long minimumDuration) {
+ MinimumDurationTask(long minimumDuration) {
super(R.string.time_elapsed);
this.minimumDuration = minimumDuration;
}
@Override
public boolean isCompleted() {
- return getObjective().isStarted() && System.currentTimeMillis() - getObjective().getStartedOn().getTime() >= minimumDuration;
+ return getObjective().isStarted() && System.currentTimeMillis() - getObjective().getStartedOn() >= minimumDuration;
+ }
+
+ @Override
+ public boolean isCompleted(long trueTime) {
+ return getObjective().isStarted() && trueTime - getObjective().getStartedOn() >= minimumDuration;
}
@Override
public String getProgress() {
- return getDurationText(System.currentTimeMillis() - getObjective().getStartedOn().getTime())
+ return getDurationText(System.currentTimeMillis() - getObjective().getStartedOn())
+ " / " + getDurationText(minimumDuration);
}
@@ -142,4 +181,107 @@ private String getDurationText(long duration) {
}
}
+ public class ExamTask extends Task {
+ @StringRes
+ int question;
+ ArrayList options = new ArrayList<>();
+ private String spIdentifier;
+ private boolean answered;
+ private long disabledTo;
+
+ ExamTask(@StringRes int task, @StringRes int question, String spIdentifier) {
+ super(task);
+ this.question = question;
+ this.spIdentifier = spIdentifier;
+ answered = SP.getBoolean("ExamTask_" + spIdentifier, false);
+ disabledTo = SP.getLong("DisabledTo_" + spIdentifier, 0L);
+ }
+
+ public void setDisabledTo(long newState) {
+ disabledTo = newState;
+ SP.putLong("DisabledTo_" + spIdentifier, disabledTo);
+ }
+
+ public long getDisabledTo() {
+ return disabledTo;
+ }
+
+ public boolean isEnabledAnswer() {
+ return disabledTo < DateUtil.now();
+ }
+
+ public void setAnswered(boolean newState) {
+ answered = newState;
+ SP.putBoolean("ExamTask_" + spIdentifier, answered);
+ }
+
+ public boolean getAnswered() {
+ return answered;
+ }
+
+ ExamTask option(Option option) {
+ options.add(option);
+ return this;
+ }
+
+ public @StringRes int getQuestion() {
+ return question;
+ }
+
+ public List getOptions() {
+ return options;
+ }
+
+ @Override
+ public boolean isCompleted() {
+ return answered;
+ }
+ }
+
+ public class Option {
+ @StringRes int option;
+ boolean isCorrect;
+
+ CheckBox cb; // TODO: change it, this will block releasing memeory
+
+ Option(@StringRes int option, boolean isCorrect) {
+ this.option = option;
+ this.isCorrect = isCorrect;
+ }
+
+ public boolean isCorrect() {
+ return isCorrect;
+ }
+
+ public CheckBox generate(Context context) {
+ cb = new CheckBox(context);
+ cb.setText(option);
+ return cb;
+ }
+
+ public boolean evaluate() {
+ boolean selection = cb.isChecked();
+ if (selection && isCorrect) return true;
+ if (!selection && !isCorrect) return true;
+ return false;
+ }
+ }
+
+ public class Hint {
+ @StringRes int hint;
+
+ Hint(@StringRes int hint) {
+ this.hint = hint;
+ }
+
+ public TextView generate(Context context) {
+ TextView textView = new TextView(context);
+ textView.setText(hint);
+ textView.setAutoLinkMask(Linkify.WEB_URLS);
+ textView.setLinksClickable(true);
+ textView.setLinkTextColor(Color.YELLOW);
+ Linkify.addLinks(textView, Linkify.WEB_URLS);
+ return textView;
+ }
+ }
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective0.java b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective0.java
new file mode 100644
index 00000000000..f6f0267a235
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective0.java
@@ -0,0 +1,84 @@
+package info.nightscout.androidaps.plugins.constraints.objectives.objectives;
+
+import java.util.List;
+
+import info.nightscout.androidaps.R;
+import info.nightscout.androidaps.db.DatabaseHelper;
+import info.nightscout.androidaps.interfaces.APSInterface;
+import info.nightscout.androidaps.interfaces.PluginBase;
+import info.nightscout.androidaps.interfaces.PluginType;
+import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin;
+import info.nightscout.androidaps.plugins.constraints.objectives.ObjectivesPlugin;
+import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin;
+import info.nightscout.androidaps.plugins.general.nsclient.NSClientPlugin;
+import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin;
+import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
+import info.nightscout.androidaps.utils.DateUtil;
+import info.nightscout.androidaps.utils.SP;
+
+public class Objective0 extends Objective {
+
+ public Objective0() {
+ super("config", R.string.objectives_0_objective, R.string.objectives_0_gate);
+ }
+
+ @Override
+ protected void setupTasks(List tasks) {
+ tasks.add(new Task(R.string.objectives_bgavailableinns) {
+ @Override
+ public boolean isCompleted() {
+ return SP.getBoolean(R.string.key_ObjectivesbgIsAvailableInNS, false);
+ }
+ });
+ tasks.add(new Task(R.string.nsclienthaswritepermission) {
+ @Override
+ public boolean isCompleted() {
+ return NSClientPlugin.getPlugin().hasWritePermission();
+ }
+ });
+ tasks.add(new Task(R.string.virtualpump_uploadstatus_title) {
+ @Override
+ public boolean isCompleted() {
+ return SP.getBoolean("virtualpump_uploadstatus", false);
+ }
+
+ @Override
+ public boolean shouldBeIgnored() {
+ return !VirtualPumpPlugin.getPlugin().isEnabled(PluginType.PUMP);
+ }
+ });
+ tasks.add(new Task(R.string.objectives_pumpstatusavailableinns) {
+ @Override
+ public boolean isCompleted() {
+ return SP.getBoolean(R.string.key_ObjectivespumpStatusIsAvailableInNS, false);
+ }
+ });
+ tasks.add(new Task(R.string.hasbgdata) {
+ @Override
+ public boolean isCompleted() {
+ return DatabaseHelper.lastBg() != null;
+ }
+ });
+ tasks.add(new Task(R.string.loopenabled) {
+ @Override
+ public boolean isCompleted() {
+ return LoopPlugin.getPlugin().isEnabled(PluginType.LOOP);
+ }
+ });
+ tasks.add(new Task(R.string.apsselected) {
+ @Override
+ public boolean isCompleted() {
+ APSInterface usedAPS = ConfigBuilderPlugin.getPlugin().getActiveAPS();
+ if (usedAPS != null && ((PluginBase) usedAPS).isEnabled(PluginType.APS))
+ return true;
+ return false;
+ }
+ });
+ tasks.add(new Task(R.string.activate_profile) {
+ @Override
+ public boolean isCompleted() {
+ return TreatmentsPlugin.getPlugin().getProfileSwitchFromHistory(DateUtil.now()) != null;
+ }
+ });
+ }
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective1.java b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective1.java
index 65a716abab2..1687b56987c 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective1.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective1.java
@@ -3,82 +3,60 @@
import java.util.List;
import info.nightscout.androidaps.R;
-import info.nightscout.androidaps.db.DatabaseHelper;
-import info.nightscout.androidaps.interfaces.APSInterface;
-import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.PluginType;
-import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin;
-import info.nightscout.androidaps.plugins.constraints.objectives.ObjectivesPlugin;
-import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin;
-import info.nightscout.androidaps.plugins.general.nsclient.NSClientPlugin;
-import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin;
-import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
-import info.nightscout.androidaps.utils.DateUtil;
+import info.nightscout.androidaps.plugins.general.actions.ActionsPlugin;
import info.nightscout.androidaps.utils.SP;
public class Objective1 extends Objective {
+
public Objective1() {
- super(0, R.string.objectives_0_objective, R.string.objectives_0_gate);
+ super("usage", R.string.objectives_usage_objective, R.string.objectives_usage_gate);
}
@Override
protected void setupTasks(List tasks) {
- tasks.add(new Task(R.string.objectives_bgavailableinns) {
+ tasks.add(new Task(R.string.objectives_useprofileswitch) {
@Override
public boolean isCompleted() {
- return ObjectivesPlugin.getPlugin().bgIsAvailableInNS;
+ return SP.getBoolean(R.string.key_objectiveuseprofileswitch, false);
}
});
- tasks.add(new Task(R.string.nsclienthaswritepermission) {
+ tasks.add(new Task(R.string.objectives_usedisconnectpump) {
@Override
public boolean isCompleted() {
- return NSClientPlugin.getPlugin().hasWritePermission();
- }
- });
- tasks.add(new Task(R.string.virtualpump_uploadstatus_title) {
- @Override
- public boolean isCompleted() {
- return SP.getBoolean("virtualpump_uploadstatus", false);
- }
-
- @Override
- public boolean shouldBeIgnored() {
- return !VirtualPumpPlugin.getPlugin().isEnabled(PluginType.PUMP);
+ return SP.getBoolean(R.string.key_objectiveusedisconnect, false);
}
- });
- tasks.add(new Task(R.string.objectives_pumpstatusavailableinns) {
+ }.hint(new Hint(R.string.disconnectpump_hint)));
+ tasks.add(new Task(R.string.objectives_usereconnectpump) {
@Override
public boolean isCompleted() {
- return ObjectivesPlugin.getPlugin().pumpStatusIsAvailableInNS;
+ return SP.getBoolean(R.string.key_objectiveusereconnect, false);
}
- });
- tasks.add(new Task(R.string.hasbgdata) {
+ }.hint(new Hint(R.string.disconnectpump_hint)));
+ tasks.add(new Task(R.string.objectives_usetemptarget) {
@Override
public boolean isCompleted() {
- return DatabaseHelper.lastBg() != null;
+ return SP.getBoolean(R.string.key_objectiveusetemptarget, false);
}
- });
- tasks.add(new Task(R.string.loopenabled) {
+ }.hint(new Hint(R.string.usetemptarget_hint)));
+ tasks.add(new Task(R.string.objectives_useactions) {
@Override
public boolean isCompleted() {
- return LoopPlugin.getPlugin().isEnabled(PluginType.LOOP);
+ return SP.getBoolean(R.string.key_objectiveuseactions, false) && ActionsPlugin.INSTANCE.isEnabled(PluginType.GENERAL) && ActionsPlugin.INSTANCE.isFragmentVisible();
}
- });
- tasks.add(new Task(R.string.apsselected) {
+ }.hint(new Hint(R.string.useaction_hint)));
+ tasks.add(new Task(R.string.objectives_useloop) {
@Override
public boolean isCompleted() {
- APSInterface usedAPS = ConfigBuilderPlugin.getPlugin().getActiveAPS();
- if (usedAPS != null && ((PluginBase) usedAPS).isEnabled(PluginType.APS))
- return true;
- return false;
+ return SP.getBoolean(R.string.key_objectiveuseloop, false);
}
- });
- tasks.add(new Task(R.string.activate_profile) {
+ }.hint(new Hint(R.string.useaction_hint)));
+ tasks.add(new Task(R.string.objectives_usescale) {
@Override
public boolean isCompleted() {
- return TreatmentsPlugin.getPlugin().getProfileSwitchFromHistory(DateUtil.now()) != null;
+ return SP.getBoolean(R.string.key_objectiveusescale, false);
}
- });
+ }.hint(new Hint(R.string.usescale_hint)));
}
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective2.java b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective2.java
index 6f97bfdd950..017ad33a8cd 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective2.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective2.java
@@ -1,36 +1,211 @@
package info.nightscout.androidaps.plugins.constraints.objectives.objectives;
+import java.util.Collections;
import java.util.List;
-import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
-import info.nightscout.androidaps.plugins.constraints.objectives.ObjectivesPlugin;
-import info.nightscout.androidaps.utils.T;
public class Objective2 extends Objective {
- public final int MANUAL_ENACTS_NEEDED = 20;
public Objective2() {
- super(1, R.string.objectives_1_objective, R.string.objectives_1_gate);
+ super("exam", R.string.objectives_exam_objective, R.string.objectives_exam_gate);
+ for (Task task : tasks) {
+ if (!task.isCompleted()) setAccomplishedOn(0);
+ }
}
@Override
protected void setupTasks(List tasks) {
- tasks.add(new MinimumDurationTask(T.days(7).msecs()));
- tasks.add(new Task(R.string.objectives_manualenacts) {
- @Override
- public boolean isCompleted() {
- return ObjectivesPlugin.getPlugin().manualEnacts >= MANUAL_ENACTS_NEEDED;
- }
-
- @Override
- public String getProgress() {
- if (ObjectivesPlugin.getPlugin().manualEnacts >= MANUAL_ENACTS_NEEDED)
- return MainApp.gs(R.string.completed_well_done);
- else
- return ObjectivesPlugin.getPlugin().manualEnacts + " / " + MANUAL_ENACTS_NEEDED;
- }
- });
+ tasks.add(new ExamTask(R.string.dia_label, R.string.dia_whatmeansdia,"dia")
+ .option(new Option(R.string.dia_minimumis3h, false))
+ .option(new Option(R.string.dia_minimumis5h, true))
+ .option(new Option(R.string.dia_meaningisequaltodiapump, false))
+ .option(new Option(R.string.dia_valuemustbedetermined, true))
+ .hint(new Hint(R.string.dia_hint1))
+ );
+ tasks.add(new ExamTask(R.string.hypott_label, R.string.hypott_whenhypott,"hypott")
+ .option(new Option(R.string.hypott_goinglow, false))
+ .option(new Option(R.string.hypott_preventoversmb, true))
+ .hint(new Hint(R.string.hypott_hint1))
+ );
+ tasks.add(new ExamTask(R.string.offlineprofile_label, R.string.offlineprofile_whatprofile,"offlineprofile")
+ .option(new Option(R.string.localprofile, true))
+ .option(new Option(R.string.nsprofile, false))
+ .option(new Option(R.string.offlineprofile_nsprofile, true))
+ .hint(new Hint(R.string.offlineprofile_hint1))
+ );
+ tasks.add(new ExamTask(R.string.pumpdisconnect_label, R.string.pumpdisconnect_label,"pumpdisconnect")
+ .option(new Option(R.string.pumpdisconnect_letknow, true))
+ .option(new Option(R.string.pumpdisconnect_suspend, false))
+ .option(new Option(R.string.pumpdisconnect_dontchnage, false))
+ .hint(new Hint(R.string.pumpdisconnect_hint1))
+ );
+ tasks.add(new ExamTask(R.string.objectives_label, R.string.objectives_howtosave,"objectives")
+ .option(new Option(R.string.objectives_exportsettings, true))
+ .option(new Option(R.string.objectives_storeelsewhere, true))
+ .option(new Option(R.string.objectives_doexportonstart, false))
+ .option(new Option(R.string.objectives_doexportafterchange, true))
+ .option(new Option(R.string.objectives_doexportafterobjective, true))
+ .option(new Option(R.string.objectives_doexportafterfirtssettings, true))
+ .hint(new Hint(R.string.objectives_hint1))
+ .hint(new Hint(R.string.objectives_hint2))
+ );
+ tasks.add(new ExamTask(R.string.noisycgm_label, R.string.noisycgm_whattodo,"noisycgm")
+ .option(new Option(R.string.nothing, false))
+ .option(new Option(R.string.disconnectpumpfor1h, false))
+ .option(new Option(R.string.noisycgm_pause, true))
+ .option(new Option(R.string.noisycgm_replacesensor, true))
+ .option(new Option(R.string.noisycgm_turnoffphone, false))
+ .option(new Option(R.string.noisycgm_checksmoothing, true))
+ .hint(new Hint(R.string.noisycgm_hint1))
+ );
+ tasks.add(new ExamTask(R.string.exercise_label, R.string.exercise_whattodo,"exercise")
+ .option(new Option(R.string.nothing, false))
+ .option(new Option(R.string.exercise_setactivitytt, true))
+ .option(new Option(R.string.exercise_switchprofilebelow100, true))
+ .option(new Option(R.string.exercise_switchprofileabove100, false))
+ .option(new Option(R.string.exercise_stoploop, false))
+ .option(new Option(R.string.exercise_doitbeforestart, true))
+ .option(new Option(R.string.exercise_afterstart, true))
+ .hint(new Hint(R.string.exercise_hint1))
+ );
+ tasks.add(new ExamTask(R.string.suspendloop_label, R.string.suspendloop_doigetinsulin,"suspendloop")
+ .option(new Option(R.string.suspendloop_yes, true))
+ .option(new Option(R.string.suspendloop_no, false))
+ );
+ tasks.add(new ExamTask(R.string.basaltest_label, R.string.basaltest_when,"basaltest")
+ .option(new Option(R.string.basaltest_beforeloop, true))
+ .option(new Option(R.string.basaltest_havingregularhypo, true))
+ .option(new Option(R.string.basaltest_havingregularhyper, true))
+ .hint(new Hint(R.string.basaltest_hint1))
+ );
+ tasks.add(new ExamTask(R.string.basalhelp_label, R.string.basalhelp_where,"basalhelp")
+ .option(new Option(R.string.basalhelp_diabetesteam, true))
+ .option(new Option(R.string.basalhelp_google, false))
+ .option(new Option(R.string.basalhelp_facebook, false))
+ .hint(new Hint(R.string.basalhelp_hint1))
+ );
+ tasks.add(new ExamTask(R.string.prerequisites_label, R.string.prerequisites_what, "prerequisites")
+ .option(new Option(R.string.prerequisites_determinedcorrectprofile, true))
+ .option(new Option(R.string.prerequisites_computer, true))
+ .option(new Option(R.string.prerequisites_phone, true))
+ .option(new Option(R.string.prerequisites_car, false))
+ .option(new Option(R.string.prerequisites_nightscout, true))
+ .option(new Option(R.string.prerequisites_tidepoolaccount, false))
+ .option(new Option(R.string.prerequisites_googleaccount, false))
+ .option(new Option(R.string.prerequisites_githubaccount, false))
+ .option(new Option(R.string.prerequisites_beanandroiddeveloper, false))
+ .option(new Option(R.string.prerequisites_own670g, false))
+ .option(new Option(R.string.prerequisites_smartwatch, false))
+ .option(new Option(R.string.prerequisites_supportedcgm, true))
+ .hint(new Hint(R.string.prerequisites_hint1))
+ );
+ tasks.add(new ExamTask(R.string.update_label, R.string.whatistrue,"update")
+ .option(new Option(R.string.update_git, true))
+ .option(new Option(R.string.update_asap, true))
+ .option(new Option(R.string.update_keys, true))
+ .option(new Option(R.string.update_neverupdate, false))
+ .option(new Option(R.string.update_askfriend, false))
+ .hint(new Hint(R.string.update_hint1))
+ );
+ tasks.add(new ExamTask(R.string.troubleshooting_label, R.string.troubleshooting_wheretoask,"troubleshooting")
+ .option(new Option(R.string.troubleshooting_fb, true))
+ .option(new Option(R.string.troubleshooting_wiki, true))
+ .option(new Option(R.string.troubleshooting_gitter, true))
+ .option(new Option(R.string.troubleshooting_googlesupport, false))
+ .option(new Option(R.string.troubleshooting_yourendo, false))
+ .hint(new Hint(R.string.troubleshooting_hint1))
+ .hint(new Hint(R.string.troubleshooting_hint2))
+ .hint(new Hint(R.string.troubleshooting_hint3))
+ );
+ tasks.add(new ExamTask(R.string.insulin_label, R.string.insulin_ultrarapid,"insulin")
+ .option(new Option(R.string.insulin_fiasp, true))
+ .option(new Option(R.string.insulin_novorapid, false))
+ .option(new Option(R.string.insulin_humalog, false))
+ .option(new Option(R.string.insulin_actrapid, false))
+ .hint(new Hint(R.string.insulin_hint1))
+ );
+ tasks.add(new ExamTask(R.string.sensitivity_label, R.string.sensitivity_which,"sensitivity")
+ .option(new Option(R.string.sensitivityweightedaverage, true))
+ .option(new Option(R.string.sensitivityoref0, false))
+ .option(new Option(R.string.sensitivityoref1, false))
+ .option(new Option(R.string.sensitivityaaps, true))
+ .hint(new Hint(R.string.sensitivity_hint1))
+ );
+ tasks.add(new ExamTask(R.string.sensitivity_label, R.string.sensitivityuam_which,"sensitivityuam")
+ .option(new Option(R.string.sensitivityweightedaverage, false))
+ .option(new Option(R.string.sensitivityoref0, false))
+ .option(new Option(R.string.sensitivityoref1, true))
+ .option(new Option(R.string.sensitivityaaps, false))
+ .hint(new Hint(R.string.sensitivity_hint1))
+ );
+ tasks.add(new ExamTask(R.string.wrongcarbs_label, R.string.wrongcarbs_whattodo,"wrongcarbs")
+ .option(new Option(R.string.wrongcarbs_addfakeinsulin, false))
+ .option(new Option(R.string.wrongcarbs_treatmentstab, true))
+ );
+ tasks.add(new ExamTask(R.string.extendedcarbs_label, R.string.extendedcarbs_handling,"extendedcarbs")
+ .option(new Option(R.string.extendedcarbs_useextendedcarbs, true))
+ .option(new Option(R.string.extendedcarbs_add, false))
+ .option(new Option(R.string.extendedcarbs_useextendedbolus, false))
+ .hint(new Hint(R.string.extendedcarbs_hint1))
+ );
+ tasks.add(new ExamTask(R.string.nsclient_label, R.string.nsclient_howcanyou,"nsclient")
+ .option(new Option(R.string.nsclient_nightscout, true))
+ .option(new Option(R.string.nsclientinternal, true))
+ .option(new Option(R.string.nsclient_dexcomfollow, true))
+ .option(new Option(R.string.nsclient_dexcomfollowxdrip, false))
+ .option(new Option(R.string.nsclient_xdripfollower, true))
+ .option(new Option(R.string.nsclient_looponiphone, false))
+ .option(new Option(R.string.nsclient_spikeiphone, true))
+ .hint(new Hint(R.string.nsclient_hint1))
+ );
+ tasks.add(new ExamTask(R.string.isf_label, R.string.whatistrue,"isf")
+ .option(new Option(R.string.isf_increasingvalue, true))
+ .option(new Option(R.string.isf_decreasingvalue, false))
+ .option(new Option(R.string.isf_noeffect, false))
+ .option(new Option(R.string.isf_preferences, false))
+ .option(new Option(R.string.isf_profile, false))
+ .hint(new Hint(R.string.isf_hint1))
+ .hint(new Hint(R.string.isf_hint2))
+ );
+ tasks.add(new ExamTask(R.string.ic_label, R.string.whatistrue,"ic")
+ .option(new Option(R.string.ic_increasingvalue, true))
+ .option(new Option(R.string.ic_decreasingvalue, false))
+ .option(new Option(R.string.ic_noeffect, false))
+ .option(new Option(R.string.ic_different, false))
+ .option(new Option(R.string.ic_meaning, false))
+ .hint(new Hint(R.string.ic_hint1))
+ );
+ tasks.add(new ExamTask(R.string.profileswitch_label, R.string.profileswitch_pctwillchange,"profileswitch")
+ .option(new Option(R.string.profileswitch_basalhigher, false))
+ .option(new Option(R.string.profileswitch_basallower, true))
+ .option(new Option(R.string.profileswitch_ichigher, true))
+ .option(new Option(R.string.profileswitch_iclower, false))
+ .option(new Option(R.string.profileswitch_isfhigher, true))
+ .option(new Option(R.string.profileswitch_isflower, false))
+ .option(new Option(R.string.profileswitch_overall, true))
+ .option(new Option(R.string.profileswitch_targethigher, false))
+ .option(new Option(R.string.profileswitch_targetlower, false))
+ .option(new Option(R.string.profileswitch_targetbottom, false))
+ .hint(new Hint(R.string.profileswitch_hint1))
+ );
+
+ tasks.add(new ExamTask(R.string.profileswitch_label, R.string.profileswitchtime_iwant,"profileswitchtime")
+ .option(new Option(R.string.profileswitchtime_1, false))
+ .option(new Option(R.string.profileswitchtime__1, true))
+ .option(new Option(R.string.profileswitchtime_60, false))
+ .option(new Option(R.string.profileswitchtime__60, false))
+ .hint(new Hint(R.string.profileswitchtime_hint1))
+ );
+
+ tasks.add(new ExamTask(R.string.other_medication_label, R.string.other_medication_text,"otherMedicationWarning")
+ .option(new Option(R.string.yes, true))
+ .option(new Option(R.string.no, false))
+ );
+
+ for (Task task : tasks)
+ Collections.shuffle(((ExamTask)task).options);
}
+
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective3.java b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective3.java
index 4924d9434c8..f8eb45bb2a6 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective3.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective3.java
@@ -1,10 +1,51 @@
package info.nightscout.androidaps.plugins.constraints.objectives.objectives;
+import android.app.Activity;
+
+import java.util.List;
+
+import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
+import info.nightscout.androidaps.plugins.constraints.objectives.ObjectivesPlugin;
+import info.nightscout.androidaps.plugins.general.nsclient.NSClientPlugin;
+import info.nightscout.androidaps.utils.SP;
+import info.nightscout.androidaps.utils.T;
public class Objective3 extends Objective {
+ public final int MANUAL_ENACTS_NEEDED = 20;
+
public Objective3() {
- super(2, R.string.objectives_2_objective, R.string.objectives_2_gate);
+ super("openloop", R.string.objectives_openloop_objective, R.string.objectives_openloop_gate);
+ hasSpecialInput = true;
+ }
+
+ @Override
+ protected void setupTasks(List tasks) {
+ tasks.add(new MinimumDurationTask(T.days(7).msecs()));
+ tasks.add(new Task(R.string.objectives_manualenacts) {
+ @Override
+ public boolean isCompleted() {
+ return SP.getInt(R.string.key_ObjectivesmanualEnacts, 0) >= MANUAL_ENACTS_NEEDED;
+ }
+
+ @Override
+ public String getProgress() {
+ if (SP.getInt(R.string.key_ObjectivesmanualEnacts, 0) >= MANUAL_ENACTS_NEEDED)
+ return MainApp.gs(R.string.completed_well_done);
+ else
+ return SP.getInt(R.string.key_ObjectivesmanualEnacts, 0) + " / " + MANUAL_ENACTS_NEEDED;
+ }
+ });
+ }
+
+ @Override
+ public boolean specialActionEnabled() {
+ return NSClientPlugin.getPlugin().nsClientService.isConnected && NSClientPlugin.getPlugin().nsClientService.hasWriteAuth;
+ }
+
+ @Override
+ public void specialAction(Activity activity, String input) {
+ ObjectivesPlugin.INSTANCE.completeObjectives(activity, input);
}
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective4.java b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective4.java
index 1bbb4ef7c26..bb46d3c338e 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective4.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective4.java
@@ -1,33 +1,10 @@
package info.nightscout.androidaps.plugins.constraints.objectives.objectives;
-import java.util.List;
-
import info.nightscout.androidaps.R;
-import info.nightscout.androidaps.interfaces.Constraint;
-import info.nightscout.androidaps.plugins.constraints.safety.SafetyPlugin;
-import info.nightscout.androidaps.utils.T;
public class Objective4 extends Objective {
public Objective4() {
- super(3, R.string.objectives_3_objective, R.string.objectives_3_gate);
- }
-
- @Override
- protected void setupTasks(List tasks) {
- tasks.add(new MinimumDurationTask(T.days(5).msecs()));
- tasks.add(new Task(R.string.closedmodeenabled) {
- @Override
- public boolean isCompleted() {
- Constraint closedLoopEnabled = new Constraint<>(true);
- SafetyPlugin.getPlugin().isClosedLoopAllowed(closedLoopEnabled);
- return closedLoopEnabled.value();
- }
- });
- }
-
- @Override
- public boolean isRevertable() {
- return true;
+ super("maxbasal", R.string.objectives_maxbasal_objective, R.string.objectives_maxbasal_gate);
}
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective5.java b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective5.java
index b04062655a2..bd3e69c7516 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective5.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective5.java
@@ -2,24 +2,26 @@
import java.util.List;
-import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
+import info.nightscout.androidaps.interfaces.Constraint;
+import info.nightscout.androidaps.plugins.constraints.safety.SafetyPlugin;
import info.nightscout.androidaps.utils.T;
public class Objective5 extends Objective {
public Objective5() {
- super(4, R.string.objectives_4_objective, R.string.objectives_4_gate);
+ super("maxiobzero", R.string.objectives_maxiobzero_objective, R.string.objectives_maxiobzero_gate);
}
@Override
protected void setupTasks(List tasks) {
- tasks.add(new MinimumDurationTask(T.days(1).msecs()));
- tasks.add(new Task(R.string.maxiobset) {
+ tasks.add(new MinimumDurationTask(T.days(5).msecs()));
+ tasks.add(new Task(R.string.closedmodeenabled) {
@Override
public boolean isCompleted() {
- double maxIOB = MainApp.getConstraintChecker().getMaxIOBAllowed().value();
- return maxIOB > 0;
+ Constraint closedLoopEnabled = new Constraint<>(true);
+ SafetyPlugin.getPlugin().isClosedLoopAllowed(closedLoopEnabled);
+ return closedLoopEnabled.value();
}
});
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective6.java b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective6.java
index 284dfa3ab00..1b224bd40c1 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective6.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective6.java
@@ -2,17 +2,25 @@
import java.util.List;
+import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.utils.T;
public class Objective6 extends Objective {
public Objective6() {
- super(5, R.string.objectives_5_objective, R.string.objectives_5_gate);
+ super("maxiob", R.string.objectives_maxiob_objective, R.string.objectives_maxiob_gate);
}
@Override
protected void setupTasks(List tasks) {
- tasks.add(new MinimumDurationTask(T.days(7).msecs()));
+ tasks.add(new MinimumDurationTask(T.days(1).msecs()));
+ tasks.add(new Task(R.string.maxiobset) {
+ @Override
+ public boolean isCompleted() {
+ double maxIOB = MainApp.getConstraintChecker().getMaxIOBAllowed().value();
+ return maxIOB > 0;
+ }
+ });
}
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective7.java b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective7.java
index f90411ecfb0..497eb0a180b 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective7.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective7.java
@@ -3,16 +3,17 @@
import java.util.List;
import info.nightscout.androidaps.R;
+import info.nightscout.androidaps.plugins.constraints.objectives.ObjectivesPlugin;
import info.nightscout.androidaps.utils.T;
public class Objective7 extends Objective {
public Objective7() {
- super(6, R.string.objectives_6_objective, 0);
+ super("autosens", R.string.objectives_autosens_objective, R.string.objectives_autosens_gate);
}
@Override
protected void setupTasks(List tasks) {
- tasks.add(new MinimumDurationTask(T.days(28).msecs()));
+ tasks.add(new MinimumDurationTask(T.days(7).msecs()));
}
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective8.java b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective8.java
index 7148f5e5add..3f943041b6e 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective8.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective8.java
@@ -3,12 +3,13 @@
import java.util.List;
import info.nightscout.androidaps.R;
+import info.nightscout.androidaps.plugins.constraints.objectives.ObjectivesPlugin;
import info.nightscout.androidaps.utils.T;
public class Objective8 extends Objective {
public Objective8() {
- super(7, R.string.objectives_7_objective, R.string.objectives_7_gate);
+ super("ama", R.string.objectives_ama_objective, 0);
}
@Override
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective9.java b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective9.java
new file mode 100644
index 00000000000..106c25cb799
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/objectives/objectives/Objective9.java
@@ -0,0 +1,18 @@
+package info.nightscout.androidaps.plugins.constraints.objectives.objectives;
+
+import java.util.List;
+
+import info.nightscout.androidaps.R;
+import info.nightscout.androidaps.utils.T;
+
+public class Objective9 extends Objective {
+
+ public Objective9() {
+ super("smb", R.string.objectives_smb_objective, R.string.objectives_smb_gate);
+ }
+
+ @Override
+ protected void setupTasks(List tasks) {
+ tasks.add(new MinimumDurationTask(T.days(28).msecs()));
+ }
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/phoneChecker/PhoneCheckerPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/phoneChecker/PhoneCheckerPlugin.kt
new file mode 100644
index 00000000000..7dbb642f459
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/phoneChecker/PhoneCheckerPlugin.kt
@@ -0,0 +1,35 @@
+package info.nightscout.androidaps.plugins.constraints.phoneChecker
+
+import android.os.Build
+import com.scottyab.rootbeer.RootBeer
+import info.nightscout.androidaps.MainApp
+import info.nightscout.androidaps.R
+import info.nightscout.androidaps.interfaces.ConstraintsInterface
+import info.nightscout.androidaps.interfaces.PluginBase
+import info.nightscout.androidaps.interfaces.PluginDescription
+import info.nightscout.androidaps.interfaces.PluginType
+
+object PhoneCheckerPlugin : PluginBase(PluginDescription()
+ .mainType(PluginType.CONSTRAINTS)
+ .neverVisible(true)
+ .alwaysEnabled(true)
+ .showInList(false)
+ .pluginName(R.string.phonechecker)
+), ConstraintsInterface {
+
+ var phoneRooted: Boolean = false
+ var devMode: Boolean = false
+ val phoneModel: String = Build.MODEL
+ val manufacturer: String = Build.MANUFACTURER
+
+ private fun isDevModeEnabled(): Boolean {
+ return android.provider.Settings.Secure.getInt(MainApp.instance().contentResolver,
+ android.provider.Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0) != 0;
+ }
+
+ override fun onStart() {
+ super.onStart()
+ phoneRooted = RootBeer(MainApp.instance()).isRootedWithoutBusyBoxCheck()
+ devMode = isDevModeEnabled()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/safety/SafetyPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/safety/SafetyPlugin.java
index 65dc119c6a3..5e7393d359d 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/safety/SafetyPlugin.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/safety/SafetyPlugin.java
@@ -13,13 +13,15 @@
import info.nightscout.androidaps.interfaces.PluginType;
import info.nightscout.androidaps.interfaces.PumpDescription;
import info.nightscout.androidaps.interfaces.PumpInterface;
-import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.aps.openAPSAMA.OpenAPSAMAPlugin;
import info.nightscout.androidaps.plugins.aps.openAPSMA.OpenAPSMAPlugin;
import info.nightscout.androidaps.plugins.aps.openAPSSMB.OpenAPSSMBPlugin;
+import info.nightscout.androidaps.plugins.bus.RxBus;
+import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin;
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;
@@ -68,11 +70,14 @@ public Constraint isClosedLoopAllowed(Constraint value) {
if (!MainApp.isEngineeringModeOrRelease()) {
if (value.value()) {
Notification n = new Notification(Notification.TOAST_ALARM, MainApp.gs(R.string.closed_loop_disabled_on_dev_branch), Notification.NORMAL);
- MainApp.bus().post(new EventNewNotification(n));
+ RxBus.INSTANCE.send(new EventNewNotification(n));
}
value.set(false, MainApp.gs(R.string.closed_loop_disabled_on_dev_branch), this);
}
-
+ PumpInterface pump = ConfigBuilderPlugin.getPlugin().getActivePump();
+ if (pump != null && !pump.isFakingTempsByExtendedBoluses() && TreatmentsPlugin.getPlugin().isInHistoryExtendedBoluslInProgress()) {
+ value.set(false, MainApp.gs(R.string.closed_loop_disabled_with_eb), this);
+ }
return value;
}
@@ -125,6 +130,10 @@ public Constraint applyBasalConstraints(Constraint absoluteRate,
if (Config.APS) {
double maxBasal = SP.getDouble(R.string.key_openapsma_max_basal, 1d);
+ if (maxBasal < profile.getMaxDailyBasal()) {
+ maxBasal = profile.getMaxDailyBasal();
+ absoluteRate.addReason(MainApp.gs(R.string.increasingmaxbasal), this);
+ }
absoluteRate.setIfSmaller(maxBasal, String.format(MainApp.gs(R.string.limitingbasalratio), maxBasal, MainApp.gs(R.string.maxvalueinpreferences)), this);
// Check percentRate but absolute rate too, because we know real current basal in pump
@@ -196,7 +205,7 @@ public Constraint applyBolusConstraints(Constraint insulin) {
PumpInterface pump = ConfigBuilderPlugin.getPlugin().getActivePump();
if (pump != null) {
- double rounded = Round.roundTo(insulin.value(), pump.getPumpDescription().pumpType.determineCorrectBolusSize(insulin.value()));
+ double rounded = pump.getPumpDescription().pumpType.determineCorrectBolusSize(insulin.value());
insulin.setIfDifferent(rounded, MainApp.gs(R.string.pumplimit), this);
}
return insulin;
@@ -213,7 +222,7 @@ public Constraint applyExtendedBolusConstraints(Constraint insul
PumpInterface pump = ConfigBuilderPlugin.getPlugin().getActivePump();
if (pump != null) {
- double rounded = Round.roundTo(insulin.value(), pump.getPumpDescription().pumpType.determineCorrectExtendedBolusSize(insulin.value()));
+ double rounded = pump.getPumpDescription().pumpType.determineCorrectExtendedBolusSize(insulin.value());
insulin.setIfDifferent(rounded, MainApp.gs(R.string.pumplimit), this);
}
return insulin;
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/signatureVerifier/SignatureVerifierPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/signatureVerifier/SignatureVerifierPlugin.java
new file mode 100644
index 00000000000..9c9e38bb46f
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/signatureVerifier/SignatureVerifierPlugin.java
@@ -0,0 +1,242 @@
+package info.nightscout.androidaps.plugins.constraints.signatureVerifier;
+
+import android.content.pm.PackageManager;
+import android.content.pm.Signature;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.spongycastle.util.encoders.Hex;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URL;
+import java.net.URLConnection;
+import java.nio.charset.StandardCharsets;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+import info.nightscout.androidaps.MainApp;
+import info.nightscout.androidaps.R;
+import info.nightscout.androidaps.interfaces.Constraint;
+import info.nightscout.androidaps.interfaces.ConstraintsInterface;
+import info.nightscout.androidaps.interfaces.PluginBase;
+import info.nightscout.androidaps.interfaces.PluginDescription;
+import info.nightscout.androidaps.interfaces.PluginType;
+import info.nightscout.androidaps.logging.L;
+import info.nightscout.androidaps.plugins.bus.RxBus;
+import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification;
+import info.nightscout.androidaps.plugins.general.overview.notifications.Notification;
+import info.nightscout.androidaps.utils.SP;
+
+/**
+ * AndroidAPS is meant to be build by the user.
+ * In case someone decides to leak a ready-to-use APK nonetheless, we can still disable it.
+ * Self-compiled APKs with privately held certificates cannot and will not be disabled.
+ */
+public class SignatureVerifierPlugin extends PluginBase implements ConstraintsInterface {
+
+ private static final String REVOKED_CERTS_URL = "https://raw.githubusercontent.com/MilosKozak/AndroidAPS/master/app/src/main/assets/revoked_certs.txt";
+ private static final long UPDATE_INTERVAL = TimeUnit.DAYS.toMillis(1);
+
+ private static SignatureVerifierPlugin plugin = new SignatureVerifierPlugin();
+
+ private Logger log = LoggerFactory.getLogger(L.CORE);
+ private final Object $lock = new Object[0];
+ private File revokedCertsFile;
+ private List revokedCerts;
+
+ public static SignatureVerifierPlugin getPlugin() {
+ return plugin;
+ }
+
+ private SignatureVerifierPlugin() {
+ super(new PluginDescription()
+ .mainType(PluginType.CONSTRAINTS)
+ .neverVisible(true)
+ .alwaysEnabled(true)
+ .showInList(false)
+ .pluginName(R.string.signature_verifier));
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ revokedCertsFile = new File(MainApp.instance().getFilesDir(), "revoked_certs.txt");
+ new Thread(() -> {
+ loadLocalRevokedCerts();
+ if (shouldDownloadCerts()) {
+ try {
+ downloadAndSaveRevokedCerts();
+ } catch (IOException e) {
+ log.error("Could not download revoked certs", e);
+ }
+ }
+ if (hasIllegalSignature()) showNotification();
+ }).start();
+ }
+
+ @Override
+ public Constraint isLoopInvocationAllowed(Constraint value) {
+ if (hasIllegalSignature()) {
+ showNotification();
+ value.set(false);
+ }
+ if (shouldDownloadCerts()) {
+ new Thread(() -> {
+ try {
+ downloadAndSaveRevokedCerts();
+ } catch (IOException e) {
+ log.error("Could not download revoked certs", e);
+ }
+ }).start();
+ }
+ return value;
+ }
+
+ private void showNotification() {
+ Notification notification = new Notification(Notification.INVALID_VERSION, MainApp.gs(R.string.running_invalid_version), Notification.URGENT);
+ RxBus.INSTANCE.send(new EventNewNotification(notification));
+ }
+
+ private boolean hasIllegalSignature() {
+ try {
+ synchronized ($lock) {
+ if (revokedCerts == null) return false;
+ Signature[] signatures = MainApp.instance().getPackageManager().getPackageInfo(MainApp.instance().getPackageName(), PackageManager.GET_SIGNATURES).signatures;
+ if (signatures != null) {
+ for (Signature signature : signatures) {
+ MessageDigest digest = MessageDigest.getInstance("SHA256");
+ byte[] fingerprint = digest.digest(signature.toByteArray());
+ for (byte[] cert : revokedCerts) {
+ if (Arrays.equals(cert, fingerprint)) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ } catch (PackageManager.NameNotFoundException | NoSuchAlgorithmException e) {
+ log.error("Error in SignatureVerifierPlugin", e);
+ }
+ return false;
+ }
+
+ public List shortHashes() {
+ List hashes = new ArrayList<>();
+ try {
+ Signature[] signatures = MainApp.instance().getPackageManager().getPackageInfo(MainApp.instance().getPackageName(), PackageManager.GET_SIGNATURES).signatures;
+ if (signatures != null) {
+ for (Signature signature : signatures) {
+ MessageDigest digest = MessageDigest.getInstance("SHA256");
+ byte[] fingerprint = digest.digest(signature.toByteArray());
+ String hash = Hex.toHexString(fingerprint);
+ log.debug("Found signature: " + hash);
+ log.debug("Found signature (short): " + singleCharMap(fingerprint));
+ hashes.add(singleCharMap(fingerprint));
+ }
+ }
+ } catch (PackageManager.NameNotFoundException | NoSuchAlgorithmException e) {
+ log.error("Error in SignatureVerifierPlugin", e);
+ }
+ return hashes;
+ }
+
+ String map = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!\"§$%&/()=?,.-;:_<>|°^`´\\@€*'#+~{}[]¿¡áéíóúàèìòùöäü`ÁÉÍÓÚÀÈÌÒÙÖÄÜ߯ÇÊËÎÏԌ۟æçêëîïôœûÿĆČĐŠŽćđšžñΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡ\u03A2ΣΤΥΦΧΨΩαβγδεζηθικλμνξοπρςστυφχψωϨϩϪϫϬϭϮϯϰϱϲϳϴϵ϶ϷϸϹϺϻϼϽϾϿЀЁЂЃЄЅІЇЈЉЊЋЌЍЎЏАБВГДЕЖЗ";
+
+ private String singleCharMap(byte[] array) {
+ StringBuilder sb = new StringBuilder();
+ for (byte b : array) {
+ sb.append(map.charAt(b & 0xFF));
+ }
+ return sb.toString();
+ }
+
+ public String singleCharUnMap(String shortHash) {
+ byte[] array = new byte[shortHash.length()];
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < array.length; i++) {
+ if (i != 0) sb.append(":");
+ sb.append(String.format("%02X", 0xFF & map.charAt(map.indexOf(shortHash.charAt(i)))));
+ }
+ return sb.toString();
+ }
+
+ private boolean shouldDownloadCerts() {
+ return System.currentTimeMillis() - SP.getLong(R.string.key_last_revoked_certs_check, 0L) >= UPDATE_INTERVAL;
+ }
+
+ private void downloadAndSaveRevokedCerts() throws IOException {
+ String download = downloadRevokedCerts();
+ saveRevokedCerts(download);
+ SP.putLong(R.string.key_last_revoked_certs_check, System.currentTimeMillis());
+ synchronized ($lock) {
+ revokedCerts = parseRevokedCertsFile(download);
+ }
+ }
+
+ private void loadLocalRevokedCerts() {
+ try {
+ String revokedCerts = readCachedDownloadedRevokedCerts();
+ if (revokedCerts == null) revokedCerts = readRevokedCertsInAssets();
+ synchronized ($lock) {
+ this.revokedCerts = parseRevokedCertsFile(revokedCerts);
+ }
+ } catch (IOException e) {
+ log.error("Error in SignatureVerifierPlugin", e);
+ }
+ }
+
+ private void saveRevokedCerts(String revokedCerts) throws IOException {
+ OutputStream outputStream = new FileOutputStream(revokedCertsFile);
+ outputStream.write(revokedCerts.getBytes(StandardCharsets.UTF_8));
+ outputStream.close();
+ }
+
+ private String downloadRevokedCerts() throws IOException {
+ URLConnection connection = new URL(REVOKED_CERTS_URL).openConnection();
+ return readInputStream(connection.getInputStream());
+ }
+
+ private String readInputStream(InputStream inputStream) throws IOException {
+ try {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ byte[] buffer = new byte[1024];
+ int read;
+ while ((read = inputStream.read(buffer)) != -1) {
+ baos.write(buffer, 0, read);
+ }
+ baos.flush();
+ return new String(baos.toByteArray(), StandardCharsets.UTF_8);
+ } finally {
+ inputStream.close();
+ }
+ }
+
+ private String readRevokedCertsInAssets() throws IOException {
+ InputStream inputStream = MainApp.instance().getAssets().open("revoked_certs.txt");
+ return readInputStream(inputStream);
+ }
+
+ private String readCachedDownloadedRevokedCerts() throws IOException {
+ if (!revokedCertsFile.exists()) return null;
+ return readInputStream(new FileInputStream(revokedCertsFile));
+ }
+
+ private List parseRevokedCertsFile(String file) {
+ List revokedCerts = new ArrayList<>();
+ for (String line : file.split("\n")) {
+ if (line.startsWith("#")) continue;
+ revokedCerts.add(Hex.decode(line.replace(" ", "").replace(":", "")));
+ }
+ return revokedCerts;
+ }
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/storage/StorageConstraintPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/storage/StorageConstraintPlugin.java
index 197fd5c17a4..f40b7728e58 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/storage/StorageConstraintPlugin.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/storage/StorageConstraintPlugin.java
@@ -17,6 +17,7 @@
import info.nightscout.androidaps.interfaces.PluginDescription;
import info.nightscout.androidaps.interfaces.PluginType;
import info.nightscout.androidaps.logging.L;
+import info.nightscout.androidaps.plugins.bus.RxBus;
import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification;
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification;
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification;
@@ -56,9 +57,9 @@ public Constraint isClosedLoopAllowed(Constraint value) {
if (diskfree < Constants.MINIMUM_FREE_SPACE) {
value.set(false, MainApp.gs(R.string.diskfull, Constants.MINIMUM_FREE_SPACE), this);
Notification notification = new Notification(Notification.DISKFULL, MainApp.gs(R.string.diskfull, Constants.MINIMUM_FREE_SPACE), Notification.NORMAL);
- MainApp.bus().post(new EventNewNotification(notification));
+ RxBus.INSTANCE.send(new EventNewNotification(notification));
} else {
- MainApp.bus().post(new EventDismissNotification(Notification.DISKFULL));
+ RxBus.INSTANCE.send(new EventDismissNotification(Notification.DISKFULL));
}
return value;
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/versionChecker/VersionCheckerPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/versionChecker/VersionCheckerPlugin.kt
new file mode 100644
index 00000000000..9d88740d4b5
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/versionChecker/VersionCheckerPlugin.kt
@@ -0,0 +1,94 @@
+package info.nightscout.androidaps.plugins.constraints.versionChecker
+
+import info.nightscout.androidaps.BuildConfig
+import info.nightscout.androidaps.MainApp
+import info.nightscout.androidaps.R
+import info.nightscout.androidaps.interfaces.Constraint
+import info.nightscout.androidaps.interfaces.ConstraintsInterface
+import info.nightscout.androidaps.interfaces.PluginBase
+import info.nightscout.androidaps.interfaces.PluginDescription
+import info.nightscout.androidaps.interfaces.PluginType
+import info.nightscout.androidaps.plugins.bus.RxBus
+import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification
+import info.nightscout.androidaps.plugins.general.overview.notifications.Notification
+import info.nightscout.androidaps.utils.SP
+import java.util.concurrent.TimeUnit
+import kotlin.math.roundToInt
+
+/**
+ * Usually we would have a class here.
+ * Instead of having a class we can use an object directly inherited from PluginBase.
+ * This is a lazy loading singleton only loaded when actually used.
+ * */
+
+object VersionCheckerPlugin : PluginBase(PluginDescription()
+ .mainType(PluginType.CONSTRAINTS)
+ .neverVisible(true)
+ .alwaysEnabled(true)
+ .showInList(false)
+ .pluginName(R.string.versionChecker)), ConstraintsInterface {
+
+ private val gracePeriod: GracePeriod
+ get() = if ((BuildConfig.VERSION_NAME.contains("RC", ignoreCase = true))) {
+ GracePeriod.RC
+ } else {
+ GracePeriod.RELEASE
+ }
+
+ override fun isClosedLoopAllowed(value: Constraint): Constraint {
+ checkWarning()
+ triggerCheckVersion()
+ return if (isOldVersion(gracePeriod.veryOld.daysToMillis()))
+ value.set(false, MainApp.gs(R.string.very_old_version), this)
+ else
+ value
+ }
+
+ private fun checkWarning() {
+ val now = System.currentTimeMillis()
+
+ if (!SP.contains(R.string.key_last_versionchecker_plugin_warning)) {
+ SP.putLong(R.string.key_last_versionchecker_plugin_warning, now)
+ return
+ }
+
+
+ if (isOldVersion(gracePeriod.warning.daysToMillis()) && shouldWarnAgain(now)) {
+ // store last notification time
+ SP.putLong(R.string.key_last_versionchecker_plugin_warning, now)
+
+ //notify
+ val message = MainApp.gs(R.string.new_version_warning,
+ ((now - SP.getLong(R.string.key_last_time_this_version_detected, now)) / 1L.daysToMillis().toDouble()).roundToInt(),
+ gracePeriod.old,
+ gracePeriod.veryOld
+ )
+ val notification = Notification(Notification.OLDVERSION, message, Notification.NORMAL)
+ RxBus.send(EventNewNotification(notification))
+ }
+ }
+
+ private fun shouldWarnAgain(now: Long) =
+ now > SP.getLong(R.string.key_last_versionchecker_plugin_warning, 0) + WARN_EVERY
+
+ override fun applyMaxIOBConstraints(maxIob: Constraint): Constraint =
+ if (isOldVersion(gracePeriod.old.daysToMillis()))
+ maxIob.set(0.toDouble(), MainApp.gs(R.string.old_version), this)
+ else
+ maxIob
+
+ private fun isOldVersion(gracePeriod: Long): Boolean {
+ val now = System.currentTimeMillis()
+ return now > SP.getLong(R.string.key_last_time_this_version_detected, 0) + gracePeriod
+ }
+
+ private val WARN_EVERY = TimeUnit.DAYS.toMillis(1)
+
+}
+
+enum class GracePeriod(val warning: Long, val old: Long, val veryOld: Long) {
+ RELEASE(30, 60, 90),
+ RC(1, 7, 14)
+}
+
+private fun Long.daysToMillis() = TimeUnit.DAYS.toMillis(this)
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/versionChecker/VersionCheckerUtils.kt b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/versionChecker/VersionCheckerUtils.kt
new file mode 100644
index 00000000000..ac9724608f2
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/versionChecker/VersionCheckerUtils.kt
@@ -0,0 +1,126 @@
+package info.nightscout.androidaps.plugins.constraints.versionChecker
+
+import android.content.Context
+import android.net.ConnectivityManager
+import info.nightscout.androidaps.BuildConfig
+import info.nightscout.androidaps.MainApp
+import info.nightscout.androidaps.R
+import info.nightscout.androidaps.logging.L
+import info.nightscout.androidaps.plugins.bus.RxBus
+import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification
+import info.nightscout.androidaps.plugins.general.overview.notifications.Notification
+import info.nightscout.androidaps.utils.SP
+import org.slf4j.LoggerFactory
+import java.io.IOException
+import java.net.URL
+import java.util.concurrent.TimeUnit
+
+// check network connection
+fun isConnected(): Boolean {
+ val connMgr = MainApp.instance().applicationContext.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
+ return connMgr.activeNetworkInfo?.isConnected ?: false
+}
+
+private val log = LoggerFactory.getLogger(L.CORE)
+
+fun triggerCheckVersion() {
+
+ if (!SP.contains(R.string.key_last_time_this_version_detected)) {
+ // On a new installation, set it as 30 days old in order to warn that there is a new version.
+ SP.putLong(R.string.key_last_time_this_version_detected, System.currentTimeMillis() - TimeUnit.DAYS.toMillis(30))
+ }
+
+ // If we are good, only check once every day.
+ if (System.currentTimeMillis() > SP.getLong(R.string.key_last_time_this_version_detected, 0) + CHECK_EVERY) {
+ checkVersion()
+ }
+}
+
+private fun checkVersion() = if (isConnected()) {
+ Thread {
+ try {
+ val version: String? = findVersion(URL("https://raw.githubusercontent.com/MilosKozak/AndroidAPS/master/app/build.gradle").readText())
+ compareWithCurrentVersion(version, BuildConfig.VERSION_NAME)
+ } catch (e: IOException) {
+ log.debug("Github master version check error: $e")
+ }
+ }.start()
+} else
+ log.debug("Github master version no checked. No connectivity")
+
+fun compareWithCurrentVersion(newVersion: String?, currentVersion: String) {
+
+ val newVersionElements = newVersion.toNumberList()
+ val currentVersionElements = currentVersion.toNumberList()
+
+ if (newVersionElements == null || newVersionElements.isEmpty()) {
+ onVersionNotDetectable()
+ return
+ }
+
+ if (currentVersionElements == null || currentVersionElements.isEmpty()) {
+ // current version scrambled?!
+ onNewVersionDetected(currentVersion, newVersion)
+ return
+ }
+
+ newVersionElements.take(3).forEachIndexed { i, newElem ->
+ val currElem: Int = currentVersionElements.getOrNull(i)
+ ?: return onNewVersionDetected(currentVersion, newVersion)
+
+ (newElem - currElem).let {
+ when {
+ it > 0 -> return onNewVersionDetected(currentVersion, newVersion)
+ it < 0 -> return onOlderVersionDetected()
+ it == 0 -> Unit
+ }
+ }
+ }
+ onSameVersionDetected()
+}
+
+private fun onOlderVersionDetected() {
+ log.debug("Version newer than master. Are you developer?")
+ SP.putLong(R.string.key_last_time_this_version_detected, System.currentTimeMillis())
+}
+
+fun onSameVersionDetected() {
+ SP.putLong(R.string.key_last_time_this_version_detected, System.currentTimeMillis())
+}
+
+fun onVersionNotDetectable() {
+ log.debug("fetch failed")
+}
+
+fun onNewVersionDetected(currentVersion: String, newVersion: String?) {
+ val now = System.currentTimeMillis()
+ if (now > SP.getLong(R.string.key_last_versionchecker_warning, 0) + WARN_EVERY) {
+ log.debug("Version ${currentVersion} outdated. Found $newVersion")
+ val notification = Notification(Notification.NEWVERSIONDETECTED, String.format(MainApp.gs(R.string.versionavailable), newVersion.toString()), Notification.LOW)
+ RxBus.send(EventNewNotification(notification))
+ SP.putLong(R.string.key_last_versionchecker_warning, now)
+ }
+}
+
+@Deprecated(replaceWith = ReplaceWith("numericVersionPart()"), message = "Will not work if RCs have another index number in it.")
+fun String.versionStrip() = this.mapNotNull {
+ when (it) {
+ in '0'..'9' -> it
+ '.' -> it
+ else -> null
+ }
+}.joinToString(separator = "")
+
+fun String.numericVersionPart(): String =
+ "(((\\d+)\\.)+(\\d+))(\\D(.*))?".toRegex().matchEntire(this)?.groupValues?.getOrNull(1) ?: ""
+
+fun String?.toNumberList() =
+ this?.numericVersionPart().takeIf { !it.isNullOrBlank() }?.split(".")?.map { it.toInt() }
+
+fun findVersion(file: String?): String? {
+ val regex = "(.*)version(.*)\"(((\\d+)\\.)+(\\d+))\"(.*)".toRegex()
+ return file?.lines()?.filter { regex.matches(it) }?.mapNotNull { regex.matchEntire(it)?.groupValues?.getOrNull(3) }?.firstOrNull()
+}
+
+val CHECK_EVERY = TimeUnit.DAYS.toMillis(1)
+val WARN_EVERY = TimeUnit.DAYS.toMillis(1)
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/actions/ActionsFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/actions/ActionsFragment.java
deleted file mode 100644
index ff99978fed2..00000000000
--- a/app/src/main/java/info/nightscout/androidaps/plugins/general/actions/ActionsFragment.java
+++ /dev/null
@@ -1,338 +0,0 @@
-package info.nightscout.androidaps.plugins.general.actions;
-
-
-import android.app.Activity;
-import android.content.Intent;
-import android.graphics.drawable.Drawable;
-import android.os.Bundle;
-import android.support.v4.app.Fragment;
-import android.support.v4.app.FragmentManager;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.LinearLayout;
-
-import com.squareup.otto.Subscribe;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import info.nightscout.androidaps.Config;
-import info.nightscout.androidaps.MainApp;
-import info.nightscout.androidaps.R;
-import info.nightscout.androidaps.activities.HistoryBrowseActivity;
-import info.nightscout.androidaps.activities.TDDStatsActivity;
-import info.nightscout.androidaps.db.ExtendedBolus;
-import info.nightscout.androidaps.db.TemporaryBasal;
-import info.nightscout.androidaps.events.EventExtendedBolusChange;
-import info.nightscout.androidaps.events.EventInitializationChanged;
-import info.nightscout.androidaps.events.EventRefreshOverview;
-import info.nightscout.androidaps.events.EventTempBasalChange;
-import info.nightscout.androidaps.interfaces.PumpInterface;
-import info.nightscout.androidaps.plugins.common.SubscriberFragment;
-import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin;
-import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions;
-import info.nightscout.androidaps.plugins.general.actions.defs.CustomAction;
-import info.nightscout.androidaps.plugins.general.actions.dialogs.FillDialog;
-import info.nightscout.androidaps.plugins.general.actions.dialogs.NewExtendedBolusDialog;
-import info.nightscout.androidaps.plugins.general.actions.dialogs.NewTempBasalDialog;
-import info.nightscout.androidaps.plugins.general.careportal.CareportalFragment;
-import info.nightscout.androidaps.plugins.general.careportal.Dialogs.NewNSTreatmentDialog;
-import info.nightscout.androidaps.plugins.general.careportal.OptionsToShow;
-import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
-import info.nightscout.androidaps.utils.FabricPrivacy;
-import info.nightscout.androidaps.utils.SingleClickButton;
-
-
-/**
- * A simple {@link Fragment} subclass.
- */
-public class ActionsFragment extends SubscriberFragment implements View.OnClickListener {
-
- static ActionsPlugin actionsPlugin = new ActionsPlugin();
-
- static public ActionsPlugin getPlugin() {
- return actionsPlugin;
- }
-
- View actionsFragmentView;
- SingleClickButton profileSwitch;
- SingleClickButton tempTarget;
- SingleClickButton extendedBolus;
- SingleClickButton extendedBolusCancel;
- SingleClickButton tempBasal;
- SingleClickButton tempBasalCancel;
- SingleClickButton fill;
- SingleClickButton tddStats;
- SingleClickButton history;
-
- private Map pumpCustomActions = new HashMap<>();
- private List pumpCustomButtons = new ArrayList<>();
-
- public ActionsFragment() {
- super();
- }
-
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- try {
- View view = inflater.inflate(R.layout.actions_fragment, container, false);
-
- profileSwitch = (SingleClickButton) view.findViewById(R.id.actions_profileswitch);
- tempTarget = (SingleClickButton) view.findViewById(R.id.actions_temptarget);
- extendedBolus = (SingleClickButton) view.findViewById(R.id.actions_extendedbolus);
- extendedBolusCancel = (SingleClickButton) view.findViewById(R.id.actions_extendedbolus_cancel);
- tempBasal = (SingleClickButton) view.findViewById(R.id.actions_settempbasal);
- tempBasalCancel = (SingleClickButton) view.findViewById(R.id.actions_canceltempbasal);
- fill = (SingleClickButton) view.findViewById(R.id.actions_fill);
- tddStats = view.findViewById(R.id.actions_tddstats);
- history = view.findViewById(R.id.actions_historybrowser);
-
- profileSwitch.setOnClickListener(this);
- tempTarget.setOnClickListener(this);
- extendedBolus.setOnClickListener(this);
- extendedBolusCancel.setOnClickListener(this);
- tempBasal.setOnClickListener(this);
- tempBasalCancel.setOnClickListener(this);
- fill.setOnClickListener(this);
- history.setOnClickListener(this);
- tddStats.setOnClickListener(this);
-
- actionsFragmentView = view;
-
- updateGUI();
- return view;
- } catch (Exception e) {
- FabricPrivacy.logException(e);
- }
-
- return null;
- }
-
- @Subscribe
- public void onStatusEvent(final EventInitializationChanged ev) {
- updateGUI();
- }
-
- @Subscribe
- public void onStatusEvent(final EventRefreshOverview ev) {
- updateGUI();
- }
-
- @Subscribe
- public void onStatusEvent(final EventExtendedBolusChange ev) {
- updateGUI();
- }
-
- @Subscribe
- public void onStatusEvent(final EventTempBasalChange ev) {
- updateGUI();
- }
-
- @Override
- protected void updateGUI() {
- Activity activity = getActivity();
- if (activity != null)
- activity.runOnUiThread(new Runnable() {
- @Override
- public void run() {
- if (ConfigBuilderPlugin.getPlugin().getActiveProfileInterface() != null && ConfigBuilderPlugin.getPlugin().getActiveProfileInterface().getProfile() != null) {
- profileSwitch.setVisibility(View.VISIBLE);
- } else {
- profileSwitch.setVisibility(View.GONE);
- }
-
- if (ProfileFunctions.getInstance().getProfile() == null) {
- tempTarget.setVisibility(View.GONE);
- extendedBolus.setVisibility(View.GONE);
- extendedBolusCancel.setVisibility(View.GONE);
- tempBasal.setVisibility(View.GONE);
- tempBasalCancel.setVisibility(View.GONE);
- fill.setVisibility(View.GONE);
- return;
- }
-
- final PumpInterface pump = ConfigBuilderPlugin.getPlugin().getActivePump();
- final boolean basalprofileEnabled = MainApp.isEngineeringModeOrRelease()
- && pump.getPumpDescription().isSetBasalProfileCapable;
-
- if (!basalprofileEnabled || !pump.isInitialized() || pump.isSuspended())
- profileSwitch.setVisibility(View.GONE);
- else
- profileSwitch.setVisibility(View.VISIBLE);
-
- if (!pump.getPumpDescription().isExtendedBolusCapable || !pump.isInitialized() || pump.isSuspended() || pump.isFakingTempsByExtendedBoluses()) {
- extendedBolus.setVisibility(View.GONE);
- extendedBolusCancel.setVisibility(View.GONE);
- } else {
- ExtendedBolus activeExtendedBolus = TreatmentsPlugin.getPlugin().getExtendedBolusFromHistory(System.currentTimeMillis());
- if (activeExtendedBolus != null) {
- extendedBolus.setVisibility(View.GONE);
- extendedBolusCancel.setVisibility(View.VISIBLE);
- extendedBolusCancel.setText(MainApp.gs(R.string.cancel) + " " + activeExtendedBolus.toString());
- } else {
- extendedBolus.setVisibility(View.VISIBLE);
- extendedBolusCancel.setVisibility(View.GONE);
- }
- }
-
-
- if (!pump.getPumpDescription().isTempBasalCapable || !pump.isInitialized() || pump.isSuspended()) {
- tempBasal.setVisibility(View.GONE);
- tempBasalCancel.setVisibility(View.GONE);
- } else {
- final TemporaryBasal activeTemp = TreatmentsPlugin.getPlugin().getTempBasalFromHistory(System.currentTimeMillis());
- if (activeTemp != null) {
- tempBasal.setVisibility(View.GONE);
- tempBasalCancel.setVisibility(View.VISIBLE);
- tempBasalCancel.setText(MainApp.gs(R.string.cancel) + " " + activeTemp.toStringShort());
- } else {
- tempBasal.setVisibility(View.VISIBLE);
- tempBasalCancel.setVisibility(View.GONE);
- }
- }
-
- if (!pump.getPumpDescription().isRefillingCapable || !pump.isInitialized() || pump.isSuspended())
- fill.setVisibility(View.GONE);
- else
- fill.setVisibility(View.VISIBLE);
-
- if (!Config.APS)
- tempTarget.setVisibility(View.GONE);
- else
- tempTarget.setVisibility(View.VISIBLE);
-
- if (!pump.getPumpDescription().supportsTDDs)
- tddStats.setVisibility(View.GONE);
- else
- tddStats.setVisibility(View.VISIBLE);
-
- checkPumpCustomActions();
-
- }
- });
- }
-
-
- View.OnClickListener pumpCustomActionsListener = v -> {
-
- SingleClickButton btn = (SingleClickButton) v;
-
- CustomAction customAction = this.pumpCustomActions.get(btn.getText().toString());
-
- ConfigBuilderPlugin.getPlugin().getActivePump().executeCustomAction(customAction.getCustomActionType());
-
- };
-
-
- private void checkPumpCustomActions() {
-
- PumpInterface activePump = ConfigBuilderPlugin.getPlugin().getActivePump();
-
- removePumpCustomActions();
-
- if (activePump == null) {
- return;
- }
-
- List customActions = activePump.getCustomActions();
-
- if (customActions != null && customActions.size() > 0) {
-
- LinearLayout ll = actionsFragmentView.findViewById(R.id.action_buttons_layout);
-
- for (CustomAction customAction : customActions) {
-
- SingleClickButton btn = new SingleClickButton(getContext(), null, android.R.attr.buttonStyle);
- btn.setText(MainApp.gs(customAction.getName()));
-
- LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
- LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT, 0.5f);
- layoutParams.setMargins(20, 8, 20, 8); // 10,3,10,3
-
- btn.setLayoutParams(layoutParams);
- btn.setOnClickListener(pumpCustomActionsListener);
-
- Drawable top = getResources().getDrawable(customAction.getIconResourceId());
- btn.setCompoundDrawablesWithIntrinsicBounds(null, top, null, null);
-
- ll.addView(btn);
-
- this.pumpCustomActions.put(MainApp.gs(customAction.getName()), customAction);
- this.pumpCustomButtons.add(btn);
-
- }
- }
-
- }
-
-
- private void removePumpCustomActions() {
-
- if (pumpCustomActions.size() == 0)
- return;
-
- LinearLayout ll = actionsFragmentView.findViewById(R.id.action_buttons_layout);
-
- for (SingleClickButton customButton : pumpCustomButtons) {
- ll.removeView(customButton);
- }
-
- pumpCustomButtons.clear();
- pumpCustomActions.clear();
- }
-
-
- @Override
- public void onClick(View view) {
- FragmentManager manager = getFragmentManager();
- switch (view.getId()) {
- case R.id.actions_profileswitch:
- NewNSTreatmentDialog newDialog = new NewNSTreatmentDialog();
- final OptionsToShow profileswitch = CareportalFragment.PROFILESWITCH;
- profileswitch.executeProfileSwitch = true;
- newDialog.setOptions(profileswitch, R.string.careportal_profileswitch);
- newDialog.show(manager, "NewNSTreatmentDialog");
- break;
- case R.id.actions_temptarget:
- NewNSTreatmentDialog newTTDialog = new NewNSTreatmentDialog();
- final OptionsToShow temptarget = CareportalFragment.TEMPTARGET;
- temptarget.executeTempTarget = true;
- newTTDialog.setOptions(temptarget, R.string.careportal_temporarytarget);
- newTTDialog.show(manager, "NewNSTreatmentDialog");
- break;
- case R.id.actions_extendedbolus:
- NewExtendedBolusDialog newExtendedDialog = new NewExtendedBolusDialog();
- newExtendedDialog.show(manager, "NewExtendedDialog");
- break;
- case R.id.actions_extendedbolus_cancel:
- if (TreatmentsPlugin.getPlugin().isInHistoryExtendedBoluslInProgress()) {
- ConfigBuilderPlugin.getPlugin().getCommandQueue().cancelExtended(null);
- }
- break;
- case R.id.actions_canceltempbasal:
- if (TreatmentsPlugin.getPlugin().isTempBasalInProgress()) {
- ConfigBuilderPlugin.getPlugin().getCommandQueue().cancelTempBasal(true, null);
- }
- break;
- case R.id.actions_settempbasal:
- NewTempBasalDialog newTempDialog = new NewTempBasalDialog();
- newTempDialog.show(manager, "NewTempDialog");
- break;
- case R.id.actions_fill:
- FillDialog fillDialog = new FillDialog();
- fillDialog.show(manager, "FillDialog");
- break;
- case R.id.actions_historybrowser:
- startActivity(new Intent(getContext(), HistoryBrowseActivity.class));
- break;
- case R.id.actions_tddstats:
- startActivity(new Intent(getContext(), TDDStatsActivity.class));
- break;
- }
- }
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/actions/ActionsFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/actions/ActionsFragment.kt
new file mode 100644
index 00000000000..e68df84fdf5
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/actions/ActionsFragment.kt
@@ -0,0 +1,264 @@
+package info.nightscout.androidaps.plugins.general.actions
+
+
+import android.content.Intent
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.LinearLayout
+import androidx.core.content.ContextCompat
+import androidx.fragment.app.Fragment
+import info.nightscout.androidaps.Config
+import info.nightscout.androidaps.MainApp
+import info.nightscout.androidaps.R
+import info.nightscout.androidaps.activities.HistoryBrowseActivity
+import info.nightscout.androidaps.activities.TDDStatsActivity
+import info.nightscout.androidaps.events.*
+import info.nightscout.androidaps.plugins.bus.RxBus
+import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin
+import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions
+import info.nightscout.androidaps.plugins.general.actions.defs.CustomAction
+import info.nightscout.androidaps.dialogs.CareDialog
+import info.nightscout.androidaps.dialogs.ExtendedBolusDialog
+import info.nightscout.androidaps.dialogs.FillDialog
+import info.nightscout.androidaps.dialogs.TempBasalDialog
+import info.nightscout.androidaps.plugins.general.careportal.CareportalFragment
+import info.nightscout.androidaps.activities.ErrorHelperActivity
+import info.nightscout.androidaps.dialogs.ProfileSwitchDialog
+import info.nightscout.androidaps.dialogs.TempTargetDialog
+import info.nightscout.androidaps.logging.L
+import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
+import info.nightscout.androidaps.queue.Callback
+import info.nightscout.androidaps.utils.*
+import io.reactivex.android.schedulers.AndroidSchedulers
+import io.reactivex.disposables.CompositeDisposable
+import kotlinx.android.synthetic.main.actions_fragment.*
+import kotlinx.android.synthetic.main.careportal_stats_fragment.*
+import org.slf4j.LoggerFactory
+import java.util.*
+
+class ActionsFragment : Fragment() {
+ private val log = LoggerFactory.getLogger(L.CORE)
+
+ private var disposable: CompositeDisposable = CompositeDisposable()
+
+ private val pumpCustomActions = HashMap()
+ private val pumpCustomButtons = ArrayList()
+
+ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
+ savedInstanceState: Bundle?): View? {
+ return inflater.inflate(R.layout.actions_fragment, container, false)
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+
+ actions_profileswitch.setOnClickListener {
+ fragmentManager?.let { ProfileSwitchDialog().show(it, "Actions") }
+ }
+ actions_temptarget.setOnClickListener {
+ fragmentManager?.let { TempTargetDialog().show(it, "Actions") }
+ }
+ actions_extendedbolus.setOnClickListener {
+ context?.let { context ->
+ OKDialog.showConfirmation(context, MainApp.gs(R.string.extended_bolus), MainApp.gs(R.string.ebstopsloop),
+ Runnable {
+ fragmentManager?.let { ExtendedBolusDialog().show(it, "Actions") }
+ }, null)
+ }
+ }
+ actions_extendedbolus_cancel.setOnClickListener {
+ if (TreatmentsPlugin.getPlugin().isInHistoryExtendedBoluslInProgress) {
+ log.debug("USER ENTRY: CANCEL EXTENDED BOLUS")
+ ConfigBuilderPlugin.getPlugin().commandQueue.cancelExtended(object : Callback() {
+ override fun run() {
+ if (!result.success) {
+ val i = Intent(MainApp.instance(), ErrorHelperActivity::class.java)
+ i.putExtra("soundid", R.raw.boluserror)
+ i.putExtra("status", result.comment)
+ i.putExtra("title", MainApp.gs(R.string.extendedbolusdeliveryerror))
+ i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ MainApp.instance().startActivity(i)
+ }
+ }
+ })
+ }
+ }
+ actions_settempbasal.setOnClickListener {
+ fragmentManager?.let { TempBasalDialog().show(it, "Actions") }
+ }
+ actions_canceltempbasal.setOnClickListener {
+ if (TreatmentsPlugin.getPlugin().isTempBasalInProgress) {
+ log.debug("USER ENTRY: CANCEL TEMP BASAL")
+ ConfigBuilderPlugin.getPlugin().commandQueue.cancelTempBasal(true, object : Callback() {
+ override fun run() {
+ if (!result.success) {
+ val i = Intent(MainApp.instance(), ErrorHelperActivity::class.java)
+ i.putExtra("soundid", R.raw.boluserror)
+ i.putExtra("status", result.comment)
+ i.putExtra("title", MainApp.gs(R.string.tempbasaldeliveryerror))
+ i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ MainApp.instance().startActivity(i)
+ }
+ }
+ })
+ }
+ }
+ actions_fill.setOnClickListener { fragmentManager?.let { FillDialog().show(it, "FillDialog") } }
+ actions_historybrowser.setOnClickListener { startActivity(Intent(context, HistoryBrowseActivity::class.java)) }
+ actions_tddstats.setOnClickListener { startActivity(Intent(context, TDDStatsActivity::class.java)) }
+ actions_bgcheck.setOnClickListener {
+ fragmentManager?.let { CareDialog().setOptions(CareDialog.EventType.BGCHECK, R.string.careportal_bgcheck).show(it, "Actions") }
+ }
+ actions_cgmsensorinsert.setOnClickListener {
+ fragmentManager?.let { CareDialog().setOptions(CareDialog.EventType.SENSOR_INSERT, R.string.careportal_cgmsensorinsert).show(it, "Actions") }
+ }
+ actions_pumpbatterychange.setOnClickListener {
+ fragmentManager?.let { CareDialog().setOptions(CareDialog.EventType.BATTERY_CHANGE, R.string.careportal_pumpbatterychange).show(it, "Actions") }
+ }
+ actions_note.setOnClickListener {
+ fragmentManager?.let { CareDialog().setOptions(CareDialog.EventType.NOTE, R.string.careportal_note).show(it, "Actions") }
+ }
+ actions_exercise.setOnClickListener {
+ fragmentManager?.let { CareDialog().setOptions(CareDialog.EventType.EXERCISE, R.string.careportal_exercise).show(it, "Actions") }
+ }
+
+ SP.putBoolean(R.string.key_objectiveuseactions, true)
+ }
+
+ @Synchronized
+ override fun onResume() {
+ super.onResume()
+ disposable += RxBus
+ .toObservable(EventInitializationChanged::class.java)
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe({ updateGui() }, { FabricPrivacy.logException(it) })
+ disposable += RxBus
+ .toObservable(EventRefreshOverview::class.java)
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe({ updateGui() }, { FabricPrivacy.logException(it) })
+ disposable += RxBus
+ .toObservable(EventExtendedBolusChange::class.java)
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe({ updateGui() }, { FabricPrivacy.logException(it) })
+ disposable += RxBus
+ .toObservable(EventTempBasalChange::class.java)
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe({ updateGui() }, { FabricPrivacy.logException(it) })
+ disposable += RxBus
+ .toObservable(EventCustomActionsChanged::class.java)
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe({ updateGui() }, { FabricPrivacy.logException(it) })
+ disposable += RxBus
+ .toObservable(EventCareportalEventChange::class.java)
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe({ updateGui() }, { FabricPrivacy.logException(it) })
+ updateGui()
+ }
+
+ @Synchronized
+ override fun onPause() {
+ super.onPause()
+ disposable.clear()
+ }
+
+ @Synchronized
+ fun updateGui() {
+ actions_profileswitch?.visibility =
+ if (ConfigBuilderPlugin.getPlugin().activeProfileInterface?.profile != null) View.VISIBLE
+ else View.GONE
+
+ if (ProfileFunctions.getInstance().profile == null) {
+ actions_temptarget?.visibility = View.GONE
+ actions_extendedbolus?.visibility = View.GONE
+ actions_extendedbolus_cancel?.visibility = View.GONE
+ actions_settempbasal?.visibility = View.GONE
+ actions_canceltempbasal?.visibility = View.GONE
+ actions_fill?.visibility = View.GONE
+ return
+ }
+
+ val pump = ConfigBuilderPlugin.getPlugin().activePump ?: return
+ val basalProfileEnabled = MainApp.isEngineeringModeOrRelease() && pump.pumpDescription.isSetBasalProfileCapable
+
+ actions_profileswitch?.visibility = if (!basalProfileEnabled || !pump.isInitialized || pump.isSuspended) View.GONE else View.VISIBLE
+
+ if (!pump.pumpDescription.isExtendedBolusCapable || !pump.isInitialized || pump.isSuspended || pump.isFakingTempsByExtendedBoluses) {
+ actions_extendedbolus?.visibility = View.GONE
+ actions_extendedbolus_cancel?.visibility = View.GONE
+ } else {
+ val activeExtendedBolus = TreatmentsPlugin.getPlugin().getExtendedBolusFromHistory(System.currentTimeMillis())
+ if (activeExtendedBolus != null) {
+ actions_extendedbolus?.visibility = View.GONE
+ actions_extendedbolus_cancel?.visibility = View.VISIBLE
+ actions_extendedbolus_cancel?.text = MainApp.gs(R.string.cancel) + " " + activeExtendedBolus.toStringMedium()
+ } else {
+ actions_extendedbolus?.visibility = View.VISIBLE
+ actions_extendedbolus_cancel?.visibility = View.GONE
+ }
+ }
+
+ if (!pump.pumpDescription.isTempBasalCapable || !pump.isInitialized || pump.isSuspended) {
+ actions_settempbasal?.visibility = View.GONE
+ actions_canceltempbasal?.visibility = View.GONE
+ } else {
+ val activeTemp = TreatmentsPlugin.getPlugin().getTempBasalFromHistory(System.currentTimeMillis())
+ if (activeTemp != null) {
+ actions_settempbasal?.visibility = View.GONE
+ actions_canceltempbasal?.visibility = View.VISIBLE
+ actions_canceltempbasal?.text = MainApp.gs(R.string.cancel) + " " + activeTemp.toStringShort()
+ } else {
+ actions_settempbasal?.visibility = View.VISIBLE
+ actions_canceltempbasal?.visibility = View.GONE
+ }
+ }
+
+ actions_fill?.visibility =
+ if (!pump.pumpDescription.isRefillingCapable || !pump.isInitialized || pump.isSuspended) View.GONE
+ else View.VISIBLE
+
+ actions_temptarget?.visibility = Config.APS.toVisibility()
+ actions_tddstats?.visibility = pump.pumpDescription.supportsTDDs.toVisibility()
+ activity?.let { activity ->
+ CareportalFragment.updateAge(activity, careportal_sensorage, careportal_insulinage, careportal_canulaage, careportal_pbage)
+ }
+ checkPumpCustomActions()
+ }
+
+ private fun checkPumpCustomActions() {
+ val activePump = ConfigBuilderPlugin.getPlugin().activePump ?: return
+ val customActions = activePump.customActions ?: return
+ removePumpCustomActions()
+
+ for (customAction in customActions) {
+ if (!customAction.isEnabled) continue
+
+ val btn = SingleClickButton(context, null, android.R.attr.buttonStyle)
+ btn.text = MainApp.gs(customAction.name)
+
+ val layoutParams = LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT, 0.5f)
+ layoutParams.setMargins(20, 8, 20, 8) // 10,3,10,3
+
+ btn.layoutParams = layoutParams
+ btn.setOnClickListener { v ->
+ val b = v as SingleClickButton
+ val action = this.pumpCustomActions[b.text.toString()]
+ ConfigBuilderPlugin.getPlugin().activePump!!.executeCustomAction(action!!.customActionType)
+ }
+ val top = activity?.let { ContextCompat.getDrawable(it, customAction.iconResourceId) }
+ btn.setCompoundDrawablesWithIntrinsicBounds(null, top, null, null)
+
+ action_buttons_layout?.addView(btn)
+
+ this.pumpCustomActions[MainApp.gs(customAction.name)] = customAction
+ this.pumpCustomButtons.add(btn)
+ }
+ }
+
+ private fun removePumpCustomActions() {
+ for (customButton in pumpCustomButtons) action_buttons_layout?.removeView(customButton)
+ pumpCustomButtons.clear()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/actions/ActionsPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/actions/ActionsPlugin.java
deleted file mode 100644
index 5d47206e5ce..00000000000
--- a/app/src/main/java/info/nightscout/androidaps/plugins/general/actions/ActionsPlugin.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package info.nightscout.androidaps.plugins.general.actions;
-
-import info.nightscout.androidaps.R;
-import info.nightscout.androidaps.interfaces.PluginBase;
-import info.nightscout.androidaps.interfaces.PluginDescription;
-import info.nightscout.androidaps.interfaces.PluginType;
-
-/**
- * Created by mike on 05.11.2016.
- */
-
-public class ActionsPlugin extends PluginBase {
-
- public ActionsPlugin() {
- super(new PluginDescription()
- .mainType(PluginType.GENERAL)
- .fragmentClass(ActionsFragment.class.getName())
- .pluginName(R.string.actions)
- .shortName(R.string.actions_shortname)
- .description(R.string.description_actions)
- );
- }
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/actions/ActionsPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/actions/ActionsPlugin.kt
new file mode 100644
index 00000000000..e534fefa26a
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/actions/ActionsPlugin.kt
@@ -0,0 +1,16 @@
+package info.nightscout.androidaps.plugins.general.actions
+
+import info.nightscout.androidaps.Config
+import info.nightscout.androidaps.R
+import info.nightscout.androidaps.interfaces.PluginBase
+import info.nightscout.androidaps.interfaces.PluginDescription
+import info.nightscout.androidaps.interfaces.PluginType
+
+object ActionsPlugin : PluginBase(PluginDescription()
+ .mainType(PluginType.GENERAL)
+ .fragmentClass(ActionsFragment::class.qualifiedName)
+ .enableByDefault(Config.APS || Config.PUMPCONTROL)
+ .visibleByDefault(Config.APS || Config.PUMPCONTROL)
+ .pluginName(R.string.actions)
+ .shortName(R.string.actions_shortname)
+ .description(R.string.description_actions))
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/actions/defs/CustomAction.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/actions/defs/CustomAction.java
deleted file mode 100644
index e5e119baad9..00000000000
--- a/app/src/main/java/info/nightscout/androidaps/plugins/general/actions/defs/CustomAction.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package info.nightscout.androidaps.plugins.general.actions.defs;
-
-import info.nightscout.androidaps.R;
-
-/**
- * Created by andy on 9/20/18.
- */
-
-public class CustomAction {
-
- private int name;
- private String iconName;
- private CustomActionType customActionType;
- private int iconResourceId;
-
-
- public CustomAction(int nameResourceId, CustomActionType actionType) {
- this.name = nameResourceId;
- this.customActionType = actionType;
- this.iconResourceId = R.drawable.icon_actions_profileswitch;
- }
-
- public CustomAction(int nameResourceId, CustomActionType actionType, int iconResourceId) {
- this.name = nameResourceId;
- this.customActionType = actionType;
- this.iconResourceId = iconResourceId;
- }
-
-
- public int getName() {
-
- return name;
- }
-
-
-
-
- public CustomActionType getCustomActionType() {
-
- return customActionType;
- }
-
-
- public int getIconResourceId() {
- return iconResourceId;
- }
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/actions/defs/CustomAction.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/actions/defs/CustomAction.kt
new file mode 100644
index 00000000000..fe9af4a03e7
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/actions/defs/CustomAction.kt
@@ -0,0 +1,10 @@
+package info.nightscout.androidaps.plugins.general.actions.defs
+
+import info.nightscout.androidaps.R
+
+class CustomAction @JvmOverloads constructor(val name: Int, val customActionType: CustomActionType?, val iconResourceId: Int = R.drawable.icon_actions_profileswitch, var isEnabled: Boolean = true) {
+
+ constructor(nameResourceId: Int, actionType: CustomActionType?, enabled: Boolean) :
+ this(nameResourceId, actionType, R.drawable.icon_actions_profileswitch, enabled)
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/actions/defs/CustomActionType.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/actions/defs/CustomActionType.java
deleted file mode 100644
index 74ecf3c0e35..00000000000
--- a/app/src/main/java/info/nightscout/androidaps/plugins/general/actions/defs/CustomActionType.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package info.nightscout.androidaps.plugins.general.actions.defs;
-
-/**
- * Created by andy on 9/20/18.
- */
-
-public interface CustomActionType {
-
- String getKey();
-
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/actions/defs/CustomActionType.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/actions/defs/CustomActionType.kt
new file mode 100644
index 00000000000..fb472d5592a
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/actions/defs/CustomActionType.kt
@@ -0,0 +1,5 @@
+package info.nightscout.androidaps.plugins.general.actions.defs
+
+interface CustomActionType {
+ val key: String?
+}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/actions/dialogs/FillDialog.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/actions/dialogs/FillDialog.java
deleted file mode 100644
index 94d548a4449..00000000000
--- a/app/src/main/java/info/nightscout/androidaps/plugins/general/actions/dialogs/FillDialog.java
+++ /dev/null
@@ -1,255 +0,0 @@
-package info.nightscout.androidaps.plugins.general.actions.dialogs;
-
-import android.content.Context;
-import android.content.Intent;
-import android.os.Bundle;
-import android.support.v4.app.DialogFragment;
-import android.support.v7.app.AlertDialog;
-import android.text.Editable;
-import android.text.Html;
-import android.text.TextWatcher;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.ViewGroup;
-import android.view.Window;
-import android.view.WindowManager;
-import android.widget.Button;
-import android.widget.CheckBox;
-import android.widget.EditText;
-import android.widget.LinearLayout;
-
-import com.google.common.base.Joiner;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.LinkedList;
-import java.util.List;
-
-import info.nightscout.androidaps.MainApp;
-import info.nightscout.androidaps.R;
-import info.nightscout.androidaps.data.DetailedBolusInfo;
-import info.nightscout.androidaps.db.CareportalEvent;
-import info.nightscout.androidaps.db.Source;
-import info.nightscout.androidaps.interfaces.Constraint;
-import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin;
-import info.nightscout.androidaps.plugins.general.nsclient.NSUpload;
-import info.nightscout.androidaps.plugins.general.overview.dialogs.ErrorHelperActivity;
-import info.nightscout.androidaps.queue.Callback;
-import info.nightscout.androidaps.utils.DecimalFormatter;
-import info.nightscout.androidaps.utils.NumberPicker;
-import info.nightscout.androidaps.utils.SP;
-import info.nightscout.androidaps.utils.SafeParse;
-import info.nightscout.androidaps.utils.ToastUtils;
-
-import static info.nightscout.androidaps.utils.DateUtil.now;
-
-public class FillDialog extends DialogFragment implements OnClickListener {
- private static Logger log = LoggerFactory.getLogger(FillDialog.class);
-
- private CheckBox pumpSiteChangeCheckbox;
- private CheckBox insulinCartridgeChangeCheckbox;
-
- private NumberPicker editInsulin;
-
- double amount1 = 0d;
- double amount2 = 0d;
- double amount3 = 0d;
-
- private EditText notesEdit;
-
- //one shot guards
- private boolean accepted;
- private boolean okClicked;
-
- final private TextWatcher textWatcher = new TextWatcher() {
- @Override
- public void afterTextChanged(Editable s) {
- validateInputs();
- }
-
- @Override
- public void beforeTextChanged(CharSequence s, int start, int count, int after) {
- }
-
- @Override
- public void onTextChanged(CharSequence s, int start, int before, int count) {
- }
- };
-
- private void validateInputs() {
- int time = editInsulin.getValue().intValue();
- if (Math.abs(time) > 12 * 60) {
- editInsulin.setValue(0d);
- ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), MainApp.gs(R.string.constraintapllied));
- }
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- View view = inflater.inflate(R.layout.actions_fill_dialog, container, false);
-
- view.findViewById(R.id.ok).setOnClickListener(this);
- view.findViewById(R.id.cancel).setOnClickListener(this);
-
- getDialog().getWindow().requestFeature(Window.FEATURE_NO_TITLE);
- getDialog().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);
-
- pumpSiteChangeCheckbox = view.findViewById(R.id.fill_catheter_change);
- insulinCartridgeChangeCheckbox = view.findViewById(R.id.fill_cartridge_change);
-
- Double maxInsulin = MainApp.getConstraintChecker().getMaxBolusAllowed().value();
- double bolusstep = ConfigBuilderPlugin.getPlugin().getActivePump().getPumpDescription().bolusStep;
- editInsulin = view.findViewById(R.id.fill_insulinamount);
- editInsulin.setParams(0d, 0d, maxInsulin, bolusstep, DecimalFormatter.pumpSupportedBolusFormat(), false, textWatcher);
-
-
- Button preset1Button = view.findViewById(R.id.fill_preset_button1);
- amount1 = SP.getDouble("fill_button1", 0.3);
- if (amount1 > 0) {
- preset1Button.setVisibility(View.VISIBLE);
- preset1Button.setText(DecimalFormatter.toPumpSupportedBolus(amount1)); // + "U");
- preset1Button.setOnClickListener(this);
- } else {
- preset1Button.setVisibility(View.GONE);
- }
- Button preset2Button = view.findViewById(R.id.fill_preset_button2);
- amount2 = SP.getDouble("fill_button2", 0d);
- if (amount2 > 0) {
- preset2Button.setVisibility(View.VISIBLE);
- preset2Button.setText(DecimalFormatter.toPumpSupportedBolus(amount2)); // + "U");
- preset2Button.setOnClickListener(this);
- } else {
- preset2Button.setVisibility(View.GONE);
- }
- Button preset3Button = view.findViewById(R.id.fill_preset_button3);
- amount3 = SP.getDouble("fill_button3", 0d);
- if (amount3 > 0) {
- preset3Button.setVisibility(View.VISIBLE);
- preset3Button.setText(DecimalFormatter.toPumpSupportedBolus(amount3)); // + "U");
- preset3Button.setOnClickListener(this);
- } else {
- preset3Button.setVisibility(View.GONE);
- }
-
- LinearLayout notesLayout = view.findViewById(R.id.fill_notes_layout);
- notesLayout.setVisibility(SP.getBoolean(R.string.key_show_notes_entry_dialogs, false) ? View.VISIBLE : View.GONE);
- notesEdit = view.findViewById(R.id.fill_notes);
-
- setCancelable(true);
- getDialog().setCanceledOnTouchOutside(false);
- return view;
- }
-
- @Override
- public void onClick(View view) {
- switch (view.getId()) {
- case R.id.ok:
- confirmAndDeliver();
- break;
- case R.id.cancel:
- dismiss();
- break;
- case R.id.fill_preset_button1:
- editInsulin.setValue(amount1);
- break;
- case R.id.fill_preset_button2:
- editInsulin.setValue(amount2);
- break;
- case R.id.fill_preset_button3:
- editInsulin.setValue(amount3);
- break;
- }
-
- }
-
- private synchronized void confirmAndDeliver() {
- if (okClicked) {
- log.debug("guarding: ok already clicked");
- dismiss();
- return;
- }
- okClicked = true;
-
- try {
- Double insulin = SafeParse.stringToDouble(editInsulin.getText());
-
- List confirmMessage = new LinkedList<>();
-
- Double insulinAfterConstraints = MainApp.getConstraintChecker().applyBolusConstraints(new Constraint<>(insulin)).value();
- if (insulinAfterConstraints > 0) {
- confirmMessage.add(MainApp.gs(R.string.fillwarning));
- confirmMessage.add("");
- confirmMessage.add(MainApp.gs(R.string.bolus) + ": " + "" + DecimalFormatter.toPumpSupportedBolus(insulinAfterConstraints) + "U" + " ");
- if (Math.abs(insulinAfterConstraints - insulin) > 0.01d)
- confirmMessage.add("" + MainApp.gs(R.string.bolusconstraintapplied) + " ");
- }
-
- if (pumpSiteChangeCheckbox.isChecked())
- confirmMessage.add("" + "" + MainApp.gs(R.string.record_pump_site_change) + " ");
-
- if (insulinCartridgeChangeCheckbox.isChecked())
- confirmMessage.add("" + "" + MainApp.gs(R.string.record_insulin_cartridge_change) + " ");
-
- final String notes = notesEdit.getText().toString();
- if (!notes.isEmpty()) {
- confirmMessage.add(MainApp.gs(R.string.careportal_newnstreatment_notes_label) + ": " + notes);
- }
-
- final Double finalInsulinAfterConstraints = insulinAfterConstraints;
-
- final Context context = getContext();
- AlertDialog.Builder builder = new AlertDialog.Builder(context);
-
- builder.setTitle(MainApp.gs(R.string.confirmation));
- if (insulinAfterConstraints > 0 || pumpSiteChangeCheckbox.isChecked() || insulinCartridgeChangeCheckbox.isChecked()) {
- builder.setMessage(Html.fromHtml(Joiner.on(" ").join(confirmMessage)));
- builder.setPositiveButton(MainApp.gs(R.string.primefill), (dialog, id) -> {
- synchronized (builder) {
- if (accepted) {
- log.debug("guarding: already accepted");
- return;
- }
- accepted = true;
-
- if (finalInsulinAfterConstraints > 0) {
- DetailedBolusInfo detailedBolusInfo = new DetailedBolusInfo();
- detailedBolusInfo.insulin = finalInsulinAfterConstraints;
- detailedBolusInfo.context = context;
- detailedBolusInfo.source = Source.USER;
- detailedBolusInfo.isValid = false; // do not count it in IOB (for pump history)
- detailedBolusInfo.notes = notes;
- ConfigBuilderPlugin.getPlugin().getCommandQueue().bolus(detailedBolusInfo, new Callback() {
- @Override
- public void run() {
- if (!result.success) {
- Intent i = new Intent(MainApp.instance(), ErrorHelperActivity.class);
- i.putExtra("soundid", R.raw.boluserror);
- i.putExtra("status", result.comment);
- i.putExtra("title", MainApp.gs(R.string.treatmentdeliveryerror));
- i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- MainApp.instance().startActivity(i);
- }
- }
- });
- }
- if (pumpSiteChangeCheckbox.isChecked())
- NSUpload.uploadEvent(CareportalEvent.SITECHANGE, now(), notes);
- if (insulinCartridgeChangeCheckbox.isChecked())
- NSUpload.uploadEvent(CareportalEvent.INSULINCHANGE, now() + 1000, notes);
- }
- });
- } else {
- builder.setMessage(MainApp.gs(R.string.no_action_selected));
- }
- builder.setNegativeButton(MainApp.gs(R.string.cancel), null);
- builder.show();
- dismiss();
- } catch (RuntimeException e) {
- log.error("Unhandled exception", e);
- }
- }
-
-}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/actions/dialogs/NewExtendedBolusDialog.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/actions/dialogs/NewExtendedBolusDialog.java
deleted file mode 100644
index 579e9e2f06f..00000000000
--- a/app/src/main/java/info/nightscout/androidaps/plugins/general/actions/dialogs/NewExtendedBolusDialog.java
+++ /dev/null
@@ -1,115 +0,0 @@
-package info.nightscout.androidaps.plugins.general.actions.dialogs;
-
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.os.Bundle;
-import android.support.v4.app.DialogFragment;
-import android.support.v7.app.AlertDialog;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.text.DecimalFormat;
-
-import info.nightscout.androidaps.MainApp;
-import info.nightscout.androidaps.R;
-import info.nightscout.androidaps.interfaces.Constraint;
-import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin;
-import info.nightscout.androidaps.plugins.general.overview.dialogs.ErrorHelperActivity;
-import info.nightscout.androidaps.queue.Callback;
-import info.nightscout.androidaps.utils.NumberPicker;
-import info.nightscout.androidaps.utils.SafeParse;
-
-public class NewExtendedBolusDialog extends DialogFragment implements View.OnClickListener {
- private static Logger log = LoggerFactory.getLogger(NewExtendedBolusDialog.class);
-
- NumberPicker editInsulin;
- NumberPicker editDuration;
-
- public NewExtendedBolusDialog() {
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- getDialog().setTitle(MainApp.gs(R.string.overview_extendedbolus_button));
-
- View view = inflater.inflate(R.layout.overview_newextendedbolus_dialog, container, false);
-
- Double maxInsulin = MainApp.getConstraintChecker().getMaxExtendedBolusAllowed().value();
- editInsulin = (NumberPicker) view.findViewById(R.id.overview_newextendedbolus_insulin);
- editInsulin.setParams(0d, 0d, maxInsulin, 0.1d, new DecimalFormat("0.00"), false);
-
- double extendedDurationStep = ConfigBuilderPlugin.getPlugin().getActivePump().getPumpDescription().extendedBolusDurationStep;
- double extendedMaxDuration = ConfigBuilderPlugin.getPlugin().getActivePump().getPumpDescription().extendedBolusMaxDuration;
- editDuration = (NumberPicker) view.findViewById(R.id.overview_newextendedbolus_duration);
- editDuration.setParams(extendedDurationStep, extendedDurationStep, extendedMaxDuration, extendedDurationStep, new DecimalFormat("0"), false);
-
- view.findViewById(R.id.ok).setOnClickListener(this);
- view.findViewById(R.id.cancel).setOnClickListener(this);
-
- setCancelable(true);
- getDialog().setCanceledOnTouchOutside(false);
- return view;
- }
-
- @Override
- public void onClick(View view) {
- switch (view.getId()) {
- case R.id.ok:
- try {
- Double insulin = SafeParse.stringToDouble(editInsulin.getText());
- int durationInMinutes = SafeParse.stringToInt(editDuration.getText());
-
- String confirmMessage = MainApp.gs(R.string.setextendedbolusquestion);
-
- Double insulinAfterConstraint = MainApp.getConstraintChecker().applyExtendedBolusConstraints(new Constraint<>(insulin)).value();
- confirmMessage += " " + insulinAfterConstraint + " U ";
- confirmMessage += MainApp.gs(R.string.duration) + " " + durationInMinutes + "min ?";
- if (Math.abs(insulinAfterConstraint - insulin) > 0.01d)
- confirmMessage += "\n" + MainApp.gs(R.string.constraintapllied);
- insulin = insulinAfterConstraint;
-
- final Double finalInsulin = insulin;
- final int finalDurationInMinutes = durationInMinutes;
-
- final Context context = getContext();
- AlertDialog.Builder builder = new AlertDialog.Builder(context);
- builder.setTitle(MainApp.gs(R.string.confirmation));
- builder.setMessage(confirmMessage);
- builder.setPositiveButton(MainApp.gs(R.string.ok), new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int id) {
- ConfigBuilderPlugin.getPlugin().getCommandQueue().extendedBolus(finalInsulin, finalDurationInMinutes, new Callback() {
- @Override
- public void run() {
- if (!result.success) {
- Intent i = new Intent(MainApp.instance(), ErrorHelperActivity.class);
- i.putExtra("soundid", R.raw.boluserror);
- i.putExtra("status", result.comment);
- i.putExtra("title", MainApp.gs(R.string.treatmentdeliveryerror));
- i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- MainApp.instance().startActivity(i);
- }
- }
- });
- }
- });
- builder.setNegativeButton(MainApp.gs(R.string.cancel), null);
- builder.show();
- dismiss();
-
- } catch (Exception e) {
- log.error("Unhandled exception", e);
- }
- break;
- case R.id.cancel:
- dismiss();
- break;
- }
- }
-
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/actions/dialogs/NewTempBasalDialog.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/actions/dialogs/NewTempBasalDialog.java
deleted file mode 100644
index 80969b51b0d..00000000000
--- a/app/src/main/java/info/nightscout/androidaps/plugins/general/actions/dialogs/NewTempBasalDialog.java
+++ /dev/null
@@ -1,196 +0,0 @@
-package info.nightscout.androidaps.plugins.general.actions.dialogs;
-
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.os.Bundle;
-import android.support.v4.app.DialogFragment;
-import android.support.v7.app.AlertDialog;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.LinearLayout;
-import android.widget.RadioButton;
-import android.widget.RadioGroup;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.text.DecimalFormat;
-
-import info.nightscout.androidaps.MainApp;
-import info.nightscout.androidaps.R;
-import info.nightscout.androidaps.data.Profile;
-import info.nightscout.androidaps.interfaces.Constraint;
-import info.nightscout.androidaps.interfaces.PumpDescription;
-import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin;
-import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions;
-import info.nightscout.androidaps.plugins.general.overview.dialogs.ErrorHelperActivity;
-import info.nightscout.androidaps.queue.Callback;
-import info.nightscout.androidaps.utils.NumberPicker;
-import info.nightscout.androidaps.utils.SafeParse;
-
-public class NewTempBasalDialog extends DialogFragment implements View.OnClickListener, RadioGroup.OnCheckedChangeListener {
- private static Logger log = LoggerFactory.getLogger(NewTempBasalDialog.class);
-
- RadioButton percentRadio;
- RadioButton absoluteRadio;
- RadioGroup basalTypeRadioGroup;
- LinearLayout typeSelectorLayout;
-
- LinearLayout percentLayout;
- LinearLayout absoluteLayout;
-
- NumberPicker basalPercent;
- NumberPicker basalAbsolute;
- NumberPicker duration;
-
- public NewTempBasalDialog() {
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- getDialog().setTitle(MainApp.gs(R.string.overview_tempbasal_button));
-
- View view = inflater.inflate(R.layout.overview_newtempbasal_dialog, container, false);
-
- percentLayout = (LinearLayout) view.findViewById(R.id.overview_newtempbasal_percent_layout);
- absoluteLayout = (LinearLayout) view.findViewById(R.id.overview_newtempbasal_absolute_layout);
- percentRadio = (RadioButton) view.findViewById(R.id.overview_newtempbasal_percent_radio);
- basalTypeRadioGroup = (RadioGroup) view.findViewById(R.id.overview_newtempbasal_radiogroup);
- absoluteRadio = (RadioButton) view.findViewById(R.id.overview_newtempbasal_absolute_radio);
- typeSelectorLayout = (LinearLayout) view.findViewById(R.id.overview_newtempbasal_typeselector_layout);
-
- PumpDescription pumpDescription = ConfigBuilderPlugin.getPlugin().getActivePump().getPumpDescription();
-
- basalPercent = (NumberPicker) view.findViewById(R.id.overview_newtempbasal_basalpercentinput);
- double maxTempPercent = pumpDescription.maxTempPercent;
- double tempPercentStep = pumpDescription.tempPercentStep;
- basalPercent.setParams(100d, 0d, maxTempPercent, tempPercentStep, new DecimalFormat("0"), true);
-
- Profile profile = ProfileFunctions.getInstance().getProfile();
- Double currentBasal = profile != null ? profile.getBasal() : 0d;
- basalAbsolute = (NumberPicker) view.findViewById(R.id.overview_newtempbasal_basalabsoluteinput);
- basalAbsolute.setParams(currentBasal, 0d, pumpDescription.maxTempAbsolute, pumpDescription.tempAbsoluteStep, new DecimalFormat("0.00"), true);
-
- double tempDurationStep = pumpDescription.tempDurationStep;
- double tempMaxDuration = pumpDescription.tempMaxDuration;
- duration = (NumberPicker) view.findViewById(R.id.overview_newtempbasal_duration);
- duration.setParams(tempDurationStep, tempDurationStep, tempMaxDuration, tempDurationStep, new DecimalFormat("0"), false);
-
- if ((pumpDescription.tempBasalStyle & PumpDescription.PERCENT) == PumpDescription.PERCENT && (pumpDescription.tempBasalStyle & PumpDescription.ABSOLUTE) == PumpDescription.ABSOLUTE) {
- // Both allowed
- typeSelectorLayout.setVisibility(View.VISIBLE);
- } else {
- typeSelectorLayout.setVisibility(View.GONE);
- }
-
- if ((pumpDescription.tempBasalStyle & PumpDescription.PERCENT) == PumpDescription.PERCENT) {
- percentRadio.setChecked(true);
- absoluteRadio.setChecked(false);
- percentLayout.setVisibility(View.VISIBLE);
- absoluteLayout.setVisibility(View.GONE);
- } else if ((pumpDescription.tempBasalStyle & PumpDescription.ABSOLUTE) == PumpDescription.ABSOLUTE) {
- percentRadio.setChecked(false);
- absoluteRadio.setChecked(true);
- percentLayout.setVisibility(View.GONE);
- absoluteLayout.setVisibility(View.VISIBLE);
- }
-
- view.findViewById(R.id.ok).setOnClickListener(this);
- view.findViewById(R.id.cancel).setOnClickListener(this);
- basalTypeRadioGroup.setOnCheckedChangeListener(this);
-
- setCancelable(true);
- getDialog().setCanceledOnTouchOutside(false);
- return view;
- }
-
- @Override
- public void onClick(View view) {
- switch (view.getId()) {
- case R.id.ok:
- try {
- int percent = 0;
- Double absolute = 0d;
- final boolean setAsPercent = percentRadio.isChecked();
- int durationInMinutes = SafeParse.stringToInt(duration.getText());
-
- Profile profile = ProfileFunctions.getInstance().getProfile();
- if (profile == null)
- return;
-
- String confirmMessage = MainApp.gs(R.string.setbasalquestion);
- if (setAsPercent) {
- int basalPercentInput = SafeParse.stringToInt(basalPercent.getText());
- percent = MainApp.getConstraintChecker().applyBasalPercentConstraints(new Constraint<>(basalPercentInput), profile).value();
- confirmMessage += "\n" + percent + "% ";
- confirmMessage += "\n" + MainApp.gs(R.string.duration) + " " + durationInMinutes + "min ?";
- if (percent != basalPercentInput)
- confirmMessage += "\n" + MainApp.gs(R.string.constraintapllied);
- } else {
- Double basalAbsoluteInput = SafeParse.stringToDouble(basalAbsolute.getText());
- absolute = MainApp.getConstraintChecker().applyBasalConstraints(new Constraint<>(basalAbsoluteInput), profile).value();
- confirmMessage += "\n" + absolute + " U/h ";
- confirmMessage += "\n" + MainApp.gs(R.string.duration) + " " + durationInMinutes + "min ?";
- if (Math.abs(absolute - basalAbsoluteInput) > 0.01d)
- confirmMessage += "\n" + MainApp.gs(R.string.constraintapllied);
- }
-
- final int finalBasalPercent = percent;
- final Double finalBasal = absolute;
- final int finalDurationInMinutes = durationInMinutes;
-
- AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
- builder.setTitle(MainApp.gs(R.string.confirmation));
- builder.setMessage(confirmMessage);
- builder.setPositiveButton(MainApp.gs(R.string.ok), new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int id) {
- Callback callback = new Callback() {
- @Override
- public void run() {
- if (!result.success) {
- Intent i = new Intent(MainApp.instance(), ErrorHelperActivity.class);
- i.putExtra("soundid", R.raw.boluserror);
- i.putExtra("status", result.comment);
- i.putExtra("title", MainApp.gs(R.string.tempbasaldeliveryerror));
- i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- MainApp.instance().startActivity(i);
- }
- }
- };
- if (setAsPercent) {
- ConfigBuilderPlugin.getPlugin().getCommandQueue().tempBasalPercent(finalBasalPercent, finalDurationInMinutes, true, profile, callback);
- } else {
- ConfigBuilderPlugin.getPlugin().getCommandQueue().tempBasalAbsolute(finalBasal, finalDurationInMinutes, true, profile, callback);
- }
- }
- });
- builder.setNegativeButton(MainApp.gs(R.string.cancel), null);
- builder.show();
- dismiss();
-
- } catch (Exception e) {
- log.error("Unhandled exception", e);
- }
- break;
- case R.id.cancel:
- dismiss();
- break;
- }
- }
-
- @Override
- public void onCheckedChanged(RadioGroup group, int checkedId) {
- switch (checkedId) {
- case R.id.overview_newtempbasal_percent_radio:
- percentLayout.setVisibility(View.VISIBLE);
- absoluteLayout.setVisibility(View.GONE);
- break;
- case R.id.overview_newtempbasal_absolute_radio:
- percentLayout.setVisibility(View.GONE);
- absoluteLayout.setVisibility(View.VISIBLE);
- break;
- }
- }
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationEvent.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationEvent.java
new file mode 100644
index 00000000000..4f7bb62c747
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationEvent.java
@@ -0,0 +1,101 @@
+package info.nightscout.androidaps.plugins.general.automation;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import info.nightscout.androidaps.plugins.general.automation.actions.Action;
+import info.nightscout.androidaps.plugins.general.automation.triggers.Trigger;
+import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerConnector;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class AutomationEvent {
+ private static final Logger log = LoggerFactory.getLogger(AutomationEvent.class);
+
+ private Trigger trigger = new TriggerConnector();
+ private List actions = new ArrayList<>();
+ private String title;
+ private boolean enabled = true;
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ public void setTrigger(Trigger trigger) {
+ this.trigger = trigger;
+ }
+
+ public Trigger getTrigger() {
+ return trigger;
+ }
+
+ public List getActions() {
+ return actions;
+ }
+
+ public boolean isEnabled() {
+ return enabled;
+ }
+
+ public void setEnabled(boolean newState) {
+ enabled = newState;
+ }
+
+ public TriggerConnector getPreconditions() {
+ TriggerConnector trigger = new TriggerConnector(TriggerConnector.Type.AND);
+ for (Action action : actions) {
+ if (action.precondition != null)
+ trigger.add(action.precondition);
+ }
+ return trigger;
+ }
+
+ public void addAction(Action action) {
+ actions.add(action);
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public String toJSON() {
+ JSONObject o = new JSONObject();
+ try {
+ // title
+ o.put("title", title);
+ o.put("enabled", enabled);
+ // trigger
+ o.put("trigger", trigger.toJSON());
+ // actions
+ JSONArray array = new JSONArray();
+ for (Action a : actions) {
+ array.put(a.toJSON());
+ }
+ o.put("actions", array);
+ } catch (JSONException e) {
+ log.error("Unhandled exception", e);
+ }
+ return o.toString();
+ }
+
+ public AutomationEvent fromJSON(String data) {
+ try {
+ JSONObject d = new JSONObject(data);
+ title = d.optString("title", "");
+ enabled = d.optBoolean("enabled", true);
+ trigger = Trigger.instantiate(d.getString("trigger"));
+ JSONArray array = d.getJSONArray("actions");
+ actions.clear();
+ for (int i = 0; i < array.length(); i++) {
+ actions.add(Action.instantiate(new JSONObject(array.getString(i))));
+ }
+ } catch (JSONException e) {
+ log.error("Unhandled exception", e);
+ }
+ return this;
+ }
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationFragment.kt
new file mode 100644
index 00000000000..1db87f64728
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationFragment.kt
@@ -0,0 +1,102 @@
+package info.nightscout.androidaps.plugins.general.automation
+
+import android.os.Bundle
+import android.text.method.ScrollingMovementMethod
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.fragment.app.Fragment
+import androidx.recyclerview.widget.ItemTouchHelper
+import androidx.recyclerview.widget.LinearLayoutManager
+import androidx.recyclerview.widget.RecyclerView
+import info.nightscout.androidaps.R
+import info.nightscout.androidaps.plugins.bus.RxBus
+import info.nightscout.androidaps.plugins.general.automation.dialogs.EditEventDialog
+import info.nightscout.androidaps.plugins.general.automation.dragHelpers.OnStartDragListener
+import info.nightscout.androidaps.plugins.general.automation.dragHelpers.SimpleItemTouchHelperCallback
+import info.nightscout.androidaps.plugins.general.automation.events.EventAutomationDataChanged
+import info.nightscout.androidaps.plugins.general.automation.events.EventAutomationUpdateGui
+import info.nightscout.androidaps.utils.FabricPrivacy
+import info.nightscout.androidaps.utils.HtmlHelper
+import info.nightscout.androidaps.utils.plusAssign
+import io.reactivex.android.schedulers.AndroidSchedulers
+import io.reactivex.disposables.CompositeDisposable
+import kotlinx.android.synthetic.main.automation_fragment.*
+
+class AutomationFragment : Fragment(), OnStartDragListener {
+
+ private var disposable: CompositeDisposable = CompositeDisposable()
+ private var eventListAdapter: EventListAdapter? = null
+
+ private var itemTouchHelper: ItemTouchHelper? = null
+
+ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
+ return inflater.inflate(R.layout.automation_fragment, container, false)
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+
+ eventListAdapter = EventListAdapter(AutomationPlugin.automationEvents, fragmentManager, activity, this)
+ automation_eventListView.layoutManager = LinearLayoutManager(context)
+ automation_eventListView.adapter = eventListAdapter
+
+ automation_logView.setMovementMethod(ScrollingMovementMethod())
+
+ automation_fabAddEvent.setOnClickListener {
+ val dialog = EditEventDialog()
+ val args = Bundle()
+ args.putString("event", AutomationEvent().toJSON())
+ args.putInt("position", -1) // New event
+ dialog.arguments = args
+ fragmentManager?.let { dialog.show(it, "EditEventDialog") }
+ }
+
+ val callback: ItemTouchHelper.Callback = SimpleItemTouchHelperCallback(eventListAdapter!!)
+ itemTouchHelper = ItemTouchHelper(callback)
+ itemTouchHelper?.attachToRecyclerView(automation_eventListView)
+
+ }
+
+ @Synchronized
+ override fun onResume() {
+ super.onResume()
+ disposable += RxBus
+ .toObservable(EventAutomationUpdateGui::class.java)
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe({
+ updateGui()
+ }, {
+ FabricPrivacy.logException(it)
+ })
+ disposable += RxBus
+ .toObservable(EventAutomationDataChanged::class.java)
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe({
+ eventListAdapter?.notifyDataSetChanged()
+ }, {
+ FabricPrivacy.logException(it)
+ })
+ updateGui()
+ }
+
+ @Synchronized
+ override fun onPause() {
+ super.onPause()
+ disposable.clear()
+ }
+
+ @Synchronized
+ private fun updateGui() {
+ eventListAdapter?.notifyDataSetChanged()
+ val sb = StringBuilder()
+ for (l in AutomationPlugin.executionLog.reversed())
+ sb.append(l).append(" ")
+ automation_logView?.text = HtmlHelper.fromHtml(sb.toString())
+ }
+
+ override fun onStartDrag(viewHolder: RecyclerView.ViewHolder) {
+ itemTouchHelper?.startDrag(viewHolder);
+ }
+
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationPlugin.kt
new file mode 100644
index 00000000000..0d220c2dd42
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationPlugin.kt
@@ -0,0 +1,235 @@
+package info.nightscout.androidaps.plugins.general.automation
+
+import android.content.Intent
+import android.os.Build
+import android.os.Handler
+import info.nightscout.androidaps.MainApp
+import info.nightscout.androidaps.R
+import info.nightscout.androidaps.events.EventChargingState
+import info.nightscout.androidaps.events.EventLocationChange
+import info.nightscout.androidaps.events.EventNetworkChange
+import info.nightscout.androidaps.events.EventPreferenceChange
+import info.nightscout.androidaps.interfaces.PluginBase
+import info.nightscout.androidaps.interfaces.PluginDescription
+import info.nightscout.androidaps.interfaces.PluginType
+import info.nightscout.androidaps.logging.L
+import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin
+import info.nightscout.androidaps.plugins.bus.RxBus
+import info.nightscout.androidaps.plugins.general.automation.actions.*
+import info.nightscout.androidaps.plugins.general.automation.events.EventAutomationDataChanged
+import info.nightscout.androidaps.plugins.general.automation.events.EventAutomationUpdateGui
+import info.nightscout.androidaps.plugins.general.automation.triggers.*
+import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventAutosensCalculationFinished
+import info.nightscout.androidaps.queue.Callback
+import info.nightscout.androidaps.services.LocationService
+import info.nightscout.androidaps.utils.*
+import io.reactivex.disposables.CompositeDisposable
+import io.reactivex.schedulers.Schedulers
+import org.json.JSONArray
+import org.json.JSONException
+import org.json.JSONObject
+import org.slf4j.LoggerFactory
+import java.util.*
+
+object AutomationPlugin : PluginBase(PluginDescription()
+ .mainType(PluginType.GENERAL)
+ .fragmentClass(AutomationFragment::class.qualifiedName)
+ .pluginName(R.string.automation)
+ .shortName(R.string.automation_short)
+ .preferencesId(R.xml.pref_automation)
+ .description(R.string.automation_description)) {
+
+ private val log = LoggerFactory.getLogger(L.AUTOMATION)
+ private var disposable: CompositeDisposable = CompositeDisposable()
+
+ private const val key_AUTOMATION_EVENTS = "AUTOMATION_EVENTS"
+
+ val automationEvents = ArrayList()
+ var executionLog: MutableList = ArrayList()
+
+ private val loopHandler = Handler()
+ private lateinit var refreshLoop: Runnable
+
+ init {
+ refreshLoop = Runnable {
+ processActions()
+ loopHandler.postDelayed(refreshLoop, T.mins(1).msecs())
+ }
+ }
+
+ override fun onStart() {
+ val context = MainApp.instance().applicationContext
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
+ context.startForegroundService(Intent(context, LocationService::class.java))
+ else
+ context.startService(Intent(context, LocationService::class.java))
+
+ super.onStart()
+ loadFromSP()
+ loopHandler.postDelayed(refreshLoop, T.mins(1).msecs())
+
+ disposable += RxBus
+ .toObservable(EventPreferenceChange::class.java)
+ .observeOn(Schedulers.io())
+ .subscribe({ e ->
+ if (e.isChanged(R.string.key_location)) {
+ context.stopService(Intent(context, LocationService::class.java))
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
+ context.startForegroundService(Intent(context, LocationService::class.java))
+ else
+ context.startService(Intent(context, LocationService::class.java))
+ }
+ }, {
+ FabricPrivacy.logException(it)
+ })
+ disposable += RxBus
+ .toObservable(EventAutomationDataChanged::class.java)
+ .observeOn(Schedulers.io())
+ .subscribe({ storeToSP() }, {
+ FabricPrivacy.logException(it)
+ })
+ disposable += RxBus
+ .toObservable(EventLocationChange::class.java)
+ .observeOn(Schedulers.io())
+ .subscribe({ e ->
+ e?.let {
+ log.debug("Grabbed location: $it.location.latitude $it.location.longitude Provider: $it.location.provider")
+ processActions()
+ }
+ }, {
+ FabricPrivacy.logException(it)
+ })
+ disposable += RxBus
+ .toObservable(EventChargingState::class.java)
+ .observeOn(Schedulers.io())
+ .subscribe({ processActions() }, {
+ FabricPrivacy.logException(it)
+ })
+ disposable += RxBus
+ .toObservable(EventNetworkChange::class.java)
+ .observeOn(Schedulers.io())
+ .subscribe({ processActions() }, {
+ FabricPrivacy.logException(it)
+ })
+ disposable += RxBus
+ .toObservable(EventAutosensCalculationFinished::class.java)
+ .observeOn(Schedulers.io())
+ .subscribe({ processActions() }, {
+ FabricPrivacy.logException(it)
+ })
+ }
+
+ override fun onStop() {
+ disposable.clear()
+ loopHandler.removeCallbacks(refreshLoop)
+ val context = MainApp.instance().applicationContext
+ context.stopService(Intent(context, LocationService::class.java))
+ super.onStop()
+ }
+
+ private fun storeToSP() {
+ val array = JSONArray()
+ try {
+ for (event in automationEvents) {
+ array.put(JSONObject(event.toJSON()))
+ }
+ } catch (e: JSONException) {
+ e.printStackTrace()
+ }
+
+ SP.putString(key_AUTOMATION_EVENTS, array.toString())
+ }
+
+ private fun loadFromSP() {
+ automationEvents.clear()
+ val data = SP.getString(key_AUTOMATION_EVENTS, "")
+ if (data != "") {
+ try {
+ val array = JSONArray(data)
+ for (i in 0 until array.length()) {
+ val o = array.getJSONObject(i)
+ val event = AutomationEvent().fromJSON(o.toString())
+ automationEvents.add(event)
+ }
+ } catch (e: JSONException) {
+ e.printStackTrace()
+ }
+ }
+ }
+
+ @Synchronized
+ private fun processActions() {
+ if (!isEnabled(PluginType.GENERAL))
+ return
+ if (LoopPlugin.getPlugin().isSuspended || !LoopPlugin.getPlugin().isEnabled(PluginType.LOOP)) {
+ if (L.isEnabled(L.AUTOMATION))
+ log.debug("Loop deactivated")
+ return
+ }
+
+ if (L.isEnabled(L.AUTOMATION))
+ log.debug("processActions")
+ for (event in automationEvents) {
+ if (event.isEnabled && event.trigger.shouldRun() && event.preconditions.shouldRun()) {
+ val actions = event.actions
+ for (action in actions) {
+ action.doAction(object : Callback() {
+ override fun run() {
+ val sb = StringBuilder()
+ sb.append(DateUtil.timeString(DateUtil.now()))
+ sb.append(" ")
+ sb.append(if (result.success) "☺" else "▼")
+ sb.append(" ")
+ sb.append(event.title)
+ sb.append(": ")
+ sb.append(action.shortDescription())
+ sb.append(": ")
+ sb.append(result.comment)
+ executionLog.add(sb.toString())
+ if (L.isEnabled(L.AUTOMATION))
+ log.debug("Executed: $sb")
+ RxBus.send(EventAutomationUpdateGui())
+ }
+ })
+ }
+ event.trigger.executed(DateUtil.now())
+ }
+ }
+ storeToSP() // save last run time
+ }
+
+ fun getActionDummyObjects(): List {
+ return listOf(
+ //ActionLoopDisable(),
+ //ActionLoopEnable(),
+ //ActionLoopResume(),
+ //ActionLoopSuspend(),
+ ActionStartTempTarget(),
+ ActionStopTempTarget(),
+ ActionNotification(),
+ ActionProfileSwitchPercent(),
+ ActionProfileSwitch(),
+ ActionSendSMS()
+ )
+ }
+
+ fun getTriggerDummyObjects(): List {
+ return listOf(
+ TriggerTime(),
+ TriggerRecurringTime(),
+ TriggerTimeRange(),
+ TriggerBg(),
+ TriggerDelta(),
+ TriggerIob(),
+ TriggerCOB(),
+ TriggerProfilePercent(),
+ TriggerTempTarget(),
+ TriggerWifiSsid(),
+ TriggerLocation(),
+ TriggerAutosensValue(),
+ TriggerBolusAgo(),
+ TriggerPumpLastConnection()
+ )
+ }
+
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/EventListAdapter.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/EventListAdapter.java
new file mode 100644
index 00000000000..87c78d02eb1
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/EventListAdapter.java
@@ -0,0 +1,186 @@
+package info.nightscout.androidaps.plugins.general.automation;
+
+import android.annotation.SuppressLint;
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Color;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.CheckBox;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+
+import androidx.annotation.DrawableRes;
+import androidx.annotation.NonNull;
+import androidx.fragment.app.FragmentManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+
+import info.nightscout.androidaps.MainApp;
+import info.nightscout.androidaps.R;
+import info.nightscout.androidaps.plugins.bus.RxBus;
+import info.nightscout.androidaps.plugins.general.automation.actions.Action;
+import info.nightscout.androidaps.plugins.general.automation.dialogs.EditEventDialog;
+import info.nightscout.androidaps.plugins.general.automation.dragHelpers.ItemTouchHelperAdapter;
+import info.nightscout.androidaps.plugins.general.automation.dragHelpers.ItemTouchHelperViewHolder;
+import info.nightscout.androidaps.plugins.general.automation.dragHelpers.OnStartDragListener;
+import info.nightscout.androidaps.plugins.general.automation.events.EventAutomationDataChanged;
+import info.nightscout.androidaps.plugins.general.automation.events.EventAutomationUpdateGui;
+import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerConnector;
+import info.nightscout.androidaps.utils.OKDialog;
+
+class EventListAdapter extends RecyclerView.Adapter implements ItemTouchHelperAdapter {
+ private final List eventList;
+ private final FragmentManager fragmentManager;
+ private final Activity activity;
+
+ private final OnStartDragListener mDragStartListener;
+
+ EventListAdapter(List events, FragmentManager fragmentManager, Activity activity, OnStartDragListener dragStartListener) {
+ this.eventList = events;
+ this.fragmentManager = fragmentManager;
+ this.activity = activity;
+ mDragStartListener = dragStartListener;
+ }
+
+ @NonNull
+ @Override
+ public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+ View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.automation_event_item, parent, false);
+ return new ViewHolder(v, parent.getContext());
+ }
+
+ private void addImage(@DrawableRes int res, Context context, LinearLayout layout) {
+ ImageView iv = new ImageView(context);
+ iv.setImageResource(res);
+ iv.setLayoutParams(new LinearLayout.LayoutParams(MainApp.dpToPx(24), MainApp.dpToPx(24)));
+ layout.addView(iv);
+ }
+
+ @SuppressLint("ClickableViewAccessibility")
+ @Override
+ public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
+ final AutomationEvent event = eventList.get(position);
+ holder.eventTitle.setText(event.getTitle());
+ holder.enabled.setChecked(event.isEnabled());
+ holder.iconLayout.removeAllViews();
+
+ // trigger icons
+ HashSet triggerIcons = new HashSet<>();
+ TriggerConnector.fillIconSet((TriggerConnector) event.getTrigger(), triggerIcons);
+ for (int res : triggerIcons) {
+ addImage(res, holder.context, holder.iconLayout);
+ }
+
+ // arrow icon
+ ImageView iv = new ImageView(holder.context);
+ iv.setImageResource(R.drawable.ic_arrow_forward_white_24dp);
+ iv.setLayoutParams(new LinearLayout.LayoutParams(MainApp.dpToPx(24), MainApp.dpToPx(24)));
+ iv.setPadding(MainApp.dpToPx(4), 0, MainApp.dpToPx(4), 0);
+ holder.iconLayout.addView(iv);
+
+ // action icons
+ HashSet actionIcons = new HashSet<>();
+ for (Action action : event.getActions()) {
+ if (action.icon().isPresent())
+ actionIcons.add(action.icon().get());
+ }
+ for (int res : actionIcons) {
+ addImage(res, holder.context, holder.iconLayout);
+ }
+
+ // enabled event
+ holder.enabled.setOnClickListener(v -> {
+ event.setEnabled((holder.enabled.isChecked()));
+ RxBus.INSTANCE.send(new EventAutomationDataChanged());
+ });
+
+ // edit event
+ holder.rootLayout.setOnClickListener(v ->
+
+ {
+ //EditEventDialog dialog = EditEventDialog.Companion.newInstance(event, false);
+ EditEventDialog dialog = new EditEventDialog();
+ Bundle args = new Bundle();
+ args.putString("event", event.toJSON());
+ args.putInt("position", position);
+ dialog.setArguments(args);
+ if (fragmentManager != null)
+ dialog.show(fragmentManager, "EditEventDialog");
+ });
+
+ // Start a drag whenever the handle view it touched
+ holder.iconSort.setOnTouchListener((v, motionEvent) ->
+
+ {
+ if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
+ mDragStartListener.onStartDrag(holder);
+ return true;
+ }
+ return v.onTouchEvent(motionEvent);
+ });
+ }
+
+ @Override
+ public int getItemCount() {
+ return eventList.size();
+ }
+
+ @Override
+ public boolean onItemMove(int fromPosition, int toPosition) {
+ Collections.swap(eventList, fromPosition, toPosition);
+ notifyItemMoved(fromPosition, toPosition);
+ RxBus.INSTANCE.send(new EventAutomationDataChanged());
+ return true;
+ }
+
+ @Override
+ public void onItemDismiss(int position) {
+ OKDialog.showConfirmation(activity, MainApp.gs(R.string.removerecord) + " " + eventList.get(position).getTitle(),
+ () -> {
+ eventList.remove(position);
+ notifyItemRemoved(position);
+ RxBus.INSTANCE.send(new EventAutomationDataChanged());
+ RxBus.INSTANCE.send(new EventAutomationUpdateGui());
+ }, () -> {
+ RxBus.INSTANCE.send(new EventAutomationUpdateGui());
+ });
+ }
+
+ static class ViewHolder extends RecyclerView.ViewHolder implements ItemTouchHelperViewHolder {
+ final RelativeLayout rootLayout;
+ final LinearLayout iconLayout;
+ final TextView eventTitle;
+ final Context context;
+ final ImageView iconSort;
+ final CheckBox enabled;
+
+ ViewHolder(View view, Context context) {
+ super(view);
+ this.context = context;
+ eventTitle = view.findViewById(R.id.viewEventTitle);
+ rootLayout = view.findViewById(R.id.rootLayout);
+ iconLayout = view.findViewById(R.id.iconLayout);
+ iconSort = view.findViewById(R.id.iconSort);
+ enabled = view.findViewById(R.id.automation_enabled);
+ }
+
+ @Override
+ public void onItemSelected() {
+ itemView.setBackgroundColor(Color.LTGRAY);
+ }
+
+ @Override
+ public void onItemClear() {
+ itemView.setBackgroundColor(MainApp.gc(R.color.ribbonDefault));
+ }
+ }
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/Action.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/Action.java
new file mode 100644
index 00000000000..ee4564fd6fb
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/Action.java
@@ -0,0 +1,107 @@
+package info.nightscout.androidaps.plugins.general.automation.actions;
+
+import android.widget.LinearLayout;
+
+import com.google.common.base.Optional;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import javax.annotation.Nullable;
+
+import info.nightscout.androidaps.plugins.general.automation.triggers.Trigger;
+import info.nightscout.androidaps.queue.Callback;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/*
+ Action ideas:
+
+ * cancel temp target
+ * change preference setting
+ * enable/disable plugin
+ * create notification
+ * create ugly alarm
+ * create profile switch
+ * set/cancel tbr
+ * set/cancel extended bolus
+ * run bolus wizard
+
+ Trigger ideas:
+
+ * location (close to)
+ * connected to specific wifi
+ * internet available/not available
+ * nsclient connected/disconnected
+ * iob
+ * cob
+ * autosens value
+ * delta, short delta, long delta
+ * last bolus ago
+ * is tbr running
+ * bolus wizard result
+ * loop is enabled, disabled, suspended, running
+
+*/
+
+
+public abstract class Action {
+ private static final Logger log = LoggerFactory.getLogger(Action.class);
+
+ public Trigger precondition = null;
+
+ public abstract int friendlyName();
+
+ public abstract String shortDescription();
+
+ public abstract void doAction(Callback callback);
+
+ public void generateDialog(LinearLayout root) {
+ }
+
+ public boolean hasDialog() {
+ return false;
+ }
+
+ public String toJSON() {
+ JSONObject o = new JSONObject();
+ try {
+ o.put("type", this.getClass().getName());
+ } catch (JSONException e) {
+ log.error("Unhandled exception", e);
+ }
+ return o.toString();
+ }
+
+ public abstract Optional icon();
+
+ public Action fromJSON(String data) {
+ return this;
+ }
+
+ @Nullable
+ public static Action instantiate(JSONObject object) {
+ try {
+ String type = object.getString("type");
+ JSONObject data = object.optJSONObject("data");
+ Class clazz = Class.forName(type);
+ return ((Action) clazz.newInstance()).fromJSON(data != null ? data.toString() : "");
+ } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | JSONException e) {
+ log.error("Unhandled exception", e);
+ }
+ return null;
+ }
+
+ public void apply(Action a) {
+ try {
+ JSONObject object = new JSONObject(a.toJSON());
+ String type = object.getString("type");
+ JSONObject data = object.getJSONObject("data");
+ if (type.equals(getClass().getName())) {
+ fromJSON(data.toString());
+ }
+ } catch (JSONException e) {
+ log.error("Unhandled exception", e);
+ }
+ }
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionLoopDisable.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionLoopDisable.java
new file mode 100644
index 00000000000..cf8326a0f23
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionLoopDisable.java
@@ -0,0 +1,49 @@
+package info.nightscout.androidaps.plugins.general.automation.actions;
+
+import com.google.common.base.Optional;
+
+import info.nightscout.androidaps.MainApp;
+import info.nightscout.androidaps.R;
+import info.nightscout.androidaps.data.PumpEnactResult;
+import info.nightscout.androidaps.events.EventRefreshOverview;
+import info.nightscout.androidaps.interfaces.PluginType;
+import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin;
+import info.nightscout.androidaps.plugins.bus.RxBus;
+import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin;
+import info.nightscout.androidaps.queue.Callback;
+
+public class ActionLoopDisable extends Action {
+ @Override
+ public int friendlyName() {
+ return R.string.disableloop;
+ }
+
+ @Override
+ public String shortDescription() {
+ return MainApp.gs(R.string.disableloop);
+ }
+
+ @Override
+ public void doAction(Callback callback) {
+ if (LoopPlugin.getPlugin().isEnabled(PluginType.LOOP)) {
+ LoopPlugin.getPlugin().setPluginEnabled(PluginType.LOOP, false);
+ ConfigBuilderPlugin.getPlugin().storeSettings("ActionLoopDisable");
+ ConfigBuilderPlugin.getPlugin().getCommandQueue().cancelTempBasal(true, new Callback() {
+ @Override
+ public void run() {
+ RxBus.INSTANCE.send(new EventRefreshOverview("ActionLoopDisable"));
+ if (callback != null)
+ callback.result(result).run();
+ }
+ });
+ } else {
+ if (callback != null)
+ callback.result(new PumpEnactResult().success(true).comment(R.string.alreadydisabled)).run();
+ }
+ }
+
+ @Override
+ public Optional icon() {
+ return Optional.of(R.drawable.ic_stop_24dp);
+ }
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionLoopEnable.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionLoopEnable.java
new file mode 100644
index 00000000000..f33bec8e3f3
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionLoopEnable.java
@@ -0,0 +1,44 @@
+package info.nightscout.androidaps.plugins.general.automation.actions;
+
+import com.google.common.base.Optional;
+
+import info.nightscout.androidaps.MainApp;
+import info.nightscout.androidaps.R;
+import info.nightscout.androidaps.data.PumpEnactResult;
+import info.nightscout.androidaps.events.EventRefreshOverview;
+import info.nightscout.androidaps.interfaces.PluginType;
+import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin;
+import info.nightscout.androidaps.plugins.bus.RxBus;
+import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin;
+import info.nightscout.androidaps.queue.Callback;
+
+public class ActionLoopEnable extends Action {
+ @Override
+ public int friendlyName() {
+ return R.string.enableloop;
+ }
+
+ @Override
+ public String shortDescription() {
+ return MainApp.gs(R.string.enableloop);
+ }
+
+ @Override
+ public void doAction(Callback callback) {
+ if (!LoopPlugin.getPlugin().isEnabled(PluginType.LOOP)) {
+ LoopPlugin.getPlugin().setPluginEnabled(PluginType.LOOP, true);
+ ConfigBuilderPlugin.getPlugin().storeSettings("ActionLoopEnable");
+ RxBus.INSTANCE.send(new EventRefreshOverview("ActionLoopEnable"));
+ if (callback != null)
+ callback.result(new PumpEnactResult().success(true).comment(R.string.ok)).run();
+ } else {
+ if (callback != null)
+ callback.result(new PumpEnactResult().success(true).comment(R.string.alreadyenabled)).run();
+ }
+ }
+
+ @Override
+ public Optional icon() {
+ return Optional.of(R.drawable.ic_play_circle_outline_24dp);
+ }
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionLoopResume.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionLoopResume.java
new file mode 100644
index 00000000000..16b478bbc22
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionLoopResume.java
@@ -0,0 +1,45 @@
+package info.nightscout.androidaps.plugins.general.automation.actions;
+
+import com.google.common.base.Optional;
+
+import info.nightscout.androidaps.MainApp;
+import info.nightscout.androidaps.R;
+import info.nightscout.androidaps.data.PumpEnactResult;
+import info.nightscout.androidaps.events.EventRefreshOverview;
+import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin;
+import info.nightscout.androidaps.plugins.bus.RxBus;
+import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin;
+import info.nightscout.androidaps.plugins.general.nsclient.NSUpload;
+import info.nightscout.androidaps.queue.Callback;
+
+public class ActionLoopResume extends Action {
+ @Override
+ public int friendlyName() {
+ return R.string.resumeloop;
+ }
+
+ @Override
+ public String shortDescription() {
+ return MainApp.gs(R.string.resumeloop);
+ }
+
+ @Override
+ public void doAction(Callback callback) {
+ if (LoopPlugin.getPlugin().isSuspended()) {
+ LoopPlugin.getPlugin().suspendTo(0);
+ ConfigBuilderPlugin.getPlugin().storeSettings("ActionLoopResume");
+ LoopPlugin.getPlugin().createOfflineEvent(0);
+ RxBus.INSTANCE.send(new EventRefreshOverview("ActionLoopResume"));
+ if (callback != null)
+ callback.result(new PumpEnactResult().success(true).comment(R.string.ok)).run();
+ } else {
+ if (callback != null)
+ callback.result(new PumpEnactResult().success(true).comment(R.string.notsuspended)).run();
+ }
+ }
+
+ @Override
+ public Optional icon() {
+ return Optional.of(R.drawable.ic_replay_24dp);
+ }
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionLoopSuspend.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionLoopSuspend.java
new file mode 100644
index 00000000000..39adbcac276
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionLoopSuspend.java
@@ -0,0 +1,95 @@
+package info.nightscout.androidaps.plugins.general.automation.actions;
+
+import android.widget.LinearLayout;
+
+import com.google.common.base.Optional;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import info.nightscout.androidaps.MainApp;
+import info.nightscout.androidaps.R;
+import info.nightscout.androidaps.data.PumpEnactResult;
+import info.nightscout.androidaps.events.EventRefreshOverview;
+import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin;
+import info.nightscout.androidaps.plugins.bus.RxBus;
+import info.nightscout.androidaps.plugins.general.automation.elements.InputDuration;
+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.JsonHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ActionLoopSuspend extends Action {
+ private static final Logger log = LoggerFactory.getLogger(ActionLoopSuspend.class);
+
+ public InputDuration minutes = new InputDuration(0, InputDuration.TimeUnit.MINUTES);
+
+ @Override
+ public int friendlyName() {
+ return R.string.suspendloop;
+ }
+
+ @Override
+ public String shortDescription() {
+ return MainApp.gs(R.string.suspendloopforXmin, minutes.getMinutes());
+ }
+
+ @Override
+ public void doAction(Callback callback) {
+ if (!LoopPlugin.getPlugin().isSuspended()) {
+ LoopPlugin.getPlugin().suspendLoop(minutes.getMinutes());
+ RxBus.INSTANCE.send(new EventRefreshOverview("ActionLoopSuspend"));
+ if (callback != null)
+ callback.result(new PumpEnactResult().success(true).comment(R.string.ok)).run();
+ } else {
+ if (callback != null)
+ callback.result(new PumpEnactResult().success(true).comment(R.string.alreadysuspended)).run();
+ }
+ }
+
+ @Override
+ public Optional