Merge pull request #2 from MilosKozak/dev

Dev
This commit is contained in:
Heiner1 2018-05-05 09:33:49 +02:00 committed by GitHub
commit dc72506cdc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
618 changed files with 38884 additions and 15777 deletions

4
.gitignore vendored
View file

@ -7,3 +7,7 @@
*.apk *.apk
build/ build/
.idea/ .idea/
app/src/main/jniLibs
full/
debug/
release/

View file

@ -2,17 +2,33 @@ language: android
jdk: oraclejdk8 jdk: oraclejdk8
env: env:
matrix: matrix:
- ANDROID_TARGET=android-23 ANDROID_ABI=x86 - ANDROID_TARGET=android-23 ANDROID_ABI=x86 org.gradle.jvmargs=-XX:-OmitStackTraceInFastThrow
android: android:
components: components:
- platform-tools - platform-tools
- tools - tools
- build-tools-26.0.2 - build-tools-27.0.2
- android-23 - android-23
- extra-google-m2repository - extra-google-m2repository
- extra-android-m2repository - extra-android-m2repository
- extra-google-google_play_services - extra-google-google_play_services
before_install:
- yes | sdkmanager "platforms;android-27"
script: script:
# Unit Test # Unit Test
- ./gradlew test - ./gradlew -Pcoverage testFullDebugUnitTest jacocoTestFullDebugUnitTestReport
after_success:
- bash <(curl -s https://codecov.io/bash)
before_cache:
- rm -f $HOME/.gradle/caches/modules-2/modules-2.lock
- rm -fr $HOME/.gradle/caches/*/plugin-resolution/
cache:
directories:
- $HOME/.gradle/caches/
- $HOME/.gradle/wrapper/
- $HOME/.android/build-cache

10
ISSUE_TEMPLATE.md Normal file
View file

@ -0,0 +1,10 @@
Reporting bugs
--------------
- Note the precise time the problem occurred and describe the circumstances and steps that caused
the problem
- Note the Build version (found in the About dialog in the app, when pressing the three dots in the
upper-right corner).
- Obtain the app's log files, which can be found on the phone in
_/storage/emulated/0/Android/data/info.nightscout.androidaps/_
See https://github.com/MilosKozak/AndroidAPS/wiki/Accessing-logfiles
- Open an issue at https://github.com/MilosKozak/AndroidAPS/issues/new

View file

@ -5,3 +5,5 @@
[![Gitter](https://badges.gitter.im/MilosKozak/AndroidAPS.svg)](https://gitter.im/MilosKozak/AndroidAPS?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Gitter](https://badges.gitter.im/MilosKozak/AndroidAPS.svg)](https://gitter.im/MilosKozak/AndroidAPS?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![Build status](https://travis-ci.org/MilosKozak/AndroidAPS.svg?branch=master)](https://travis-ci.org/MilosKozak/AndroidAPS) [![Build status](https://travis-ci.org/MilosKozak/AndroidAPS.svg?branch=master)](https://travis-ci.org/MilosKozak/AndroidAPS)
[![codecov](https://codecov.io/gh/MilosKozak/AndroidAPS/branch/master/graph/badge.svg)](https://codecov.io/gh/MilosKozak/AndroidAPS)
dev: [![codecov](https://codecov.io/gh/MilosKozak/AndroidAPS/branch/dev/graph/badge.svg)](https://codecov.io/gh/MilosKozak/AndroidAPS)

View file

@ -0,0 +1,7 @@
Follow this link to get the source PSD file for the Steampunk graphics. The file could not be included in the repository as it exceeds Github's 25 mb limit.
Note, the source image size is 1600x1600. The image size should be reduced to 400x400 prior to export of final PNG.
https://drive.google.com/drive/folders/1MrdgnQz3wOniDvRSMhAsqHBYb2WmE5i0
Graphics created by (Github): andrew-warrington

1
app/.gitignore vendored
View file

@ -1 +0,0 @@
/build

View file

@ -1,17 +1,31 @@
buildscript { buildscript {
repositories { repositories {
maven { url 'https://maven.fabric.io/public' } maven { url 'https://maven.fabric.io/public' }
jcenter()
} }
dependencies { dependencies {
classpath 'io.fabric.tools:gradle:1.+' classpath 'io.fabric.tools:gradle:1.+'
classpath 'com.dicedmelon.gradle:jacoco-android:0.1.2'
} }
} }
apply plugin: 'com.android.application' apply plugin: "com.android.application"
apply plugin: 'io.fabric' apply plugin: "io.fabric"
apply plugin: "jacoco-android"
apply plugin: 'com.jakewharton.butterknife'
ext {
supportLibraryVersion = "27.1.0"
ormLiteVersion = "4.46"
powermockVersion = "1.7.3"
dexmakerVersion = "1.2"
butterknifeVersion = "8.8.1"
}
repositories { repositories {
maven { url 'https://maven.fabric.io/public' } maven { url 'https://maven.fabric.io/public' }
jcenter { url "https://jcenter.bintray.com/" }
} }
def generateGitBuild = { -> def generateGitBuild = { ->
@ -35,32 +49,48 @@ def generateGitBuild = { ->
return stringBuilder.toString() return stringBuilder.toString()
} }
tasks.matching {it instanceof Test}.all {
testLogging.events = ["failed", "skipped", "started"]
testLogging.exceptionFormat = "full"
}
android { android {
compileSdkVersion 23 compileSdkVersion 27
buildToolsVersion "26.0.2"
defaultConfig { defaultConfig {
applicationId "info.nightscout.androidaps" applicationId "info.nightscout.androidaps"
minSdkVersion 21 minSdkVersion 21
targetSdkVersion 23 targetSdkVersion 25
multiDexEnabled true multiDexEnabled true
versionCode 1500 versionCode 1500
version "1.56-dev" version "1.60e-dev"
buildConfigField "String", "VERSION", '"' + version + '"' buildConfigField "String", "VERSION", '"' + version + '"'
buildConfigField "String", "BUILDVERSION", generateGitBuild() buildConfigField "String", "BUILDVERSION", generateGitBuild()
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
ndk { ndk {
moduleName "BleCommandUtil" moduleName "BleCommandUtil"
} }
} }
lintOptions { lintOptions {
// TODO remove once wear dependency com.google.android.gms:play-services-wearable:7.3.0
// has been upgraded (requiring significant code changes), which currently fails release
// build with a deprecation warning
abortOnError false
// (disabled entirely to avoid reports on the error, which would still be displayed
// and it's easy to overlook that it's ignored)
checkReleaseBuilds false
disable 'MissingTranslation' disable 'MissingTranslation'
disable 'ExtraTranslation'
} }
buildTypes { buildTypes {
release { release {
minifyEnabled false minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
} }
debug {
testCoverageEnabled (project.hasProperty('coverage') ? true : false)
}
} }
productFlavors { productFlavors {
flavorDimensions "standard" flavorDimensions "standard"
@ -74,21 +104,8 @@ android {
buildConfigField "boolean", "APS", "true" buildConfigField "boolean", "APS", "true"
buildConfigField "boolean", "PUMPDRIVERS", "true" buildConfigField "boolean", "PUMPDRIVERS", "true"
buildConfigField "boolean", "NSCLIENTOLNY", "false" buildConfigField "boolean", "NSCLIENTOLNY", "false"
buildConfigField "boolean", "CLOSEDLOOP", "true"
buildConfigField "boolean", "G5UPLOADER", "false"
}
openloop {
dimension "standard"
resValue "string", "app_name", "AndroidAPS"
versionName version
manifestPlaceholders = [
appIcon: "@mipmap/blueowl"
]
buildConfigField "boolean", "APS", "true"
buildConfigField "boolean", "PUMPDRIVERS", "true"
buildConfigField "boolean", "NSCLIENTOLNY", "false"
buildConfigField "boolean", "CLOSEDLOOP", "false"
buildConfigField "boolean", "G5UPLOADER", "false" buildConfigField "boolean", "G5UPLOADER", "false"
buildConfigField "boolean", "PUMPCONTROL", "false"
} }
pumpcontrol { pumpcontrol {
dimension "standard" dimension "standard"
@ -100,8 +117,8 @@ android {
buildConfigField "boolean", "APS", "false" buildConfigField "boolean", "APS", "false"
buildConfigField "boolean", "PUMPDRIVERS", "true" buildConfigField "boolean", "PUMPDRIVERS", "true"
buildConfigField "boolean", "NSCLIENTOLNY", "false" buildConfigField "boolean", "NSCLIENTOLNY", "false"
buildConfigField "boolean", "CLOSEDLOOP", "false"
buildConfigField "boolean", "G5UPLOADER", "false" buildConfigField "boolean", "G5UPLOADER", "false"
buildConfigField "boolean", "PUMPCONTROL", "true"
} }
nsclient { nsclient {
dimension "standard" dimension "standard"
@ -113,8 +130,8 @@ android {
buildConfigField "boolean", "APS", "false" buildConfigField "boolean", "APS", "false"
buildConfigField "boolean", "PUMPDRIVERS", "false" buildConfigField "boolean", "PUMPDRIVERS", "false"
buildConfigField "boolean", "NSCLIENTOLNY", "true" buildConfigField "boolean", "NSCLIENTOLNY", "true"
buildConfigField "boolean", "CLOSEDLOOP", "false"
buildConfigField "boolean", "G5UPLOADER", "false" buildConfigField "boolean", "G5UPLOADER", "false"
buildConfigField "boolean", "PUMPCONTROL", "false"
} }
g5uploader { g5uploader {
dimension "standard" dimension "standard"
@ -126,11 +143,20 @@ android {
buildConfigField "boolean", "APS", "false" buildConfigField "boolean", "APS", "false"
buildConfigField "boolean", "PUMPDRIVERS", "false" buildConfigField "boolean", "PUMPDRIVERS", "false"
buildConfigField "boolean", "NSCLIENTOLNY", "false" buildConfigField "boolean", "NSCLIENTOLNY", "false"
buildConfigField "boolean", "CLOSEDLOOP", "false"
buildConfigField "boolean", "G5UPLOADER", "true" buildConfigField "boolean", "G5UPLOADER", "true"
buildConfigField "boolean", "PUMPCONTROL", "false"
} }
} }
} compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
testOptions {
unitTests.returnDefaultValues = true
unitTests.includeAndroidResources = true
}
}
allprojects { allprojects {
repositories { repositories {
@ -141,51 +167,100 @@ allprojects {
} }
} }
configurations {
libs
}
dependencies { dependencies {
wearApp project(':wear') wearApp project(':wear')
compile fileTree(include: ['*.jar'], dir: 'libs') implementation fileTree(include: ['*.jar'], dir: 'libs')
compile('com.crashlytics.sdk.android:crashlytics:2.6.7@aar') { implementation("com.crashlytics.sdk.android:crashlytics:2.6.7@aar") {
transitive = true; transitive = true;
} }
compile('com.crashlytics.sdk.android:answers:1.3.12@aar') { implementation("com.crashlytics.sdk.android:answers:1.3.12@aar") {
transitive = true; transitive = true;
} }
libs "MilosKozak:danars-support-lib:master@zip"
compile 'com.android.support:appcompat-v7:23.4.0' implementation "com.android.support:appcompat-v7:${supportLibraryVersion}"
compile 'com.android.support:support-v4:23.4.0' implementation "com.android.support:support-v4:${supportLibraryVersion}"
compile 'com.android.support:cardview-v7:23.4.0' implementation "com.android.support:cardview-v7:${supportLibraryVersion}"
compile 'com.android.support:recyclerview-v7:23.4.0' implementation "com.android.support:recyclerview-v7:${supportLibraryVersion}"
compile 'com.android.support:gridlayout-v7:23.4.0' implementation "com.android.support:gridlayout-v7:${supportLibraryVersion}"
compile "com.android.support:design:23.4.0" implementation "com.android.support:design:${supportLibraryVersion}"
compile "com.android.support:percent:23.4.0" implementation "com.android.support:percent:${supportLibraryVersion}"
compile 'com.wdullaer:materialdatetimepicker:2.3.0' implementation "com.wdullaer:materialdatetimepicker:2.3.0"
compile 'com.squareup:otto:1.3.7' implementation 'com.android.support.constraint:constraint-layout:1.0.2'
compile 'com.j256.ormlite:ormlite-core:4.46' implementation "com.squareup:otto:1.3.7"
compile 'com.j256.ormlite:ormlite-android:4.46' implementation "com.j256.ormlite:ormlite-core:${ormLiteVersion}"
compile('com.github.tony19:logback-android-classic:1.1.1-6') { implementation "com.j256.ormlite:ormlite-android:${ormLiteVersion}"
exclude group: 'com.google.android', module: 'android' implementation("com.github.tony19:logback-android-classic:1.1.1-6") {
exclude group: "com.google.android", module: "android"
} }
compile 'org.apache.commons:commons-lang3:3.6' implementation "org.apache.commons:commons-lang3:3.6"
compile 'org.slf4j:slf4j-api:1.7.12' implementation "org.slf4j:slf4j-api:1.7.12"
compile 'com.jjoe64:graphview:4.0.1' implementation "com.jjoe64:graphview:4.0.1"
compile 'com.joanzapata.iconify:android-iconify-fontawesome:2.1.1' implementation "com.joanzapata.iconify:android-iconify-fontawesome:2.1.1"
compile 'com.google.android.gms:play-services-wearable:7.5.0' implementation "com.google.android.gms:play-services-wearable:7.5.0"
compile 'junit:junit:4.12' implementation(name: "android-edittext-validator-v1.3.4-mod", ext: "aar")
testCompile 'org.json:json:20140107' implementation(name: "sightparser-release", ext: "aar")
testCompile 'org.mockito:mockito-core:2.7.22'
androidTestCompile 'org.mockito:mockito-core:2.7.22' implementation("com.google.android:flexbox:0.3.0") {
androidTestCompile 'com.google.dexmaker:dexmaker:1.2' exclude group: "com.android.support"
androidTestCompile 'com.google.dexmaker:dexmaker-mockito:1.2'
compile(name: 'android-edittext-validator-v1.3.4-mod', ext: 'aar')
compile('com.google.android:flexbox:0.3.0') {
exclude group: 'com.android.support'
} }
compile('io.socket:socket.io-client:0.8.3') { implementation("io.socket:socket.io-client:1.0.0") {
// excluding org.json which is provided by Android // excluding org.json which is provided by Android
exclude group: 'org.json', module: 'json' exclude group: "org.json", module: "json"
} }
compile 'com.google.code.gson:gson:2.7' implementation "com.google.code.gson:gson:2.7"
compile 'com.google.guava:guava:20.0' implementation "com.google.guava:guava:20.0"
implementation "net.danlew:android.joda:2.9.9.1"
implementation "uk.com.robust-it:cloning:1.9.9"
implementation 'org.mozilla:rhino:1.7.7.2'
implementation "com.jakewharton:butterknife:${butterknifeVersion}"
annotationProcessor "com.jakewharton:butterknife-compiler:${butterknifeVersion}"
testImplementation "junit:junit:4.12"
testImplementation "org.json:json:20140107"
testImplementation "org.mockito:mockito-core:2.7.22"
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.4.2"
testImplementation "com.google.truth:truth:0.39"
testImplementation 'org.robolectric:robolectric:3.8'
testImplementation "org.skyscreamer:jsonassert:1.5.0"
androidTestImplementation "org.mockito:mockito-core:2.7.22"
androidTestImplementation "com.google.dexmaker:dexmaker:${dexmakerVersion}"
androidTestImplementation "com.google.dexmaker:dexmaker-mockito:${dexmakerVersion}"
} }
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)
into outputDir
}
task copyLibs(dependsOn: unzip, type: Copy) {
def src = file("${buildDir}/unpacked/dist/danars-support-lib-master")
def target = file("src/main/jniLibs/")
from src
into target
}
task full_clean(type: Delete) {
delete file("src/main/jniLibs")
}
clean.dependsOn full_clean
preBuild.dependsOn copyLibs

Binary file not shown.

Binary file not shown.

View file

@ -15,9 +15,11 @@
<uses-permission android:name="android.permission.SEND_MMS" /> <uses-permission android:name="android.permission.SEND_MMS" />
<uses-permission android:name="android.permission.VIBRATE" /> <uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="com.google.android.permission.PROVIDE_BACKGROUND" /> <uses-permission android:name="com.google.android.permission.PROVIDE_BACKGROUND" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="sugar.free.sightremote.HISTORY_BROADCASTS" />
<uses-permission-sdk-23 android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" /> <uses-permission-sdk-23 android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
@ -47,7 +49,7 @@
android:theme="@style/Theme.AppCompat.Translucent" /> android:theme="@style/Theme.AppCompat.Translucent" />
<activity android:name=".AgreementActivity" /> <activity android:name=".AgreementActivity" />
<activity android:name=".plugins.PumpDanaR.activities.DanaRHistoryActivity" /> <activity android:name=".plugins.PumpDanaR.activities.DanaRHistoryActivity" />
<activity android:name=".plugins.PumpDanaR.activities.DanaRStatsActivity" /> <activity android:name=".TDDStatsActivity" />
<activity android:name=".plugins.Overview.activities.QuickWizardListActivity"> <activity android:name=".plugins.Overview.activities.QuickWizardListActivity">
<intent-filter> <intent-filter>
<action android:name="info.nightscout.androidaps.plugins.Overview.activities.QuickWizardListActivity" /> <action android:name="info.nightscout.androidaps.plugins.Overview.activities.QuickWizardListActivity" />
@ -61,6 +63,7 @@
</intent-filter> </intent-filter>
</activity> </activity>
<activity android:name=".plugins.PumpDanaRS.activities.PairingHelperActivity" /> <activity android:name=".plugins.PumpDanaRS.activities.PairingHelperActivity" />
<activity android:name=".HistoryBrowseActivity" />
<receiver <receiver
android:name=".receivers.DataReceiver" android:name=".receivers.DataReceiver"
@ -110,6 +113,14 @@
</intent-filter> </intent-filter>
</receiver> </receiver>
<!-- Network change local receiver -->
<receiver android:name=".receivers.NetworkChangeReceiver">
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
<action android:name="android.net.wifi.WIFI_STATE_CHANGED" />
</intent-filter>
</receiver>
<!-- Service processing incomming data --> <!-- Service processing incomming data -->
<service <service
android:name=".Services.DataService" android:name=".Services.DataService"

View file

@ -0,0 +1,20 @@
// IRTHandler.aidl
package org.monkey.d.ruffy.ruffy.driver;
// Declare any non-default types here with import statements
import org.monkey.d.ruffy.ruffy.driver.display.Menu;
interface IRTHandler {
void log(String message);
void fail(String message);
void requestBluetooth();
void rtStopped();
void rtStarted();
void rtClearDisplay();
void rtUpdateDisplay(in byte[] quarter, int which);
void rtDisplayHandleMenu(in Menu menu);
void rtDisplayHandleNoMenu();
}

View file

@ -0,0 +1,23 @@
// IRuffyService.aidl
package org.monkey.d.ruffy.ruffy.driver;
// Declare any non-default types here with import statements
import org.monkey.d.ruffy.ruffy.driver.IRTHandler;
interface IRuffyService {
void setHandler(IRTHandler handler);
/** Connect to the pump
*
* @return 0 if successful, -1 otherwise
*/
int doRTConnect();
/** Disconnect from the pump */
void doRTDisconnect();
void rtSendKey(byte keyCode, boolean changed);
void resetPairing();
boolean isConnected();
}

View file

@ -0,0 +1,3 @@
package org.monkey.d.ruffy.ruffy.driver.display;
parcelable Menu;

View file

@ -0,0 +1 @@
//b916a900c0899ef58ad58c7427d1c30d3c8731f4

View file

@ -0,0 +1,61 @@
'use strict';
function reason(rT, msg) {
rT.reason = (rT.reason ? rT.reason + '. ' : '') + msg;
console.error(msg);
}
var tempBasalFunctions = {};
tempBasalFunctions.getMaxSafeBasal = function getMaxSafeBasal(profile) {
var max_daily_safety_multiplier = (isNaN(profile.max_daily_safety_multiplier) || profile.max_daily_safety_multiplier == null) ? 3 : profile.max_daily_safety_multiplier;
var current_basal_safety_multiplier = (isNaN(profile.current_basal_safety_multiplier) || profile.current_basal_safety_multiplier == null) ? 4 : profile.current_basal_safety_multiplier;
return Math.min(profile.max_basal, max_daily_safety_multiplier * profile.max_daily_basal, current_basal_safety_multiplier * profile.current_basal);
};
tempBasalFunctions.setTempBasal = function setTempBasal(rate, duration, profile, rT, currenttemp) {
//var maxSafeBasal = Math.min(profile.max_basal, 3 * profile.max_daily_basal, 4 * profile.current_basal);
var maxSafeBasal = tempBasalFunctions.getMaxSafeBasal(profile);
var round_basal = require('./round-basal');
if (rate < 0) {
rate = 0;
} // if >30m @ 0 required, zero temp will be extended to 30m instead
else if (rate > maxSafeBasal) {
rate = maxSafeBasal;
}
var suggestedRate = round_basal(rate, profile);
if (typeof(currenttemp) !== 'undefined' && typeof(currenttemp.duration) !== 'undefined' && typeof(currenttemp.rate) !== 'undefined' && currenttemp.duration > (duration-10) && currenttemp.duration <= 120 && suggestedRate <= currenttemp.rate * 1.2 && suggestedRate >= currenttemp.rate * 0.8) {
rT.reason += " "+currenttemp.duration+"m left and " + currenttemp.rate + " ~ req " + suggestedRate + "U/hr: no temp required";
return rT;
}
if (suggestedRate === profile.current_basal) {
if (profile.skip_neutral_temps) {
if (typeof(currenttemp) !== 'undefined' && typeof(currenttemp.duration) !== 'undefined' && currenttemp.duration > 0) {
reason(rT, 'Suggested rate is same as profile rate, a temp basal is active, canceling current temp');
rT.duration = 0;
rT.rate = 0;
return rT;
} else {
reason(rT, 'Suggested rate is same as profile rate, no temp basal is active, doing nothing');
return rT;
}
} else {
reason(rT, 'Setting neutral temp basal of ' + profile.current_basal + 'U/hr');
rT.duration = duration;
rT.rate = suggestedRate;
return rT;
}
} else {
rT.duration = duration;
rT.rate = suggestedRate;
return rT;
}
};
module.exports = tempBasalFunctions;

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,6 @@
<configuration> <configuration>
<!-- Create a file appender for a log in the application's data directory --> <!-- Create a file appender for a log in the application's data directory -->
<property name="EXT_FILES_DIR" value="${EXT_DIR:-/sdcard}/Android/data/${PACKAGE_NAME}/files"/> <property scope="context" name="EXT_FILES_DIR" value="${EXT_DIR:-/sdcard}/Android/data/${PACKAGE_NAME}/files"/>
<appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender"> <appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${EXT_FILES_DIR}/AndroidAPS.log</file> <file>${EXT_FILES_DIR}/AndroidAPS.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">

View file

@ -11,11 +11,11 @@ public class Config {
// PLUGINS // PLUGINS
public static final boolean NSCLIENT = BuildConfig.NSCLIENTOLNY; public static final boolean NSCLIENT = BuildConfig.NSCLIENTOLNY;
public static final boolean G5UPLOADER = BuildConfig.G5UPLOADER; public static final boolean G5UPLOADER = BuildConfig.G5UPLOADER;
public static final boolean PUMPCONTROL = BuildConfig.PUMPCONTROL;
public static final boolean DANAR = BuildConfig.PUMPDRIVERS; public static final boolean HWPUMPS = BuildConfig.PUMPDRIVERS;
public static final boolean ACTION = !BuildConfig.NSCLIENTOLNY && !BuildConfig.G5UPLOADER; public static final boolean ACTION = !BuildConfig.NSCLIENTOLNY && !BuildConfig.G5UPLOADER;
public static final boolean VIRTUALPUMP = !BuildConfig.NSCLIENTOLNY && !BuildConfig.G5UPLOADER;
public static final boolean MDI = !BuildConfig.NSCLIENTOLNY && !BuildConfig.G5UPLOADER; public static final boolean MDI = !BuildConfig.NSCLIENTOLNY && !BuildConfig.G5UPLOADER;
public static final boolean OTHERPROFILES = !BuildConfig.NSCLIENTOLNY && !BuildConfig.G5UPLOADER; public static final boolean OTHERPROFILES = !BuildConfig.NSCLIENTOLNY && !BuildConfig.G5UPLOADER;
public static final boolean SAFETY = !BuildConfig.NSCLIENTOLNY && !BuildConfig.G5UPLOADER; public static final boolean SAFETY = !BuildConfig.NSCLIENTOLNY && !BuildConfig.G5UPLOADER;
@ -30,12 +30,12 @@ public class Config {
public static final boolean logPumpComm = true; public static final boolean logPumpComm = true;
public static final boolean logPrefsChange = true; public static final boolean logPrefsChange = true;
public static final boolean logConfigBuilder = true; public static final boolean logConfigBuilder = true;
public static final boolean logConstraintsChanges = true;
public static final boolean logNSUpload = true; public static final boolean logNSUpload = true;
public static final boolean logPumpActions = true; public static final boolean logPumpActions = true;
public static final boolean logCongigBuilderActions = true; public static final boolean logCongigBuilderActions = true;
public static final boolean logAutosensData = false; public static final boolean logAutosensData = false;
public static final boolean logEvents = false; public static final boolean logEvents = false;
public static final boolean logProfile = false;
// DanaR specific // DanaR specific
public static final boolean logDanaBTComm = true; public static final boolean logDanaBTComm = true;

View file

@ -1,6 +1,6 @@
package info.nightscout.androidaps; package info.nightscout.androidaps;
import com.j256.ormlite.stmt.query.In; import info.nightscout.utils.T;
/** /**
* Created by mike on 07.06.2016. * Created by mike on 07.06.2016.
@ -14,10 +14,11 @@ public class Constants {
public static final double defaultDIA = 3d; public static final double defaultDIA = 3d;
public static final double basalAbsoluteOnlyForCheckLimit = 10101010d; public static final Double REALLYHIGHBASALRATE = 1111111d;
public static final Integer basalPercentOnlyForCheckLimit = 10101010; public static final Integer REALLYHIGHPERCENTBASALRATE = 1111111;
public static final double bolusOnlyForCheckLimit = 10101010d; public static final double REALLYHIGHBOLUS = 1111111d;
public static final Integer carbsOnlyForCheckLimit = 10101010; public static final Integer REALLYHIGHCARBS = 1111111;
public static final double REALLYHIGHIOB = 1111111d;
public static final Integer notificationID = 556677; public static final Integer notificationID = 556677;
@ -35,20 +36,20 @@ public class Constants {
public static final int CPP_MIN_TIMESHIFT = -6; public static final int CPP_MIN_TIMESHIFT = -6;
public static final int CPP_MAX_TIMESHIFT = 23; public static final int CPP_MAX_TIMESHIFT = 23;
// Very Hard Limits Ranges
// First value is the Lowest and second value is the Highest a Limit can define
public static final int[] VERY_HARD_LIMIT_MIN_BG = {72,180};
public static final int[] VERY_HARD_LIMIT_MAX_BG = {90,270};
public static final int[] VERY_HARD_LIMIT_TARGET_BG = {80,200};
// Very Hard Limits Ranges for Temp Targets
public static final int[] VERY_HARD_LIMIT_TEMP_MIN_BG = {72,180};
public static final int[] VERY_HARD_LIMIT_TEMP_MAX_BG = {72,270};
public static final int[] VERY_HARD_LIMIT_TEMP_TARGET_BG = {72,200};
//DanaR //DanaR
public static final double dailyLimitWarning = 0.95d; public static final double dailyLimitWarning = 0.95d;
// Temp targets
public static final int defaultActivityTTDuration = 90; // min
public static final double defaultActivityTTmgdl = 140d;
public static final double defaultActivityTTmmol = 8d;
public static final int defaultEatingSoonTTDuration = 45; // min
public static final double defaultEatingSoonTTmgdl = 90d;
public static final double defaultEatingSoonTTmmol = 5d;
public static final int defaultHypoTTDuration = 30; // min
public static final double defaultHypoTTmgdl = 120d;
public static final double defaultHypoTTmmol = 6.5d;
//NSClientInternal //NSClientInternal
public static final int MAX_LOG_LINES = 100; public static final int MAX_LOG_LINES = 100;
@ -58,8 +59,12 @@ public class Constants {
//Autosens //Autosens
public static final double DEVIATION_TO_BE_EQUAL = 2.0; public static final double DEVIATION_TO_BE_EQUAL = 2.0;
public static final double DEFAULT_MAX_ABSORPTION_TIME = 6.0;
// Pump // Pump
public static final int PUMP_MAX_CONNECTION_TIME_IN_SECONDS = 120 - 1; public static final int PUMP_MAX_CONNECTION_TIME_IN_SECONDS = 120 - 1;
public static final int MIN_WATCHDOG_INTERVAL_IN_SECONDS = 12 * 60; public static final int MIN_WATCHDOG_INTERVAL_IN_SECONDS = 12 * 60;
//SMS Communicator
public static final long SMS_CONFIRM_TIMEOUT = T.mins(5).msecs();
} }

View file

@ -0,0 +1,404 @@
package info.nightscout.androidaps;
import android.app.Activity;
import android.os.Bundle;
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;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.SeekBar;
import android.widget.TextView;
import com.jjoe64.graphview.GraphView;
import com.squareup.otto.Subscribe;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Calendar;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import butterknife.OnLongClick;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.events.EventCustomCalculationFinished;
import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.IobCobCalculator.IobCobCalculatorPlugin;
import info.nightscout.androidaps.plugins.IobCobCalculator.events.EventAutosensCalculationFinished;
import info.nightscout.androidaps.plugins.Overview.OverviewFragment;
import info.nightscout.androidaps.plugins.Overview.OverviewPlugin;
import info.nightscout.androidaps.plugins.Overview.graphData.GraphData;
import info.nightscout.utils.DateUtil;
import info.nightscout.utils.SP;
public class HistoryBrowseActivity extends AppCompatActivity {
private static Logger log = LoggerFactory.getLogger(HistoryBrowseActivity.class);
ImageButton chartButton;
boolean showBasal = true;
boolean showIob, showCob, showDev, showRat, 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;
private int rangeToDisplay = 24; // for graph
private long start;
IobCobCalculatorPlugin iobCobCalculatorPlugin;
EventCustomCalculationFinished eventCustomCalculationFinished = new EventCustomCalculationFinished();
public HistoryBrowseActivity() {
iobCobCalculatorPlugin = new IobCobCalculatorPlugin();
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_historybrowse);
ButterKnife.bind(this);
bgGraph.getGridLabelRenderer().setGridColor(MainApp.sResources.getColor(R.color.graphgrid));
bgGraph.getGridLabelRenderer().reloadStyles();
iobGraph.getGridLabelRenderer().setGridColor(MainApp.sResources.getColor(R.color.graphgrid));
iobGraph.getGridLabelRenderer().reloadStyles();
iobGraph.getGridLabelRenderer().setHorizontalLabelsVisible(false);
bgGraph.getGridLabelRenderer().setLabelVerticalWidth(50);
iobGraph.getGridLabelRenderer().setLabelVerticalWidth(50);
iobGraph.getGridLabelRenderer().setNumVerticalLabels(5);
setupChartMenu();
// set start of current day
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();
}
@Override
protected void onResume() {
super.onResume();
updateGUI("onResume");
}
@OnClick(R.id.historybrowse_start)
void onClickStart() {
}
@OnClick(R.id.historybrowse_left)
void onClickLeft() {
start -= rangeToDisplay * 60 * 60 * 1000L;
updateGUI("left");
iobCobCalculatorPlugin.clearCache();
iobCobCalculatorPlugin.runCalculation("onClickLeft", start, true, eventCustomCalculationFinished);
}
@OnClick(R.id.historybrowse_right)
void onClickRight() {
start += rangeToDisplay * 60 * 60 * 1000L;
updateGUI("right");
iobCobCalculatorPlugin.clearCache();
iobCobCalculatorPlugin.runCalculation("onClickRight", start, true, eventCustomCalculationFinished);
}
@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("resetToMidnight");
iobCobCalculatorPlugin.clearCache();
iobCobCalculatorPlugin.runCalculation("onClickEnd", start, true, eventCustomCalculationFinished);
}
@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");
iobCobCalculatorPlugin.clearCache();
iobCobCalculatorPlugin.runCalculation("onLongClickZoom", start, true, eventCustomCalculationFinished);
return true;
}
@OnClick(R.id.historybrowse_date)
void onClickDate() {
}
@Subscribe
public void onStatusEvent(final EventAutosensCalculationFinished e) {
Activity activity = this;
if (activity != null && e.cause == eventCustomCalculationFinished) {
log.debug("EventAutosensCalculationFinished");
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
updateGUI("EventAutosensCalculationFinished");
}
});
}
}
void updateGUI(String from) {
final PumpInterface pump = ConfigBuilderPlugin.getActivePump();
final Profile profile = MainApp.getConfigBuilder().getProfile();
if (profile == null) {
noProfile.setVisibility(View.VISIBLE);
return;
} else {
noProfile.setVisibility(View.GONE);
}
final String units = profile.getUnits();
double lowLineSetting = SP.getDouble("low_mark", Profile.fromMgdlToUnits(OverviewPlugin.bgTargetLow, units));
double highLineSetting = SP.getDouble("high_mark", Profile.fromMgdlToUnits(OverviewPlugin.bgTargetHigh, units));
if (lowLineSetting < 1)
lowLineSetting = Profile.fromMgdlToUnits(76d, units);
if (highLineSetting < 1)
highLineSetting = Profile.fromMgdlToUnits(180d, units);
final double lowLine = lowLineSetting;
final double highLine = highLineSetting;
final boolean showPrediction = false;
int hoursToFetch;
final long toTime;
final long fromTime;
//if (showPrediction) {
//int predHours = (int) (Math.ceil(((DetermineBasalResultAMA) finalLastRun.constraintsProcessed).getLatestPredictionsTime() - System.currentTimeMillis()) / (60 * 60 * 1000));
//predHours = Math.min(2, predHours);
//predHours = Math.max(0, predHours);
//hoursToFetch = rangeToDisplay - predHours;
//toTime = calendar.getTimeInMillis() + 100000; // little bit more to avoid wrong rounding - Graphview specific
//fromTime = toTime - hoursToFetch * 60 * 60 * 1000L;
//endTime = toTime + predHours * 60 * 60 * 1000L;
//} else {
fromTime = start + 100000;
toTime = start + rangeToDisplay * 60 * 60 * 1000L;
//}
buttonDate.setText(DateUtil.dateAndTimeString(start));
buttonZoom.setText(String.valueOf(rangeToDisplay));
log.debug("Period: " + DateUtil.dateAndTimeString(fromTime) + " - " + DateUtil.dateAndTimeString(toTime));
final long pointer = System.currentTimeMillis();
// ------------------ 1st graph
final GraphData graphData = new GraphData(bgGraph, IobCobCalculatorPlugin.getPlugin());
// **** In range Area ****
graphData.addInRangeArea(fromTime, toTime, lowLine, highLine);
// **** BG ****
if (showPrediction)
//graphData.addBgReadings(fromTime, toTime, lowLine, highLine, (DetermineBasalResultAMA) finalLastRun.constraintsProcessed);
;
else
graphData.addBgReadings(fromTime, toTime, lowLine, highLine, null);
// set manual x bounds to have nice steps
graphData.formatAxis(fromTime, toTime);
// Treatments
graphData.addTreatments(fromTime, toTime);
// add basal data
if (pump.getPumpDescription().isTempBasalCapable && showBasal) {
graphData.addBasals(fromTime, toTime, lowLine / graphData.maxY / 1.2d);
}
// **** NOW line ****
graphData.addNowLine(pointer);
// ------------------ 2nd graph
final GraphData secondGraphData = new GraphData(iobGraph, iobCobCalculatorPlugin);
boolean useIobForScale = false;
boolean useCobForScale = false;
boolean useDevForScale = false;
boolean useRatioForScale = false;
boolean useDevSlopeForScale = false;
if (showIob) {
useIobForScale = true;
} else if (showCob) {
useCobForScale = true;
} else if (showDev) {
useDevForScale = true;
} else if (showRat) {
useRatioForScale = true;
} else if (showDevslope) {
useDevSlopeForScale = true;
}
if (showIob)
secondGraphData.addIob(fromTime, toTime, useIobForScale, 1d);
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 (showDevslope)
secondGraphData.addDeviationSlope(fromTime, toTime, useDevSlopeForScale, 1d);
// **** NOW line ****
// set manual x bounds to have nice steps
secondGraphData.formatAxis(fromTime, toTime);
secondGraphData.addNowLine(pointer);
// do GUI update
if (showIob || showCob || showDev || showRat || showDevslope) {
iobGraph.setVisibility(View.VISIBLE);
} else {
iobGraph.setVisibility(View.GONE);
}
// finally enforce drawing of graphs
graphData.performUpdate();
secondGraphData.performUpdate();
}
private void setupChartMenu() {
chartButton = (ImageButton) findViewById(R.id.overview_chartMenuButton);
chartButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
MenuItem item;
CharSequence title;
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();
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.IOB.ordinal(), Menu.NONE, MainApp.gs(R.string.overview_show_iob));
title = item.getTitle();
s = new SpannableString(title);
s.setSpan(new ForegroundColorSpan(ResourcesCompat.getColor(getResources(), R.color.iob, null)), 0, s.length(), 0);
item.setTitle(s);
item.setCheckable(true);
item.setChecked(showIob);
item = popup.getMenu().add(Menu.NONE, OverviewFragment.CHARTTYPE.COB.ordinal(), Menu.NONE, MainApp.gs(R.string.overview_show_cob));
title = item.getTitle();
s = new SpannableString(title);
s.setSpan(new ForegroundColorSpan(ResourcesCompat.getColor(getResources(), R.color.cob, null)), 0, s.length(), 0);
item.setTitle(s);
item.setCheckable(true);
item.setChecked(showCob);
item = popup.getMenu().add(Menu.NONE, OverviewFragment.CHARTTYPE.DEV.ordinal(), Menu.NONE, MainApp.gs(R.string.overview_show_deviations));
title = item.getTitle();
s = new SpannableString(title);
s.setSpan(new ForegroundColorSpan(ResourcesCompat.getColor(getResources(), R.color.deviations, null)), 0, s.length(), 0);
item.setTitle(s);
item.setCheckable(true);
item.setChecked(showDev);
item = popup.getMenu().add(Menu.NONE, OverviewFragment.CHARTTYPE.SEN.ordinal(), Menu.NONE, MainApp.gs(R.string.overview_show_sensitivity));
title = item.getTitle();
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);
if (MainApp.devBranch) {
item = popup.getMenu().add(Menu.NONE, OverviewFragment.CHARTTYPE.DEVSLOPE.ordinal(), Menu.NONE, "Deviation slope");
title = item.getTitle();
s = new SpannableString(title);
s.setSpan(new ForegroundColorSpan(ResourcesCompat.getColor(getResources(), R.color.devslopepos, null)), 0, s.length(), 0);
item.setTitle(s);
item.setCheckable(true);
item.setChecked(showDevslope);
}
popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
if (item.getItemId() == OverviewFragment.CHARTTYPE.BAS.ordinal()) {
showBasal = !item.isChecked();
} else if (item.getItemId() == OverviewFragment.CHARTTYPE.IOB.ordinal()) {
showIob = !item.isChecked();
} else if (item.getItemId() == OverviewFragment.CHARTTYPE.COB.ordinal()) {
showCob = !item.isChecked();
} else if (item.getItemId() == OverviewFragment.CHARTTYPE.DEV.ordinal()) {
showDev = !item.isChecked();
} else if (item.getItemId() == OverviewFragment.CHARTTYPE.SEN.ordinal()) {
showRat = !item.isChecked();
} else if (item.getItemId() == OverviewFragment.CHARTTYPE.DEVSLOPE.ordinal()) {
showDevslope = !item.isChecked();
}
updateGUI("onGraphCheckboxesCheckedChanged");
return true;
}
});
chartButton.setImageResource(R.drawable.ic_arrow_drop_up_white_24dp);
popup.setOnDismissListener(new PopupMenu.OnDismissListener() {
@Override
public void onDismiss(PopupMenu menu) {
chartButton.setImageResource(R.drawable.ic_arrow_drop_down_white_24dp);
}
});
popup.show();
}
});
}
}

View file

@ -19,6 +19,9 @@ import android.support.v4.view.ViewPager;
import android.support.v7.app.AlertDialog; import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity; import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.PopupMenu; import android.support.v7.widget.PopupMenu;
import android.text.SpannableString;
import android.text.method.LinkMovementMethod;
import android.text.util.Linkify;
import android.view.MenuInflater; import android.view.MenuInflater;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.MotionEvent; import android.view.MotionEvent;
@ -27,6 +30,7 @@ import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager; import android.view.inputmethod.InputMethodManager;
import android.widget.EditText; import android.widget.EditText;
import android.widget.ImageButton; import android.widget.ImageButton;
import android.widget.TextView;
import com.joanzapata.iconify.Iconify; import com.joanzapata.iconify.Iconify;
import com.joanzapata.iconify.fonts.FontAwesomeModule; import com.joanzapata.iconify.fonts.FontAwesomeModule;
@ -35,14 +39,16 @@ import com.squareup.otto.Subscribe;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.Services.AlarmSoundService;
import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.events.EventAppExit; import info.nightscout.androidaps.events.EventAppExit;
import info.nightscout.androidaps.events.EventFeatureRunning;
import info.nightscout.androidaps.events.EventPreferenceChange; import info.nightscout.androidaps.events.EventPreferenceChange;
import info.nightscout.androidaps.events.EventRefreshGui; import info.nightscout.androidaps.events.EventRefreshGui;
import info.nightscout.androidaps.interfaces.PluginBase; import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.Food.FoodPlugin;
import info.nightscout.androidaps.plugins.Overview.events.EventSetWakeLock; import info.nightscout.androidaps.plugins.Overview.events.EventSetWakeLock;
import info.nightscout.androidaps.plugins.Treatments.TreatmentsPlugin;
import info.nightscout.androidaps.tabs.SlidingTabLayout; import info.nightscout.androidaps.tabs.SlidingTabLayout;
import info.nightscout.androidaps.tabs.TabPageAdapter; import info.nightscout.androidaps.tabs.TabPageAdapter;
import info.nightscout.utils.ImportExportPrefs; import info.nightscout.utils.ImportExportPrefs;
@ -82,7 +88,7 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
Manifest.permission.WRITE_EXTERNAL_STORAGE}, CASE_STORAGE); Manifest.permission.WRITE_EXTERNAL_STORAGE}, CASE_STORAGE);
} }
askForBatteryOptimizationPermission(); askForBatteryOptimizationPermission();
checkUpgradeToProfileTarget(); doMigrations();
if (Config.logFunctionCalls) if (Config.logFunctionCalls)
log.debug("onCreate"); log.debug("onCreate");
@ -112,12 +118,16 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
runOnUiThread(new Runnable() { runOnUiThread(new Runnable() {
@Override @Override
public void run() { public void run() {
recreate(); if (ev.recreate) {
try { // activity may be destroyed recreate();
setUpTabs(true); } else {
} catch (IllegalStateException e) { try { // activity may be destroyed
log.error("Unhandled exception", e); setUpTabs(true);
} catch (IllegalStateException e) {
log.error("Unhandled exception", e);
}
} }
boolean lockScreen = BuildConfig.NSCLIENTOLNY && SP.getBoolean("lockscreen", false); boolean lockScreen = BuildConfig.NSCLIENTOLNY && SP.getBoolean("lockscreen", false);
if (lockScreen) if (lockScreen)
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
@ -159,6 +169,19 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
} }
} }
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 private void checkUpgradeToProfileTarget() { // TODO: can be removed in the future
boolean oldKeyExists = SP.contains("openapsma_min_bg"); boolean oldKeyExists = SP.contains("openapsma_min_bg");
if (oldKeyExists) { if (oldKeyExists) {
@ -205,6 +228,7 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
super.onResume(); super.onResume();
askForSMSPermissions(); askForSMSPermissions();
askForLocationPermissions(); askForLocationPermissions();
MainApp.bus().post(new EventFeatureRunning(EventFeatureRunning.Feature.MAIN));
} }
@Override @Override
@ -223,7 +247,7 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
if (!pm.isIgnoringBatteryOptimizations(packageName)) { if (!pm.isIgnoringBatteryOptimizations(packageName)) {
log.debug("Requesting ignore battery optimization"); log.debug("Requesting ignore battery optimization");
OKDialog.show(this, getString(R.string.pleaseallowpermission), String.format(getString(R.string.needwhitelisting), getString(R.string.app_name)), new Runnable() { OKDialog.show(this, MainApp.gs(R.string.pleaseallowpermission), String.format(MainApp.gs(R.string.needwhitelisting), MainApp.gs(R.string.app_name)), new Runnable() {
@Override @Override
public void run() { public void run() {
@ -236,7 +260,7 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
startActivity(intent); startActivity(intent);
} catch (ActivityNotFoundException e) { } catch (ActivityNotFoundException e) {
final String msg = getString(R.string.batteryoptimalizationerror); final String msg = MainApp.gs(R.string.batteryoptimalizationerror);
ToastUtils.showToastInUiThread(getApplicationContext(), msg); ToastUtils.showToastInUiThread(getApplicationContext(), msg);
log.error(msg); log.error(msg);
} }
@ -341,6 +365,9 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
} }
}, null); }, null);
break; break;
case R.id.nav_historybrowser:
startActivity(new Intent(v.getContext(), HistoryBrowseActivity.class));
break;
case R.id.nav_resetdb: case R.id.nav_resetdb:
new AlertDialog.Builder(v.getContext()) new AlertDialog.Builder(v.getContext())
.setTitle(R.string.nav_resetdb) .setTitle(R.string.nav_resetdb)
@ -350,6 +377,10 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
@Override @Override
public void onClick(DialogInterface dialog, int which) { public void onClick(DialogInterface dialog, int which) {
MainApp.getDbHelper().resetDatabases(); MainApp.getDbHelper().resetDatabases();
// should be handled by Plugin-Interface and
// additional service interface and plugin registry
FoodPlugin.getPlugin().getService().resetFood();
TreatmentsPlugin.getPlugin().getService().resetTreatments();
} }
}) })
.create() .create()
@ -368,17 +399,24 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
break; break;
case R.id.nav_about: case R.id.nav_about:
AlertDialog.Builder builder = new AlertDialog.Builder(v.getContext()); AlertDialog.Builder builder = new AlertDialog.Builder(v.getContext());
builder.setTitle(getString(R.string.app_name) + " " + BuildConfig.VERSION); builder.setTitle(MainApp.gs(R.string.app_name) + " " + BuildConfig.VERSION);
if (Config.NSCLIENT|| Config.G5UPLOADER) if (Config.NSCLIENT || Config.G5UPLOADER)
builder.setIcon(R.mipmap.yellowowl); builder.setIcon(R.mipmap.yellowowl);
else else
builder.setIcon(R.mipmap.blueowl); builder.setIcon(R.mipmap.blueowl);
String message = "Build: " + BuildConfig.BUILDVERSION + "\n"; String message = "Build: " + BuildConfig.BUILDVERSION + "\n";
message += MainApp.sResources.getString(R.string.configbuilder_nightscoutversion_label) + " " + ConfigBuilderPlugin.nightscoutVersionName; message += "Flavor: " + BuildConfig.FLAVOR + BuildConfig.BUILD_TYPE + "\n";
builder.setMessage(message); message += MainApp.gs(R.string.configbuilder_nightscoutversion_label) + " " + ConfigBuilderPlugin.nightscoutVersionName;
builder.setPositiveButton(MainApp.sResources.getString(R.string.ok), null); if (MainApp.engineeringMode)
message += "\n" + MainApp.gs(R.string.engineering_mode_enabled);
message += MainApp.gs(R.string.about_link_urls);
final SpannableString messageSpanned = new SpannableString(message);
Linkify.addLinks(messageSpanned, Linkify.WEB_URLS);
builder.setMessage(messageSpanned);
builder.setPositiveButton(MainApp.gs(R.string.ok), null);
AlertDialog alertDialog = builder.create(); AlertDialog alertDialog = builder.create();
alertDialog.show(); alertDialog.show();
((TextView)alertDialog.findViewById(android.R.id.message)).setMovementMethod(LinkMovementMethod.getInstance());
break; break;
case R.id.nav_exit: case R.id.nav_exit:
log.debug("Exiting"); log.debug("Exiting");

View file

@ -1,7 +1,6 @@
package info.nightscout.androidaps; package info.nightscout.androidaps;
import android.app.Application; import android.app.Application;
import android.content.Intent;
import android.content.IntentFilter; import android.content.IntentFilter;
import android.content.res.Resources; import android.content.res.Resources;
import android.os.SystemClock; import android.os.SystemClock;
@ -16,65 +15,68 @@ import com.squareup.otto.Bus;
import com.squareup.otto.LoggingBus; import com.squareup.otto.LoggingBus;
import com.squareup.otto.ThreadEnforcer; import com.squareup.otto.ThreadEnforcer;
import net.danlew.android.joda.JodaTimeAndroid;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
import ch.qos.logback.classic.LoggerContext;
import info.nightscout.androidaps.Services.Intents; import info.nightscout.androidaps.Services.Intents;
import info.nightscout.androidaps.data.ConstraintChecker;
import info.nightscout.androidaps.db.DatabaseHelper; import info.nightscout.androidaps.db.DatabaseHelper;
import info.nightscout.androidaps.interfaces.InsulinInterface;
import info.nightscout.androidaps.interfaces.PluginBase; import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.PluginType;
import info.nightscout.androidaps.interfaces.PumpInterface; import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.plugins.Actions.ActionsFragment; import info.nightscout.androidaps.plugins.Actions.ActionsFragment;
import info.nightscout.androidaps.plugins.Careportal.CareportalPlugin; import info.nightscout.androidaps.plugins.Careportal.CareportalPlugin;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderFragment;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.ConstraintsObjectives.ObjectivesPlugin; import info.nightscout.androidaps.plugins.ConstraintsObjectives.ObjectivesPlugin;
import info.nightscout.androidaps.plugins.ConstraintsSafety.SafetyPlugin; import info.nightscout.androidaps.plugins.ConstraintsSafety.SafetyPlugin;
import info.nightscout.androidaps.plugins.Food.FoodPlugin; import info.nightscout.androidaps.plugins.Food.FoodPlugin;
import info.nightscout.androidaps.plugins.Insulin.InsulinFastactingPlugin;
import info.nightscout.androidaps.plugins.Insulin.InsulinFastactingProlongedPlugin;
import info.nightscout.androidaps.plugins.Insulin.InsulinOrefFreePeakPlugin; import info.nightscout.androidaps.plugins.Insulin.InsulinOrefFreePeakPlugin;
import info.nightscout.androidaps.plugins.Insulin.InsulinOrefRapidActingPlugin; import info.nightscout.androidaps.plugins.Insulin.InsulinOrefRapidActingPlugin;
import info.nightscout.androidaps.plugins.Insulin.InsulinOrefUltraRapidActingPlugin; import info.nightscout.androidaps.plugins.Insulin.InsulinOrefUltraRapidActingPlugin;
import info.nightscout.androidaps.plugins.IobCobCalculator.IobCobCalculatorPlugin; import info.nightscout.androidaps.plugins.IobCobCalculator.IobCobCalculatorPlugin;
import info.nightscout.androidaps.plugins.Loop.LoopPlugin; import info.nightscout.androidaps.plugins.Loop.LoopPlugin;
import info.nightscout.androidaps.plugins.NSClientInternal.NSClientInternalPlugin; import info.nightscout.androidaps.plugins.NSClientInternal.NSClientPlugin;
import info.nightscout.androidaps.plugins.NSClientInternal.receivers.AckAlarmReceiver; import info.nightscout.androidaps.plugins.NSClientInternal.receivers.AckAlarmReceiver;
import info.nightscout.androidaps.plugins.OpenAPSAMA.OpenAPSAMAPlugin; import info.nightscout.androidaps.plugins.OpenAPSAMA.OpenAPSAMAPlugin;
import info.nightscout.androidaps.plugins.OpenAPSMA.OpenAPSMAPlugin; import info.nightscout.androidaps.plugins.OpenAPSMA.OpenAPSMAPlugin;
import info.nightscout.androidaps.plugins.OpenAPSSMB.OpenAPSSMBPlugin;
import info.nightscout.androidaps.plugins.Overview.OverviewPlugin; import info.nightscout.androidaps.plugins.Overview.OverviewPlugin;
import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification;
import info.nightscout.androidaps.plugins.Overview.notifications.Notification;
import info.nightscout.androidaps.plugins.Persistentnotification.PersistentNotificationPlugin; import info.nightscout.androidaps.plugins.Persistentnotification.PersistentNotificationPlugin;
import info.nightscout.androidaps.plugins.ProfileCircadianPercentage.CircadianPercentageProfileFragment; import info.nightscout.androidaps.plugins.ProfileLocal.LocalProfilePlugin;
import info.nightscout.androidaps.plugins.ProfileLocal.LocalProfileFragment;
import info.nightscout.androidaps.plugins.ProfileNS.NSProfilePlugin; import info.nightscout.androidaps.plugins.ProfileNS.NSProfilePlugin;
import info.nightscout.androidaps.plugins.ProfileSimple.SimpleProfilePlugin; import info.nightscout.androidaps.plugins.ProfileSimple.SimpleProfilePlugin;
import info.nightscout.androidaps.plugins.PumpCombo.ComboPlugin;
import info.nightscout.androidaps.plugins.PumpDanaR.DanaRPlugin; import info.nightscout.androidaps.plugins.PumpDanaR.DanaRPlugin;
import info.nightscout.androidaps.plugins.PumpDanaR.services.DanaRExecutionService;
import info.nightscout.androidaps.plugins.PumpDanaRKorean.DanaRKoreanPlugin; import info.nightscout.androidaps.plugins.PumpDanaRKorean.DanaRKoreanPlugin;
import info.nightscout.androidaps.plugins.PumpDanaRKorean.services.DanaRKoreanExecutionService;
import info.nightscout.androidaps.plugins.PumpDanaRS.DanaRSPlugin; import info.nightscout.androidaps.plugins.PumpDanaRS.DanaRSPlugin;
import info.nightscout.androidaps.plugins.PumpDanaRS.services.DanaRSService;
import info.nightscout.androidaps.plugins.PumpDanaRv2.DanaRv2Plugin; import info.nightscout.androidaps.plugins.PumpDanaRv2.DanaRv2Plugin;
import info.nightscout.androidaps.plugins.PumpDanaRv2.services.DanaRv2ExecutionService; import info.nightscout.androidaps.plugins.PumpInsight.InsightPlugin;
import info.nightscout.androidaps.plugins.PumpMDI.MDIPlugin; import info.nightscout.androidaps.plugins.PumpMDI.MDIPlugin;
import info.nightscout.androidaps.plugins.PumpVirtual.VirtualPumpPlugin; import info.nightscout.androidaps.plugins.PumpVirtual.VirtualPumpPlugin;
import info.nightscout.androidaps.plugins.SensitivityAAPS.SensitivityAAPSPlugin; import info.nightscout.androidaps.plugins.SensitivityAAPS.SensitivityAAPSPlugin;
import info.nightscout.androidaps.plugins.SensitivityOref0.SensitivityOref0Plugin; import info.nightscout.androidaps.plugins.SensitivityOref0.SensitivityOref0Plugin;
import info.nightscout.androidaps.plugins.SensitivityWeightedAverage.SensitivityWeightedAveragePlugin; import info.nightscout.androidaps.plugins.SensitivityWeightedAverage.SensitivityWeightedAveragePlugin;
import info.nightscout.androidaps.plugins.SmsCommunicator.SmsCommunicatorPlugin; import info.nightscout.androidaps.plugins.SmsCommunicator.SmsCommunicatorPlugin;
import info.nightscout.androidaps.plugins.SourceDexcomG5.SourceDexcomG5Plugin; import info.nightscout.androidaps.plugins.Source.SourceDexcomG5Plugin;
import info.nightscout.androidaps.plugins.SourceGlimp.SourceGlimpPlugin; import info.nightscout.androidaps.plugins.Source.SourceGlimpPlugin;
import info.nightscout.androidaps.plugins.SourceMM640g.SourceMM640gPlugin; import info.nightscout.androidaps.plugins.Source.SourceMM640gPlugin;
import info.nightscout.androidaps.plugins.SourceNSClient.SourceNSClientPlugin; import info.nightscout.androidaps.plugins.Source.SourceNSClientPlugin;
import info.nightscout.androidaps.plugins.SourceXdrip.SourceXdripPlugin; import info.nightscout.androidaps.plugins.Source.SourceXdripPlugin;
import info.nightscout.androidaps.plugins.Treatments.TreatmentsPlugin; import info.nightscout.androidaps.plugins.Treatments.TreatmentsPlugin;
import info.nightscout.androidaps.plugins.Wear.WearPlugin; import info.nightscout.androidaps.plugins.Wear.WearPlugin;
import info.nightscout.androidaps.plugins.XDripStatusline.StatuslinePlugin; import info.nightscout.androidaps.plugins.XDripStatusline.StatuslinePlugin;
import info.nightscout.androidaps.receivers.DataReceiver; import info.nightscout.androidaps.receivers.DataReceiver;
import info.nightscout.androidaps.receivers.KeepAliveReceiver; import info.nightscout.androidaps.receivers.KeepAliveReceiver;
import info.nightscout.androidaps.receivers.NSAlarmReceiver; import info.nightscout.androidaps.receivers.NSAlarmReceiver;
import info.nightscout.utils.FabricPrivacy;
import info.nightscout.utils.NSUpload; import info.nightscout.utils.NSUpload;
import io.fabric.sdk.android.Fabric; import io.fabric.sdk.android.Fabric;
@ -89,6 +91,7 @@ public class MainApp extends Application {
private static DatabaseHelper sDatabaseHelper = null; private static DatabaseHelper sDatabaseHelper = null;
private static ConfigBuilderPlugin sConfigBuilder = null; private static ConfigBuilderPlugin sConfigBuilder = null;
private static ConstraintChecker sConstraintsChecker = null;
private static ArrayList<PluginBase> pluginsList = null; private static ArrayList<PluginBase> pluginsList = null;
@ -97,19 +100,39 @@ public class MainApp extends Application {
private static AckAlarmReceiver ackAlarmReciever = new AckAlarmReceiver(); private static AckAlarmReceiver ackAlarmReciever = new AckAlarmReceiver();
private LocalBroadcastManager lbm; private LocalBroadcastManager lbm;
public static boolean devBranch;
public static boolean engineeringMode;
@Override @Override
public void onCreate() { public void onCreate() {
super.onCreate(); super.onCreate();
Fabric.with(this, new Crashlytics()); sInstance = this;
Fabric.with(this, new Answers()); sResources = getResources();
Crashlytics.setString("BUILDVERSION", BuildConfig.BUILDVERSION); sConstraintsChecker = new ConstraintChecker(this);
sDatabaseHelper = OpenHelperManager.getHelper(sInstance, DatabaseHelper.class);
try {
if (FabricPrivacy.fabricEnabled()) {
Fabric.with(this, new Crashlytics());
Fabric.with(this, new Answers());
Crashlytics.setString("BUILDVERSION", BuildConfig.BUILDVERSION);
}
} catch (Exception e) {
android.util.Log.e("ANDROIDAPS", "Error with Fabric init! " + e);
}
JodaTimeAndroid.init(this);
log.info("Version: " + BuildConfig.VERSION_NAME); log.info("Version: " + BuildConfig.VERSION_NAME);
log.info("BuildVersion: " + BuildConfig.BUILDVERSION); log.info("BuildVersion: " + BuildConfig.BUILDVERSION);
sBus = Config.logEvents ? new LoggingBus(ThreadEnforcer.ANY) : new Bus(ThreadEnforcer.ANY); String extFilesDir = this.getLogDirectory();
File engineeringModeSemaphore = new File(extFilesDir, "engineering_mode");
sInstance = this; engineeringMode = engineeringModeSemaphore.exists() && engineeringModeSemaphore.isFile();
sResources = getResources(); devBranch = BuildConfig.VERSION.contains("dev");
sBus = Config.logEvents ? new LoggingBus(ThreadEnforcer.ANY) : new Bus(ThreadEnforcer.ANY);
registerLocalBroadcastReceiver(); registerLocalBroadcastReceiver();
@ -119,29 +142,29 @@ public class MainApp extends Application {
pluginsList.add(OverviewPlugin.getPlugin()); pluginsList.add(OverviewPlugin.getPlugin());
pluginsList.add(IobCobCalculatorPlugin.getPlugin()); pluginsList.add(IobCobCalculatorPlugin.getPlugin());
if (Config.ACTION) pluginsList.add(ActionsFragment.getPlugin()); if (Config.ACTION) pluginsList.add(ActionsFragment.getPlugin());
pluginsList.add(InsulinFastactingPlugin.getPlugin());
pluginsList.add(InsulinFastactingProlongedPlugin.getPlugin());
pluginsList.add(InsulinOrefRapidActingPlugin.getPlugin()); pluginsList.add(InsulinOrefRapidActingPlugin.getPlugin());
pluginsList.add(InsulinOrefUltraRapidActingPlugin.getPlugin()); pluginsList.add(InsulinOrefUltraRapidActingPlugin.getPlugin());
pluginsList.add(InsulinOrefFreePeakPlugin.getPlugin()); pluginsList.add(InsulinOrefFreePeakPlugin.getPlugin());
pluginsList.add(SensitivityOref0Plugin.getPlugin()); pluginsList.add(SensitivityOref0Plugin.getPlugin());
pluginsList.add(SensitivityAAPSPlugin.getPlugin()); pluginsList.add(SensitivityAAPSPlugin.getPlugin());
pluginsList.add(SensitivityWeightedAveragePlugin.getPlugin()); pluginsList.add(SensitivityWeightedAveragePlugin.getPlugin());
if (Config.DANAR) pluginsList.add(DanaRPlugin.getPlugin()); if (Config.HWPUMPS) pluginsList.add(DanaRPlugin.getPlugin());
if (Config.DANAR) pluginsList.add(DanaRKoreanPlugin.getPlugin()); if (Config.HWPUMPS) pluginsList.add(DanaRKoreanPlugin.getPlugin());
if (Config.DANAR) pluginsList.add(DanaRv2Plugin.getPlugin()); if (Config.HWPUMPS) pluginsList.add(DanaRv2Plugin.getPlugin());
if (Config.DANAR) pluginsList.add(DanaRSPlugin.getPlugin()); if (Config.HWPUMPS) pluginsList.add(DanaRSPlugin.getPlugin());
pluginsList.add(CareportalPlugin.getPlugin()); pluginsList.add(CareportalPlugin.getPlugin());
if (Config.HWPUMPS && engineeringMode)
pluginsList.add(InsightPlugin.getPlugin()); // <-- Enable Insight plugin here
if (Config.HWPUMPS) pluginsList.add(ComboPlugin.getPlugin());
if (Config.MDI) pluginsList.add(MDIPlugin.getPlugin()); if (Config.MDI) pluginsList.add(MDIPlugin.getPlugin());
if (Config.VIRTUALPUMP) pluginsList.add(VirtualPumpPlugin.getPlugin()); pluginsList.add(VirtualPumpPlugin.getPlugin());
if (Config.APS) pluginsList.add(LoopPlugin.getPlugin()); if (Config.APS) pluginsList.add(LoopPlugin.getPlugin());
if (Config.APS) pluginsList.add(OpenAPSMAPlugin.getPlugin()); if (Config.APS) pluginsList.add(OpenAPSMAPlugin.getPlugin());
if (Config.APS) pluginsList.add(OpenAPSAMAPlugin.getPlugin()); if (Config.APS) pluginsList.add(OpenAPSAMAPlugin.getPlugin());
if (Config.APS) pluginsList.add(OpenAPSSMBPlugin.getPlugin());
pluginsList.add(NSProfilePlugin.getPlugin()); pluginsList.add(NSProfilePlugin.getPlugin());
if (Config.OTHERPROFILES) pluginsList.add(SimpleProfilePlugin.getPlugin()); if (Config.OTHERPROFILES) pluginsList.add(SimpleProfilePlugin.getPlugin());
if (Config.OTHERPROFILES) pluginsList.add(LocalProfileFragment.getPlugin()); if (Config.OTHERPROFILES) pluginsList.add(LocalProfilePlugin.getPlugin());
if (Config.OTHERPROFILES)
pluginsList.add(CircadianPercentageProfileFragment.getPlugin());
pluginsList.add(TreatmentsPlugin.getPlugin()); pluginsList.add(TreatmentsPlugin.getPlugin());
if (Config.SAFETY) pluginsList.add(SafetyPlugin.getPlugin()); if (Config.SAFETY) pluginsList.add(SafetyPlugin.getPlugin());
if (Config.APS) pluginsList.add(ObjectivesPlugin.getPlugin()); if (Config.APS) pluginsList.add(ObjectivesPlugin.getPlugin());
@ -161,27 +184,33 @@ public class MainApp extends Application {
pluginsList.add(WearPlugin.initPlugin(this)); pluginsList.add(WearPlugin.initPlugin(this));
pluginsList.add(StatuslinePlugin.initPlugin(this)); pluginsList.add(StatuslinePlugin.initPlugin(this));
pluginsList.add(new PersistentNotificationPlugin(this)); pluginsList.add(new PersistentNotificationPlugin(this));
pluginsList.add(NSClientInternalPlugin.getPlugin()); pluginsList.add(NSClientPlugin.getPlugin());
pluginsList.add(sConfigBuilder = ConfigBuilderFragment.getPlugin()); pluginsList.add(sConfigBuilder = ConfigBuilderPlugin.getPlugin());
MainApp.getConfigBuilder().initialize(); MainApp.getConfigBuilder().initialize();
} }
NSUpload.uploadAppStart(); NSUpload.uploadAppStart();
if (MainApp.getConfigBuilder().isClosedModeEnabled())
Answers.getInstance().logCustom(new CustomEvent("AppStart-ClosedLoop"));
else
Answers.getInstance().logCustom(new CustomEvent("AppStart"));
new Thread(new Runnable() { if (Config.NSCLIENT)
@Override FabricPrivacy.getInstance().logCustom(new CustomEvent("AppStart-NSClient"));
public void run() { else if (Config.G5UPLOADER)
FabricPrivacy.getInstance().logCustom(new CustomEvent("AppStart-G5Uploader"));
else if (Config.PUMPCONTROL)
FabricPrivacy.getInstance().logCustom(new CustomEvent("AppStart-PumpControl"));
else if (MainApp.getConstraintChecker().isClosedLoopAllowed().value())
FabricPrivacy.getInstance().logCustom(new CustomEvent("AppStart-ClosedLoop"));
else
FabricPrivacy.getInstance().logCustom(new CustomEvent("AppStart-OpenLoop"));
final PumpInterface pump = ConfigBuilderPlugin.getActivePump();
if (pump != null) {
new Thread(() -> {
SystemClock.sleep(5000); SystemClock.sleep(5000);
ConfigBuilderPlugin.getCommandQueue().readStatus("Initialization", null); ConfigBuilderPlugin.getCommandQueue().readStatus("Initialization", null);
startKeepAliveService(); startKeepAliveService();
} }).start();
}).start(); }
} }
private void registerLocalBroadcastReceiver() { private void registerLocalBroadcastReceiver() {
@ -216,24 +245,48 @@ public class MainApp extends Application {
} }
} }
public void stopKeepAliveService() { public void stopKeepAliveService() {
if (keepAliveReceiver != null) if (keepAliveReceiver != null)
keepAliveReceiver.cancelAlarm(this); KeepAliveReceiver.cancelAlarm(this);
}
public static void subscribe(Object subscriber) {
try {
bus().register(subscriber);
} catch (IllegalArgumentException e) {
// already registered
}
}
public static void unsubscribe(Object subscriber) {
try {
bus().unregister(subscriber);
} catch (IllegalArgumentException e) {
// already unregistered
}
} }
public static Bus bus() { public static Bus bus() {
return sBus; return sBus;
} }
public static String gs(int id) {
return sResources.getString(id);
}
public static String gs(int id, Object... args) {
return sResources.getString(id, args);
}
public static int gc(int id) {
return sResources.getColor(id);
}
public static MainApp instance() { public static MainApp instance() {
return sInstance; return sInstance;
} }
public static DatabaseHelper getDbHelper() { public static DatabaseHelper getDbHelper() {
if (sDatabaseHelper == null) {
sDatabaseHelper = OpenHelperManager.getHelper(sInstance, DatabaseHelper.class);
}
return sDatabaseHelper; return sDatabaseHelper;
} }
@ -248,11 +301,15 @@ public class MainApp extends Application {
return sConfigBuilder; return sConfigBuilder;
} }
public static ConstraintChecker getConstraintChecker() {
return sConstraintsChecker;
}
public static ArrayList<PluginBase> getPluginsList() { public static ArrayList<PluginBase> getPluginsList() {
return pluginsList; return pluginsList;
} }
public static ArrayList<PluginBase> getSpecificPluginsList(int type) { public static ArrayList<PluginBase> getSpecificPluginsList(PluginType type) {
ArrayList<PluginBase> newList = new ArrayList<>(); ArrayList<PluginBase> newList = new ArrayList<>();
if (pluginsList != null) { if (pluginsList != null) {
@ -266,20 +323,7 @@ public class MainApp extends Application {
return newList; return newList;
} }
@Nullable public static ArrayList<PluginBase> getSpecificPluginsVisibleInList(PluginType type) {
public static InsulinInterface getInsulinIterfaceById(int id) {
if (pluginsList != null) {
for (PluginBase p : pluginsList) {
if (p.getType() == PluginBase.INSULIN && ((InsulinInterface) p).getId() == id)
return (InsulinInterface) p;
}
} else {
log.error("InsulinInterface not found");
}
return null;
}
public static ArrayList<PluginBase> getSpecificPluginsVisibleInList(int type) {
ArrayList<PluginBase> newList = new ArrayList<>(); ArrayList<PluginBase> newList = new ArrayList<>();
if (pluginsList != null) { if (pluginsList != null) {
@ -308,7 +352,7 @@ public class MainApp extends Application {
return newList; return newList;
} }
public static ArrayList<PluginBase> getSpecificPluginsVisibleInListByInterface(Class interfaceClass, int type) { public static ArrayList<PluginBase> getSpecificPluginsVisibleInListByInterface(Class interfaceClass, PluginType type) {
ArrayList<PluginBase> newList = new ArrayList<>(); ArrayList<PluginBase> newList = new ArrayList<>();
if (pluginsList != null) { if (pluginsList != null) {
@ -336,9 +380,27 @@ public class MainApp extends Application {
return null; return null;
} }
public static boolean isEngineeringModeOrRelease() {
if (!BuildConfig.APS)
return true;
return engineeringMode || !devBranch;
}
public static boolean isDev() {
return devBranch;
}
public String getLogDirectory() {
LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
return lc.getProperty("EXT_FILES_DIR");
}
@Override @Override
public void onTerminate() { public void onTerminate() {
super.onTerminate(); super.onTerminate();
sDatabaseHelper.close(); if (sDatabaseHelper != null) {
sDatabaseHelper.close();
sDatabaseHelper = null;
}
} }
} }

View file

@ -4,7 +4,6 @@ import android.content.SharedPreferences;
import android.os.Bundle; import android.os.Bundle;
import android.preference.EditTextPreference; import android.preference.EditTextPreference;
import android.preference.ListPreference; import android.preference.ListPreference;
import android.preference.MultiSelectListPreference;
import android.preference.Preference; import android.preference.Preference;
import android.preference.PreferenceActivity; import android.preference.PreferenceActivity;
import android.preference.PreferenceFragment; import android.preference.PreferenceFragment;
@ -15,23 +14,27 @@ import android.text.TextUtils;
import info.nightscout.androidaps.events.EventPreferenceChange; import info.nightscout.androidaps.events.EventPreferenceChange;
import info.nightscout.androidaps.events.EventRefreshGui; import info.nightscout.androidaps.events.EventRefreshGui;
import info.nightscout.androidaps.interfaces.PluginBase; import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.PluginType;
import info.nightscout.androidaps.plugins.Careportal.CareportalPlugin; import info.nightscout.androidaps.plugins.Careportal.CareportalPlugin;
import info.nightscout.androidaps.plugins.ConstraintsSafety.SafetyPlugin; import info.nightscout.androidaps.plugins.ConstraintsSafety.SafetyPlugin;
import info.nightscout.androidaps.plugins.Insulin.InsulinOrefFreePeakPlugin; import info.nightscout.androidaps.plugins.Insulin.InsulinOrefFreePeakPlugin;
import info.nightscout.androidaps.plugins.Loop.LoopPlugin; import info.nightscout.androidaps.plugins.Loop.LoopPlugin;
import info.nightscout.androidaps.plugins.NSClientInternal.NSClientInternalPlugin; import info.nightscout.androidaps.plugins.NSClientInternal.NSClientPlugin;
import info.nightscout.androidaps.plugins.OpenAPSAMA.OpenAPSAMAPlugin; import info.nightscout.androidaps.plugins.OpenAPSAMA.OpenAPSAMAPlugin;
import info.nightscout.androidaps.plugins.OpenAPSMA.OpenAPSMAPlugin; import info.nightscout.androidaps.plugins.OpenAPSMA.OpenAPSMAPlugin;
import info.nightscout.androidaps.plugins.OpenAPSSMB.OpenAPSSMBPlugin;
import info.nightscout.androidaps.plugins.PumpCombo.ComboPlugin;
import info.nightscout.androidaps.plugins.PumpDanaR.DanaRPlugin; import info.nightscout.androidaps.plugins.PumpDanaR.DanaRPlugin;
import info.nightscout.androidaps.plugins.PumpDanaRKorean.DanaRKoreanPlugin; import info.nightscout.androidaps.plugins.PumpDanaRKorean.DanaRKoreanPlugin;
import info.nightscout.androidaps.plugins.PumpDanaRS.DanaRSPlugin; import info.nightscout.androidaps.plugins.PumpDanaRS.DanaRSPlugin;
import info.nightscout.androidaps.plugins.PumpDanaRv2.DanaRv2Plugin; import info.nightscout.androidaps.plugins.PumpDanaRv2.DanaRv2Plugin;
import info.nightscout.androidaps.plugins.PumpInsight.InsightPlugin;
import info.nightscout.androidaps.plugins.PumpVirtual.VirtualPumpPlugin; import info.nightscout.androidaps.plugins.PumpVirtual.VirtualPumpPlugin;
import info.nightscout.androidaps.plugins.SensitivityAAPS.SensitivityAAPSPlugin; import info.nightscout.androidaps.plugins.SensitivityAAPS.SensitivityAAPSPlugin;
import info.nightscout.androidaps.plugins.SensitivityOref0.SensitivityOref0Plugin; import info.nightscout.androidaps.plugins.SensitivityOref0.SensitivityOref0Plugin;
import info.nightscout.androidaps.plugins.SensitivityWeightedAverage.SensitivityWeightedAveragePlugin; import info.nightscout.androidaps.plugins.SensitivityWeightedAverage.SensitivityWeightedAveragePlugin;
import info.nightscout.androidaps.plugins.SmsCommunicator.SmsCommunicatorPlugin; import info.nightscout.androidaps.plugins.SmsCommunicator.SmsCommunicatorPlugin;
import info.nightscout.androidaps.plugins.SourceDexcomG5.SourceDexcomG5Plugin; import info.nightscout.androidaps.plugins.Source.SourceDexcomG5Plugin;
import info.nightscout.androidaps.plugins.Wear.WearPlugin; import info.nightscout.androidaps.plugins.Wear.WearPlugin;
import info.nightscout.androidaps.plugins.XDripStatusline.StatuslinePlugin; import info.nightscout.androidaps.plugins.XDripStatusline.StatuslinePlugin;
import info.nightscout.utils.LocaleHelper; import info.nightscout.utils.LocaleHelper;
@ -58,14 +61,15 @@ public class PreferencesActivity extends PreferenceActivity implements SharedPre
if (key.equals("language")) { if (key.equals("language")) {
String lang = sharedPreferences.getString("language", "en"); String lang = sharedPreferences.getString("language", "en");
LocaleHelper.setLocale(getApplicationContext(), lang); LocaleHelper.setLocale(getApplicationContext(), lang);
recreate(); MainApp.bus().post(new EventRefreshGui(true));
MainApp.bus().post(new EventRefreshGui()); //recreate() does not update language so better close settings
finish();
} }
if (key.equals("short_tabtitles")) { if (key.equals("short_tabtitles")) {
MainApp.bus().post(new EventRefreshGui()); MainApp.bus().post(new EventRefreshGui());
} }
if (key.equals("openapsama_useautosens") && SP.getBoolean("openapsama_useautosens", false)) { if (key.equals(MainApp.gs(R.string.key_openapsama_useautosens)) && SP.getBoolean(R.string.key_openapsama_useautosens, false)) {
OKDialog.show(this, MainApp.sResources.getString(R.string.configbuilder_sensitivity), MainApp.sResources.getString(R.string.sensitivity_warning), null); OKDialog.show(this, MainApp.gs(R.string.configbuilder_sensitivity), MainApp.gs(R.string.sensitivity_warning), null);
} }
updatePrefSummary(myPreferenceFragment.getPreference(key)); updatePrefSummary(myPreferenceFragment.getPreference(key));
} }
@ -79,13 +83,13 @@ public class PreferencesActivity extends PreferenceActivity implements SharedPre
EditTextPreference editTextPref = (EditTextPreference) pref; EditTextPreference editTextPref = (EditTextPreference) pref;
if (pref.getKey().contains("password") || pref.getKey().contains("secret")) { if (pref.getKey().contains("password") || pref.getKey().contains("secret")) {
pref.setSummary("******"); pref.setSummary("******");
} else if (pref.getKey().equals(MainApp.sResources.getString(R.string.key_danars_name))) { } else if (pref.getKey().equals(MainApp.gs(R.string.key_danars_name))) {
pref.setSummary(SP.getString(R.string.key_danars_name, "")); pref.setSummary(SP.getString(R.string.key_danars_name, ""));
} else if (editTextPref.getText() != null && !editTextPref.getText().equals("")) { } else if (editTextPref.getText() != null && !editTextPref.getText().equals("")) {
((EditTextPreference) pref).setDialogMessage(editTextPref.getDialogMessage()); ((EditTextPreference) pref).setDialogMessage(editTextPref.getDialogMessage());
pref.setSummary(editTextPref.getText()); pref.setSummary(editTextPref.getText());
} else if (pref.getKey().contains("smscommunicator_allowednumbers") && TextUtils.isEmpty(editTextPref.getText().trim())) { } else if (pref.getKey().contains("smscommunicator_allowednumbers") && TextUtils.isEmpty(editTextPref.getText().trim())) {
pref.setSummary(MainApp.sResources.getString(R.string.smscommunicator_allowednumbers_summary)); pref.setSummary(MainApp.gs(R.string.smscommunicator_allowednumbers_summary));
} }
} }
} }
@ -110,7 +114,7 @@ public class PreferencesActivity extends PreferenceActivity implements SharedPre
id = args.getInt("id"); id = args.getInt("id");
} }
void addPreferencesFromResourceIfEnabled(PluginBase p, int type) { void addPreferencesFromResourceIfEnabled(PluginBase p, PluginType type) {
if (p.isEnabled(type) && p.getPreferencesId() != -1) if (p.isEnabled(type) && p.getPreferencesId() != -1)
addPreferencesFromResource(p.getPreferencesId()); addPreferencesFromResource(p.getPreferencesId());
} }
@ -125,64 +129,62 @@ public class PreferencesActivity extends PreferenceActivity implements SharedPre
if (id != -1) { if (id != -1) {
addPreferencesFromResource(id); addPreferencesFromResource(id);
addPreferencesFromResource(R.xml.pref_advanced);
} else { } else {
if (!Config.NSCLIENT && !Config.G5UPLOADER) { if (!Config.NSCLIENT && !Config.G5UPLOADER) {
addPreferencesFromResource(R.xml.pref_password); addPreferencesFromResource(R.xml.pref_password);
} }
addPreferencesFromResource(R.xml.pref_age); addPreferencesFromResource(R.xml.pref_age);
addPreferencesFromResource(R.xml.pref_language); addPreferencesFromResource(R.xml.pref_language);
if (!Config.NSCLIENT && !Config.G5UPLOADER) { addPreferencesFromResource(R.xml.pref_overview);
addPreferencesFromResource(R.xml.pref_quickwizard);
} addPreferencesFromResourceIfEnabled(SourceDexcomG5Plugin.getPlugin(), PluginType.BGSOURCE);
addPreferencesFromResourceIfEnabled(SourceDexcomG5Plugin.getPlugin(), PluginBase.BGSOURCE); addPreferencesFromResourceIfEnabled(CareportalPlugin.getPlugin(), PluginType.GENERAL);
addPreferencesFromResourceIfEnabled(CareportalPlugin.getPlugin(), PluginBase.GENERAL); addPreferencesFromResourceIfEnabled(SafetyPlugin.getPlugin(), PluginType.CONSTRAINTS);
addPreferencesFromResourceIfEnabled(SafetyPlugin.getPlugin(), PluginBase.CONSTRAINTS);
if (Config.APS) { if (Config.APS) {
addPreferencesFromResourceIfEnabled(LoopPlugin.getPlugin(), PluginBase.LOOP); addPreferencesFromResourceIfEnabled(LoopPlugin.getPlugin(), PluginType.LOOP);
addPreferencesFromResourceIfEnabled(OpenAPSMAPlugin.getPlugin(), PluginBase.APS); addPreferencesFromResourceIfEnabled(OpenAPSMAPlugin.getPlugin(), PluginType.APS);
addPreferencesFromResourceIfEnabled(OpenAPSAMAPlugin.getPlugin(), PluginBase.APS); addPreferencesFromResourceIfEnabled(OpenAPSAMAPlugin.getPlugin(), PluginType.APS);
addPreferencesFromResourceIfEnabled(OpenAPSSMBPlugin.getPlugin(), PluginType.APS);
} }
addPreferencesFromResourceIfEnabled(SensitivityAAPSPlugin.getPlugin(), PluginBase.SENSITIVITY); addPreferencesFromResourceIfEnabled(SensitivityAAPSPlugin.getPlugin(), PluginType.SENSITIVITY);
addPreferencesFromResourceIfEnabled(SensitivityWeightedAveragePlugin.getPlugin(), PluginBase.SENSITIVITY); addPreferencesFromResourceIfEnabled(SensitivityWeightedAveragePlugin.getPlugin(), PluginType.SENSITIVITY);
addPreferencesFromResourceIfEnabled(SensitivityOref0Plugin.getPlugin(), PluginBase.SENSITIVITY); addPreferencesFromResourceIfEnabled(SensitivityOref0Plugin.getPlugin(), PluginType.SENSITIVITY);
if (!Config.NSCLIENT && !Config.G5UPLOADER) { if (Config.HWPUMPS) {
addPreferencesFromResource(R.xml.pref_profile); addPreferencesFromResourceIfEnabled(DanaRPlugin.getPlugin(), PluginType.PUMP);
} addPreferencesFromResourceIfEnabled(DanaRKoreanPlugin.getPlugin(), PluginType.PUMP);
addPreferencesFromResourceIfEnabled(DanaRv2Plugin.getPlugin(), PluginType.PUMP);
addPreferencesFromResourceIfEnabled(DanaRSPlugin.getPlugin(), PluginType.PUMP);
addPreferencesFromResourceIfEnabled(InsightPlugin.getPlugin(), PluginType.PUMP);
addPreferencesFromResourceIfEnabled(ComboPlugin.getPlugin(), PluginType.PUMP);
if (Config.DANAR) { if (DanaRPlugin.getPlugin().isEnabled(PluginType.PROFILE)
addPreferencesFromResourceIfEnabled(DanaRPlugin.getPlugin(), PluginBase.PUMP); || DanaRKoreanPlugin.getPlugin().isEnabled(PluginType.PROFILE)
addPreferencesFromResourceIfEnabled(DanaRKoreanPlugin.getPlugin(), PluginBase.PUMP); || DanaRv2Plugin.getPlugin().isEnabled(PluginType.PROFILE)
addPreferencesFromResourceIfEnabled(DanaRv2Plugin.getPlugin(), PluginBase.PUMP); || DanaRSPlugin.getPlugin().isEnabled(PluginType.PROFILE)) {
addPreferencesFromResourceIfEnabled(DanaRSPlugin.getPlugin(), PluginBase.PUMP);
if (DanaRPlugin.getPlugin().isEnabled(PluginBase.PROFILE)
|| DanaRKoreanPlugin.getPlugin().isEnabled(PluginBase.PROFILE)
|| DanaRv2Plugin.getPlugin().isEnabled(PluginBase.PROFILE)
|| DanaRSPlugin.getPlugin().isEnabled(PluginBase.PROFILE)) {
addPreferencesFromResource(R.xml.pref_danarprofile); addPreferencesFromResource(R.xml.pref_danarprofile);
} }
} }
if (!Config.NSCLIENT && !Config.G5UPLOADER) { if (!Config.NSCLIENT && !Config.G5UPLOADER) {
addPreferencesFromResourceIfEnabled(VirtualPumpPlugin.getPlugin(), PluginBase.PUMP); addPreferencesFromResourceIfEnabled(VirtualPumpPlugin.getPlugin(), PluginType.PUMP);
} }
addPreferencesFromResourceIfEnabled(InsulinOrefFreePeakPlugin.getPlugin(), PluginBase.INSULIN); addPreferencesFromResourceIfEnabled(InsulinOrefFreePeakPlugin.getPlugin(), PluginType.INSULIN);
addPreferencesFromResourceIfEnabled(NSClientInternalPlugin.getPlugin(), PluginBase.GENERAL); addPreferencesFromResourceIfEnabled(NSClientPlugin.getPlugin(), PluginType.GENERAL);
addPreferencesFromResourceIfEnabled(SmsCommunicatorPlugin.getPlugin(), PluginBase.GENERAL); addPreferencesFromResourceIfEnabled(SmsCommunicatorPlugin.getPlugin(), PluginType.GENERAL);
if (!Config.NSCLIENT && !Config.G5UPLOADER) { if (!Config.NSCLIENT && !Config.G5UPLOADER) {
addPreferencesFromResource(R.xml.pref_others); addPreferencesFromResource(R.xml.pref_others);
} }
addPreferencesFromResource(R.xml.pref_advanced); addPreferencesFromResource(R.xml.pref_datachoices);
addPreferencesFromResourceIfEnabled(WearPlugin.getPlugin(), PluginBase.GENERAL); addPreferencesFromResourceIfEnabled(WearPlugin.getPlugin(), PluginType.GENERAL);
addPreferencesFromResourceIfEnabled(StatuslinePlugin.getPlugin(), PluginBase.GENERAL); addPreferencesFromResourceIfEnabled(StatuslinePlugin.getPlugin(), PluginType.GENERAL);
} }
initSummary(getPreferenceScreen()); initSummary(getPreferenceScreen());

View file

@ -1,8 +1,10 @@
package info.nightscout.androidaps.Services; package info.nightscout.androidaps.Services;
import android.app.Service; import android.app.Service;
import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.res.AssetFileDescriptor; import android.content.res.AssetFileDescriptor;
import android.media.AudioManager;
import android.media.MediaPlayer; import android.media.MediaPlayer;
import android.os.IBinder; import android.os.IBinder;
@ -53,7 +55,10 @@ public class AlarmSoundService extends Service {
log.error("Unhandled exception", e); log.error("Unhandled exception", e);
} }
player.setLooping(true); // Set looping player.setLooping(true); // Set looping
player.setVolume(100, 100); AudioManager manager = (AudioManager)this.getSystemService(Context.AUDIO_SERVICE);
if (manager == null || !manager.isMusicActive()) {
player.setVolume(100, 100);
}
try { try {
player.prepare(); player.prepare();

View file

@ -15,30 +15,33 @@ import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.Config; import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.ProfileStore;
import info.nightscout.androidaps.db.BgReading; import info.nightscout.androidaps.db.BgReading;
import info.nightscout.androidaps.db.CareportalEvent; import info.nightscout.androidaps.db.CareportalEvent;
import info.nightscout.androidaps.events.EventNewBasalProfile; import info.nightscout.androidaps.events.EventNsFood;
import info.nightscout.androidaps.events.EventNsTreatment;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.ConstraintsObjectives.ObjectivesPlugin; import info.nightscout.androidaps.plugins.ConstraintsObjectives.ObjectivesPlugin;
import info.nightscout.androidaps.plugins.NSClientInternal.data.NSDeviceStatus;
import info.nightscout.androidaps.plugins.NSClientInternal.data.NSMbg; import info.nightscout.androidaps.plugins.NSClientInternal.data.NSMbg;
import info.nightscout.androidaps.plugins.NSClientInternal.data.NSSgv;
import info.nightscout.androidaps.data.ProfileStore;
import info.nightscout.androidaps.plugins.NSClientInternal.data.NSSettingsStatus; import info.nightscout.androidaps.plugins.NSClientInternal.data.NSSettingsStatus;
import info.nightscout.androidaps.plugins.Overview.notifications.Notification; import info.nightscout.androidaps.plugins.NSClientInternal.data.NSSgv;
import info.nightscout.androidaps.plugins.Overview.OverviewPlugin; import info.nightscout.androidaps.plugins.Overview.OverviewPlugin;
import info.nightscout.androidaps.plugins.Overview.events.EventDismissNotification; import info.nightscout.androidaps.plugins.Overview.events.EventDismissNotification;
import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification; import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification;
import info.nightscout.androidaps.plugins.Overview.notifications.Notification;
import info.nightscout.androidaps.plugins.ProfileNS.NSProfilePlugin; import info.nightscout.androidaps.plugins.ProfileNS.NSProfilePlugin;
import info.nightscout.androidaps.plugins.ProfileNS.events.EventNSProfileUpdateGUI;
import info.nightscout.androidaps.plugins.PumpDanaR.activities.DanaRNSHistorySync; import info.nightscout.androidaps.plugins.PumpDanaR.activities.DanaRNSHistorySync;
import info.nightscout.androidaps.plugins.SmsCommunicator.events.EventNewSMS; import info.nightscout.androidaps.plugins.SmsCommunicator.events.EventNewSMS;
import info.nightscout.androidaps.plugins.SourceDexcomG5.SourceDexcomG5Plugin; import info.nightscout.androidaps.plugins.Source.SourceDexcomG5Plugin;
import info.nightscout.androidaps.plugins.SourceGlimp.SourceGlimpPlugin; import info.nightscout.androidaps.plugins.Source.SourceGlimpPlugin;
import info.nightscout.androidaps.plugins.SourceMM640g.SourceMM640gPlugin; import info.nightscout.androidaps.plugins.Source.SourceMM640gPlugin;
import info.nightscout.androidaps.plugins.SourceNSClient.SourceNSClientPlugin; import info.nightscout.androidaps.plugins.Source.SourceNSClientPlugin;
import info.nightscout.androidaps.plugins.SourceXdrip.SourceXdripPlugin; import info.nightscout.androidaps.plugins.Source.SourceXdripPlugin;
import info.nightscout.androidaps.receivers.DataReceiver; import info.nightscout.androidaps.receivers.DataReceiver;
import info.nightscout.androidaps.plugins.NSClientInternal.data.NSDeviceStatus;
import info.nightscout.utils.BundleLogger; import info.nightscout.utils.BundleLogger;
import info.nightscout.utils.JsonHelper;
import info.nightscout.utils.NSUpload; import info.nightscout.utils.NSUpload;
import info.nightscout.utils.SP; import info.nightscout.utils.SP;
@ -61,32 +64,37 @@ public class DataService extends IntentService {
protected void onHandleIntent(final Intent intent) { protected void onHandleIntent(final Intent intent) {
if (Config.logFunctionCalls) if (Config.logFunctionCalls)
log.debug("onHandleIntent " + BundleLogger.log(intent.getExtras())); log.debug("onHandleIntent " + BundleLogger.log(intent.getExtras()));
if (ConfigBuilderPlugin.getPlugin().getActiveBgSource() == null) {
if (ConfigBuilderPlugin.getActiveBgSource().getClass().equals(SourceXdripPlugin.class)) {
xDripEnabled = true; xDripEnabled = true;
nsClientEnabled = false; nsClientEnabled = false;
mm640gEnabled = false; mm640gEnabled = false;
glimpEnabled = false; glimpEnabled = false;
dexcomG5Enabled = false; dexcomG5Enabled = false;
} else if (ConfigBuilderPlugin.getActiveBgSource().getClass().equals(SourceNSClientPlugin.class)) { } else if (ConfigBuilderPlugin.getPlugin().getActiveBgSource().getClass().equals(SourceXdripPlugin.class)) {
xDripEnabled = true;
nsClientEnabled = false;
mm640gEnabled = false;
glimpEnabled = false;
dexcomG5Enabled = false;
} else if (ConfigBuilderPlugin.getPlugin().getActiveBgSource().getClass().equals(SourceNSClientPlugin.class)) {
xDripEnabled = false; xDripEnabled = false;
nsClientEnabled = true; nsClientEnabled = true;
mm640gEnabled = false; mm640gEnabled = false;
glimpEnabled = false; glimpEnabled = false;
dexcomG5Enabled = false; dexcomG5Enabled = false;
} else if (ConfigBuilderPlugin.getActiveBgSource().getClass().equals(SourceMM640gPlugin.class)) { } else if (ConfigBuilderPlugin.getPlugin().getActiveBgSource().getClass().equals(SourceMM640gPlugin.class)) {
xDripEnabled = false; xDripEnabled = false;
nsClientEnabled = false; nsClientEnabled = false;
mm640gEnabled = true; mm640gEnabled = true;
glimpEnabled = false; glimpEnabled = false;
dexcomG5Enabled = false; dexcomG5Enabled = false;
} else if (ConfigBuilderPlugin.getActiveBgSource().getClass().equals(SourceGlimpPlugin.class)) { } else if (ConfigBuilderPlugin.getPlugin().getActiveBgSource().getClass().equals(SourceGlimpPlugin.class)) {
xDripEnabled = false; xDripEnabled = false;
nsClientEnabled = false; nsClientEnabled = false;
mm640gEnabled = false; mm640gEnabled = false;
glimpEnabled = true; glimpEnabled = true;
dexcomG5Enabled = false; dexcomG5Enabled = false;
} else if (ConfigBuilderPlugin.getActiveBgSource().getClass().equals(SourceDexcomG5Plugin.class)) { } else if (ConfigBuilderPlugin.getPlugin().getActiveBgSource().getClass().equals(SourceDexcomG5Plugin.class)) {
xDripEnabled = false; xDripEnabled = false;
nsClientEnabled = false; nsClientEnabled = false;
mm640gEnabled = false; mm640gEnabled = false;
@ -94,9 +102,14 @@ public class DataService extends IntentService {
dexcomG5Enabled = true; dexcomG5Enabled = true;
} }
boolean isNSProfile = ConfigBuilderPlugin.getActiveProfileInterface().getClass().equals(NSProfilePlugin.class); boolean isNSProfile = MainApp.getConfigBuilder().getActiveProfileInterface() != null && MainApp.getConfigBuilder().getActiveProfileInterface().getClass().equals(NSProfilePlugin.class);
boolean acceptNSData = !SP.getBoolean(R.string.key_ns_upload_only, false);
Bundle bundles = intent.getExtras();
if (bundles != null && bundles.containsKey("islocal")) {
acceptNSData = acceptNSData || bundles.getBoolean("islocal");
}
boolean nsUploadOnly = SP.getBoolean(R.string.key_ns_upload_only, false);
if (intent != null) { if (intent != null) {
final String action = intent.getAction(); final String action = intent.getAction();
@ -117,17 +130,15 @@ public class DataService extends IntentService {
handleNewDataFromDexcomG5(intent); handleNewDataFromDexcomG5(intent);
} }
} else if (Intents.ACTION_NEW_SGV.equals(action)) { } else if (Intents.ACTION_NEW_SGV.equals(action)) {
// always handle SGV if NS-Client is the source if (nsClientEnabled || SP.getBoolean(R.string.key_ns_autobackfill, true))
if (nsClientEnabled) {
handleNewDataFromNSClient(intent); handleNewDataFromNSClient(intent);
}
// Objectives 0 // Objectives 0
ObjectivesPlugin.bgIsAvailableInNS = true; ObjectivesPlugin.bgIsAvailableInNS = true;
ObjectivesPlugin.saveProgress(); ObjectivesPlugin.saveProgress();
} else if (isNSProfile && Intents.ACTION_NEW_PROFILE.equals(action) || Intents.ACTION_NEW_DEVICESTATUS.equals(action)) { } else if (isNSProfile && Intents.ACTION_NEW_PROFILE.equals(action) || Intents.ACTION_NEW_DEVICESTATUS.equals(action)) {
// always handle Profile if NSProfile is enabled without looking at nsUploadOnly // always handle Profile if NSProfile is enabled without looking at nsUploadOnly
handleNewDataFromNSClient(intent); handleNewDataFromNSClient(intent);
} else if (!nsUploadOnly && } else if (acceptNSData &&
(Intents.ACTION_NEW_TREATMENT.equals(action) || (Intents.ACTION_NEW_TREATMENT.equals(action) ||
Intents.ACTION_CHANGED_TREATMENT.equals(action) || Intents.ACTION_CHANGED_TREATMENT.equals(action) ||
Intents.ACTION_REMOVED_TREATMENT.equals(action) || Intents.ACTION_REMOVED_TREATMENT.equals(action) ||
@ -186,7 +197,8 @@ public class DataService extends IntentService {
bgReading.direction = bundle.getString(Intents.EXTRA_BG_SLOPE_NAME); bgReading.direction = bundle.getString(Intents.EXTRA_BG_SLOPE_NAME);
bgReading.date = bundle.getLong(Intents.EXTRA_TIMESTAMP); bgReading.date = bundle.getLong(Intents.EXTRA_TIMESTAMP);
bgReading.raw = bundle.getDouble(Intents.EXTRA_RAW); bgReading.raw = bundle.getDouble(Intents.EXTRA_RAW);
String source = bundle.getString(Intents.XDRIP_DATA_SOURCE_DESCRIPTION, "no Source specified");
SourceXdripPlugin.getPlugin().setSource(source);
MainApp.getDbHelper().createIfNotExists(bgReading, "XDRIP"); MainApp.getDbHelper().createIfNotExists(bgReading, "XDRIP");
} }
@ -218,7 +230,7 @@ public class DataService extends IntentService {
try { try {
JSONArray jsonArray = new JSONArray(data); JSONArray jsonArray = new JSONArray(data);
log.debug("Received Dexcom Data size:" + jsonArray.length()); log.debug("Received Dexcom Data size:" + jsonArray.length());
for(int i = 0; i < jsonArray.length(); i++) { for (int i = 0; i < jsonArray.length(); i++) {
JSONObject json = jsonArray.getJSONObject(i); JSONObject json = jsonArray.getJSONObject(i);
bgReading.value = json.getInt("m_value"); bgReading.value = json.getInt("m_value");
bgReading.direction = json.getString("m_trend"); bgReading.direction = json.getString("m_trend");
@ -228,6 +240,9 @@ public class DataService extends IntentService {
if (isNew && SP.getBoolean(R.string.key_dexcomg5_nsupload, false)) { if (isNew && SP.getBoolean(R.string.key_dexcomg5_nsupload, false)) {
NSUpload.uploadBg(bgReading); NSUpload.uploadBg(bgReading);
} }
if (isNew && SP.getBoolean(R.string.key_dexcomg5_xdripupload, false)) {
NSUpload.sendToXdrip(bgReading);
}
} }
} catch (JSONException e) { } catch (JSONException e) {
@ -289,7 +304,7 @@ public class DataService extends IntentService {
log.debug("Got versions: NSClient: " + ConfigBuilderPlugin.nsClientVersionName + " Nightscout: " + ConfigBuilderPlugin.nightscoutVersionName); log.debug("Got versions: NSClient: " + ConfigBuilderPlugin.nsClientVersionName + " Nightscout: " + ConfigBuilderPlugin.nightscoutVersionName);
try { try {
if (ConfigBuilderPlugin.nsClientVersionCode < MainApp.instance().getPackageManager().getPackageInfo(MainApp.instance().getPackageName(), 0).versionCode) { if (ConfigBuilderPlugin.nsClientVersionCode < MainApp.instance().getPackageManager().getPackageInfo(MainApp.instance().getPackageName(), 0).versionCode) {
Notification notification = new Notification(Notification.OLD_NSCLIENT, MainApp.sResources.getString(R.string.unsupportedclientver), Notification.URGENT); Notification notification = new Notification(Notification.OLD_NSCLIENT, MainApp.gs(R.string.unsupportedclientver), Notification.URGENT);
MainApp.bus().post(new EventNewNotification(notification)); MainApp.bus().post(new EventNewNotification(notification));
} else { } else {
MainApp.bus().post(new EventDismissNotification(Notification.OLD_NSCLIENT)); MainApp.bus().post(new EventDismissNotification(Notification.OLD_NSCLIENT));
@ -298,13 +313,13 @@ public class DataService extends IntentService {
log.error("Unhandled exception", e); log.error("Unhandled exception", e);
} }
if (ConfigBuilderPlugin.nightscoutVersionCode < Config.SUPPORTEDNSVERSION) { if (ConfigBuilderPlugin.nightscoutVersionCode < Config.SUPPORTEDNSVERSION) {
Notification notification = new Notification(Notification.OLD_NS, MainApp.sResources.getString(R.string.unsupportednsversion), Notification.URGENT); Notification notification = new Notification(Notification.OLD_NS, MainApp.gs(R.string.unsupportednsversion), Notification.NORMAL);
MainApp.bus().post(new EventNewNotification(notification)); MainApp.bus().post(new EventNewNotification(notification));
} else { } else {
MainApp.bus().post(new EventDismissNotification(Notification.OLD_NS)); MainApp.bus().post(new EventDismissNotification(Notification.OLD_NS));
} }
} else { } else {
Notification notification = new Notification(Notification.OLD_NSCLIENT, MainApp.sResources.getString(R.string.unsupportedclientver), Notification.URGENT); Notification notification = new Notification(Notification.OLD_NSCLIENT, MainApp.gs(R.string.unsupportedclientver), Notification.URGENT);
MainApp.bus().post(new EventNewNotification(notification)); MainApp.bus().post(new EventNewNotification(notification));
} }
if (bundles.containsKey("status")) { if (bundles.containsKey("status")) {
@ -358,9 +373,8 @@ public class DataService extends IntentService {
String activeProfile = bundles.getString("activeprofile"); String activeProfile = bundles.getString("activeprofile");
String profile = bundles.getString("profile"); String profile = bundles.getString("profile");
ProfileStore profileStore = new ProfileStore(new JSONObject(profile)); ProfileStore profileStore = new ProfileStore(new JSONObject(profile));
NSProfilePlugin.storeNewProfile(profileStore); NSProfilePlugin.getPlugin().storeNewProfile(profileStore);
MainApp.bus().post(new EventNewBasalProfile()); MainApp.bus().post(new EventNSProfileUpdateGUI());
if (Config.logIncommingData) if (Config.logIncommingData)
log.debug("Received profileStore: " + activeProfile + " " + profile); log.debug("Received profileStore: " + activeProfile + " " + profile);
} catch (JSONException e) { } catch (JSONException e) {
@ -371,19 +385,18 @@ public class DataService extends IntentService {
if (intent.getAction().equals(Intents.ACTION_NEW_TREATMENT) || intent.getAction().equals(Intents.ACTION_CHANGED_TREATMENT)) { if (intent.getAction().equals(Intents.ACTION_NEW_TREATMENT) || intent.getAction().equals(Intents.ACTION_CHANGED_TREATMENT)) {
try { try {
if (bundles.containsKey("treatment")) { if (bundles.containsKey("treatment")) {
String trstring = bundles.getString("treatment"); JSONObject json = new JSONObject(bundles.getString("treatment"));
handleAddChangeDataFromNS(trstring); handleTreatmentFromNS(json, intent);
} }
if (bundles.containsKey("treatments")) { if (bundles.containsKey("treatments")) {
String trstring = bundles.getString("treatments"); String trstring = bundles.getString("treatments");
JSONArray jsonArray = new JSONArray(trstring); JSONArray jsonArray = new JSONArray(trstring);
for (int i = 0; i < jsonArray.length(); i++) { for (int i = 0; i < jsonArray.length(); i++) {
JSONObject trJson = jsonArray.getJSONObject(i); JSONObject json = jsonArray.getJSONObject(i);
String trstr = trJson.toString(); handleTreatmentFromNS(json, intent);
handleAddChangeDataFromNS(trstr);
} }
} }
} catch (Exception e) { } catch (JSONException e) {
log.error("Unhandled exception", e); log.error("Unhandled exception", e);
} }
} }
@ -392,21 +405,19 @@ public class DataService extends IntentService {
try { try {
if (bundles.containsKey("treatment")) { if (bundles.containsKey("treatment")) {
String trstring = bundles.getString("treatment"); String trstring = bundles.getString("treatment");
JSONObject trJson = new JSONObject(trstring); JSONObject json = new JSONObject(trstring);
String _id = trJson.getString("_id"); handleTreatmentFromNS(json);
handleRemovedRecordFromNS(_id);
} }
if (bundles.containsKey("treatments")) { if (bundles.containsKey("treatments")) {
String trstring = bundles.getString("treatments"); String trstring = bundles.getString("treatments");
JSONArray jsonArray = new JSONArray(trstring); JSONArray jsonArray = new JSONArray(trstring);
for (int i = 0; i < jsonArray.length(); i++) { for (int i = 0; i < jsonArray.length(); i++) {
JSONObject trJson = jsonArray.getJSONObject(i); JSONObject json = jsonArray.getJSONObject(i);
String _id = trJson.getString("_id"); handleTreatmentFromNS(json);
handleRemovedRecordFromNS(_id);
} }
} }
} catch (Exception e) { } catch (JSONException e) {
log.error("Unhandled exception", e); log.error("Unhandled exception", e);
} }
} }
@ -465,59 +476,25 @@ public class DataService extends IntentService {
} }
} }
if (intent.getAction().equals(Intents.ACTION_NEW_FOOD) || intent.getAction().equals(Intents.ACTION_CHANGED_FOOD)) { if (intent.getAction().equals(Intents.ACTION_NEW_FOOD)
try { || intent.getAction().equals(Intents.ACTION_CHANGED_FOOD)) {
if (bundles.containsKey("food")) { int mode = Intents.ACTION_NEW_FOOD.equals(intent.getAction()) ? EventNsFood.ADD : EventNsFood.UPDATE;
String trstring = bundles.getString("food"); EventNsFood evt = new EventNsFood(mode, bundles);
handleAddChangeFoodRecord(new JSONObject(trstring)); MainApp.bus().post(evt);
}
if (bundles.containsKey("foods")) {
String trstring = bundles.getString("foods");
JSONArray jsonArray = new JSONArray(trstring);
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject trJson = jsonArray.getJSONObject(i);
handleAddChangeFoodRecord(trJson);
}
}
} catch (Exception e) {
log.error("Unhandled exception", e);
}
} }
if (intent.getAction().equals(Intents.ACTION_REMOVED_FOOD)) { if (intent.getAction().equals(Intents.ACTION_REMOVED_FOOD)) {
try { EventNsFood evt = new EventNsFood(EventNsFood.REMOVE, bundles);
if (bundles.containsKey("food")) { MainApp.bus().post(evt);
String trstring = bundles.getString("food");
JSONObject trJson = new JSONObject(trstring);
String _id = trJson.getString("_id");
handleRemovedFoodRecord(_id);
}
if (bundles.containsKey("foods")) {
String trstring = bundles.getString("foods");
JSONArray jsonArray = new JSONArray(trstring);
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject trJson = jsonArray.getJSONObject(i);
String _id = trJson.getString("_id");
handleRemovedFoodRecord(_id);
}
}
} catch (Exception e) {
log.error("Unhandled exception", e);
}
} }
} }
private void handleRemovedFoodRecord(String _id) { private void handleTreatmentFromNS(JSONObject json) {
MainApp.getDbHelper().foodHelper.deleteFoodById(_id); // new DB model
} EventNsTreatment evtTreatment = new EventNsTreatment(EventNsTreatment.REMOVE, json);
MainApp.bus().post(evtTreatment);
public void handleAddChangeFoodRecord(JSONObject trJson) throws JSONException { // old DB model
MainApp.getDbHelper().foodHelper.createFoodFromJsonIfNotExists(trJson); String _id = JsonHelper.safeGetString(json, "_id");
}
private void handleRemovedRecordFromNS(String _id) {
MainApp.getDbHelper().deleteTreatmentById(_id);
MainApp.getDbHelper().deleteTempTargetById(_id); MainApp.getDbHelper().deleteTempTargetById(_id);
MainApp.getDbHelper().deleteTempBasalById(_id); MainApp.getDbHelper().deleteTempBasalById(_id);
MainApp.getDbHelper().deleteExtendedBolusById(_id); MainApp.getDbHelper().deleteExtendedBolusById(_id);
@ -525,85 +502,53 @@ public class DataService extends IntentService {
MainApp.getDbHelper().deleteProfileSwitchById(_id); MainApp.getDbHelper().deleteProfileSwitchById(_id);
} }
private void handleAddChangeDataFromNS(String trstring) throws JSONException { private void handleTreatmentFromNS(JSONObject json, Intent intent) throws JSONException {
JSONObject trJson = new JSONObject(trstring); // new DB model
handleDanaRHistoryRecords(trJson); // update record _id in history int mode = Intents.ACTION_NEW_TREATMENT.equals(intent.getAction()) ? EventNsTreatment.ADD : EventNsTreatment.UPDATE;
handleAddChangeTempTargetRecord(trJson); double insulin = JsonHelper.safeGetDouble(json, "insulin");
handleAddChangeTempBasalRecord(trJson); double carbs = JsonHelper.safeGetDouble(json, "carbs");
handleAddChangeExtendedBolusRecord(trJson); String eventType = JsonHelper.safeGetString(json, "eventType");
handleAddChangeCareportalEventRecord(trJson); if (insulin > 0 || carbs > 0) {
handleAddChangeTreatmentRecord(trJson); EventNsTreatment evtTreatment = new EventNsTreatment(mode, json);
handleAddChangeProfileSwitchRecord(trJson); MainApp.bus().post(evtTreatment);
} } else if (json.has(DanaRNSHistorySync.DANARSIGNATURE)) {
// old DB model
public void handleDanaRHistoryRecords(JSONObject trJson) { MainApp.getDbHelper().updateDanaRHistoryRecordId(json);
if (trJson.has(DanaRNSHistorySync.DANARSIGNATURE)) { } else if (eventType.equals(CareportalEvent.TEMPORARYTARGET)) {
MainApp.getDbHelper().updateDanaRHistoryRecordId(trJson); MainApp.getDbHelper().createTemptargetFromJsonIfNotExists(json);
} } else if (eventType.equals(CareportalEvent.TEMPBASAL)) {
} MainApp.getDbHelper().createTempBasalFromJsonIfNotExists(json);
} else if (eventType.equals(CareportalEvent.COMBOBOLUS)) {
public void handleAddChangeTreatmentRecord(JSONObject trJson) throws JSONException { MainApp.getDbHelper().createExtendedBolusFromJsonIfNotExists(json);
if (trJson.has("insulin") || trJson.has("carbs")) { } else if (eventType.equals(CareportalEvent.PROFILESWITCH)) {
MainApp.getDbHelper().createTreatmentFromJsonIfNotExists(trJson); MainApp.getDbHelper().createProfileSwitchFromJsonIfNotExists(json);
return; } else if (eventType.equals(CareportalEvent.SITECHANGE) ||
} eventType.equals(CareportalEvent.INSULINCHANGE) ||
} eventType.equals(CareportalEvent.SENSORCHANGE) ||
eventType.equals(CareportalEvent.BGCHECK) ||
public void handleAddChangeTempTargetRecord(JSONObject trJson) throws JSONException { eventType.equals(CareportalEvent.NOTE) ||
if (trJson.has("eventType") && trJson.getString("eventType").equals(CareportalEvent.TEMPORARYTARGET)) { eventType.equals(CareportalEvent.NONE) ||
MainApp.getDbHelper().createTemptargetFromJsonIfNotExists(trJson); eventType.equals(CareportalEvent.ANNOUNCEMENT) ||
} eventType.equals(CareportalEvent.QUESTION) ||
} eventType.equals(CareportalEvent.EXERCISE) ||
eventType.equals(CareportalEvent.OPENAPSOFFLINE) ||
public void handleAddChangeTempBasalRecord(JSONObject trJson) throws JSONException { eventType.equals(CareportalEvent.PUMPBATTERYCHANGE)) {
if (trJson.has("eventType") && trJson.getString("eventType").equals(CareportalEvent.TEMPBASAL)) { MainApp.getDbHelper().createCareportalEventFromJsonIfNotExists(json);
MainApp.getDbHelper().createTempBasalFromJsonIfNotExists(trJson);
}
}
public void handleAddChangeExtendedBolusRecord(JSONObject trJson) throws JSONException {
if (trJson.has("eventType") && trJson.getString("eventType").equals(CareportalEvent.COMBOBOLUS)) {
MainApp.getDbHelper().createExtendedBolusFromJsonIfNotExists(trJson);
}
}
public void handleAddChangeCareportalEventRecord(JSONObject trJson) throws JSONException {
if (trJson.has("insulin") && trJson.getDouble("insulin") > 0)
return;
if (trJson.has("carbs") && trJson.getDouble("carbs") > 0)
return;
if (trJson.has("eventType") && (
trJson.getString("eventType").equals(CareportalEvent.SITECHANGE) ||
trJson.getString("eventType").equals(CareportalEvent.INSULINCHANGE) ||
trJson.getString("eventType").equals(CareportalEvent.SENSORCHANGE) ||
trJson.getString("eventType").equals(CareportalEvent.BGCHECK) ||
trJson.getString("eventType").equals(CareportalEvent.NOTE) ||
trJson.getString("eventType").equals(CareportalEvent.NONE) ||
trJson.getString("eventType").equals(CareportalEvent.ANNOUNCEMENT) ||
trJson.getString("eventType").equals(CareportalEvent.QUESTION) ||
trJson.getString("eventType").equals(CareportalEvent.EXERCISE) ||
trJson.getString("eventType").equals(CareportalEvent.OPENAPSOFFLINE) ||
trJson.getString("eventType").equals(CareportalEvent.PUMPBATTERYCHANGE)
)) {
MainApp.getDbHelper().createCareportalEventFromJsonIfNotExists(trJson);
} }
if (trJson.has("eventType") && trJson.getString("eventType").equals(CareportalEvent.ANNOUNCEMENT)) { if (eventType.equals(CareportalEvent.ANNOUNCEMENT)) {
long date = trJson.getLong("mills"); long date = JsonHelper.safeGetLong(json,"mills");
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
if (date > now - 15 * 60 * 1000L && trJson.has("notes")) { String enteredBy = JsonHelper.safeGetString(json, "enteredBy", "");
Notification announcement = new Notification(Notification.NSANNOUNCEMENT, trJson.getString("notes"), Notification.ANNOUNCEMENT, 60); String notes = JsonHelper.safeGetString(json, "notes", "");
if (date > now - 15 * 60 * 1000L && !notes.isEmpty()
&& !enteredBy.equals(SP.getString("careportal_enteredby", "AndroidAPS"))) {
Notification announcement = new Notification(Notification.NSANNOUNCEMENT, notes, Notification.ANNOUNCEMENT, 60);
MainApp.bus().post(new EventNewNotification(announcement)); MainApp.bus().post(new EventNewNotification(announcement));
} }
} }
} }
public void handleAddChangeProfileSwitchRecord(JSONObject trJson) throws JSONException {
if (trJson.has("eventType") && trJson.getString("eventType").equals(CareportalEvent.PROFILESWITCH)) {
MainApp.getDbHelper().createProfileSwitchFromJsonIfNotExists(trJson);
}
}
private void handleNewSMS(Intent intent) { private void handleNewSMS(Intent intent) {
Bundle bundle = intent.getExtras(); Bundle bundle = intent.getExtras();
if (bundle == null) return; if (bundle == null) return;

View file

@ -37,6 +37,8 @@ public interface Intents {
String EXTRA_SENSOR_BATTERY = "com.eveningoutpost.dexdrip.Extras.SensorBattery"; String EXTRA_SENSOR_BATTERY = "com.eveningoutpost.dexdrip.Extras.SensorBattery";
String EXTRA_TIMESTAMP = "com.eveningoutpost.dexdrip.Extras.Time"; String EXTRA_TIMESTAMP = "com.eveningoutpost.dexdrip.Extras.Time";
String EXTRA_RAW = "com.eveningoutpost.dexdrip.Extras.Raw"; String EXTRA_RAW = "com.eveningoutpost.dexdrip.Extras.Raw";
String XDRIP_DATA_SOURCE_DESCRIPTION = "com.eveningoutpost.dexdrip.Extras.SourceDesc";
String ACTION_NEW_BG_ESTIMATE_NO_DATA = "com.eveningoutpost.dexdrip.BgEstimateNoData"; String ACTION_NEW_BG_ESTIMATE_NO_DATA = "com.eveningoutpost.dexdrip.BgEstimateNoData";

View file

@ -1,11 +1,9 @@
package info.nightscout.androidaps.plugins.PumpDanaR.activities; package info.nightscout.androidaps;
import android.app.Activity; import android.app.Activity;
import android.graphics.Color; import android.graphics.Color;
import android.graphics.Rect; import android.graphics.Rect;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.LinearLayoutManager;
import android.text.TextUtils; import android.text.TextUtils;
import android.view.KeyEvent; import android.view.KeyEvent;
@ -35,21 +33,26 @@ import java.util.Date;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.db.DanaRHistoryRecord; import info.nightscout.androidaps.db.DanaRHistoryRecord;
import info.nightscout.androidaps.db.TDD;
import info.nightscout.androidaps.events.EventPumpStatusChanged; import info.nightscout.androidaps.events.EventPumpStatusChanged;
import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.PumpDanaR.DanaRPlugin;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.RecordTypes; import info.nightscout.androidaps.plugins.PumpDanaR.comm.RecordTypes;
import info.nightscout.androidaps.plugins.PumpDanaR.events.EventDanaRSyncStatus; import info.nightscout.androidaps.plugins.PumpDanaR.events.EventDanaRSyncStatus;
import info.nightscout.androidaps.plugins.PumpDanaRKorean.DanaRKoreanPlugin;
import info.nightscout.androidaps.plugins.PumpDanaRS.DanaRSPlugin;
import info.nightscout.androidaps.plugins.PumpDanaRv2.DanaRv2Plugin;
import info.nightscout.androidaps.plugins.PumpInsight.InsightPlugin;
import info.nightscout.androidaps.queue.Callback; import info.nightscout.androidaps.queue.Callback;
import info.nightscout.utils.DecimalFormatter; import info.nightscout.utils.DecimalFormatter;
import info.nightscout.utils.SP; import info.nightscout.utils.SP;
import info.nightscout.utils.SafeParse; import info.nightscout.utils.SafeParse;
public class DanaRStatsActivity extends Activity { public class TDDStatsActivity extends Activity {
private static Logger log = LoggerFactory.getLogger(DanaRStatsActivity.class); private static Logger log = LoggerFactory.getLogger(TDDStatsActivity.class);
TextView statusView, statsMessage, totalBaseBasal2; TextView statusView, statsMessage, totalBaseBasal2;
EditText totalBaseBasal; EditText totalBaseBasal;
@ -60,10 +63,10 @@ public class DanaRStatsActivity extends Activity {
double magicNumber; double magicNumber;
DecimalFormat decimalFormat; DecimalFormat decimalFormat;
List<DanaRHistoryRecord> historyList = new ArrayList<>(); List<TDD> historyList = new ArrayList<>();
List<DanaRHistoryRecord> dummies; List<TDD> dummies;
public DanaRStatsActivity() { public TDDStatsActivity() {
super(); super();
} }
@ -126,6 +129,9 @@ public class DanaRStatsActivity extends Activity {
} }
totalBaseBasal.setText(TBB); totalBaseBasal.setText(TBB);
if (!ConfigBuilderPlugin.getActivePump().getPumpDescription().needsManualTDDLoad)
reloadButton.setVisibility(View.GONE);
// stats table // stats table
tl = (TableLayout) findViewById(R.id.main_table); tl = (TableLayout) findViewById(R.id.main_table);
TableRow tr_head = new TableRow(this); TableRow tr_head = new TableRow(this);
@ -135,27 +141,27 @@ public class DanaRStatsActivity extends Activity {
TableLayout.LayoutParams.WRAP_CONTENT)); TableLayout.LayoutParams.WRAP_CONTENT));
TextView label_date = new TextView(this); TextView label_date = new TextView(this);
label_date.setText(getString(R.string.danar_stats_date)); label_date.setText(MainApp.gs(R.string.danar_stats_date));
label_date.setTextColor(Color.WHITE); label_date.setTextColor(Color.WHITE);
tr_head.addView(label_date); tr_head.addView(label_date);
TextView label_basalrate = new TextView(this); TextView label_basalrate = new TextView(this);
label_basalrate.setText(getString(R.string.danar_stats_basalrate)); label_basalrate.setText(MainApp.gs(R.string.danar_stats_basalrate));
label_basalrate.setTextColor(Color.WHITE); label_basalrate.setTextColor(Color.WHITE);
tr_head.addView(label_basalrate); tr_head.addView(label_basalrate);
TextView label_bolus = new TextView(this); TextView label_bolus = new TextView(this);
label_bolus.setText(getString(R.string.danar_stats_bolus)); label_bolus.setText(MainApp.gs(R.string.danar_stats_bolus));
label_bolus.setTextColor(Color.WHITE); label_bolus.setTextColor(Color.WHITE);
tr_head.addView(label_bolus); tr_head.addView(label_bolus);
TextView label_tdd = new TextView(this); TextView label_tdd = new TextView(this);
label_tdd.setText(getString(R.string.danar_stats_tdd)); label_tdd.setText(MainApp.gs(R.string.danar_stats_tdd));
label_tdd.setTextColor(Color.WHITE); label_tdd.setTextColor(Color.WHITE);
tr_head.addView(label_tdd); tr_head.addView(label_tdd);
TextView label_ratio = new TextView(this); TextView label_ratio = new TextView(this);
label_ratio.setText(getString(R.string.danar_stats_ratio)); label_ratio.setText(MainApp.gs(R.string.danar_stats_ratio));
label_ratio.setTextColor(Color.WHITE); label_ratio.setTextColor(Color.WHITE);
tr_head.addView(label_ratio); tr_head.addView(label_ratio);
@ -173,17 +179,17 @@ public class DanaRStatsActivity extends Activity {
TableLayout.LayoutParams.WRAP_CONTENT)); TableLayout.LayoutParams.WRAP_CONTENT));
TextView label_cum_amount_days = new TextView(this); TextView label_cum_amount_days = new TextView(this);
label_cum_amount_days.setText(getString(R.string.danar_stats_amount_days)); label_cum_amount_days.setText(MainApp.gs(R.string.danar_stats_amount_days));
label_cum_amount_days.setTextColor(Color.WHITE); label_cum_amount_days.setTextColor(Color.WHITE);
ctr_head.addView(label_cum_amount_days); ctr_head.addView(label_cum_amount_days);
TextView label_cum_tdd = new TextView(this); TextView label_cum_tdd = new TextView(this);
label_cum_tdd.setText(getString(R.string.danar_stats_tdd)); label_cum_tdd.setText(MainApp.gs(R.string.danar_stats_tdd));
label_cum_tdd.setTextColor(Color.WHITE); label_cum_tdd.setTextColor(Color.WHITE);
ctr_head.addView(label_cum_tdd); ctr_head.addView(label_cum_tdd);
TextView label_cum_ratio = new TextView(this); TextView label_cum_ratio = new TextView(this);
label_cum_ratio.setText(getString(R.string.danar_stats_ratio)); label_cum_ratio.setText(MainApp.gs(R.string.danar_stats_ratio));
label_cum_ratio.setTextColor(Color.WHITE); label_cum_ratio.setTextColor(Color.WHITE);
ctr_head.addView(label_cum_ratio); ctr_head.addView(label_cum_ratio);
@ -201,17 +207,17 @@ public class DanaRStatsActivity extends Activity {
TableLayout.LayoutParams.WRAP_CONTENT)); TableLayout.LayoutParams.WRAP_CONTENT));
TextView label_exp_weight = new TextView(this); TextView label_exp_weight = new TextView(this);
label_exp_weight.setText(getString(R.string.danar_stats_weight)); label_exp_weight.setText(MainApp.gs(R.string.danar_stats_weight));
label_exp_weight.setTextColor(Color.WHITE); label_exp_weight.setTextColor(Color.WHITE);
etr_head.addView(label_exp_weight); etr_head.addView(label_exp_weight);
TextView label_exp_tdd = new TextView(this); TextView label_exp_tdd = new TextView(this);
label_exp_tdd.setText(getString(R.string.danar_stats_tdd)); label_exp_tdd.setText(MainApp.gs(R.string.danar_stats_tdd));
label_exp_tdd.setTextColor(Color.WHITE); label_exp_tdd.setTextColor(Color.WHITE);
etr_head.addView(label_exp_tdd); etr_head.addView(label_exp_tdd);
TextView label_exp_ratio = new TextView(this); TextView label_exp_ratio = new TextView(this);
label_exp_ratio.setText(getString(R.string.danar_stats_ratio)); label_exp_ratio.setText(MainApp.gs(R.string.danar_stats_ratio));
label_exp_ratio.setTextColor(Color.WHITE); label_exp_ratio.setTextColor(Color.WHITE);
etr_head.addView(label_exp_ratio); etr_head.addView(label_exp_ratio);
@ -229,13 +235,13 @@ public class DanaRStatsActivity extends Activity {
reloadButton.setVisibility(View.GONE); reloadButton.setVisibility(View.GONE);
statusView.setVisibility(View.VISIBLE); statusView.setVisibility(View.VISIBLE);
statsMessage.setVisibility(View.VISIBLE); statsMessage.setVisibility(View.VISIBLE);
statsMessage.setText(getString(R.string.danar_stats_warning_Message)); statsMessage.setText(MainApp.gs(R.string.danar_stats_warning_Message));
} }
}); });
ConfigBuilderPlugin.getCommandQueue().loadHistory(RecordTypes.RECORD_TYPE_DAILY, new Callback() { ConfigBuilderPlugin.getCommandQueue().loadTDDs( new Callback() {
@Override @Override
public void run() { public void run() {
loadDataFromDB(RecordTypes.RECORD_TYPE_DAILY); loadDataFromDB();
runOnUiThread(new Runnable() { runOnUiThread(new Runnable() {
@Override @Override
public void run() { public void run() {
@ -268,18 +274,18 @@ public class DanaRStatsActivity extends Activity {
} else { } else {
SP.putString("TBB", totalBaseBasal.getText().toString()); SP.putString("TBB", totalBaseBasal.getText().toString());
TBB = SP.getString("TBB", ""); TBB = SP.getString("TBB", "");
loadDataFromDB(RecordTypes.RECORD_TYPE_DAILY); loadDataFromDB();
InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE); InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(totalBaseBasal.getWindowToken(), 0); imm.hideSoftInputFromWindow(totalBaseBasal.getWindowToken(), 0);
} }
} }
}); });
loadDataFromDB(RecordTypes.RECORD_TYPE_DAILY); loadDataFromDB();
} }
private void loadDataFromDB(byte type) { private void loadDataFromDB() {
historyList = MainApp.getDbHelper().getDanaRHistoryRecordsByType(type); historyList = MainApp.getDbHelper().getTDDs();
//only use newest 10 //only use newest 10
historyList = historyList.subList(0, Math.min(10, historyList.size())); historyList = historyList.subList(0, Math.min(10, historyList.size()));
@ -288,24 +294,24 @@ public class DanaRStatsActivity extends Activity {
dummies = new LinkedList(); dummies = new LinkedList();
DateFormat df = new SimpleDateFormat("dd.MM."); DateFormat df = new SimpleDateFormat("dd.MM.");
for (int i = 0; i < historyList.size() - 1; i++) { for (int i = 0; i < historyList.size() - 1; i++) {
DanaRHistoryRecord elem1 = historyList.get(i); TDD elem1 = historyList.get(i);
DanaRHistoryRecord elem2 = historyList.get(i + 1); TDD elem2 = historyList.get(i + 1);
if (!df.format(new Date(elem1.recordDate)).equals(df.format(new Date(elem2.recordDate + 25 * 60 * 60 * 1000)))) { if (!df.format(new Date(elem1.date)).equals(df.format(new Date(elem2.date + 25 * 60 * 60 * 1000)))) {
DanaRHistoryRecord dummy = new DanaRHistoryRecord(); TDD dummy = new TDD();
dummy.recordDate = elem1.recordDate - 24 * 60 * 60 * 1000; dummy.date = elem1.date - 24 * 60 * 60 * 1000;
dummy.recordDailyBasal = elem1.recordDailyBasal / 2; dummy.basal = elem1.basal / 2;
dummy.recordDailyBolus = elem1.recordDailyBolus / 2; dummy.bolus = elem1.bolus / 2;
dummies.add(dummy); dummies.add(dummy);
elem1.recordDailyBasal /= 2; elem1.basal /= 2;
elem1.recordDailyBolus /= 2; elem1.bolus /= 2;
} }
} }
historyList.addAll(dummies); historyList.addAll(dummies);
Collections.sort(historyList, new Comparator<DanaRHistoryRecord>() { Collections.sort(historyList, new Comparator<TDD>() {
@Override @Override
public int compare(DanaRHistoryRecord lhs, DanaRHistoryRecord rhs) { public int compare(TDD lhs, TDD rhs) {
return (int) (rhs.recordDate - lhs.recordDate); return (int) (rhs.date - lhs.date);
} }
}); });
@ -333,11 +339,13 @@ public class DanaRStatsActivity extends Activity {
double weighted05 = 0d; double weighted05 = 0d;
double weighted07 = 0d; double weighted07 = 0d;
for (DanaRHistoryRecord record : historyList) {
double tdd = record.recordDailyBolus + record.recordDailyBasal; //TDD table
for (TDD record : historyList) {
double tdd = record.getTotal();
// Create the table row // Create the table row
TableRow tr = new TableRow(DanaRStatsActivity.this); TableRow tr = new TableRow(TDDStatsActivity.this);
if (i % 2 != 0) tr.setBackgroundColor(Color.DKGRAY); if (i % 2 != 0) tr.setBackgroundColor(Color.DKGRAY);
if (dummies.contains(record)) { if (dummies.contains(record)) {
tr.setBackgroundColor(Color.argb(125, 255, 0, 0)); tr.setBackgroundColor(Color.argb(125, 255, 0, 0));
@ -348,31 +356,31 @@ public class DanaRStatsActivity extends Activity {
TableLayout.LayoutParams.WRAP_CONTENT)); TableLayout.LayoutParams.WRAP_CONTENT));
// Here create the TextView dynamically // Here create the TextView dynamically
TextView labelDATE = new TextView(DanaRStatsActivity.this); TextView labelDATE = new TextView(TDDStatsActivity.this);
labelDATE.setId(200 + i); labelDATE.setId(200 + i);
labelDATE.setText(df.format(new Date(record.recordDate))); labelDATE.setText(df.format(new Date(record.date)));
labelDATE.setTextColor(Color.WHITE); labelDATE.setTextColor(Color.WHITE);
tr.addView(labelDATE); tr.addView(labelDATE);
TextView labelBASAL = new TextView(DanaRStatsActivity.this); TextView labelBASAL = new TextView(TDDStatsActivity.this);
labelBASAL.setId(300 + i); labelBASAL.setId(300 + i);
labelBASAL.setText(DecimalFormatter.to2Decimal(record.recordDailyBasal) + " U"); labelBASAL.setText(DecimalFormatter.to2Decimal(record.basal) + " U");
labelBASAL.setTextColor(Color.WHITE); labelBASAL.setTextColor(Color.WHITE);
tr.addView(labelBASAL); tr.addView(labelBASAL);
TextView labelBOLUS = new TextView(DanaRStatsActivity.this); TextView labelBOLUS = new TextView(TDDStatsActivity.this);
labelBOLUS.setId(400 + i); labelBOLUS.setId(400 + i);
labelBOLUS.setText(DecimalFormatter.to2Decimal(record.recordDailyBolus) + " U"); labelBOLUS.setText(DecimalFormatter.to2Decimal(record.bolus) + " U");
labelBOLUS.setTextColor(Color.WHITE); labelBOLUS.setTextColor(Color.WHITE);
tr.addView(labelBOLUS); tr.addView(labelBOLUS);
TextView labelTDD = new TextView(DanaRStatsActivity.this); TextView labelTDD = new TextView(TDDStatsActivity.this);
labelTDD.setId(500 + i); labelTDD.setId(500 + i);
labelTDD.setText(DecimalFormatter.to2Decimal(tdd) + " U"); labelTDD.setText(DecimalFormatter.to2Decimal(tdd) + " U");
labelTDD.setTextColor(Color.WHITE); labelTDD.setTextColor(Color.WHITE);
tr.addView(labelTDD); tr.addView(labelTDD);
TextView labelRATIO = new TextView(DanaRStatsActivity.this); TextView labelRATIO = new TextView(TDDStatsActivity.this);
labelRATIO.setId(600 + i); labelRATIO.setId(600 + i);
labelRATIO.setText(Math.round(100 * tdd / magicNumber) + " %"); labelRATIO.setText(Math.round(100 * tdd / magicNumber) + " %");
labelRATIO.setTextColor(Color.WHITE); labelRATIO.setTextColor(Color.WHITE);
@ -383,11 +391,23 @@ public class DanaRStatsActivity extends Activity {
TableLayout.LayoutParams.MATCH_PARENT, TableLayout.LayoutParams.MATCH_PARENT,
TableLayout.LayoutParams.WRAP_CONTENT)); TableLayout.LayoutParams.WRAP_CONTENT));
sum = sum + tdd; i++;
}
i = 0;
//cumulative TDDs
for (TDD record : historyList) {
if(!historyList.isEmpty() && df.format(new Date(record.date)).equals(df.format(new Date()))) {
//Today should not be included
continue;
}
i++; i++;
sum = sum + record.getTotal();
// Create the cumtable row // Create the cumtable row
TableRow ctr = new TableRow(DanaRStatsActivity.this); TableRow ctr = new TableRow(TDDStatsActivity.this);
if (i % 2 == 0) ctr.setBackgroundColor(Color.DKGRAY); if (i % 2 == 0) ctr.setBackgroundColor(Color.DKGRAY);
ctr.setId(700 + i); ctr.setId(700 + i);
ctr.setLayoutParams(new TableLayout.LayoutParams( ctr.setLayoutParams(new TableLayout.LayoutParams(
@ -395,19 +415,19 @@ public class DanaRStatsActivity extends Activity {
TableLayout.LayoutParams.WRAP_CONTENT)); TableLayout.LayoutParams.WRAP_CONTENT));
// Here create the TextView dynamically // Here create the TextView dynamically
TextView labelDAYS = new TextView(DanaRStatsActivity.this); TextView labelDAYS = new TextView(TDDStatsActivity.this);
labelDAYS.setId(800 + i); labelDAYS.setId(800 + i);
labelDAYS.setText("" + i); labelDAYS.setText("" + i);
labelDAYS.setTextColor(Color.WHITE); labelDAYS.setTextColor(Color.WHITE);
ctr.addView(labelDAYS); ctr.addView(labelDAYS);
TextView labelCUMTDD = new TextView(DanaRStatsActivity.this); TextView labelCUMTDD = new TextView(TDDStatsActivity.this);
labelCUMTDD.setId(900 + i); labelCUMTDD.setId(900 + i);
labelCUMTDD.setText(DecimalFormatter.to2Decimal(sum / i) + " U"); labelCUMTDD.setText(DecimalFormatter.to2Decimal(sum / i) + " U");
labelCUMTDD.setTextColor(Color.WHITE); labelCUMTDD.setTextColor(Color.WHITE);
ctr.addView(labelCUMTDD); ctr.addView(labelCUMTDD);
TextView labelCUMRATIO = new TextView(DanaRStatsActivity.this); TextView labelCUMRATIO = new TextView(TDDStatsActivity.this);
labelCUMRATIO.setId(1000 + i); labelCUMRATIO.setId(1000 + i);
labelCUMRATIO.setText(Math.round(100 * sum / i / magicNumber) + " %"); labelCUMRATIO.setText(Math.round(100 * sum / i / magicNumber) + " %");
labelCUMRATIO.setTextColor(Color.WHITE); labelCUMRATIO.setTextColor(Color.WHITE);
@ -419,20 +439,25 @@ public class DanaRStatsActivity extends Activity {
TableLayout.LayoutParams.WRAP_CONTENT)); TableLayout.LayoutParams.WRAP_CONTENT));
} }
if (historyList.size() < 3 || !(df.format(new Date(historyList.get(0).recordDate)).equals(df.format(new Date(System.currentTimeMillis() - 1000 * 60 * 60 * 24))))) { if (isOldData(historyList) && ConfigBuilderPlugin.getActivePump().getPumpDescription().needsManualTDDLoad) {
statsMessage.setVisibility(View.VISIBLE); statsMessage.setVisibility(View.VISIBLE);
statsMessage.setText(getString(R.string.danar_stats_olddata_Message)); statsMessage.setText(MainApp.gs(R.string.danar_stats_olddata_Message));
} else { } else {
tl.setBackgroundColor(Color.TRANSPARENT); tl.setBackgroundColor(Color.TRANSPARENT);
} }
if(!historyList.isEmpty() && df.format(new Date(historyList.get(0).date)).equals(df.format(new Date()))) {
//Today should not be included
historyList.remove(0);
}
Collections.reverse(historyList); Collections.reverse(historyList);
i = 0; i = 0;
for (DanaRHistoryRecord record : historyList) { for (TDD record : historyList) {
double tdd = record.recordDailyBolus + record.recordDailyBasal; double tdd = record.getTotal();
if (i == 0) { if (i == 0) {
weighted03 = tdd; weighted03 = tdd;
weighted05 = tdd; weighted05 = tdd;
@ -447,7 +472,7 @@ public class DanaRStatsActivity extends Activity {
} }
// Create the exptable row // Create the exptable row
TableRow etr = new TableRow(DanaRStatsActivity.this); TableRow etr = new TableRow(TDDStatsActivity.this);
if (i % 2 != 0) etr.setBackgroundColor(Color.DKGRAY); if (i % 2 != 0) etr.setBackgroundColor(Color.DKGRAY);
etr.setId(1100 + i); etr.setId(1100 + i);
etr.setLayoutParams(new TableLayout.LayoutParams( etr.setLayoutParams(new TableLayout.LayoutParams(
@ -455,13 +480,13 @@ public class DanaRStatsActivity extends Activity {
TableLayout.LayoutParams.WRAP_CONTENT)); TableLayout.LayoutParams.WRAP_CONTENT));
// Here create the TextView dynamically // Here create the TextView dynamically
TextView labelWEIGHT = new TextView(DanaRStatsActivity.this); TextView labelWEIGHT = new TextView(TDDStatsActivity.this);
labelWEIGHT.setId(1200 + i); labelWEIGHT.setId(1200 + i);
labelWEIGHT.setText("0.3\n" + "0.5\n" + "0.7"); labelWEIGHT.setText("0.3\n" + "0.5\n" + "0.7");
labelWEIGHT.setTextColor(Color.WHITE); labelWEIGHT.setTextColor(Color.WHITE);
etr.addView(labelWEIGHT); etr.addView(labelWEIGHT);
TextView labelEXPTDD = new TextView(DanaRStatsActivity.this); TextView labelEXPTDD = new TextView(TDDStatsActivity.this);
labelEXPTDD.setId(1300 + i); labelEXPTDD.setId(1300 + i);
labelEXPTDD.setText(DecimalFormatter.to2Decimal(weighted03) labelEXPTDD.setText(DecimalFormatter.to2Decimal(weighted03)
+ " U\n" + DecimalFormatter.to2Decimal(weighted05) + " U\n" + DecimalFormatter.to2Decimal(weighted05)
@ -469,7 +494,7 @@ public class DanaRStatsActivity extends Activity {
labelEXPTDD.setTextColor(Color.WHITE); labelEXPTDD.setTextColor(Color.WHITE);
etr.addView(labelEXPTDD); etr.addView(labelEXPTDD);
TextView labelEXPRATIO = new TextView(DanaRStatsActivity.this); TextView labelEXPRATIO = new TextView(TDDStatsActivity.this);
labelEXPRATIO.setId(1400 + i); labelEXPRATIO.setId(1400 + i);
labelEXPRATIO.setText(Math.round(100 * weighted03 / magicNumber) + " %\n" labelEXPRATIO.setText(Math.round(100 * weighted03 / magicNumber) + " %\n"
+ Math.round(100 * weighted05 / magicNumber) + " %\n" + Math.round(100 * weighted05 / magicNumber) + " %\n"
@ -516,4 +541,19 @@ public class DanaRStatsActivity extends Activity {
} }
); );
} }
public static boolean isOldData(List<TDD> historyList) {
Object activePump = MainApp.getConfigBuilder().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(InsightPlugin.class);
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))))));
}
} }

View file

@ -0,0 +1,198 @@
package info.nightscout.androidaps.data;
import java.util.ArrayList;
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.interfaces.BgSourceInterface;
import info.nightscout.androidaps.interfaces.Constraint;
import info.nightscout.androidaps.interfaces.ConstraintsInterface;
import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.PluginType;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
/**
* Created by mike on 19.03.2018.
*/
public class ConstraintChecker implements ConstraintsInterface {
private MainApp mainApp;
public ConstraintChecker(MainApp mainApp) {
this.mainApp = mainApp;
}
public Constraint<Boolean> isLoopInvokationAllowed() {
return isLoopInvokationAllowed(new Constraint<>(true));
}
public Constraint<Boolean> isClosedLoopAllowed() {
return isClosedLoopAllowed(new Constraint<>(true));
}
public Constraint<Boolean> isAutosensModeEnabled() {
return isAutosensModeEnabled(new Constraint<>(true));
}
public Constraint<Boolean> isAMAModeEnabled() {
return isAMAModeEnabled(new Constraint<>(true));
}
public Constraint<Boolean> isSMBModeEnabled() {
return isSMBModeEnabled(new Constraint<>(true));
}
public Constraint<Boolean> isAdvancedFilteringEnabled() {
return isAdvancedFilteringEnabled(new Constraint<>(true));
}
public Constraint<Double> getMaxBasalAllowed(Profile profile) {
return applyBasalConstraints(new Constraint<>(Constants.REALLYHIGHBASALRATE), profile);
}
public Constraint<Integer> getMaxBasalPercentAllowed(Profile profile) {
return applyBasalPercentConstraints(new Constraint<>(Constants.REALLYHIGHPERCENTBASALRATE), profile);
}
public Constraint<Double> getMaxBolusAllowed() {
return applyBolusConstraints(new Constraint<>(Constants.REALLYHIGHBOLUS));
}
public Constraint<Integer> getMaxCarbsAllowed() {
return applyCarbsConstraints(new Constraint<>(Constants.REALLYHIGHCARBS));
}
public Constraint<Double> getMaxIOBAllowed() {
return applyMaxIOBConstraints(new Constraint<>(Constants.REALLYHIGHIOB));
}
@Override
public Constraint<Boolean> isLoopInvokationAllowed(Constraint<Boolean> value) {
ArrayList<PluginBase> constraintsPlugins = mainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class);
for (PluginBase p : constraintsPlugins) {
ConstraintsInterface constraint = (ConstraintsInterface) p;
if (!p.isEnabled(PluginType.CONSTRAINTS)) continue;
constraint.isLoopInvokationAllowed(value);
}
return value;
}
@Override
public Constraint<Boolean> isClosedLoopAllowed(Constraint<Boolean> value) {
ArrayList<PluginBase> constraintsPlugins = mainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class);
for (PluginBase p : constraintsPlugins) {
ConstraintsInterface constraint = (ConstraintsInterface) p;
if (!p.isEnabled(PluginType.CONSTRAINTS)) continue;
constraint.isClosedLoopAllowed(value);
}
return value;
}
@Override
public Constraint<Boolean> isAutosensModeEnabled(Constraint<Boolean> value) {
ArrayList<PluginBase> constraintsPlugins = mainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class);
for (PluginBase p : constraintsPlugins) {
ConstraintsInterface constraint = (ConstraintsInterface) p;
if (!p.isEnabled(PluginType.CONSTRAINTS)) continue;
constraint.isAutosensModeEnabled(value);
}
return value;
}
@Override
public Constraint<Boolean> isAMAModeEnabled(Constraint<Boolean> value) {
ArrayList<PluginBase> constraintsPlugins = mainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class);
for (PluginBase p : constraintsPlugins) {
ConstraintsInterface constrain = (ConstraintsInterface) p;
if (!p.isEnabled(PluginType.CONSTRAINTS)) continue;
constrain.isAMAModeEnabled(value);
}
return value;
}
@Override
public Constraint<Boolean> isSMBModeEnabled(Constraint<Boolean> value) {
ArrayList<PluginBase> constraintsPlugins = mainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class);
for (PluginBase p : constraintsPlugins) {
ConstraintsInterface constraint = (ConstraintsInterface) p;
if (!p.isEnabled(PluginType.CONSTRAINTS)) continue;
constraint.isSMBModeEnabled(value);
}
return value;
}
@Override
public Constraint<Boolean> isAdvancedFilteringEnabled(Constraint<Boolean> value) {
ArrayList<PluginBase> constraintsPlugins = mainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class);
for (PluginBase p : constraintsPlugins) {
ConstraintsInterface constraint = (ConstraintsInterface) p;
if (!p.isEnabled(PluginType.CONSTRAINTS)) continue;
constraint.isAdvancedFilteringEnabled(value);
}
return value;
}
@Override
public Constraint<Double> applyBasalConstraints(Constraint<Double> absoluteRate, Profile profile) {
ArrayList<PluginBase> constraintsPlugins = mainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class);
for (PluginBase p : constraintsPlugins) {
ConstraintsInterface constraint = (ConstraintsInterface) p;
if (!p.isEnabled(PluginType.CONSTRAINTS)) continue;
constraint.applyBasalConstraints(absoluteRate, profile);
}
return absoluteRate;
}
@Override
public Constraint<Integer> applyBasalPercentConstraints(Constraint<Integer> percentRate, Profile profile) {
ArrayList<PluginBase> constraintsPlugins = mainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class);
for (PluginBase p : constraintsPlugins) {
ConstraintsInterface constrain = (ConstraintsInterface) p;
if (!p.isEnabled(PluginType.CONSTRAINTS)) continue;
constrain.applyBasalPercentConstraints(percentRate, profile);
}
return percentRate;
}
@Override
public Constraint<Double> applyBolusConstraints(Constraint<Double> insulin) {
ArrayList<PluginBase> constraintsPlugins = mainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class);
for (PluginBase p : constraintsPlugins) {
ConstraintsInterface constrain = (ConstraintsInterface) p;
if (!p.isEnabled(PluginType.CONSTRAINTS)) continue;
constrain.applyBolusConstraints(insulin);
}
return insulin;
}
@Override
public Constraint<Integer> applyCarbsConstraints(Constraint<Integer> carbs) {
ArrayList<PluginBase> constraintsPlugins = mainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class);
for (PluginBase p : constraintsPlugins) {
ConstraintsInterface constrain = (ConstraintsInterface) p;
if (!p.isEnabled(PluginType.CONSTRAINTS)) continue;
constrain.applyCarbsConstraints(carbs);
}
return carbs;
}
@Override
public Constraint<Double> applyMaxIOBConstraints(Constraint<Double> maxIob) {
ArrayList<PluginBase> constraintsPlugins = mainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class);
for (PluginBase p : constraintsPlugins) {
ConstraintsInterface constrain = (ConstraintsInterface) p;
if (!p.isEnabled(PluginType.CONSTRAINTS)) continue;
constrain.applyMaxIOBConstraints(maxIob);
}
return maxIob;
}
}

View file

@ -2,14 +2,14 @@ package info.nightscout.androidaps.data;
import android.content.Context; import android.content.Context;
import com.rits.cloning.Cloner;
import org.json.JSONObject; import org.json.JSONObject;
import java.util.Date; import java.util.Date;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.db.CareportalEvent; import info.nightscout.androidaps.db.CareportalEvent;
import info.nightscout.androidaps.db.Source; import info.nightscout.androidaps.db.Source;
import info.nightscout.androidaps.interfaces.InsulinInterface;
/** /**
* Created by mike on 29.05.2017. * Created by mike on 29.05.2017.
@ -29,6 +29,28 @@ public class DetailedBolusInfo {
public Context context = null; // context for progress dialog public Context context = null; // context for progress dialog
public long pumpId = 0; // id of record if comming from pump history (not a newly created treatment) public long pumpId = 0; // id of record if comming from pump history (not a newly created treatment)
public boolean isSMB = false; // is a Super-MicroBolus public boolean isSMB = false; // is a Super-MicroBolus
public long deliverAt = 0; // SMB should be delivered within 1 min from this time
public String notes = null;
public DetailedBolusInfo copy() {
DetailedBolusInfo n = new DetailedBolusInfo();
n.date = date;
n.eventType = eventType;
n.insulin = insulin;
n.carbs = carbs;
n.source = source;
n.isValid = isValid;
n.glucose = glucose;
n.glucoseType = glucoseType;
n.carbTime = carbTime;
n.boluscalc = boluscalc;
n.context = context;
n.pumpId = pumpId;
n.isSMB = isSMB;
n.deliverAt = deliverAt;
n.notes = notes;
return n;
}
@Override @Override
public String toString() { public String toString() {
@ -37,6 +59,7 @@ public class DetailedBolusInfo {
" carbs: " + carbs + " carbs: " + carbs +
" isValid: " + isValid + " isValid: " + isValid +
" carbTime: " + carbTime + " carbTime: " + carbTime +
" isSMB: " + isSMB; " isSMB: " + isSMB +
" deliverAt: " + new Date(deliverAt).toLocaleString();
} }
} }

View file

@ -21,6 +21,7 @@ import java.util.List;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
import info.nightscout.androidaps.db.BgReading; import info.nightscout.androidaps.db.BgReading;
import info.nightscout.utils.DateUtil;
import info.nightscout.utils.DecimalFormatter; import info.nightscout.utils.DecimalFormatter;
import info.nightscout.utils.Round; import info.nightscout.utils.Round;
@ -35,21 +36,15 @@ public class GlucoseStatus {
public double avgdelta = 0d; public double avgdelta = 0d;
public double short_avgdelta = 0d; public double short_avgdelta = 0d;
public double long_avgdelta = 0d; public double long_avgdelta = 0d;
public long date = 0L;
@Override @Override
public String toString() { public String toString() {
return MainApp.sResources.getString(R.string.glucose) + " " + DecimalFormatter.to0Decimal(glucose) + " mg/dl\n" + return MainApp.gs(R.string.glucose) + " " + DecimalFormatter.to0Decimal(glucose) + " mg/dl\n" +
MainApp.sResources.getString(R.string.delta) + " " + DecimalFormatter.to0Decimal(delta) + " mg/dl\n" + MainApp.gs(R.string.delta) + " " + DecimalFormatter.to0Decimal(delta) + " mg/dl\n" +
MainApp.sResources.getString(R.string.short_avgdelta) + " " + DecimalFormatter.to2Decimal(short_avgdelta) + " mg/dl\n" + MainApp.gs(R.string.short_avgdelta) + " " + DecimalFormatter.to2Decimal(short_avgdelta) + " mg/dl\n" +
MainApp.sResources.getString(R.string.long_avgdelta) + " " + DecimalFormatter.to2Decimal(long_avgdelta) + " mg/dl"; MainApp.gs(R.string.long_avgdelta) + " " + DecimalFormatter.to2Decimal(long_avgdelta) + " mg/dl";
}
public Spanned toSpanned() {
return Html.fromHtml("<b>" + MainApp.sResources.getString(R.string.glucose) + "</b>: " + DecimalFormatter.to0Decimal(glucose) + " mg/dl<br>" +
"<b>" + MainApp.sResources.getString(R.string.delta) + "</b>: " + DecimalFormatter.to0Decimal(delta) + " mg/dl<br>" +
"<b>" + MainApp.sResources.getString(R.string.short_avgdelta) + "</b>: " + DecimalFormatter.to2Decimal(short_avgdelta) + " mg/dl<br>" +
"<b>" + MainApp.sResources.getString(R.string.long_avgdelta) + "</b>: " + DecimalFormatter.to2Decimal(long_avgdelta) + " mg/dl");
} }
public GlucoseStatus() { public GlucoseStatus() {
@ -64,14 +59,25 @@ public class GlucoseStatus {
return this; return this;
} }
@Nullable @Nullable
public static GlucoseStatus getGlucoseStatusData() { public static GlucoseStatus getGlucoseStatusData(){
return getGlucoseStatusData(false);
}
@Nullable
public static GlucoseStatus getGlucoseStatusData(boolean allowOldData) {
// load 45min // load 45min
long fromtime = (long) (System.currentTimeMillis() - 60 * 1000L * 45); long fromtime = DateUtil.now() - 60 * 1000L * 45;
List<BgReading> data = MainApp.getDbHelper().getBgreadingsDataFromTime(fromtime, false); List<BgReading> data = MainApp.getDbHelper().getBgreadingsDataFromTime(fromtime, false);
int sizeRecords = data.size(); int sizeRecords = data.size();
if (sizeRecords < 1 || data.get(0).date < System.currentTimeMillis() - 7 * 60 * 1000L) { if (sizeRecords == 0) {
return null;
}
if (data.get(0).date < DateUtil.now() - 7 * 60 * 1000L && !allowOldData) {
return null; return null;
} }
@ -79,13 +85,14 @@ public class GlucoseStatus {
long now_date = now.date; long now_date = now.date;
double change; double change;
if (sizeRecords < 2) { if (sizeRecords == 1) {
GlucoseStatus status = new GlucoseStatus(); GlucoseStatus status = new GlucoseStatus();
status.glucose = now.value; status.glucose = now.value;
status.short_avgdelta = 0d; status.short_avgdelta = 0d;
status.delta = 0d; status.delta = 0d;
status.long_avgdelta = 0d; status.long_avgdelta = 0d;
status.avgdelta = 0d; // for OpenAPS MA status.avgdelta = 0d; // for OpenAPS MA
status.date = now_date;
return status.round(); return status.round();
} }
@ -126,6 +133,7 @@ public class GlucoseStatus {
GlucoseStatus status = new GlucoseStatus(); GlucoseStatus status = new GlucoseStatus();
status.glucose = now.value; status.glucose = now.value;
status.date = now_date;
status.short_avgdelta = average(short_deltas); status.short_avgdelta = average(short_deltas);

View file

@ -16,7 +16,11 @@ import info.nightscout.androidaps.interfaces.Interval;
public abstract class Intervals<T extends Interval> { public abstract class Intervals<T extends Interval> {
LongSparseArray<T> rawData = new LongSparseArray<T>(); // oldest at index 0 LongSparseArray<T> rawData; // oldest at index 0
public Intervals() {
rawData = new LongSparseArray<T>();
}
public synchronized Intervals reset() { public synchronized Intervals reset() {
rawData = new LongSparseArray<T>(); rawData = new LongSparseArray<T>();
@ -27,8 +31,7 @@ public abstract class Intervals<T extends Interval> {
/** /**
* The List must be sorted by `T.start()` in ascending order * The List must be sorted by `T.start()` in ascending order
* */
* */
public synchronized void add(List<T> list) { public synchronized void add(List<T> list) {
for (T interval : list) { for (T interval : list) {
rawData.put(interval.start(), interval); rawData.put(interval.start(), interval);
@ -36,6 +39,10 @@ public abstract class Intervals<T extends Interval> {
merge(); merge();
} }
public synchronized void add(T interval) {
rawData.put(interval.start(), interval);
merge();
}
public synchronized List<T> getList() { public synchronized List<T> getList() {
@ -47,7 +54,7 @@ public abstract class Intervals<T extends Interval> {
public synchronized List<T> getReversedList() { public synchronized List<T> getReversedList() {
List<T> list = new ArrayList<>(); List<T> list = new ArrayList<>();
for (int i = rawData.size() -1; i>=0; i--) for (int i = rawData.size() - 1; i >= 0; i--)
list.add(rawData.valueAt(i)); list.add(rawData.valueAt(i));
return list; return list;
} }
@ -86,5 +93,4 @@ public abstract class Intervals<T extends Interval> {
} }
} }

View file

@ -7,9 +7,41 @@ public class Iob {
public double iobContrib = 0d; public double iobContrib = 0d;
public double activityContrib = 0d; public double activityContrib = 0d;
public Iob iobContrib(double iobContrib) {
this.iobContrib = iobContrib;
return this;
}
public Iob activityContrib(double activityContrib) {
this.activityContrib = activityContrib;
return this;
}
public Iob plus(Iob iob) { public Iob plus(Iob iob) {
iobContrib += iob.iobContrib; iobContrib += iob.iobContrib;
activityContrib += iob.activityContrib; activityContrib += iob.activityContrib;
return this; return this;
} }
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Iob iob = (Iob) o;
if (Double.compare(iob.iobContrib, iobContrib) != 0) return false;
return Double.compare(iob.activityContrib, activityContrib) == 0;
}
@Override
public int hashCode() {
int result;
long temp;
temp = Double.doubleToLongBits(iobContrib);
result = (int) (temp ^ (temp >>> 32));
temp = Double.doubleToLongBits(activityContrib);
result = 31 * result + (int) (temp ^ (temp >>> 32));
return result;
}
} }

View file

@ -1,5 +1,7 @@
package info.nightscout.androidaps.data; package info.nightscout.androidaps.data;
import com.rits.cloning.Cloner;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -21,8 +23,8 @@ public class IobTotal {
public double hightempinsulin; public double hightempinsulin;
// oref1 // oref1
public double microBolusInsulin; public long lastBolusTime;
public double microBolusIOB; public IobTotal iobWithZeroTemp;
public double netInsulin = 0d; // for calculations from temp basals only public double netInsulin = 0d; // for calculations from temp basals only
public double netRatio = 0d; // net ratio at start of temp basal public double netRatio = 0d; // net ratio at start of temp basal
@ -31,6 +33,12 @@ public class IobTotal {
long time; long time;
public IobTotal copy() {
Cloner cloner = new Cloner();
return cloner.deepClone(this);
}
public IobTotal(long time) { public IobTotal(long time) {
this.iob = 0d; this.iob = 0d;
this.activity = 0d; this.activity = 0d;
@ -38,8 +46,7 @@ public class IobTotal {
this.basaliob = 0d; this.basaliob = 0d;
this.netbasalinsulin = 0d; this.netbasalinsulin = 0d;
this.hightempinsulin = 0d; this.hightempinsulin = 0d;
this.microBolusInsulin = 0d; this.lastBolusTime = 0;
this.microBolusIOB = 0d;
this.time = time; this.time = time;
} }
@ -52,8 +59,6 @@ public class IobTotal {
hightempinsulin += other.hightempinsulin; hightempinsulin += other.hightempinsulin;
netInsulin += other.netInsulin; netInsulin += other.netInsulin;
extendedBolusInsulin += other.extendedBolusInsulin; extendedBolusInsulin += other.extendedBolusInsulin;
microBolusInsulin += other.microBolusInsulin;
microBolusIOB += other.microBolusIOB;
return this; return this;
} }
@ -62,11 +67,13 @@ public class IobTotal {
result.iob = bolusIOB.iob + basalIob.basaliob; result.iob = bolusIOB.iob + basalIob.basaliob;
result.activity = bolusIOB.activity + basalIob.activity; result.activity = bolusIOB.activity + basalIob.activity;
result.bolussnooze = bolusIOB.bolussnooze; result.bolussnooze = bolusIOB.bolussnooze;
result.basaliob = basalIob.basaliob; result.basaliob = bolusIOB.basaliob + basalIob.basaliob;
result.netbasalinsulin = basalIob.netbasalinsulin; result.netbasalinsulin = bolusIOB.netbasalinsulin + basalIob.netbasalinsulin;
result.hightempinsulin = basalIob.hightempinsulin; result.hightempinsulin = basalIob.hightempinsulin + bolusIOB.hightempinsulin;
result.microBolusInsulin = bolusIOB.microBolusInsulin + basalIob.microBolusInsulin; result.netInsulin = basalIob.netInsulin + bolusIOB.netInsulin;
result.microBolusIOB = bolusIOB.microBolusIOB + basalIob.microBolusIOB; result.extendedBolusInsulin = basalIob.extendedBolusInsulin + bolusIOB.extendedBolusInsulin;
result.lastBolusTime = bolusIOB.lastBolusTime;
result.iobWithZeroTemp = basalIob.iobWithZeroTemp;
return result; return result;
} }
@ -77,8 +84,8 @@ public class IobTotal {
this.basaliob = Round.roundTo(this.basaliob, 0.001); this.basaliob = Round.roundTo(this.basaliob, 0.001);
this.netbasalinsulin = Round.roundTo(this.netbasalinsulin, 0.001); this.netbasalinsulin = Round.roundTo(this.netbasalinsulin, 0.001);
this.hightempinsulin = Round.roundTo(this.hightempinsulin, 0.001); this.hightempinsulin = Round.roundTo(this.hightempinsulin, 0.001);
this.microBolusInsulin = Round.roundTo(this.microBolusInsulin, 0.001); this.netInsulin = Round.roundTo(this.netInsulin, 0.001);
this.microBolusIOB = Round.roundTo(this.microBolusIOB, 0.001); this.extendedBolusInsulin = Round.roundTo(this.extendedBolusInsulin, 0.001);
return this; return this;
} }
@ -102,7 +109,24 @@ public class IobTotal {
json.put("basaliob", basaliob); json.put("basaliob", basaliob);
json.put("bolussnooze", bolussnooze); json.put("bolussnooze", bolussnooze);
json.put("activity", activity); json.put("activity", activity);
json.put("lastBolusTime", lastBolusTime);
json.put("time", DateUtil.toISOString(new Date(time))); json.put("time", DateUtil.toISOString(new Date(time)));
/*
This is requested by SMB determine_basal but by based on Scott's info
it's MDT specific safety check only
It's causing rounding issues in determine_basal
JSONObject lastTemp = new JSONObject();
lastTemp.put("date", lastTempDate);
lastTemp.put("rate", lastTempRate);
lastTemp.put("duration", lastTempDuration);
json.put("lastTemp", lastTemp);
*/
if (iobWithZeroTemp != null) {
JSONObject iwzt = iobWithZeroTemp.determineBasalJson();
json.put("iobWithZeroTemp", iwzt);
}
} catch (JSONException e) { } catch (JSONException e) {
log.error("Unhandled exception", e); log.error("Unhandled exception", e);
} }

View file

@ -7,4 +7,9 @@ public class MealData {
public double boluses = 0d; public double boluses = 0d;
public double carbs = 0d; public double carbs = 0d;
public double mealCOB = 0.0d; public double mealCOB = 0.0d;
public double slopeFromMaxDeviation = 0;
public double slopeFromMinDeviation = 999;
public long lastBolusTime;
public long lastCarbTime = 0L;
public double usedMinCarbsImpact = 0d;
} }

View file

@ -2,7 +2,9 @@ package info.nightscout.androidaps.data;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.support.v4.util.LongSparseArray;
import info.nightscout.androidaps.db.TemporaryBasal;
import info.nightscout.androidaps.interfaces.Interval; import info.nightscout.androidaps.interfaces.Interval;
/** /**
@ -11,6 +13,14 @@ import info.nightscout.androidaps.interfaces.Interval;
public class NonOverlappingIntervals<T extends Interval> extends Intervals<T> { public class NonOverlappingIntervals<T extends Interval> extends Intervals<T> {
public NonOverlappingIntervals() {
super();
}
public NonOverlappingIntervals (Intervals<T> other) {
rawData = other.rawData.clone();
}
protected synchronized void merge() { protected synchronized void merge() {
for (int index = 0; index < rawData.size() - 1; index++) { for (int index = 0; index < rawData.size() - 1; index++) {
Interval i = rawData.valueAt(index); Interval i = rawData.valueAt(index);
@ -27,4 +37,5 @@ public class NonOverlappingIntervals<T extends Interval> extends Intervals<T> {
if (index >= 0) return rawData.valueAt(index); if (index >= 0) return rawData.valueAt(index);
return null; return null;
} }
} }

View file

@ -11,18 +11,26 @@ import info.nightscout.androidaps.interfaces.Interval;
public class OverlappingIntervals<T extends Interval> extends Intervals<T> { public class OverlappingIntervals<T extends Interval> extends Intervals<T> {
public OverlappingIntervals() {
super();
}
public OverlappingIntervals(Intervals<T> other) {
rawData = other.rawData.clone();
}
protected synchronized void merge() { protected synchronized void merge() {
boolean needToCut = false; boolean needToCut = false;
long cutTime = 0; long cutTime = 0;
for (int index = rawData.size()-1; index >= 0; index--) { //begin with newest for (int index = rawData.size() - 1; index >= 0; index--) { //begin with newest
Interval cur = rawData.valueAt(index); Interval cur = rawData.valueAt(index);
if (cur.isEndingEvent()){ if (cur.isEndingEvent()) {
needToCut = true; needToCut = true;
cutTime = cur.start(); cutTime = cur.start();
} else { } else {
//event that is no EndingEvent might need to be stopped by an ending event //event that is no EndingEvent might need to be stopped by an ending event
if(needToCut&&cur.end() > cutTime){ if (needToCut && cur.end() > cutTime) {
cur.cutEndTo(cutTime); cur.cutEndTo(cutTime);
} }
} }
@ -31,9 +39,9 @@ public class OverlappingIntervals<T extends Interval> extends Intervals<T> {
@Nullable @Nullable
public synchronized T getValueByInterval(long time) { public synchronized T getValueByInterval(long time) {
for (int index = rawData.size()-1; index >= 0; index--) { //begin with newest for (int index = rawData.size() - 1; index >= 0; index--) { //begin with newest
T cur = rawData.valueAt(index); T cur = rawData.valueAt(index);
if (cur.match(time)){ if (cur.match(time)) {
return cur; return cur;
} }
} }

View file

@ -2,8 +2,6 @@ package info.nightscout.androidaps.data;
import android.support.v4.util.LongSparseArray; import android.support.v4.util.LongSparseArray;
import com.crashlytics.android.Crashlytics;
import org.json.JSONArray; import org.json.JSONArray;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
@ -14,49 +12,76 @@ import java.text.DecimalFormat;
import java.util.Calendar; import java.util.Calendar;
import java.util.TimeZone; import java.util.TimeZone;
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.Constants; import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
import info.nightscout.androidaps.plugins.Overview.notifications.Notification; import info.nightscout.androidaps.interfaces.PumpDescription;
import info.nightscout.androidaps.plugins.Overview.events.EventDismissNotification; import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification; import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification;
import info.nightscout.androidaps.plugins.Overview.notifications.Notification;
import info.nightscout.utils.DateUtil;
import info.nightscout.utils.DecimalFormatter; import info.nightscout.utils.DecimalFormatter;
import info.nightscout.utils.ToastUtils; import info.nightscout.utils.FabricPrivacy;
public class Profile { public class Profile {
private static Logger log = LoggerFactory.getLogger(Profile.class); private static Logger log = LoggerFactory.getLogger(Profile.class);
private JSONObject json; private JSONObject json;
private String units = null; private String units;
private double dia = Constants.defaultDIA; private double dia;
private TimeZone timeZone = TimeZone.getDefault(); private TimeZone timeZone;
private JSONArray isf; private JSONArray isf;
private LongSparseArray<Double> isf_v = null; // oldest at index 0 private LongSparseArray<Double> isf_v; // oldest at index 0
private JSONArray ic; private JSONArray ic;
private LongSparseArray<Double> ic_v = null; // oldest at index 0 private LongSparseArray<Double> ic_v; // oldest at index 0
private JSONArray basal; private JSONArray basal;
private LongSparseArray<Double> basal_v = null; // oldest at index 0 private LongSparseArray<Double> basal_v; // oldest at index 0
private JSONArray targetLow; private JSONArray targetLow;
private LongSparseArray<Double> targetLow_v = null; // oldest at index 0 private LongSparseArray<Double> targetLow_v; // oldest at index 0
private JSONArray targetHigh; private JSONArray targetHigh;
private LongSparseArray<Double> targetHigh_v = null; // oldest at index 0 private LongSparseArray<Double> targetHigh_v; // oldest at index 0
private int percentage = 100; private int percentage;
private int timeshift = 0; private int timeshift;
protected boolean isValid;
protected boolean isValidated;
// Default constructor for tests
protected Profile() {
}
// Constructor from profileStore JSON
public Profile(JSONObject json, String units) { public Profile(JSONObject json, String units) {
this(json, 100, 0); init(json, 100, 0);
if (this.units == null) { if (this.units == null) {
if (units != null) if (units != null)
this.units = units; this.units = units;
else { else {
Crashlytics.log("Profile failover failed too"); FabricPrivacy.log("Profile failover failed too");
this.units = Constants.MGDL; this.units = Constants.MGDL;
} }
} }
} }
public Profile(JSONObject json, int percentage, int timeshift) { public Profile(JSONObject json, int percentage, int timeshift) {
init(json, percentage, timeshift);
}
protected void init(JSONObject json, int percentage, int timeshift) {
units = null;
dia = Constants.defaultDIA;
timeZone = TimeZone.getDefault();
isf_v = null;
ic_v = null;
basal_v = null;
targetLow_v = null;
targetHigh_v = null;
isValid = true;
isValidated = false;
this.percentage = percentage; this.percentage = percentage;
this.timeshift = timeshift; this.timeshift = timeshift;
this.json = json; this.json = json;
@ -70,60 +95,21 @@ public class Profile {
if (json.has("timezone")) if (json.has("timezone"))
timeZone = TimeZone.getTimeZone(json.getString("timezone")); timeZone = TimeZone.getTimeZone(json.getString("timezone"));
isf = json.getJSONArray("sens"); isf = json.getJSONArray("sens");
if (getIsf(0) == null) {
int defaultISF = units.equals(Constants.MGDL) ? 400 : 20;
isf = new JSONArray("[{\"time\":\"00:00\",\"value\":\"" + defaultISF + "\",\"timeAsSeconds\":\"0\"}]");
Notification noisf = new Notification(Notification.ISF_MISSING, MainApp.sResources.getString(R.string.isfmissing), Notification.URGENT);
MainApp.bus().post(new EventNewNotification(noisf));
} else {
MainApp.bus().post(new EventDismissNotification(Notification.ISF_MISSING));
}
ic = json.getJSONArray("carbratio"); ic = json.getJSONArray("carbratio");
if (getIc(0) == null) {
int defaultIC = 25;
ic = new JSONArray("[{\"time\":\"00:00\",\"value\":\"" + defaultIC + "\",\"timeAsSeconds\":\"0\"}]");
Notification noic = new Notification(Notification.IC_MISSING, MainApp.sResources.getString(R.string.icmissing), Notification.URGENT);
MainApp.bus().post(new EventNewNotification(noic));
} else {
MainApp.bus().post(new EventDismissNotification(Notification.IC_MISSING));
}
basal = json.getJSONArray("basal"); basal = json.getJSONArray("basal");
if (getBasal(0) == null) {
double defaultBasal = 0.1d;
basal = new JSONArray("[{\"time\":\"00:00\",\"value\":\"" + defaultBasal + "\",\"timeAsSeconds\":\"0\"}]");
Notification nobasal = new Notification(Notification.BASAL_MISSING, MainApp.sResources.getString(R.string.basalmissing), Notification.URGENT);
MainApp.bus().post(new EventNewNotification(nobasal));
} else {
MainApp.bus().post(new EventDismissNotification(Notification.BASAL_MISSING));
}
targetLow = json.getJSONArray("target_low"); targetLow = json.getJSONArray("target_low");
if (getTargetLow(0) == null) {
double defaultLow = units.equals(Constants.MGDL) ? 120 : 6;
targetLow = new JSONArray("[{\"time\":\"00:00\",\"value\":\"" + defaultLow + "\",\"timeAsSeconds\":\"0\"}]");
Notification notarget = new Notification(Notification.TARGET_MISSING, MainApp.sResources.getString(R.string.targetmissing), Notification.URGENT);
MainApp.bus().post(new EventNewNotification(notarget));
} else {
MainApp.bus().post(new EventDismissNotification(Notification.TARGET_MISSING));
}
targetHigh = json.getJSONArray("target_high"); targetHigh = json.getJSONArray("target_high");
if (getTargetHigh(0) == null) {
double defaultHigh = units.equals(Constants.MGDL) ? 160 : 8;
targetHigh = new JSONArray("[{\"time\":\"00:00\",\"value\":\"" + defaultHigh + "\",\"timeAsSeconds\":\"0\"}]");
Notification notarget = new Notification(Notification.TARGET_MISSING, MainApp.sResources.getString(R.string.targetmissing), Notification.URGENT);
MainApp.bus().post(new EventNewNotification(notarget));
} else {
MainApp.bus().post(new EventDismissNotification(Notification.TARGET_MISSING));
}
} catch (JSONException e) { } catch (JSONException e) {
log.error("Unhandled exception", e); log.error("Unhandled exception", e);
ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), MainApp.sResources.getString(R.string.invalidprofile)); isValid = false;
isValidated = true;
} }
} }
public String log() { public String log() {
String ret = "\n"; String ret = "\n";
for (Integer hour = 0; hour < 24; hour++) { for (Integer hour = 0; hour < 24; hour++) {
double value = getBasal((Integer) (hour * 60 * 60)); double value = getBasalTimeFromMidnight((Integer) (hour * 60 * 60));
ret += "NS basal value for " + hour + ":00 is " + value + "\n"; ret += "NS basal value for " + hour + ":00 is " + value + "\n";
} }
ret += "NS units: " + getUnits(); ret += "NS units: " + getUnits();
@ -145,6 +131,10 @@ public class Profile {
} }
// mmol or mg/dl // mmol or mg/dl
public void setUnits(String units) {
this.units = units;
}
public String getUnits() { public String getUnits() {
return units; return units;
} }
@ -154,17 +144,30 @@ public class Profile {
} }
private LongSparseArray<Double> convertToSparseArray(JSONArray array) { private LongSparseArray<Double> convertToSparseArray(JSONArray array) {
if (array == null) {
isValid = false;
return new LongSparseArray<>();
}
double multiplier = getMultiplier(array); double multiplier = getMultiplier(array);
LongSparseArray<Double> sparse = new LongSparseArray<>(); LongSparseArray<Double> sparse = new LongSparseArray<>();
for (Integer index = 0; index < array.length(); index++) { for (Integer index = 0; index < array.length(); index++) {
try { try {
JSONObject o = array.getJSONObject(index); final JSONObject o = array.getJSONObject(index);
long tas = getShitfTimeSecs((int) o.getLong("timeAsSeconds")); long tas = 0;
Double value = o.getDouble("value") * multiplier; try {
tas = getShitfTimeSecs((int) o.getLong("timeAsSeconds"));
} catch (JSONException e) {
String time = o.getString("time");
tas = getShitfTimeSecs(DateUtil.toSeconds(time));
//log.debug(">>>>>>>>>>>> Used recalculated timeAsSecons: " + time + " " + tas);
}
double value = o.getDouble("value") * multiplier;
sparse.put(tas, value); sparse.put(tas, value);
} catch (JSONException e) { } catch (JSONException e) {
log.error("Unhandled exception", e); log.error("Unhandled exception", e);
log.error(json.toString());
} }
} }
@ -176,6 +179,79 @@ public class Profile {
return sparse; return sparse;
} }
public synchronized boolean isValid(String from) {
if (!isValid)
return false;
if (!isValidated) {
if (basal_v == null)
basal_v = convertToSparseArray(basal);
validate(basal_v);
if (isf_v == null)
isf_v = convertToSparseArray(isf);
validate(isf_v);
if (ic_v == null)
ic_v = convertToSparseArray(ic);
validate(ic_v);
if (targetLow_v == null)
targetLow_v = convertToSparseArray(targetLow);
validate(targetLow_v);
if (targetHigh_v == null)
targetHigh_v = convertToSparseArray(targetHigh);
validate(targetHigh_v);
isValidated = true;
}
if (isValid) {
// Check for hours alignment
PumpInterface pump = MainApp.getConfigBuilder().getActivePump();
if (pump != null && !pump.getPumpDescription().is30minBasalRatesCapable) {
for (int index = 0; index < basal_v.size(); index++) {
long secondsFromMidnight = basal_v.keyAt(index);
if (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));
}
}
}
// Check for minimal basal value
if (pump != null) {
PumpDescription description = pump.getPumpDescription();
for (int i = 0; i < basal_v.size(); i++) {
if (basal_v.valueAt(i) < description.basalMinimumRate) {
basal_v.setValueAt(i, description.basalMinimumRate);
sendBelowMinimumNotification(from);
}
}
} else {
// if pump not available (at start)
// do not store converted array
basal_v = null;
isValidated = false;
}
}
return isValid;
}
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)));
}
private void validate(LongSparseArray array) {
if (array.size() == 0) {
isValid = false;
return;
}
for (int index = 0; index < array.size(); index++) {
if (array.valueAt(index).equals(0d)) {
isValid = false;
return;
}
}
}
/*
private Double getValueToTime(JSONArray array, Integer timeAsSeconds) { private Double getValueToTime(JSONArray array, Integer timeAsSeconds) {
Double lastValue = null; Double lastValue = null;
@ -195,11 +271,12 @@ public class Profile {
} }
return lastValue; return lastValue;
} }
*/
Integer getShitfTimeSecs(Integer originalTime) { Integer getShitfTimeSecs(Integer originalTime) {
Integer shiftedTime = originalTime + timeshift * 60 * 60; Integer shiftedTime = originalTime + timeshift * 60 * 60;
shiftedTime = (shiftedTime + 24 * 60 * 60) % (24 * 60 * 60); shiftedTime = (shiftedTime + 24 * 60 * 60) % (24 * 60 * 60);
if (timeshift != 0) if (timeshift != 0 && Config.logProfile)
log.debug("(Sec) Original time: " + originalTime + " ShiftedTime: " + shiftedTime); log.debug("(Sec) Original time: " + originalTime + " ShiftedTime: " + shiftedTime);
return shiftedTime; return shiftedTime;
} }
@ -236,7 +313,7 @@ public class Profile {
return multiplier; return multiplier;
} }
private Double getValueToTime(LongSparseArray<Double> array, Integer timeAsSeconds) { private double getValueToTime(LongSparseArray<Double> array, Integer timeAsSeconds) {
Double lastValue = null; Double lastValue = null;
for (Integer index = 0; index < array.size(); index++) { for (Integer index = 0; index < array.size(); index++) {
@ -251,7 +328,7 @@ public class Profile {
return lastValue; return lastValue;
} }
private String format_HH_MM(Integer timeAsSeconds) { protected String format_HH_MM(Integer timeAsSeconds) {
String time; String time;
int hour = timeAsSeconds / 60 / 60; int hour = timeAsSeconds / 60 / 60;
int minutes = (timeAsSeconds - hour * 60 * 60) / 60; int minutes = (timeAsSeconds - hour * 60 * 60) / 60;
@ -278,123 +355,144 @@ public class Profile {
return retValue; return retValue;
} }
public Double getIsf() { public double getIsf() {
return getIsf(secondsFromMidnight(System.currentTimeMillis())); return getIsfTimeFromMidnight(secondsFromMidnight(System.currentTimeMillis()));
} }
public Double getIsf(long time) { public double getIsf(long time) {
return getIsf(secondsFromMidnight(time)); return getIsfTimeFromMidnight(secondsFromMidnight(time));
} }
public Double getIsf(Integer timeAsSeconds) { double getIsfTimeFromMidnight(int timeAsSeconds) {
if (isf_v == null) if (isf_v == null)
isf_v = convertToSparseArray(isf); isf_v = convertToSparseArray(isf);
return getValueToTime(isf_v, timeAsSeconds); return getValueToTime(isf_v, timeAsSeconds);
} }
public String getIsfList() { public String getIsfList() {
if (isf_v == null)
isf_v = convertToSparseArray(isf);
return getValuesList(isf_v, null, new DecimalFormat("0.0"), getUnits() + "/U"); return getValuesList(isf_v, null, new DecimalFormat("0.0"), getUnits() + "/U");
} }
public Double getIc() { public double getIc() {
return getIc(secondsFromMidnight(System.currentTimeMillis())); return getIcTimeFromMidnight(secondsFromMidnight(System.currentTimeMillis()));
} }
public Double getIc(long time) { public double getIc(long time) {
return getIc(secondsFromMidnight(time)); return getIcTimeFromMidnight(secondsFromMidnight(time));
} }
public Double getIc(Integer timeAsSeconds) { public double getIcTimeFromMidnight(int timeAsSeconds) {
if (ic_v == null) if (ic_v == null)
ic_v = convertToSparseArray(ic); ic_v = convertToSparseArray(ic);
return getValueToTime(ic_v, timeAsSeconds); return getValueToTime(ic_v, timeAsSeconds);
} }
public String getIcList() { public String getIcList() {
return getValuesList(ic_v, null, new DecimalFormat("0.0"), " g/U"); if (ic_v == null)
ic_v = convertToSparseArray(ic);
return getValuesList(ic_v, null, new DecimalFormat("0.0"), "g/U");
} }
public Double getBasal() { public double getBasal() {
return getBasal(secondsFromMidnight(System.currentTimeMillis())); return getBasalTimeFromMidnight(secondsFromMidnight(System.currentTimeMillis()));
} }
public Double getBasal(long time) { public double getBasal(long time) {
return getBasal(secondsFromMidnight(time)); return getBasalTimeFromMidnight(secondsFromMidnight(time));
} }
public Double getBasal(Integer timeAsSeconds) { public synchronized double getBasalTimeFromMidnight(int timeAsSeconds) {
if (basal_v == null) if (basal_v == null) {
basal_v = convertToSparseArray(basal); basal_v = convertToSparseArray(basal);
}
return getValueToTime(basal_v, timeAsSeconds); return getValueToTime(basal_v, timeAsSeconds);
} }
public String getBasalList() { public String getBasalList() {
return getValuesList(basal_v, null, new DecimalFormat("0.00"), "U"); if (basal_v == null)
basal_v = convertToSparseArray(basal);
return getValuesList(basal_v, null, new DecimalFormat("0.00"), "U/h");
} }
public class BasalValue { public class BasalValue {
public BasalValue(Integer timeAsSeconds, Double value) { public BasalValue(int timeAsSeconds, double value) {
this.timeAsSeconds = timeAsSeconds; this.timeAsSeconds = timeAsSeconds;
this.value = value; this.value = value;
} }
public Integer timeAsSeconds; public int timeAsSeconds;
public Double value; public double value;
} }
public BasalValue[] getBasalValues() { public synchronized BasalValue[] getBasalValues() {
if (basal_v == null)
basal_v = convertToSparseArray(basal);
BasalValue[] ret = new BasalValue[basal_v.size()]; BasalValue[] ret = new BasalValue[basal_v.size()];
for (Integer index = 0; index < basal_v.size(); index++) { for (Integer index = 0; index < basal_v.size(); index++) {
Integer tas = (int) basal_v.keyAt(index); Integer tas = (int) basal_v.keyAt(index);
Double value = basal_v.valueAt(index); double value = basal_v.valueAt(index);
ret[index] = new BasalValue(tas, value); ret[index] = new BasalValue(tas, value);
} }
return ret; return ret;
} }
public Double getTargetLow() { public double getTarget(){
return getTargetLow(secondsFromMidnight(System.currentTimeMillis())); return getTarget(secondsFromMidnight(System.currentTimeMillis()));
} }
public Double getTargetLow(long time) { protected double getTarget(int timeAsSeconds) {
return getTargetLow(secondsFromMidnight(time)); return (getTargetLowTimeFromMidnight(timeAsSeconds) + getTargetHighTimeFromMidnight(timeAsSeconds))/2;
} }
public Double getTargetLow(Integer timeAsSeconds) { public double getTargetLow() {
return getTargetLowTimeFromMidnight(secondsFromMidnight(System.currentTimeMillis()));
}
public double getTargetLow(long time) {
return getTargetLowTimeFromMidnight(secondsFromMidnight(time));
}
public double getTargetLowTimeFromMidnight(int timeAsSeconds) {
if (targetLow_v == null) if (targetLow_v == null)
targetLow_v = convertToSparseArray(targetLow); targetLow_v = convertToSparseArray(targetLow);
return getValueToTime(targetLow_v, timeAsSeconds); return getValueToTime(targetLow_v, timeAsSeconds);
} }
public Double getTargetHigh() { public double getTargetHigh() {
return getTargetHigh(secondsFromMidnight(System.currentTimeMillis())); return getTargetHighTimeFromMidnight(secondsFromMidnight(System.currentTimeMillis()));
} }
public Double getTargetHigh(long time) { public double getTargetHigh(long time) {
return getTargetHigh(secondsFromMidnight(time)); return getTargetHighTimeFromMidnight(secondsFromMidnight(time));
} }
public Double getTargetHigh(Integer timeAsSeconds) { public double getTargetHighTimeFromMidnight(int timeAsSeconds) {
if (targetHigh_v == null) if (targetHigh_v == null)
targetHigh_v = convertToSparseArray(targetHigh); targetHigh_v = convertToSparseArray(targetHigh);
return getValueToTime(targetHigh_v, timeAsSeconds); return getValueToTime(targetHigh_v, timeAsSeconds);
} }
public String getTargetList() { public String getTargetList() {
if (targetLow_v == null)
targetLow_v = convertToSparseArray(targetLow);
if (targetHigh_v == null)
targetHigh_v = convertToSparseArray(targetHigh);
return getValuesList(targetLow_v, targetHigh_v, new DecimalFormat("0.0"), getUnits()); return getValuesList(targetLow_v, targetHigh_v, new DecimalFormat("0.0"), getUnits());
} }
public double getMaxDailyBasal() { public double getMaxDailyBasal() {
Double max = 0d; double max = 0d;
for (Integer hour = 0; hour < 24; hour++) { for (int hour = 0; hour < 24; hour++) {
double value = getBasal((Integer) (hour * 60 * 60)); double value = getBasalTimeFromMidnight((Integer) (hour * 60 * 60));
if (value > max) max = value; if (value > max) max = value;
} }
return max; return max;
} }
public static Integer secondsFromMidnight() { public static int secondsFromMidnight() {
Calendar c = Calendar.getInstance(); Calendar c = Calendar.getInstance();
long now = c.getTimeInMillis(); long now = c.getTimeInMillis();
c.set(Calendar.HOUR_OF_DAY, 0); c.set(Calendar.HOUR_OF_DAY, 0);
@ -405,7 +503,7 @@ public class Profile {
return (int) (passed / 1000); return (int) (passed / 1000);
} }
public static Integer secondsFromMidnight(long date) { public static int secondsFromMidnight(long date) {
Calendar c = Calendar.getInstance(); Calendar c = Calendar.getInstance();
c.setTimeInMillis(date); c.setTimeInMillis(date);
c.set(Calendar.HOUR_OF_DAY, 0); c.set(Calendar.HOUR_OF_DAY, 0);
@ -416,22 +514,22 @@ public class Profile {
return (int) (passed / 1000); return (int) (passed / 1000);
} }
public static Double toMgdl(Double value, String units) { public static double toMgdl(double value, String units) {
if (units.equals(Constants.MGDL)) return value; if (units.equals(Constants.MGDL)) return value;
else return value * Constants.MMOLL_TO_MGDL; else return value * Constants.MMOLL_TO_MGDL;
} }
public static Double toMmol(Double value, String units) { public static double toMmol(double value, String units) {
if (units.equals(Constants.MGDL)) return value * Constants.MGDL_TO_MMOLL; if (units.equals(Constants.MGDL)) return value * Constants.MGDL_TO_MMOLL;
else return value; else return value;
} }
public static Double fromMgdlToUnits(Double value, String units) { public static double fromMgdlToUnits(double value, String units) {
if (units.equals(Constants.MGDL)) return value; if (units.equals(Constants.MGDL)) return value;
else return value * Constants.MGDL_TO_MMOLL; else return value * Constants.MGDL_TO_MMOLL;
} }
public static Double toUnits(Double valueInMgdl, Double valueInMmol, String units) { public static double toUnits(Double valueInMgdl, Double valueInMmol, String units) {
if (units.equals(Constants.MGDL)) return valueInMgdl; if (units.equals(Constants.MGDL)) return valueInMgdl;
else return valueInMmol; else return valueInMmol;
} }
@ -457,7 +555,7 @@ public class Profile {
public double percentageBasalSum() { public double percentageBasalSum() {
double result = 0d; double result = 0d;
for (int i = 0; i < 24; i++) { for (int i = 0; i < 24; i++) {
result += getBasal((Integer) (i * 60 * 60)); result += getBasalTimeFromMidnight(i * 60 * 60);
} }
return result; return result;
} }
@ -466,7 +564,7 @@ public class Profile {
public double baseBasalSum() { public double baseBasalSum() {
double result = 0d; double result = 0d;
for (int i = 0; i < 24; i++) { for (int i = 0; i < 24; i++) {
result += getBasal((Integer) (i * 60 * 60)) / getMultiplier(basal_v); result += getBasalTimeFromMidnight(i * 60 * 60) / getMultiplier(basal_v);
} }
return result; return result;
} }

View file

@ -3,10 +3,14 @@ package info.nightscout.androidaps.data;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.support.v4.util.LongSparseArray; import android.support.v4.util.LongSparseArray;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import info.nightscout.androidaps.interfaces.Interval; import info.nightscout.androidaps.interfaces.Interval;
import info.nightscout.utils.DateUtil;
/** /**
* Created by mike on 09.05.2017. * Created by mike on 09.05.2017.
@ -16,8 +20,17 @@ import info.nightscout.androidaps.interfaces.Interval;
// When no interval match the lastest record without duration is used // When no interval match the lastest record without duration is used
public class ProfileIntervals<T extends Interval> { public class ProfileIntervals<T extends Interval> {
private static Logger log = LoggerFactory.getLogger(ProfileIntervals.class);
private LongSparseArray<T> rawData = new LongSparseArray<>(); // oldest at index 0 private LongSparseArray<T> rawData; // oldest at index 0
public ProfileIntervals () {
rawData = new LongSparseArray<>();
}
public ProfileIntervals (ProfileIntervals<T> other) {
rawData = other.rawData.clone();
}
public synchronized ProfileIntervals reset() { public synchronized ProfileIntervals reset() {
rawData = new LongSparseArray<>(); rawData = new LongSparseArray<>();
@ -25,13 +38,16 @@ public class ProfileIntervals<T extends Interval> {
} }
public synchronized void add(T newInterval) { public synchronized void add(T newInterval) {
rawData.put(newInterval.start(), newInterval); if (newInterval.isValid()) {
merge(); rawData.put(newInterval.start(), newInterval);
merge();
}
} }
public synchronized void add(List<T> list) { public synchronized void add(List<T> list) {
for (T interval : list) { for (T interval : list) {
rawData.put(interval.start(), interval); if (interval.isValid())
rawData.put(interval.start(), interval);
} }
merge(); merge();
} }
@ -50,6 +66,13 @@ public class ProfileIntervals<T extends Interval> {
public synchronized Interval getValueToTime(long time) { public synchronized Interval getValueToTime(long time) {
int index = binarySearch(time); int index = binarySearch(time);
if (index >= 0) return rawData.valueAt(index); if (index >= 0) return rawData.valueAt(index);
// if we request data older than first record, use oldest with zero duration instead
for (index = 0; index < rawData.size(); index++) {
if (rawData.valueAt(index).durationInMsec() == 0) {
//log.debug("Requested profile for time: " + DateUtil.dateAndTimeString(time) + ". Providing oldest record: " + rawData.valueAt(0).toString());
return rawData.valueAt(index);
}
}
return null; return null;
} }
@ -62,7 +85,7 @@ public class ProfileIntervals<T extends Interval> {
public synchronized List<T> getReversedList() { public synchronized List<T> getReversedList() {
List<T> list = new ArrayList<>(); List<T> list = new ArrayList<>();
for (int i = rawData.size() -1; i>=0; i--) for (int i = rawData.size() - 1; i >= 0; i--)
list.add(rawData.valueAt(i)); list.add(rawData.valueAt(i));
return list; return list;
} }
@ -106,4 +129,9 @@ public class ProfileIntervals<T extends Interval> {
public synchronized T getReversed(int index) { public synchronized T getReversed(int index) {
return rawData.valueAt(size() - 1 - index); return rawData.valueAt(size() - 1 - index);
} }
@Override
public String toString() {
return rawData.toString();
}
} }

View file

@ -13,7 +13,7 @@ import info.nightscout.androidaps.R;
import info.nightscout.utils.DecimalFormatter; import info.nightscout.utils.DecimalFormatter;
import info.nightscout.utils.Round; import info.nightscout.utils.Round;
public class PumpEnactResult extends Object { public class PumpEnactResult {
private static Logger log = LoggerFactory.getLogger(PumpEnactResult.class); private static Logger log = LoggerFactory.getLogger(PumpEnactResult.class);
public boolean success = false; // request was processed successfully (but possible no change was needed) public boolean success = false; // request was processed successfully (but possible no change was needed)
@ -21,19 +21,19 @@ public class PumpEnactResult extends Object {
public String comment = ""; public String comment = "";
// Result of basal change // Result of basal change
public Integer duration = -1; // duration set [minutes] public int duration = -1; // duration set [minutes]
public Double absolute = -1d; // absolute rate [U/h] , isPercent = false public double absolute = -1d; // absolute rate [U/h] , isPercent = false
public Integer percent = -1; // percent of current basal [%] (100% = current basal), isPercent = true public int percent = -1; // percent of current basal [%] (100% = current basal), isPercent = true
public boolean isPercent = false; // if true percent is used, otherwise absolute public boolean isPercent = false; // if true percent is used, otherwise absolute
public boolean isTempCancel = false; // if true we are caceling temp basal public boolean isTempCancel = false; // if true we are caceling temp basal
// Result of treatment delivery // Result of treatment delivery
public Double bolusDelivered = 0d; // real value of delivered insulin public double bolusDelivered = 0d; // real value of delivered insulin
public Double carbsDelivered = 0d; // real value of delivered carbs public double carbsDelivered = 0d; // real value of delivered carbs
public boolean queued = false; public boolean queued = false;
public PumpEnactResult success(boolean success) { public PumpEnactResult success(boolean success) {
this.success = success; this.success = success;
return this; return this;
} }
@ -47,16 +47,21 @@ public class PumpEnactResult extends Object {
return this; return this;
} }
public PumpEnactResult duration(Integer duration) { public PumpEnactResult duration(int duration) {
this.duration = duration; this.duration = duration;
return this; return this;
} }
public PumpEnactResult absolute(Double absolute) { public PumpEnactResult absolute(double absolute) {
this.absolute = absolute; this.absolute = absolute;
return this; return this;
} }
public PumpEnactResult percent(int percent) {
this.percent = percent;
return this;
}
public PumpEnactResult isPercent(boolean isPercent) { public PumpEnactResult isPercent(boolean isPercent) {
this.isPercent = isPercent; this.isPercent = isPercent;
return this; return this;
@ -67,12 +72,12 @@ public class PumpEnactResult extends Object {
return this; return this;
} }
public PumpEnactResult bolusDelivered(Double bolusDelivered) { public PumpEnactResult bolusDelivered(double bolusDelivered) {
this.bolusDelivered = bolusDelivered; this.bolusDelivered = bolusDelivered;
return this; return this;
} }
public PumpEnactResult carbsDelivered(Double carbsDelivered) { public PumpEnactResult carbsDelivered(double carbsDelivered) {
this.carbsDelivered = carbsDelivered; this.carbsDelivered = carbsDelivered;
return this; return this;
} }
@ -82,72 +87,96 @@ public class PumpEnactResult extends Object {
return this; return this;
} }
public String log() { public String log() {
return "Success: " + success + " Enacted: " + enacted + " Comment: " + comment + " Duration: " + duration + " Absolute: " + absolute + " Percent: " + percent + " IsPercent: " + isPercent + " Queued: " + queued; return "Success: " + success +
" Enacted: " + enacted +
" Comment: " + comment +
" Duration: " + duration +
" Absolute: " + absolute +
" Percent: " + percent +
" IsPercent: " + isPercent +
" IsTempCancel: " + isTempCancel +
" bolusDelivered: " + bolusDelivered +
" carbsDelivered: " + carbsDelivered +
" Queued: " + queued;
} }
public String toString() { public String toString() {
String ret = MainApp.sResources.getString(R.string.success) + ": " + success; String ret = MainApp.gs(R.string.success) + ": " + success;
if (enacted) { if (enacted) {
if (isTempCancel) { if (bolusDelivered > 0) {
ret += "\n" + MainApp.sResources.getString(R.string.enacted) + ": " + enacted; ret += "\n" + MainApp.gs(R.string.enacted) + ": " + enacted;
ret += "\n" + MainApp.sResources.getString(R.string.comment) + ": " + comment + "\n" + ret += "\n" + MainApp.gs(R.string.comment) + ": " + comment;
MainApp.sResources.getString(R.string.canceltemp); ret += "\n" + MainApp.gs(R.string.smb_shortname)
+ ": " + bolusDelivered + " " + MainApp.gs(R.string.insulin_unit_shortname);
} else if (isTempCancel) {
ret += "\n" + MainApp.gs(R.string.enacted) + ": " + enacted;
if (!comment.isEmpty())
ret += "\n" + MainApp.gs(R.string.comment) + ": " + comment;
ret += "\n" + MainApp.gs(R.string.canceltemp);
} else if (isPercent) { } else if (isPercent) {
ret += "\n" + MainApp.sResources.getString(R.string.enacted) + ": " + enacted; ret += "\n" + MainApp.gs(R.string.enacted) + ": " + enacted;
ret += "\n" + MainApp.sResources.getString(R.string.comment) + ": " + comment; if (!comment.isEmpty())
ret += "\n" + MainApp.sResources.getString(R.string.duration) + ": " + duration + " min"; ret += "\n" + MainApp.gs(R.string.comment) + ": " + comment;
ret += "\n" + MainApp.sResources.getString(R.string.percent) + ": " + percent + "%"; ret += "\n" + MainApp.gs(R.string.duration) + ": " + duration + " min";
ret += "\n" + MainApp.gs(R.string.percent) + ": " + percent + "%";
} else { } else {
ret += "\n" + MainApp.sResources.getString(R.string.enacted) + ": " + enacted; ret += "\n" + MainApp.gs(R.string.enacted) + ": " + enacted;
ret += "\n" + MainApp.sResources.getString(R.string.comment) + ": " + comment; if (!comment.isEmpty())
ret += "\n" + MainApp.sResources.getString(R.string.duration) + ": " + duration + " min"; ret += "\n" + MainApp.gs(R.string.comment) + ": " + comment;
ret += "\n" + MainApp.sResources.getString(R.string.absolute) + ": " + absolute + " U/h"; ret += "\n" + MainApp.gs(R.string.duration) + ": " + duration + " min";
ret += "\n" + MainApp.gs(R.string.absolute) + ": " + absolute + " U/h";
} }
} else { } else {
ret += "\n" + MainApp.sResources.getString(R.string.comment) + ": " + comment; ret += "\n" + MainApp.gs(R.string.comment) + ": " + comment;
} }
return ret; return ret;
} }
public Spanned toSpanned() { public String toHtml() {
String ret = MainApp.sResources.getString(R.string.success) + ": " + success; String ret = "<b>" + MainApp.gs(R.string.success) + "</b>: " + success;
if (queued) { if (queued) {
ret = MainApp.sResources.getString(R.string.waitingforpumpresult); ret = MainApp.gs(R.string.waitingforpumpresult);
} else if (enacted) { } else if (enacted) {
if (isTempCancel) { if (bolusDelivered > 0) {
ret += "<br><b>" + MainApp.sResources.getString(R.string.enacted) + "</b>: " + enacted; ret += "<br><b>" + MainApp.gs(R.string.enacted) + "</b>: " + enacted;
ret += "<br><b>" + MainApp.sResources.getString(R.string.comment) + "</b>: " + comment + if (!comment.isEmpty())
"<br>" + MainApp.sResources.getString(R.string.canceltemp); ret += "<br><b>" + MainApp.gs(R.string.comment) + "</b>: " + comment;
} else if (isPercent) { ret += "<br><b>" + MainApp.gs(R.string.smb_shortname) + "</b>: " + bolusDelivered + " " + MainApp.gs(R.string.insulin_unit_shortname);
ret += "<br><b>" + MainApp.sResources.getString(R.string.enacted) + "</b>: " + enacted; } else if (isTempCancel) {
ret += "<br><b>" + MainApp.sResources.getString(R.string.comment) + "</b>: " + comment; ret += "<br><b>" + MainApp.gs(R.string.enacted) + "</b>: " + enacted;
ret += "<br><b>" + MainApp.sResources.getString(R.string.duration) + "</b>: " + duration + " min"; ret += "<br><b>" + MainApp.gs(R.string.comment) + "</b>: " + comment +
ret += "<br><b>" + MainApp.sResources.getString(R.string.percent) + "</b>: " + percent + "%"; "<br>" + MainApp.gs(R.string.canceltemp);
} else { } else if (isPercent && percent != -1) {
ret += "<br><b>" + MainApp.sResources.getString(R.string.enacted) + "</b>: " + enacted; ret += "<br><b>" + MainApp.gs(R.string.enacted) + "</b>: " + enacted;
ret += "<br><b>" + MainApp.sResources.getString(R.string.comment) + "</b>: " + comment; if (!comment.isEmpty())
ret += "<br><b>" + MainApp.sResources.getString(R.string.duration) + "</b>: " + duration + " min"; ret += "<br><b>" + MainApp.gs(R.string.comment) + "</b>: " + comment;
ret += "<br><b>" + MainApp.sResources.getString(R.string.absolute) + "</b>: " + DecimalFormatter.to2Decimal(absolute) + " U/h"; ret += "<br><b>" + MainApp.gs(R.string.duration) + "</b>: " + duration + " min";
ret += "<br><b>" + MainApp.gs(R.string.percent) + "</b>: " + percent + "%";
} else if (absolute != -1) {
ret += "<br><b>" + MainApp.gs(R.string.enacted) + "</b>: " + enacted;
if (!comment.isEmpty())
ret += "<br><b>" + MainApp.gs(R.string.comment) + "</b>: " + comment;
ret += "<br><b>" + MainApp.gs(R.string.duration) + "</b>: " + duration + " min";
ret += "<br><b>" + MainApp.gs(R.string.absolute) + "</b>: " + DecimalFormatter.to2Decimal(absolute) + " U/h";
} }
} else { } else {
ret += "<br><b>" + MainApp.sResources.getString(R.string.comment) + "</b>: " + comment; ret += "<br><b>" + MainApp.gs(R.string.comment) + "</b>: " + comment;
} }
return Html.fromHtml(ret); return ret;
} }
public PumpEnactResult() { public JSONObject json(Profile profile) {
}
public JSONObject json() {
JSONObject result = new JSONObject(); JSONObject result = new JSONObject();
try { try {
if (isTempCancel) { if (bolusDelivered > 0) {
result.put("smb", bolusDelivered);
} else if (isTempCancel) {
result.put("rate", 0); result.put("rate", 0);
result.put("duration", 0); result.put("duration", 0);
} else if (isPercent) { } else if (isPercent) {
// Nightscout is expecting absolute value // Nightscout is expecting absolute value
Double abs = Round.roundTo(MainApp.getConfigBuilder().getProfile().getBasal() * percent / 100, 0.01); Double abs = Round.roundTo(profile.getBasal() * percent / 100, 0.01);
result.put("rate", abs); result.put("rate", abs);
result.put("duration", duration); result.put("duration", duration);
} else { } else {

View file

@ -0,0 +1,90 @@
package info.nightscout.androidaps.data;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.MainApp;
import info.nightscout.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();
}
}

View file

@ -0,0 +1,242 @@
package info.nightscout.androidaps.data;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Date;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.db.BgReading;
import info.nightscout.androidaps.db.TempTarget;
import info.nightscout.androidaps.interfaces.TreatmentsInterface;
import info.nightscout.androidaps.plugins.IobCobCalculator.CobInfo;
import info.nightscout.androidaps.plugins.IobCobCalculator.IobCobCalculatorPlugin;
import info.nightscout.androidaps.plugins.Loop.LoopPlugin;
import info.nightscout.androidaps.plugins.Treatments.TreatmentsPlugin;
import info.nightscout.utils.BolusWizard;
import info.nightscout.utils.DateUtil;
import info.nightscout.utils.SP;
/**
* Created by mike on 25.12.2017.
*/
public class QuickWizardEntry {
private static Logger log = LoggerFactory.getLogger(QuickWizardEntry.class);
public JSONObject storage;
public int position;
public static final int YES = 0;
public static final int NO = 1;
public static final int POSITIVE_ONLY = 2;
public static final int NEGATIVE_ONLY = 3;
/*
{
buttonText: "Meal",
carbs: 36,
validFrom: 8 * 60 * 60, // seconds from midnight
validTo: 9 * 60 * 60, // seconds from midnight
useBG: 0,
useCOB: 0,
useBolusIOB: 0,
useBasalIOB: 0,
useTrend: 0,
useSuperBolus: 0,
useTemptarget: 0
}
*/
public QuickWizardEntry() {
String emptyData = "{\"buttonText\":\"\",\"carbs\":0,\"validFrom\":0,\"validTo\":86340}";
try {
storage = new JSONObject(emptyData);
} catch (JSONException e) {
log.error("Unhandled exception", e);
}
position = -1;
}
public QuickWizardEntry(JSONObject entry, int position) {
storage = entry;
this.position = position;
}
public Boolean isActive() {
return Profile.secondsFromMidnight() >= validFrom() && Profile.secondsFromMidnight() <= validTo();
}
public BolusWizard doCalc(Profile profile, TempTarget tempTarget, BgReading lastBG, boolean _synchronized) {
BolusWizard wizard = new BolusWizard();
//BG
double bg = 0;
if (lastBG != null && useBG() == YES) {
bg = lastBG.valueToUnits(profile.getUnits());
}
// COB
double cob = 0d;
if (useCOB() == YES) {
CobInfo cobInfo = IobCobCalculatorPlugin.getPlugin().getCobInfo(_synchronized, "QuickWizard COB");
if (cobInfo.displayCob != null)
cob = cobInfo.displayCob;
}
// Temp target
if (useTempTarget() == NO) {
tempTarget = null;
}
// Bolus IOB
boolean bolusIOB = false;
if (useBolusIOB() == YES) {
bolusIOB = true;
}
// Basal IOB
TreatmentsInterface treatments = TreatmentsPlugin.getPlugin();
treatments.updateTotalIOBTempBasals();
IobTotal basalIob = treatments.getLastCalculationTempBasals().round();
boolean basalIOB = false;
if (useBasalIOB() == YES) {
basalIOB = true;
} else if (useBasalIOB() == POSITIVE_ONLY && basalIob.iob > 0) {
basalIOB = true;
} else if (useBasalIOB() == NEGATIVE_ONLY && basalIob.iob < 0) {
basalIOB = true;
}
// SuperBolus
boolean superBolus = false;
if (useSuperBolus() == YES && SP.getBoolean(R.string.key_usesuperbolus, false)) {
superBolus = true;
}
final LoopPlugin loopPlugin = LoopPlugin.getPlugin();
if (loopPlugin.isEnabled(loopPlugin.getType()) && loopPlugin.isSuperBolus())
superBolus = false;
// Trend
GlucoseStatus glucoseStatus = GlucoseStatus.getGlucoseStatusData();
boolean trend = false;
if (useTrend() == YES) {
trend = true;
} else if (useTrend() == POSITIVE_ONLY && glucoseStatus != null && glucoseStatus.short_avgdelta > 0) {
trend = true;
} else if (useTrend() == NEGATIVE_ONLY && glucoseStatus != null && glucoseStatus.short_avgdelta < 0) {
trend = true;
}
wizard.doCalc(profile, tempTarget, carbs(), cob, bg, 0d, bolusIOB, basalIOB, superBolus, trend);
return wizard;
}
public String buttonText() {
try {
return storage.getString("buttonText");
} catch (JSONException e) {
log.error("Unhandled exception", e);
}
return "";
}
public Integer carbs() {
try {
return storage.getInt("carbs");
} catch (JSONException e) {
log.error("Unhandled exception", e);
}
return 0;
}
public Date validFromDate() {
return DateUtil.toDate(validFrom());
}
public Date validToDate() {
return DateUtil.toDate(validTo());
}
public Integer validFrom() {
try {
return storage.getInt("validFrom");
} catch (JSONException e) {
log.error("Unhandled exception", e);
}
return 0;
}
public Integer validTo() {
try {
return storage.getInt("validTo");
} catch (JSONException e) {
log.error("Unhandled exception", e);
}
return 0;
}
public int useBG() {
try {
return storage.getInt("useBG");
} catch (JSONException e) {
//log.error("Unhandled exception", e);
}
return YES;
}
public int useCOB() {
try {
return storage.getInt("useCOB");
} catch (JSONException e) {
//log.error("Unhandled exception", e);
}
return NO;
}
public int useBolusIOB() {
try {
return storage.getInt("useBolusIOB");
} catch (JSONException e) {
//log.error("Unhandled exception", e);
}
return YES;
}
public int useBasalIOB() {
try {
return storage.getInt("useBasalIOB");
} catch (JSONException e) {
//log.error("Unhandled exception", e);
}
return YES;
}
public int useTrend() {
try {
return storage.getInt("useTrend");
} catch (JSONException e) {
//log.error("Unhandled exception", e);
}
return NO;
}
public int useSuperBolus() {
try {
return storage.getInt("useSuperBolus");
} catch (JSONException e) {
//log.error("Unhandled exception", e);
}
return NO;
}
public int useTempTarget() {
try {
return storage.getInt("useTempTarget");
} catch (JSONException e) {
//log.error("Unhandled exception", e);
}
return NO;
}
}

View file

@ -1,5 +1,7 @@
package info.nightscout.androidaps.db; package info.nightscout.androidaps.db;
import android.content.res.Resources;
import com.j256.ormlite.field.DatabaseField; import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable; import com.j256.ormlite.table.DatabaseTable;
@ -17,7 +19,6 @@ import info.nightscout.androidaps.plugins.NSClientInternal.data.NSSgv;
import info.nightscout.androidaps.plugins.Overview.OverviewPlugin; import info.nightscout.androidaps.plugins.Overview.OverviewPlugin;
import info.nightscout.androidaps.plugins.Overview.graphExtensions.DataPointWithLabelInterface; import info.nightscout.androidaps.plugins.Overview.graphExtensions.DataPointWithLabelInterface;
import info.nightscout.androidaps.plugins.Overview.graphExtensions.PointsWithLabelGraphSeries; import info.nightscout.androidaps.plugins.Overview.graphExtensions.PointsWithLabelGraphSeries;
import info.nightscout.utils.DateUtil;
import info.nightscout.utils.DecimalFormatter; import info.nightscout.utils.DecimalFormatter;
import info.nightscout.utils.SP; import info.nightscout.utils.SP;
@ -43,7 +44,11 @@ public class BgReading implements DataPointWithLabelInterface {
@DatabaseField @DatabaseField
public String _id = null; // NS _id public String _id = null; // NS _id
public boolean isPrediction = false; // true when drawing predictions as bg points public boolean isCOBPrediction = false; // true when drawing predictions as bg points (COB)
public boolean isaCOBPrediction = false; // true when drawing predictions as bg points (aCOB)
public boolean isIOBPrediction = false; // true when drawing predictions as bg points (IOB)
public boolean isUAMPrediction = false; // true when drawing predictions as bg points (UAM)
public boolean isZTPrediction = false; // true when drawing predictions as bg points (ZT)
public BgReading() { public BgReading() {
} }
@ -53,6 +58,7 @@ public class BgReading implements DataPointWithLabelInterface {
value = sgv.getMgdl(); value = sgv.getMgdl();
raw = sgv.getFiltered() != null ? sgv.getFiltered() : value; raw = sgv.getFiltered() != null ? sgv.getFiltered() : value;
direction = sgv.getDirection(); direction = sgv.getDirection();
_id = sgv.getId();
} }
public Double valueToUnits(String units) { public Double valueToUnits(String units) {
@ -183,13 +189,15 @@ public class BgReading implements DataPointWithLabelInterface {
@Override @Override
public PointsWithLabelGraphSeries.Shape getShape() { public PointsWithLabelGraphSeries.Shape getShape() {
return PointsWithLabelGraphSeries.Shape.POINT; if (isPrediction())
return PointsWithLabelGraphSeries.Shape.PREDICTION;
else
return PointsWithLabelGraphSeries.Shape.BG;
} }
@Override @Override
public float getSize() { public float getSize() {
boolean isTablet = MainApp.sResources.getBoolean(R.bool.isTablet); return 1;
return isTablet ? 8 : 5;
} }
@Override @Override
@ -204,8 +212,8 @@ public class BgReading implements DataPointWithLabelInterface {
highLine = Profile.fromMgdlToUnits(OverviewPlugin.bgTargetHigh, units); highLine = Profile.fromMgdlToUnits(OverviewPlugin.bgTargetHigh, units);
} }
int color = MainApp.sResources.getColor(R.color.inrange); int color = MainApp.sResources.getColor(R.color.inrange);
if (isPrediction) if (isPrediction())
color = MainApp.sResources.getColor(R.color.prediction); return getPredectionColor();
else if (valueToUnits(units) < lowLine) else if (valueToUnits(units) < lowLine)
color = MainApp.sResources.getColor(R.color.low); color = MainApp.sResources.getColor(R.color.low);
else if (valueToUnits(units) > highLine) else if (valueToUnits(units) > highLine)
@ -213,4 +221,22 @@ public class BgReading implements DataPointWithLabelInterface {
return color; return color;
} }
public int getPredectionColor() {
if (isIOBPrediction)
return MainApp.sResources.getColor(R.color.iob);
if (isCOBPrediction)
return MainApp.sResources.getColor(R.color.cob);
if (isaCOBPrediction)
return 0x80FFFFFF & MainApp.sResources.getColor(R.color.cob);
if (isUAMPrediction)
return MainApp.sResources.getColor(R.color.uam);
if (isZTPrediction)
return MainApp.sResources.getColor(R.color.zt);
return R.color.mdtp_white;
}
private boolean isPrediction() {
return isaCOBPrediction || isCOBPrediction || isIOBPrediction || isUAMPrediction || isZTPrediction;
}
} }

View file

@ -5,6 +5,7 @@ import android.graphics.Color;
import com.j256.ormlite.field.DatabaseField; import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable; import com.j256.ormlite.table.DatabaseTable;
import org.apache.commons.lang3.StringUtils;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -94,7 +95,15 @@ public class CareportalEvent implements DataPointWithLabelInterface {
if (OverviewFragment.shorttextmode) if (OverviewFragment.shorttextmode)
return diff.get(TimeUnit.DAYS) +"d" + diff.get(TimeUnit.HOURS) + "h"; return diff.get(TimeUnit.DAYS) +"d" + diff.get(TimeUnit.HOURS) + "h";
else else
return diff.get(TimeUnit.DAYS) + " " + MainApp.sResources.getString(R.string.days) + " " + diff.get(TimeUnit.HOURS) + " " + MainApp.sResources.getString(R.string.hours); return diff.get(TimeUnit.DAYS) + " " + MainApp.gs(R.string.days) + " " + diff.get(TimeUnit.HOURS) + " " + MainApp.gs(R.string.hours);
}
public boolean isOlderThan(double hours) {
Map<TimeUnit, Long> diff = computeDiff(date, System.currentTimeMillis());
if(diff.get(TimeUnit.DAYS)*24 + diff.get(TimeUnit.HOURS) > hours)
return true;
else
return false;
} }
public String log() { public String log() {
@ -184,13 +193,24 @@ public class CareportalEvent implements DataPointWithLabelInterface {
try { try {
JSONObject object = new JSONObject(json); JSONObject object = new JSONObject(json);
if (object.has("notes")) if (object.has("notes"))
return object.getString("notes"); return StringUtils.abbreviate(object.getString("notes"), 40);
} catch (JSONException e) { } catch (JSONException e) {
log.error("Unhandled exception", e); log.error("Unhandled exception", e);
} }
return Translator.translate(eventType); return Translator.translate(eventType);
} }
public String getNotes() {
try {
JSONObject object = new JSONObject(json);
if (object.has("notes"))
return object.getString("notes");
} catch (JSONException e) {
log.error("Unhandled exception", e);
}
return "";
}
@Override @Override
public long getDuration() { public long getDuration() {
try { try {
@ -242,4 +262,5 @@ public class CareportalEvent implements DataPointWithLabelInterface {
return Color.GRAY; return Color.GRAY;
return Color.GRAY; return Color.GRAY;
} }
} }

View file

@ -31,9 +31,9 @@ import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.Constants; import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.data.ProfileStore;
import info.nightscout.androidaps.events.EventCareportalEventChange; import info.nightscout.androidaps.events.EventCareportalEventChange;
import info.nightscout.androidaps.events.EventExtendedBolusChange; import info.nightscout.androidaps.events.EventExtendedBolusChange;
import info.nightscout.androidaps.events.EventFoodDatabaseChanged;
import info.nightscout.androidaps.events.EventNewBG; import info.nightscout.androidaps.events.EventNewBG;
import info.nightscout.androidaps.events.EventProfileSwitchChange; import info.nightscout.androidaps.events.EventProfileSwitchChange;
import info.nightscout.androidaps.events.EventRefreshOverview; import info.nightscout.androidaps.events.EventRefreshOverview;
@ -42,11 +42,23 @@ import info.nightscout.androidaps.events.EventReloadTempBasalData;
import info.nightscout.androidaps.events.EventReloadTreatmentData; import info.nightscout.androidaps.events.EventReloadTreatmentData;
import info.nightscout.androidaps.events.EventTempBasalChange; import info.nightscout.androidaps.events.EventTempBasalChange;
import info.nightscout.androidaps.events.EventTempTargetChange; import info.nightscout.androidaps.events.EventTempTargetChange;
import info.nightscout.androidaps.events.EventTreatmentChange;
import info.nightscout.androidaps.plugins.IobCobCalculator.events.EventNewHistoryData; import info.nightscout.androidaps.plugins.IobCobCalculator.events.EventNewHistoryData;
import info.nightscout.androidaps.plugins.PumpDanaR.activities.DanaRNSHistorySync; import info.nightscout.androidaps.plugins.PumpDanaR.activities.DanaRNSHistorySync;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.RecordTypes;
import info.nightscout.androidaps.plugins.PumpVirtual.VirtualPumpPlugin; import info.nightscout.androidaps.plugins.PumpVirtual.VirtualPumpPlugin;
import info.nightscout.utils.JsonHelper;
import info.nightscout.utils.NSUpload;
import info.nightscout.utils.PercentageSplitter;
import info.nightscout.utils.ToastUtils;
/**
* This Helper contains all resource to provide a central DB management functionality. Only methods handling
* data-structure (and not the DB content) should be contained in here (meaning DDL and not SQL).
* <p>
* This class can safely be called from Services, but should not call Services to avoid circular dependencies.
* One major issue with this (right now) are the scheduled events, which are put into the service. Therefor all
* direct calls to the corresponding methods (eg. resetDatabases) should be done by a central service.
*/
public class DatabaseHelper extends OrmLiteSqliteOpenHelper { public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
private static Logger log = LoggerFactory.getLogger(DatabaseHelper.class); private static Logger log = LoggerFactory.getLogger(DatabaseHelper.class);
@ -55,23 +67,19 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
public static final String DATABASE_TEMPORARYBASALS = "TemporaryBasals"; public static final String DATABASE_TEMPORARYBASALS = "TemporaryBasals";
public static final String DATABASE_EXTENDEDBOLUSES = "ExtendedBoluses"; public static final String DATABASE_EXTENDEDBOLUSES = "ExtendedBoluses";
public static final String DATABASE_TEMPTARGETS = "TempTargets"; public static final String DATABASE_TEMPTARGETS = "TempTargets";
public static final String DATABASE_TREATMENTS = "Treatments";
public static final String DATABASE_DANARHISTORY = "DanaRHistory"; public static final String DATABASE_DANARHISTORY = "DanaRHistory";
public static final String DATABASE_DBREQUESTS = "DBRequests"; public static final String DATABASE_DBREQUESTS = "DBRequests";
public static final String DATABASE_CAREPORTALEVENTS = "CareportalEvents"; public static final String DATABASE_CAREPORTALEVENTS = "CareportalEvents";
public static final String DATABASE_PROFILESWITCHES = "ProfileSwitches"; public static final String DATABASE_PROFILESWITCHES = "ProfileSwitches";
public static final String DATABASE_FOODS = "Foods"; public static final String DATABASE_TDDS = "TDDs";
private static final int DATABASE_VERSION = 8; private static final int DATABASE_VERSION = 8;
private static Long earliestDataChange = null; public static Long earliestDataChange = null;
private static final ScheduledExecutorService bgWorker = Executors.newSingleThreadScheduledExecutor(); private static final ScheduledExecutorService bgWorker = Executors.newSingleThreadScheduledExecutor();
private static ScheduledFuture<?> scheduledBgPost = null; private static ScheduledFuture<?> scheduledBgPost = null;
private static final ScheduledExecutorService treatmentsWorker = Executors.newSingleThreadScheduledExecutor();
private static ScheduledFuture<?> scheduledTratmentPost = null;
private static final ScheduledExecutorService tempBasalsWorker = Executors.newSingleThreadScheduledExecutor(); private static final ScheduledExecutorService tempBasalsWorker = Executors.newSingleThreadScheduledExecutor();
private static ScheduledFuture<?> scheduledTemBasalsPost = null; private static ScheduledFuture<?> scheduledTemBasalsPost = null;
@ -87,7 +95,8 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
private static final ScheduledExecutorService profileSwitchEventWorker = Executors.newSingleThreadScheduledExecutor(); private static final ScheduledExecutorService profileSwitchEventWorker = Executors.newSingleThreadScheduledExecutor();
private static ScheduledFuture<?> scheduledProfileSwitchEventPost = null; private static ScheduledFuture<?> scheduledProfileSwitchEventPost = null;
public FoodHelper foodHelper = new FoodHelper(this); private int oldVersion = 0;
private int newVersion = 0;
public DatabaseHelper(Context context) { public DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION); super(context, DATABASE_NAME, null, DATABASE_VERSION);
@ -100,7 +109,6 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
try { try {
log.info("onCreate"); log.info("onCreate");
TableUtils.createTableIfNotExists(connectionSource, TempTarget.class); TableUtils.createTableIfNotExists(connectionSource, TempTarget.class);
TableUtils.createTableIfNotExists(connectionSource, Treatment.class);
TableUtils.createTableIfNotExists(connectionSource, BgReading.class); TableUtils.createTableIfNotExists(connectionSource, BgReading.class);
TableUtils.createTableIfNotExists(connectionSource, DanaRHistoryRecord.class); TableUtils.createTableIfNotExists(connectionSource, DanaRHistoryRecord.class);
TableUtils.createTableIfNotExists(connectionSource, DbRequest.class); TableUtils.createTableIfNotExists(connectionSource, DbRequest.class);
@ -108,7 +116,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
TableUtils.createTableIfNotExists(connectionSource, ExtendedBolus.class); TableUtils.createTableIfNotExists(connectionSource, ExtendedBolus.class);
TableUtils.createTableIfNotExists(connectionSource, CareportalEvent.class); TableUtils.createTableIfNotExists(connectionSource, CareportalEvent.class);
TableUtils.createTableIfNotExists(connectionSource, ProfileSwitch.class); TableUtils.createTableIfNotExists(connectionSource, ProfileSwitch.class);
TableUtils.createTableIfNotExists(connectionSource, Food.class); TableUtils.createTableIfNotExists(connectionSource, TDD.class);
} catch (SQLException e) { } catch (SQLException e) {
log.error("Can't create database", e); log.error("Can't create database", e);
throw new RuntimeException(e); throw new RuntimeException(e);
@ -118,14 +126,14 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
@Override @Override
public void onUpgrade(SQLiteDatabase database, ConnectionSource connectionSource, int oldVersion, int newVersion) { public void onUpgrade(SQLiteDatabase database, ConnectionSource connectionSource, int oldVersion, int newVersion) {
try { try {
this.oldVersion = oldVersion;
this.newVersion = newVersion;
if (oldVersion == 7 && newVersion == 8) { if (oldVersion == 7 && newVersion == 8) {
log.debug("Upgrading database from v7 to v8"); log.debug("Upgrading database from v7 to v8");
TableUtils.dropTable(connectionSource, Treatment.class, true);
TableUtils.createTableIfNotExists(connectionSource, Treatment.class);
} else { } else {
log.info(DatabaseHelper.class.getName(), "onUpgrade"); log.info(DatabaseHelper.class.getName(), "onUpgrade");
TableUtils.dropTable(connectionSource, TempTarget.class, true); TableUtils.dropTable(connectionSource, TempTarget.class, true);
TableUtils.dropTable(connectionSource, Treatment.class, true);
TableUtils.dropTable(connectionSource, BgReading.class, true); TableUtils.dropTable(connectionSource, BgReading.class, true);
TableUtils.dropTable(connectionSource, DanaRHistoryRecord.class, true); TableUtils.dropTable(connectionSource, DanaRHistoryRecord.class, true);
TableUtils.dropTable(connectionSource, DbRequest.class, true); TableUtils.dropTable(connectionSource, DbRequest.class, true);
@ -133,7 +141,6 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
TableUtils.dropTable(connectionSource, ExtendedBolus.class, true); TableUtils.dropTable(connectionSource, ExtendedBolus.class, true);
TableUtils.dropTable(connectionSource, CareportalEvent.class, true); TableUtils.dropTable(connectionSource, CareportalEvent.class, true);
TableUtils.dropTable(connectionSource, ProfileSwitch.class, true); TableUtils.dropTable(connectionSource, ProfileSwitch.class, true);
TableUtils.dropTable(connectionSource, Food.class, true);
onCreate(database, connectionSource); onCreate(database, connectionSource);
} }
} catch (SQLException e) { } catch (SQLException e) {
@ -142,6 +149,14 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
} }
} }
public int getOldVersion() {
return oldVersion;
}
public int getNewVersion() {
return newVersion;
}
/** /**
* Close the database connections and clear any cached DAOs. * Close the database connections and clear any cached DAOs.
*/ */
@ -150,40 +165,6 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
super.close(); super.close();
} }
public void cleanUpDatabases() {
// TODO: call it somewhere
log.debug("Before BgReadings size: " + DatabaseUtils.queryNumEntries(getReadableDatabase(), DATABASE_BGREADINGS));
getWritableDatabase().delete(DATABASE_BGREADINGS, "date" + " < '" + (System.currentTimeMillis() - Constants.hoursToKeepInDatabase * 60 * 60 * 1000L) + "'", null);
log.debug("After BgReadings size: " + DatabaseUtils.queryNumEntries(getReadableDatabase(), DATABASE_BGREADINGS));
log.debug("Before TempTargets size: " + DatabaseUtils.queryNumEntries(getReadableDatabase(), DATABASE_TEMPTARGETS));
getWritableDatabase().delete(DATABASE_TEMPTARGETS, "date" + " < '" + (System.currentTimeMillis() - Constants.hoursToKeepInDatabase * 60 * 60 * 1000L) + "'", null);
log.debug("After TempTargets size: " + DatabaseUtils.queryNumEntries(getReadableDatabase(), DATABASE_TEMPTARGETS));
log.debug("Before Treatments size: " + DatabaseUtils.queryNumEntries(getReadableDatabase(), DATABASE_TREATMENTS));
getWritableDatabase().delete(DATABASE_TREATMENTS, "date" + " < '" + (System.currentTimeMillis() - Constants.hoursToKeepInDatabase * 60 * 60 * 1000L) + "'", null);
log.debug("After Treatments size: " + DatabaseUtils.queryNumEntries(getReadableDatabase(), DATABASE_TREATMENTS));
log.debug("Before History size: " + DatabaseUtils.queryNumEntries(getReadableDatabase(), DATABASE_DANARHISTORY));
getWritableDatabase().delete(DATABASE_DANARHISTORY, "recordDate" + " < '" + (System.currentTimeMillis() - Constants.daysToKeepHistoryInDatabase * 24 * 60 * 60 * 1000L) + "'", null);
log.debug("After History size: " + DatabaseUtils.queryNumEntries(getReadableDatabase(), DATABASE_DANARHISTORY));
log.debug("Before TemporaryBasals size: " + DatabaseUtils.queryNumEntries(getReadableDatabase(), DATABASE_TEMPORARYBASALS));
getWritableDatabase().delete(DATABASE_TEMPORARYBASALS, "recordDate" + " < '" + (System.currentTimeMillis() - Constants.daysToKeepHistoryInDatabase * 24 * 60 * 60 * 1000L) + "'", null);
log.debug("After TemporaryBasals size: " + DatabaseUtils.queryNumEntries(getReadableDatabase(), DATABASE_TEMPORARYBASALS));
log.debug("Before ExtendedBoluses size: " + DatabaseUtils.queryNumEntries(getReadableDatabase(), DATABASE_EXTENDEDBOLUSES));
getWritableDatabase().delete(DATABASE_EXTENDEDBOLUSES, "recordDate" + " < '" + (System.currentTimeMillis() - Constants.daysToKeepHistoryInDatabase * 24 * 60 * 60 * 1000L) + "'", null);
log.debug("After ExtendedBoluses size: " + DatabaseUtils.queryNumEntries(getReadableDatabase(), DATABASE_EXTENDEDBOLUSES));
log.debug("Before CareportalEvent size: " + DatabaseUtils.queryNumEntries(getReadableDatabase(), DATABASE_CAREPORTALEVENTS));
getWritableDatabase().delete(DATABASE_CAREPORTALEVENTS, "recordDate" + " < '" + (System.currentTimeMillis() - Constants.daysToKeepHistoryInDatabase * 24 * 60 * 60 * 1000L) + "'", null);
log.debug("After CareportalEvent size: " + DatabaseUtils.queryNumEntries(getReadableDatabase(), DATABASE_CAREPORTALEVENTS));
log.debug("Before ProfileSwitch size: " + DatabaseUtils.queryNumEntries(getReadableDatabase(), DATABASE_PROFILESWITCHES));
getWritableDatabase().delete(DATABASE_PROFILESWITCHES, "recordDate" + " < '" + (System.currentTimeMillis() - Constants.daysToKeepHistoryInDatabase * 24 * 60 * 60 * 1000L) + "'", null);
log.debug("After ProfileSwitch size: " + DatabaseUtils.queryNumEntries(getReadableDatabase(), DATABASE_PROFILESWITCHES));
}
public long size(String database) { public long size(String database) {
return DatabaseUtils.queryNumEntries(getReadableDatabase(), database); return DatabaseUtils.queryNumEntries(getReadableDatabase(), database);
@ -194,7 +175,6 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
public void resetDatabases() { public void resetDatabases() {
try { try {
TableUtils.dropTable(connectionSource, TempTarget.class, true); TableUtils.dropTable(connectionSource, TempTarget.class, true);
TableUtils.dropTable(connectionSource, Treatment.class, true);
TableUtils.dropTable(connectionSource, BgReading.class, true); TableUtils.dropTable(connectionSource, BgReading.class, true);
TableUtils.dropTable(connectionSource, DanaRHistoryRecord.class, true); TableUtils.dropTable(connectionSource, DanaRHistoryRecord.class, true);
TableUtils.dropTable(connectionSource, DbRequest.class, true); TableUtils.dropTable(connectionSource, DbRequest.class, true);
@ -202,8 +182,8 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
TableUtils.dropTable(connectionSource, ExtendedBolus.class, true); TableUtils.dropTable(connectionSource, ExtendedBolus.class, true);
TableUtils.dropTable(connectionSource, CareportalEvent.class, true); TableUtils.dropTable(connectionSource, CareportalEvent.class, true);
TableUtils.dropTable(connectionSource, ProfileSwitch.class, true); TableUtils.dropTable(connectionSource, ProfileSwitch.class, true);
TableUtils.dropTable(connectionSource, TDD.class, true);
TableUtils.createTableIfNotExists(connectionSource, TempTarget.class); TableUtils.createTableIfNotExists(connectionSource, TempTarget.class);
TableUtils.createTableIfNotExists(connectionSource, Treatment.class);
TableUtils.createTableIfNotExists(connectionSource, BgReading.class); TableUtils.createTableIfNotExists(connectionSource, BgReading.class);
TableUtils.createTableIfNotExists(connectionSource, DanaRHistoryRecord.class); TableUtils.createTableIfNotExists(connectionSource, DanaRHistoryRecord.class);
TableUtils.createTableIfNotExists(connectionSource, DbRequest.class); TableUtils.createTableIfNotExists(connectionSource, DbRequest.class);
@ -211,20 +191,18 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
TableUtils.createTableIfNotExists(connectionSource, ExtendedBolus.class); TableUtils.createTableIfNotExists(connectionSource, ExtendedBolus.class);
TableUtils.createTableIfNotExists(connectionSource, CareportalEvent.class); TableUtils.createTableIfNotExists(connectionSource, CareportalEvent.class);
TableUtils.createTableIfNotExists(connectionSource, ProfileSwitch.class); TableUtils.createTableIfNotExists(connectionSource, ProfileSwitch.class);
foodHelper.resetFood(); TableUtils.createTableIfNotExists(connectionSource, TDD.class);
updateEarliestDataChange(0); updateEarliestDataChange(0);
} catch (SQLException e) { } catch (SQLException e) {
log.error("Unhandled exception", e); log.error("Unhandled exception", e);
} }
VirtualPumpPlugin.setFakingStatus(true); VirtualPumpPlugin.setFakingStatus(true);
scheduleBgChange(); // trigger refresh scheduleBgChange(null); // trigger refresh
scheduleTemporaryBasalChange(); scheduleTemporaryBasalChange();
scheduleTreatmentChange();
scheduleExtendedBolusChange(); scheduleExtendedBolusChange();
scheduleTemporaryTargetChange(); scheduleTemporaryTargetChange();
scheduleCareportalEventChange(); scheduleCareportalEventChange();
scheduleProfileSwitchChange(); scheduleProfileSwitchChange();
foodHelper.scheduleFoodChange();
new java.util.Timer().schedule( new java.util.Timer().schedule(
new java.util.TimerTask() { new java.util.TimerTask() {
@Override @Override
@ -236,17 +214,6 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
); );
} }
public void resetTreatments() {
try {
TableUtils.dropTable(connectionSource, Treatment.class, true);
TableUtils.createTableIfNotExists(connectionSource, Treatment.class);
updateEarliestDataChange(0);
} catch (SQLException e) {
log.error("Unhandled exception", e);
}
scheduleTreatmentChange();
}
public void resetTempTargets() { public void resetTempTargets() {
try { try {
TableUtils.dropTable(connectionSource, TempTarget.class, true); TableUtils.dropTable(connectionSource, TempTarget.class, true);
@ -300,16 +267,21 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
scheduleProfileSwitchChange(); scheduleProfileSwitchChange();
} }
public void resetTDDs() {
try {
TableUtils.dropTable(connectionSource, TDD.class, true);
TableUtils.createTableIfNotExists(connectionSource, TDD.class);
} catch (SQLException e) {
log.error("Unhandled exception", e);
}
}
// ------------------ getDao ------------------------------------------- // ------------------ getDao -------------------------------------------
private Dao<TempTarget, Long> getDaoTempTargets() throws SQLException { private Dao<TempTarget, Long> getDaoTempTargets() throws SQLException {
return getDao(TempTarget.class); return getDao(TempTarget.class);
} }
private Dao<Treatment, Long> getDaoTreatments() throws SQLException {
return getDao(Treatment.class);
}
private Dao<BgReading, Long> getDaoBgReadings() throws SQLException { private Dao<BgReading, Long> getDaoBgReadings() throws SQLException {
return getDao(BgReading.class); return getDao(BgReading.class);
} }
@ -318,6 +290,10 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
return getDao(DanaRHistoryRecord.class); return getDao(DanaRHistoryRecord.class);
} }
private Dao<TDD, String> getDaoTDD() throws SQLException {
return getDao(TDD.class);
}
private Dao<DbRequest, String> getDaoDbRequest() throws SQLException { private Dao<DbRequest, String> getDaoDbRequest() throws SQLException {
return getDao(DbRequest.class); return getDao(DbRequest.class);
} }
@ -338,7 +314,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
return getDao(ProfileSwitch.class); return getDao(ProfileSwitch.class);
} }
public long roundDateToSec(long date) { public static long roundDateToSec(long date) {
return date - date % 1000; return date - date % 1000;
} }
// ------------------- BgReading handling ----------------------- // ------------------- BgReading handling -----------------------
@ -350,7 +326,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
if (old == null) { if (old == null) {
getDaoBgReadings().create(bgReading); getDaoBgReadings().create(bgReading);
log.debug("BG: New record from: " + from + " " + bgReading.toString()); log.debug("BG: New record from: " + from + " " + bgReading.toString());
scheduleBgChange(); scheduleBgChange(bgReading);
return true; return true;
} }
if (!old.isEqual(bgReading)) { if (!old.isEqual(bgReading)) {
@ -358,7 +334,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
old.copyFrom(bgReading); old.copyFrom(bgReading);
getDaoBgReadings().update(old); getDaoBgReadings().update(old);
log.debug("BG: Updating record from: " + from + " New data: " + old.toString()); log.debug("BG: Updating record from: " + from + " New data: " + old.toString());
scheduleBgChange(); scheduleBgChange(bgReading);
return false; return false;
} }
} catch (SQLException e) { } catch (SQLException e) {
@ -367,11 +343,20 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
return false; return false;
} }
private static void scheduleBgChange() { public void update(BgReading bgReading) {
bgReading.date = roundDateToSec(bgReading.date);
try {
getDaoBgReadings().update(bgReading);
} catch (SQLException e) {
log.error("Unhandled exception", e);
}
}
private static void scheduleBgChange(@Nullable final BgReading bgReading) {
class PostRunnable implements Runnable { class PostRunnable implements Runnable {
public void run() { public void run() {
log.debug("Firing EventNewBg"); log.debug("Firing EventNewBg");
MainApp.bus().post(new EventNewBG()); MainApp.bus().post(new EventNewBG(bgReading));
scheduledBgPost = null; scheduledBgPost = null;
} }
} }
@ -386,8 +371,8 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
} }
/* /*
* Return last BgReading from database or null if db is empty * Return last BgReading from database or null if db is empty
*/ */
@Nullable @Nullable
public static BgReading lastBg() { public static BgReading lastBg() {
List<BgReading> bgList = null; List<BgReading> bgList = null;
@ -397,7 +382,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
QueryBuilder<BgReading, Long> queryBuilder = daoBgReadings.queryBuilder(); QueryBuilder<BgReading, Long> queryBuilder = daoBgReadings.queryBuilder();
queryBuilder.orderBy("date", false); queryBuilder.orderBy("date", false);
queryBuilder.limit(1L); queryBuilder.limit(1L);
queryBuilder.where().gt("value", 38); queryBuilder.where().gt("value", 38).and().eq("isValid", true);
PreparedQuery<BgReading> preparedQuery = queryBuilder.prepare(); PreparedQuery<BgReading> preparedQuery = queryBuilder.prepare();
bgList = daoBgReadings.query(preparedQuery); bgList = daoBgReadings.query(preparedQuery);
@ -411,9 +396,9 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
} }
/* /*
* Return bg reading if not old ( <9 min ) * Return bg reading if not old ( <9 min )
* or null if older * or null if older
*/ */
@Nullable @Nullable
public static BgReading actualBg() { public static BgReading actualBg() {
BgReading lastBg = lastBg(); BgReading lastBg = lastBg();
@ -435,7 +420,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
QueryBuilder<BgReading, Long> queryBuilder = daoBgreadings.queryBuilder(); QueryBuilder<BgReading, Long> queryBuilder = daoBgreadings.queryBuilder();
queryBuilder.orderBy("date", ascending); queryBuilder.orderBy("date", ascending);
Where where = queryBuilder.where(); Where where = queryBuilder.where();
where.ge("date", mills).and().gt("value", 38); where.ge("date", mills).and().gt("value", 38).and().eq("isValid", true);
PreparedQuery<BgReading> preparedQuery = queryBuilder.prepare(); PreparedQuery<BgReading> preparedQuery = queryBuilder.prepare();
bgReadings = daoBgreadings.query(preparedQuery); bgReadings = daoBgreadings.query(preparedQuery);
return bgReadings; return bgReadings;
@ -445,6 +430,50 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
return new ArrayList<BgReading>(); return new ArrayList<BgReading>();
} }
public List<BgReading> getAllBgreadingsDataFromTime(long mills, boolean ascending) {
try {
Dao<BgReading, Long> daoBgreadings = getDaoBgReadings();
List<BgReading> bgReadings;
QueryBuilder<BgReading, Long> queryBuilder = daoBgreadings.queryBuilder();
queryBuilder.orderBy("date", ascending);
Where where = queryBuilder.where();
where.ge("date", mills);
PreparedQuery<BgReading> preparedQuery = queryBuilder.prepare();
bgReadings = daoBgreadings.query(preparedQuery);
return bgReadings;
} catch (SQLException e) {
log.error("Unhandled exception", e);
}
return new ArrayList<BgReading>();
}
// ------------------- TDD handling -----------------------
public void createOrUpdateTDD(TDD tdd) {
try {
Dao<TDD, String> dao = getDaoTDD();
dao.createOrUpdate(tdd);
} catch (SQLException e) {
ToastUtils.showToastInUiThread(MainApp.instance(), "createOrUpdate-Exception");
log.error("Unhandled exception", e);
}
}
public List<TDD> getTDDs() {
List<TDD> tddList;
try {
QueryBuilder<TDD, String> queryBuilder = getDaoTDD().queryBuilder();
queryBuilder.orderBy("date", false);
queryBuilder.limit(10L);
PreparedQuery<TDD> preparedQuery = queryBuilder.prepare();
tddList = getDaoTDD().query(preparedQuery);
} catch (SQLException e) {
log.error("Unhandled exception", e);
tddList = new ArrayList<>();
}
return tddList;
}
// ------------- DbRequests handling ------------------- // ------------- DbRequests handling -------------------
public void create(DbRequest dbr) { public void create(DbRequest dbr) {
@ -473,7 +502,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
return 0; return 0;
} }
public int deleteDbRequestbyMongoId(String action, String id) { public void deleteDbRequestbyMongoId(String action, String id) {
try { try {
QueryBuilder<DbRequest, String> queryBuilder = getDaoDbRequest().queryBuilder(); QueryBuilder<DbRequest, String> queryBuilder = getDaoDbRequest().queryBuilder();
Where where = queryBuilder.where(); Where where = queryBuilder.where();
@ -481,16 +510,12 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
queryBuilder.limit(10L); queryBuilder.limit(10L);
PreparedQuery<DbRequest> preparedQuery = queryBuilder.prepare(); PreparedQuery<DbRequest> preparedQuery = queryBuilder.prepare();
List<DbRequest> dbList = getDaoDbRequest().query(preparedQuery); List<DbRequest> dbList = getDaoDbRequest().query(preparedQuery);
if (dbList.size() != 1) { for (DbRequest r : dbList) {
log.error("deleteDbRequestbyMongoId query size: " + dbList.size()); delete(r);
} else {
//log.debug("Treatment findTreatmentById found: " + trList.get(0).log());
return delete(dbList.get(0));
} }
} catch (SQLException e) { } catch (SQLException e) {
log.error("Unhandled exception", e); log.error("Unhandled exception", e);
} }
return 0;
} }
public void deleteAllDbRequests() { public void deleteAllDbRequests() {
@ -512,146 +537,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
// -------------------- TREATMENT HANDLING ------------------- // -------------------- TREATMENT HANDLING -------------------
// return true if new record is created public static void updateEarliestDataChange(long newDate) {
public boolean createOrUpdate(Treatment treatment) {
try {
Treatment old;
treatment.date = roundDateToSec(treatment.date);
if (treatment.source == Source.PUMP) {
// check for changed from pump change in NS
QueryBuilder<Treatment, Long> queryBuilder = getDaoTreatments().queryBuilder();
Where where = queryBuilder.where();
where.eq("pumpId", treatment.pumpId);
PreparedQuery<Treatment> preparedQuery = queryBuilder.prepare();
List<Treatment> trList = getDaoTreatments().query(preparedQuery);
if (trList.size() > 0) {
// do nothing, pump history record cannot be changed
return false;
}
getDaoTreatments().create(treatment);
log.debug("TREATMENT: New record from: " + Source.getString(treatment.source) + " " + treatment.toString());
updateEarliestDataChange(treatment.date);
scheduleTreatmentChange();
return true;
}
if (treatment.source == Source.NIGHTSCOUT) {
old = getDaoTreatments().queryForId(treatment.date);
if (old != null) {
if (!old.isEqual(treatment)) {
boolean historyChange = old.isDataChanging(treatment);
long oldDate = old.date;
getDaoTreatments().delete(old); // need to delete/create because date may change too
old.copyFrom(treatment);
getDaoTreatments().create(old);
log.debug("TREATMENT: Updating record by date from: " + Source.getString(treatment.source) + " " + old.toString());
if (historyChange) {
updateEarliestDataChange(oldDate);
updateEarliestDataChange(old.date);
}
scheduleTreatmentChange();
return true;
}
return false;
}
// find by NS _id
if (treatment._id != null) {
QueryBuilder<Treatment, Long> queryBuilder = getDaoTreatments().queryBuilder();
Where where = queryBuilder.where();
where.eq("_id", treatment._id);
PreparedQuery<Treatment> preparedQuery = queryBuilder.prepare();
List<Treatment> trList = getDaoTreatments().query(preparedQuery);
if (trList.size() > 0) {
old = trList.get(0);
if (!old.isEqual(treatment)) {
boolean historyChange = old.isDataChanging(treatment);
long oldDate = old.date;
getDaoTreatments().delete(old); // need to delete/create because date may change too
old.copyFrom(treatment);
getDaoTreatments().create(old);
log.debug("TREATMENT: Updating record by _id from: " + Source.getString(treatment.source) + " " + old.toString());
if (historyChange) {
updateEarliestDataChange(oldDate);
updateEarliestDataChange(old.date);
}
scheduleTreatmentChange();
return true;
}
}
}
getDaoTreatments().create(treatment);
log.debug("TREATMENT: New record from: " + Source.getString(treatment.source) + " " + treatment.toString());
updateEarliestDataChange(treatment.date);
scheduleTreatmentChange();
return true;
}
if (treatment.source == Source.USER) {
getDaoTreatments().create(treatment);
log.debug("TREATMENT: New record from: " + Source.getString(treatment.source) + " " + treatment.toString());
updateEarliestDataChange(treatment.date);
scheduleTreatmentChange();
return true;
}
} catch (SQLException e) {
log.error("Unhandled exception", e);
}
return false;
}
public void delete(Treatment treatment) {
try {
getDaoTreatments().delete(treatment);
updateEarliestDataChange(treatment.date);
} catch (SQLException e) {
log.error("Unhandled exception", e);
}
scheduleTreatmentChange();
}
public void update(Treatment treatment) {
try {
getDaoTreatments().update(treatment);
updateEarliestDataChange(treatment.date);
} catch (SQLException e) {
log.error("Unhandled exception", e);
}
scheduleTreatmentChange();
}
public void deleteTreatmentById(String _id) {
Treatment stored = findTreatmentById(_id);
if (stored != null) {
log.debug("TREATMENT: Removing Treatment record from database: " + stored.toString());
delete(stored);
updateEarliestDataChange(stored.date);
scheduleTreatmentChange();
}
}
@Nullable
public Treatment findTreatmentById(String _id) {
try {
Dao<Treatment, Long> daoTreatments = getDaoTreatments();
QueryBuilder<Treatment, Long> queryBuilder = daoTreatments.queryBuilder();
Where where = queryBuilder.where();
where.eq("_id", _id);
queryBuilder.limit(10L);
PreparedQuery<Treatment> preparedQuery = queryBuilder.prepare();
List<Treatment> trList = daoTreatments.query(preparedQuery);
if (trList.size() != 1) {
//log.debug("Treatment findTreatmentById query size: " + trList.size());
return null;
} else {
//log.debug("Treatment findTreatmentById found: " + trList.get(0).log());
return trList.get(0);
}
} catch (SQLException e) {
log.error("Unhandled exception", e);
}
return null;
}
private void updateEarliestDataChange(long newDate) {
if (earliestDataChange == null) { if (earliestDataChange == null) {
earliestDataChange = newDate; earliestDataChange = newDate;
return; return;
@ -661,73 +547,6 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
} }
} }
private static void scheduleTreatmentChange() {
class PostRunnable implements Runnable {
public void run() {
log.debug("Firing EventTreatmentChange");
MainApp.bus().post(new EventReloadTreatmentData(new EventTreatmentChange()));
if (earliestDataChange != null)
MainApp.bus().post(new EventNewHistoryData(earliestDataChange));
earliestDataChange = null;
scheduledTratmentPost = null;
}
}
// prepare task for execution in 1 sec
// cancel waiting task to prevent sending multiple posts
if (scheduledTratmentPost != null)
scheduledTratmentPost.cancel(false);
Runnable task = new PostRunnable();
final int sec = 1;
scheduledTratmentPost = treatmentsWorker.schedule(task, sec, TimeUnit.SECONDS);
}
public List<Treatment> getTreatmentDataFromTime(long mills, boolean ascending) {
try {
Dao<Treatment, Long> daoTreatments = getDaoTreatments();
List<Treatment> treatments;
QueryBuilder<Treatment, Long> queryBuilder = daoTreatments.queryBuilder();
queryBuilder.orderBy("date", ascending);
Where where = queryBuilder.where();
where.ge("date", mills);
PreparedQuery<Treatment> preparedQuery = queryBuilder.prepare();
treatments = daoTreatments.query(preparedQuery);
return treatments;
} catch (SQLException e) {
log.error("Unhandled exception", e);
}
return new ArrayList<Treatment>();
}
public void createTreatmentFromJsonIfNotExists(JSONObject trJson) {
try {
Treatment treatment = new Treatment();
treatment.source = Source.NIGHTSCOUT;
treatment.date = roundDateToSec(trJson.getLong("mills"));
treatment.carbs = trJson.has("carbs") ? trJson.getDouble("carbs") : 0;
treatment.insulin = trJson.has("insulin") ? trJson.getDouble("insulin") : 0d;
treatment.pumpId = trJson.has("pumpId") ? trJson.getLong("pumpId") : 0;
treatment._id = trJson.getString("_id");
if (trJson.has("isSMB"))
treatment.isSMB = trJson.getBoolean("isSMB");
if (trJson.has("eventType")) {
treatment.mealBolus = !trJson.get("eventType").equals("Correction Bolus");
double carbs = treatment.carbs;
if (trJson.has("boluscalc")) {
JSONObject boluscalc = trJson.getJSONObject("boluscalc");
if (boluscalc.has("carbs")) {
carbs = Math.max(boluscalc.getDouble("carbs"), carbs);
}
}
if (carbs <= 0)
treatment.mealBolus = false;
}
createOrUpdate(treatment);
} catch (JSONException e) {
log.error("Unhandled exception", e);
}
}
// ---------------- TempTargets handling --------------- // ---------------- TempTargets handling ---------------
public List<TempTarget> getTemptargetsDataFromTime(long mills, boolean ascending) { public List<TempTarget> getTemptargetsDataFromTime(long mills, boolean ascending) {
@ -845,15 +664,15 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
public void createTemptargetFromJsonIfNotExists(JSONObject trJson) { public void createTemptargetFromJsonIfNotExists(JSONObject trJson) {
try { try {
String units = MainApp.getConfigBuilder().getProfileUnits(); String units = JsonHelper.safeGetString(trJson, "units", MainApp.getConfigBuilder().getProfileUnits());
TempTarget tempTarget = new TempTarget(); TempTarget tempTarget = new TempTarget()
tempTarget.date = trJson.getLong("mills"); .date(trJson.getLong("mills"))
tempTarget.durationInMinutes = trJson.getInt("duration"); .duration(trJson.getInt("duration"))
tempTarget.low = Profile.toMgdl(trJson.getDouble("targetBottom"), units); .low(Profile.toMgdl(trJson.getDouble("targetBottom"), units))
tempTarget.high = Profile.toMgdl(trJson.getDouble("targetTop"), units); .high(Profile.toMgdl(trJson.getDouble("targetTop"), units))
tempTarget.reason = trJson.getString("reason"); .reason(trJson.getString("reason"))
tempTarget._id = trJson.getString("_id"); ._id(trJson.getString("_id"))
tempTarget.source = Source.NIGHTSCOUT; .source(Source.NIGHTSCOUT);
createOrUpdate(tempTarget); createOrUpdate(tempTarget);
} catch (JSONException e) { } catch (JSONException e) {
log.error("Unhandled exception", e); log.error("Unhandled exception", e);
@ -893,6 +712,12 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
public void createOrUpdate(DanaRHistoryRecord record) { public void createOrUpdate(DanaRHistoryRecord record) {
try { try {
getDaoDanaRHistory().createOrUpdate(record); getDaoDanaRHistory().createOrUpdate(record);
//If it is a TDD, store it for stats also.
if (record.recordCode == RecordTypes.RECORD_TYPE_DAILY) {
createOrUpdateTDD(new TDD(record.recordDate, record.recordDailyBolus, record.recordDailyBasal, 0));
}
} catch (SQLException e) { } catch (SQLException e) {
log.error("Unhandled exception", e); log.error("Unhandled exception", e);
} }
@ -1122,10 +947,10 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
} }
createOrUpdate(extendedBolus); createOrUpdate(extendedBolus);
} else { } else {
TemporaryBasal tempBasal = new TemporaryBasal(); TemporaryBasal tempBasal = new TemporaryBasal()
tempBasal.date = trJson.getLong("mills"); .date(trJson.getLong("mills"))
tempBasal.source = Source.NIGHTSCOUT; .source(Source.NIGHTSCOUT)
tempBasal.pumpId = trJson.has("pumpId") ? trJson.getLong("pumpId") : 0; .pumpId(trJson.has("pumpId") ? trJson.getLong("pumpId") : 0);
if (trJson.has("duration")) { if (trJson.has("duration")) {
tempBasal.durationInMinutes = trJson.getInt("duration"); tempBasal.durationInMinutes = trJson.getInt("duration");
} }
@ -1329,37 +1154,10 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
} }
*/ */
public void createExtendedBolusFromJsonIfNotExists(JSONObject trJson) { public void createExtendedBolusFromJsonIfNotExists(JSONObject json) {
try { ExtendedBolus extendedBolus = ExtendedBolus.createFromJson(json);
QueryBuilder<ExtendedBolus, Long> queryBuilder = null; if (extendedBolus != null)
queryBuilder = getDaoExtendedBolus().queryBuilder();
Where where = queryBuilder.where();
where.eq("_id", trJson.getString("_id")).or().eq("date", trJson.getLong("mills"));
PreparedQuery<ExtendedBolus> preparedQuery = queryBuilder.prepare();
List<ExtendedBolus> list = getDaoExtendedBolus().query(preparedQuery);
ExtendedBolus extendedBolus;
if (list.size() == 0) {
extendedBolus = new ExtendedBolus();
extendedBolus.source = Source.NIGHTSCOUT;
if (Config.logIncommingData)
log.debug("Adding ExtendedBolus record to database: " + trJson.toString());
// Record does not exists. add
} else if (list.size() == 1) {
extendedBolus = list.get(0);
if (Config.logIncommingData)
log.debug("Updating ExtendedBolus record in database: " + trJson.toString());
} else {
log.error("Something went wrong");
return;
}
extendedBolus.date = trJson.getLong("mills");
extendedBolus.durationInMinutes = trJson.has("duration") ? trJson.getInt("duration") : 0;
extendedBolus.insulin = trJson.getDouble("relative");
extendedBolus._id = trJson.getString("_id");
createOrUpdate(extendedBolus); createOrUpdate(extendedBolus);
} catch (SQLException | JSONException e) {
log.error("Unhandled exception", e);
}
} }
private static void scheduleExtendedBolusChange() { private static void scheduleExtendedBolusChange() {
@ -1405,6 +1203,15 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
scheduleCareportalEventChange(); scheduleCareportalEventChange();
} }
public CareportalEvent getCareportalEventFromTimestamp(long timestamp) {
try {
return getDaoCareportalEvents().queryForId(timestamp);
} catch (SQLException e) {
log.error("Unhandled exception", e);
}
return null;
}
@Nullable @Nullable
public CareportalEvent getLastCareportalEvent(String event) { public CareportalEvent getLastCareportalEvent(String event) {
try { try {
@ -1439,12 +1246,26 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
} catch (SQLException e) { } catch (SQLException e) {
log.error("Unhandled exception", e); log.error("Unhandled exception", e);
} }
return new ArrayList<CareportalEvent>(); return new ArrayList<>();
}
public List<CareportalEvent> getCareportalEventsFromTime(boolean ascending) {
try {
List<CareportalEvent> careportalEvents;
QueryBuilder<CareportalEvent, Long> queryBuilder = getDaoCareportalEvents().queryBuilder();
queryBuilder.orderBy("date", ascending);
PreparedQuery<CareportalEvent> preparedQuery = queryBuilder.prepare();
careportalEvents = getDaoCareportalEvents().query(preparedQuery);
return careportalEvents;
} catch (SQLException e) {
log.error("Unhandled exception", e);
}
return new ArrayList<>();
} }
public void deleteCareportalEventById(String _id) { public void deleteCareportalEventById(String _id) {
try { try {
QueryBuilder<CareportalEvent, Long> queryBuilder = null; QueryBuilder<CareportalEvent, Long> queryBuilder;
queryBuilder = getDaoCareportalEvents().queryBuilder(); queryBuilder = getDaoCareportalEvents().queryBuilder();
Where where = queryBuilder.where(); Where where = queryBuilder.where();
where.eq("_id", _id); where.eq("_id", _id);
@ -1467,7 +1288,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
public void createCareportalEventFromJsonIfNotExists(JSONObject trJson) { public void createCareportalEventFromJsonIfNotExists(JSONObject trJson) {
try { try {
QueryBuilder<CareportalEvent, Long> queryBuilder = null; QueryBuilder<CareportalEvent, Long> queryBuilder;
queryBuilder = getDaoCareportalEvents().queryBuilder(); queryBuilder = getDaoCareportalEvents().queryBuilder();
Where where = queryBuilder.where(); Where where = queryBuilder.where();
where.eq("_id", trJson.getString("_id")).or().eq("date", trJson.getLong("mills")); where.eq("_id", trJson.getString("_id")).or().eq("date", trJson.getLong("mills"));
@ -1524,14 +1345,14 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
List<ProfileSwitch> profileSwitches; List<ProfileSwitch> profileSwitches;
QueryBuilder<ProfileSwitch, Long> queryBuilder = daoProfileSwitch.queryBuilder(); QueryBuilder<ProfileSwitch, Long> queryBuilder = daoProfileSwitch.queryBuilder();
queryBuilder.orderBy("date", ascending); queryBuilder.orderBy("date", ascending);
queryBuilder.limit(20L); queryBuilder.limit(100L);
PreparedQuery<ProfileSwitch> preparedQuery = queryBuilder.prepare(); PreparedQuery<ProfileSwitch> preparedQuery = queryBuilder.prepare();
profileSwitches = daoProfileSwitch.query(preparedQuery); profileSwitches = daoProfileSwitch.query(preparedQuery);
return profileSwitches; return profileSwitches;
} catch (SQLException e) { } catch (SQLException e) {
log.error("Unhandled exception", e); log.error("Unhandled exception", e);
} }
return new ArrayList<ProfileSwitch>(); return new ArrayList<>();
} }
public boolean createOrUpdate(ProfileSwitch profileSwitch) { public boolean createOrUpdate(ProfileSwitch profileSwitch) {
@ -1572,6 +1393,8 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
} }
} }
} }
// look for already added percentage from NS
profileSwitch.profileName = PercentageSplitter.pureName(profileSwitch.profileName);
getDaoProfileSwitch().create(profileSwitch); getDaoProfileSwitch().create(profileSwitch);
log.debug("PROFILESWITCH: New record from: " + Source.getString(profileSwitch.source) + " " + profileSwitch.toString()); log.debug("PROFILESWITCH: New record from: " + Source.getString(profileSwitch.source) + " " + profileSwitch.toString());
scheduleProfileSwitchChange(); scheduleProfileSwitchChange();
@ -1645,6 +1468,19 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
profileSwitch.percentage = trJson.getInt("percentage"); profileSwitch.percentage = trJson.getInt("percentage");
if (trJson.has("profileJson")) if (trJson.has("profileJson"))
profileSwitch.profileJson = trJson.getString("profileJson"); profileSwitch.profileJson = trJson.getString("profileJson");
else {
ProfileStore store = MainApp.getConfigBuilder().getActiveProfileInterface().getProfile();
Profile profile = store.getSpecificProfile(profileSwitch.profileName);
if (profile != null) {
profileSwitch.profileJson = profile.getData().toString();
log.debug("Profile switch prefilled with JSON from local store");
// Update data in NS
NSUpload.updateProfileSwitch(profileSwitch);
} else {
log.debug("JSON for profile switch doesn't exist. Ignoring: " + trJson.toString());
return;
}
}
if (trJson.has("profilePlugin")) if (trJson.has("profilePlugin"))
profileSwitch.profilePlugin = trJson.getString("profilePlugin"); profileSwitch.profilePlugin = trJson.getString("profilePlugin");
createOrUpdate(profileSwitch); createOrUpdate(profileSwitch);

View file

@ -9,24 +9,25 @@ import android.graphics.Color;
import com.j256.ormlite.field.DatabaseField; import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable; import com.j256.ormlite.table.DatabaseTable;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.util.Date;
import java.util.Objects; import java.util.Objects;
import info.nightscout.androidaps.Constants; import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.data.Iob; import info.nightscout.androidaps.data.Iob;
import info.nightscout.androidaps.data.IobTotal; import info.nightscout.androidaps.data.IobTotal;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.interfaces.InsulinInterface; import info.nightscout.androidaps.interfaces.InsulinInterface;
import info.nightscout.androidaps.interfaces.Interval; import info.nightscout.androidaps.interfaces.Interval;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.Overview.graphExtensions.DataPointWithLabelInterface; import info.nightscout.androidaps.plugins.Overview.graphExtensions.DataPointWithLabelInterface;
import info.nightscout.androidaps.plugins.Overview.graphExtensions.PointsWithLabelGraphSeries; import info.nightscout.androidaps.plugins.Overview.graphExtensions.PointsWithLabelGraphSeries;
import info.nightscout.androidaps.plugins.Treatments.Treatment;
import info.nightscout.utils.DateUtil; import info.nightscout.utils.DateUtil;
import info.nightscout.utils.DecimalFormatter; import info.nightscout.utils.DecimalFormatter;
import info.nightscout.utils.JsonHelper;
import info.nightscout.utils.Round; import info.nightscout.utils.Round;
/** /**
@ -91,6 +92,16 @@ public class ExtendedBolus implements Interval, DataPointWithLabelInterface {
pumpId = t.pumpId; pumpId = t.pumpId;
} }
public static ExtendedBolus createFromJson(JSONObject json) {
ExtendedBolus extendedBolus = new ExtendedBolus();
extendedBolus.source = Source.NIGHTSCOUT;
extendedBolus.date = JsonHelper.safeGetLong(json, "mills");
extendedBolus.durationInMinutes = JsonHelper.safeGetInt(json, "duration");
extendedBolus.insulin = JsonHelper.safeGetDouble(json, "relative") / 60 * extendedBolus.durationInMinutes;
extendedBolus._id = JsonHelper.safeGetString(json, "_id");
extendedBolus.pumpId = JsonHelper.safeGetLong(json, "pumpId");
return extendedBolus;
}
// -------- Interval interface --------- // -------- Interval interface ---------
Long cuttedEnd = null; Long cuttedEnd = null;
@ -147,6 +158,11 @@ public class ExtendedBolus implements Interval, DataPointWithLabelInterface {
return durationInMinutes == 0; return durationInMinutes == 0;
} }
@Override
public boolean isValid() {
return true;
}
// -------- Interval interface end --------- // -------- Interval interface end ---------
public String log() { public String log() {
@ -280,4 +296,5 @@ public class ExtendedBolus implements Interval, DataPointWithLabelInterface {
public int getColor() { public int getColor() {
return Color.CYAN; return Color.CYAN;
} }
} }

View file

@ -1,207 +0,0 @@
package info.nightscout.androidaps.db;
import com.j256.ormlite.android.AndroidConnectionSource;
import com.j256.ormlite.dao.Dao;
import com.j256.ormlite.stmt.PreparedQuery;
import com.j256.ormlite.stmt.QueryBuilder;
import com.j256.ormlite.stmt.Where;
import com.j256.ormlite.table.TableUtils;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.events.EventFoodDatabaseChanged;
/**
* Created by mike on 24.09.2017.
*/
public class FoodHelper {
private static Logger log = LoggerFactory.getLogger(FoodHelper.class);
DatabaseHelper databaseHelper;
private static final ScheduledExecutorService foodEventWorker = Executors.newSingleThreadScheduledExecutor();
private static ScheduledFuture<?> scheduledFoodEventPost = null;
public FoodHelper(DatabaseHelper databaseHelper) {
this.databaseHelper = databaseHelper;
}
private Dao<Food, Long> getDaoFood() throws SQLException {
return databaseHelper.getDao(Food.class);
}
public void resetFood() {
try {
TableUtils.dropTable(databaseHelper.getConnectionSource(), Food.class, true);
TableUtils.createTableIfNotExists(databaseHelper.getConnectionSource(), Food.class);
} catch (SQLException e) {
log.error("Unhandled exception", e);
}
scheduleFoodChange();
}
public List<Food> getFoodData() {
try {
Dao<Food, Long> daoFood = getDaoFood();
List<Food> foods;
QueryBuilder<Food, Long> queryBuilder = daoFood.queryBuilder();
PreparedQuery<Food> preparedQuery = queryBuilder.prepare();
foods = daoFood.query(preparedQuery);
return foods;
} catch (SQLException e) {
log.error("Unhandled exception", e);
}
return new ArrayList<>();
}
public boolean createOrUpdate(Food food) {
try {
// find by NS _id
if (food._id != null) {
Food old;
QueryBuilder<Food, Long> queryBuilder = getDaoFood().queryBuilder();
Where where = queryBuilder.where();
where.eq("_id", food._id);
PreparedQuery<Food> preparedQuery = queryBuilder.prepare();
List<Food> found = getDaoFood().query(preparedQuery);
if (found.size() > 0) {
old = found.get(0);
if (!old.isEqual(food)) {
getDaoFood().delete(old); // need to delete/create because date may change too
old.copyFrom(food);
getDaoFood().create(old);
log.debug("FOOD: Updating record by _id: " + old.toString());
scheduleFoodChange();
return true;
} else {
return false;
}
}
}
getDaoFood().createOrUpdate(food);
log.debug("FOOD: New record: " + food.toString());
scheduleFoodChange();
return true;
} catch (SQLException e) {
log.error("Unhandled exception", e);
}
return false;
}
public void delete(Food food) {
try {
getDaoFood().delete(food);
scheduleFoodChange();
} catch (SQLException e) {
log.error("Unhandled exception", e);
}
}
public static void scheduleFoodChange() {
class PostRunnable implements Runnable {
public void run() {
log.debug("Firing EventFoodChange");
MainApp.bus().post(new EventFoodDatabaseChanged());
scheduledFoodEventPost = null;
}
}
// prepare task for execution in 1 sec
// cancel waiting task to prevent sending multiple posts
if (scheduledFoodEventPost != null)
scheduledFoodEventPost.cancel(false);
Runnable task = new PostRunnable();
final int sec = 1;
scheduledFoodEventPost = foodEventWorker.schedule(task, sec, TimeUnit.SECONDS);
}
/*
{
"_id": "551ee3ad368e06e80856e6a9",
"type": "food",
"category": "Zakladni",
"subcategory": "Napoje",
"name": "Mleko",
"portion": 250,
"carbs": 12,
"gi": 1,
"created_at": "2015-04-14T06:59:16.500Z",
"unit": "ml"
}
*/
public void createFoodFromJsonIfNotExists(JSONObject trJson) {
try {
Food food = new Food();
if (trJson.has("type") && trJson.getString("type").equals("food")) {
if (trJson.has("_id"))
food._id = trJson.getString("_id");
if (trJson.has("category"))
food.category = trJson.getString("category");
if (trJson.has("subcategory"))
food.subcategory = trJson.getString("subcategory");
if (trJson.has("name"))
food.name = trJson.getString("name");
if (trJson.has("unit"))
food.units = trJson.getString("unit");
if (trJson.has("portion"))
food.portion = trJson.getDouble("portion");
if (trJson.has("carbs"))
food.carbs = trJson.getInt("carbs");
if (trJson.has("gi"))
food.gi = trJson.getInt("gi");
if (trJson.has("energy"))
food.energy = trJson.getInt("energy");
if (trJson.has("protein"))
food.protein = trJson.getInt("protein");
if (trJson.has("fat"))
food.fat = trJson.getInt("fat");
}
createOrUpdate(food);
} catch (JSONException e) {
log.error("Unhandled exception", e);
}
}
public void deleteFoodById(String _id) {
Food stored = findFoodById(_id);
if (stored != null) {
log.debug("FOOD: Removing Food record from database: " + stored.toString());
delete(stored);
scheduleFoodChange();
}
}
public Food findFoodById(String _id) {
try {
QueryBuilder<Food, Long> queryBuilder = getDaoFood().queryBuilder();
Where where = queryBuilder.where();
where.eq("_id", _id);
PreparedQuery<Food> preparedQuery = queryBuilder.prepare();
List<Food> list = getDaoFood().query(preparedQuery);
if (list.size() == 1) {
return list.get(0);
} else {
return null;
}
} catch (SQLException e) {
log.error("Unhandled exception", e);
}
return null;
}
}

View file

@ -0,0 +1,15 @@
package info.nightscout.androidaps.db;
import java.util.concurrent.ScheduledFuture;
/**
* Created by triplem on 05.01.18.
*/
public interface ICallback {
void setPost(ScheduledFuture<?> post);
ScheduledFuture<?> getPost();
}

View file

@ -1,6 +1,7 @@
package info.nightscout.androidaps.db; package info.nightscout.androidaps.db;
import android.graphics.Color; import android.graphics.Color;
import android.support.annotation.Nullable;
import com.j256.ormlite.field.DatabaseField; import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable; import com.j256.ormlite.table.DatabaseTable;
@ -12,10 +13,14 @@ import org.slf4j.LoggerFactory;
import java.util.Objects; import java.util.Objects;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.interfaces.Interval; import info.nightscout.androidaps.interfaces.Interval;
import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification;
import info.nightscout.androidaps.plugins.Overview.graphExtensions.DataPointWithLabelInterface; import info.nightscout.androidaps.plugins.Overview.graphExtensions.DataPointWithLabelInterface;
import info.nightscout.androidaps.plugins.Overview.graphExtensions.PointsWithLabelGraphSeries; import info.nightscout.androidaps.plugins.Overview.graphExtensions.PointsWithLabelGraphSeries;
import info.nightscout.androidaps.plugins.Overview.notifications.Notification;
import info.nightscout.androidaps.plugins.ProfileLocal.LocalProfilePlugin; import info.nightscout.androidaps.plugins.ProfileLocal.LocalProfilePlugin;
import info.nightscout.utils.DateUtil; import info.nightscout.utils.DateUtil;
import info.nightscout.utils.DecimalFormatter; import info.nightscout.utils.DecimalFormatter;
@ -56,12 +61,39 @@ public class ProfileSwitch implements Interval, DataPointWithLabelInterface {
private Profile profile = null; private Profile profile = null;
public ProfileSwitch date(long date) {
this.date = date;
return this;
}
public ProfileSwitch profileName(String profileName) {
this.profileName = profileName;
return this;
}
public ProfileSwitch profile(Profile profile) {
this.profile = profile;
return this;
}
public ProfileSwitch source(int source) {
this.source = source;
return this;
}
public ProfileSwitch duration(int duration) {
this.durationInMinutes = duration;
return this;
}
@Nullable
public Profile getProfileObject() { public Profile getProfileObject() {
if (profile == null) if (profile == null)
try { try {
profile = new Profile(new JSONObject(profileJson), percentage, timeshift); profile = new Profile(new JSONObject(profileJson), percentage, timeshift);
} catch (JSONException e) { } catch (Exception e) {
log.error("Unhandled exception", e); log.error("Unhandled exception", e);
log.error("Unhandled exception", profileJson);
} }
return profile; return profile;
} }
@ -171,6 +203,20 @@ public class ProfileSwitch implements Interval, DataPointWithLabelInterface {
return durationInMinutes == 0; return durationInMinutes == 0;
} }
@Override
public boolean isValid() {
boolean isValid = getProfileObject() != null && getProfileObject().isValid(DateUtil.dateAndTimeString(date));
if (!isValid)
createNotificationInvalidProfile(DateUtil.dateAndTimeString(date));
return isValid;
}
public 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));
}
// -------- Interval interface end --------- // -------- Interval interface end ---------
// ----------------- DataPointInterface -------------------- // ----------------- DataPointInterface --------------------

View file

@ -0,0 +1,46 @@
package info.nightscout.androidaps.db;
import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Objects;
/**
* Created by mike on 20.09.2017.
*/
@DatabaseTable(tableName = DatabaseHelper.DATABASE_TDDS)
public class TDD {
private static Logger log = LoggerFactory.getLogger(TDD.class);
@DatabaseField(id = true)
public long date;
@DatabaseField
public double bolus;
@DatabaseField
public double basal;
@DatabaseField
public double total;
public double getTotal(){
return (total > 0d) ? total:(bolus+basal);
}
public TDD() { }
public TDD(long date, double bolus, double basal, double total){
this.date = date;
this.bolus = bolus;
this.basal = basal;
this.total = total;
}
}

View file

@ -41,6 +41,10 @@ public class TempTarget implements Interval {
@DatabaseField @DatabaseField
public int durationInMinutes; public int durationInMinutes;
public double target() {
return (low + high) / 2;
}
public boolean isEqual(TempTarget other) { public boolean isEqual(TempTarget other) {
if (date != other.date) { if (date != other.date) {
return false; return false;
@ -67,6 +71,41 @@ public class TempTarget implements Interval {
reason = t.reason; reason = t.reason;
} }
public TempTarget date(long date) {
this.date = date;
return this;
}
public TempTarget low(double low) {
this.low = low;
return this;
}
public TempTarget high(double high) {
this.high = high;
return this;
}
public TempTarget duration(int duration) {
this.durationInMinutes = duration;
return this;
}
public TempTarget reason(String reason) {
this.reason = reason;
return this;
}
public TempTarget _id(String _id) {
this._id = _id;
return this;
}
public TempTarget source(int source) {
this.source = source;
return this;
}
// -------- Interval interface --------- // -------- Interval interface ---------
Long cuttedEnd = null; Long cuttedEnd = null;
@ -123,6 +162,11 @@ public class TempTarget implements Interval {
return durationInMinutes == 0; return durationInMinutes == 0;
} }
@Override
public boolean isValid() {
return true;
}
// -------- Interval interface end --------- // -------- Interval interface end ---------
public String lowValueToUnitsToString(String units) { public String lowValueToUnitsToString(String units) {

View file

@ -6,7 +6,6 @@ import com.j256.ormlite.table.DatabaseTable;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.util.Date;
import java.util.Objects; import java.util.Objects;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
@ -17,6 +16,7 @@ import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.interfaces.InsulinInterface; import info.nightscout.androidaps.interfaces.InsulinInterface;
import info.nightscout.androidaps.interfaces.Interval; import info.nightscout.androidaps.interfaces.Interval;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.Treatments.Treatment;
import info.nightscout.utils.DateUtil; import info.nightscout.utils.DateUtil;
import info.nightscout.utils.DecimalFormatter; import info.nightscout.utils.DecimalFormatter;
import info.nightscout.utils.SP; import info.nightscout.utils.SP;
@ -60,8 +60,36 @@ public class TemporaryBasal implements Interval {
public TemporaryBasal() { public TemporaryBasal() {
} }
public TemporaryBasal(long date) { public TemporaryBasal date(long date) {
this.date = date; this.date = date;
return this;
}
public TemporaryBasal duration(int durationInMinutes) {
this.durationInMinutes = durationInMinutes;
return this;
}
public TemporaryBasal absolute(double absoluteRate) {
this.absoluteRate = absoluteRate;
this.isAbsolute = true;
return this;
}
public TemporaryBasal percent(int percentRate) {
this.percentRate = percentRate;
this.isAbsolute = false;
return this;
}
public TemporaryBasal source(int source) {
this.source = source;
return this;
}
public TemporaryBasal pumpId(long pumpId) {
this.pumpId = pumpId;
return this;
} }
public TemporaryBasal(ExtendedBolus extendedBolus) { public TemporaryBasal(ExtendedBolus extendedBolus) {
@ -182,9 +210,14 @@ public class TemporaryBasal implements Interval {
return durationInMinutes == 0; return durationInMinutes == 0;
} }
@Override
public boolean isValid() {
return true;
}
// -------- Interval interface end --------- // -------- Interval interface end ---------
public IobTotal iobCalc(long time) { public IobTotal iobCalc(long time, Profile profile) {
if(isFakeExtended){ if(isFakeExtended){
log.error("iobCalc should only be called on Extended boluses separately"); log.error("iobCalc should only be called on Extended boluses separately");
@ -192,7 +225,6 @@ public class TemporaryBasal implements Interval {
} }
IobTotal result = new IobTotal(time); IobTotal result = new IobTotal(time);
Profile profile = MainApp.getConfigBuilder().getProfile(time);
InsulinInterface insulinInterface = ConfigBuilderPlugin.getActiveInsulin(); InsulinInterface insulinInterface = ConfigBuilderPlugin.getActiveInsulin();
int realDuration = getDurationToTime(time); int realDuration = getDurationToTime(time);
@ -257,13 +289,13 @@ public class TemporaryBasal implements Interval {
return (remainingMin < 0) ? 0 : Math.round(remainingMin); return (remainingMin < 0) ? 0 : Math.round(remainingMin);
} }
public double tempBasalConvertedToAbsolute(long time) { public double tempBasalConvertedToAbsolute(long time, Profile profile) {
if(isFakeExtended){ if(isFakeExtended){
return MainApp.getConfigBuilder().getProfile(time).getBasal(time) + netExtendedRate; return profile.getBasal(time) + netExtendedRate;
} else if (isAbsolute) { } else if (isAbsolute) {
return absoluteRate; return absoluteRate;
} else { } else {
return MainApp.getConfigBuilder().getProfile(time).getBasal(time) * percentRate / 100; return profile.getBasal(time) * percentRate / 100;
} }
} }
@ -320,13 +352,13 @@ public class TemporaryBasal implements Interval {
if(profile != null) { if(profile != null) {
double basal = profile.getBasal(); double basal = profile.getBasal();
if(basal != 0){ if(basal != 0){
return Math.round(rate*100d/basal) + "% "; return Math.round(rate*100d/basal) + "%";
} }
} }
} }
return DecimalFormatter.to2Decimal(rate) + "U/h "; return DecimalFormatter.to2Decimal(rate) + "U/h";
} else { // percent } else { // percent
return percentRate + "% "; return percentRate + "%";
} }
} }

View file

@ -0,0 +1,8 @@
package info.nightscout.androidaps.events;
/**
* Created by mike on 23.01.2018.
*/
public class EventAppInitialized extends Event {
}

View file

@ -0,0 +1,13 @@
package info.nightscout.androidaps.events;
public class EventChargingState {
public boolean isCharging = false;
public EventChargingState() {}
public EventChargingState(boolean isCharging) {
this.isCharging = isCharging;
}
}

View file

@ -0,0 +1,8 @@
package info.nightscout.androidaps.events;
/**
* Created by mike on 13.02.2018.
*/
public class EventCustomCalculationFinished extends Event {
}

View file

@ -0,0 +1,36 @@
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
}
}

View file

@ -0,0 +1,14 @@
package info.nightscout.androidaps.events;
public class EventNetworkChange extends Event {
public boolean mobileConnected = false;
public boolean wifiConnected = false;
public String ssid = "";
public boolean roaming = false;
public String getSsid() {
return ssid.replace("SSID: ","").replaceAll("\"","");
}
}

View file

@ -1,7 +1,17 @@
package info.nightscout.androidaps.events; package info.nightscout.androidaps.events;
import android.support.annotation.Nullable;
import info.nightscout.androidaps.db.BgReading;
/** /**
* Created by mike on 05.06.2016. * Created by mike on 05.06.2016.
*/ */
public class EventNewBG extends EventLoop { public class EventNewBG extends EventLoop {
@Nullable
public final BgReading bgReading;
public EventNewBG(BgReading bgReading) {
this.bgReading = bgReading;
}
} }

View file

@ -0,0 +1,35 @@
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;
}
}

View file

@ -0,0 +1,36 @@
package info.nightscout.androidaps.events;
import org.json.JSONObject;
/**
* Event which is published with data fetched from NightScout specific for the
* Treatment-class.
* <p>
* 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;
}
}

View file

@ -12,11 +12,11 @@ public class EventPreferenceChange extends Event {
} }
public EventPreferenceChange(int resourceID) { public EventPreferenceChange(int resourceID) {
changedKey = MainApp.sResources.getString(resourceID); changedKey = MainApp.gs(resourceID);
} }
public boolean isChanged(int id) { public boolean isChanged(int id) {
return changedKey.equals(MainApp.sResources.getString(id)); return changedKey.equals(MainApp.gs(id));
} }
public boolean isChanged(String id) { public boolean isChanged(String id) {

View file

@ -46,13 +46,13 @@ public class EventPumpStatusChanged extends Event {
public String textStatus() { public String textStatus() {
if (sStatus == CONNECTING) if (sStatus == CONNECTING)
return String.format(MainApp.sResources.getString(R.string.danar_history_connectingfor), sSecondsElapsed); return String.format(MainApp.gs(R.string.danar_history_connectingfor), sSecondsElapsed);
else if (sStatus == CONNECTED) else if (sStatus == CONNECTED)
return MainApp.sResources.getString(R.string.connected); return MainApp.gs(R.string.connected);
else if (sStatus == PERFORMING) else if (sStatus == PERFORMING)
return sPerfomingAction; return sPerfomingAction;
else if (sStatus == DISCONNECTING) else if (sStatus == DISCONNECTING)
return MainApp.sResources.getString(R.string.disconnecting); return MainApp.gs(R.string.disconnecting);
else if (sStatus == DISCONNECTED) else if (sStatus == DISCONNECTED)
return ""; return "";
return ""; return "";

View file

@ -4,4 +4,11 @@ package info.nightscout.androidaps.events;
* Created by mike on 13.06.2016. * Created by mike on 13.06.2016.
*/ */
public class EventRefreshGui extends Event { public class EventRefreshGui extends Event {
public boolean recreate = false;
public EventRefreshGui(boolean recreate) {
this.recreate = recreate;
}
public EventRefreshGui(){
this(false);
}
} }

View file

@ -1,7 +1,17 @@
package info.nightscout.androidaps.events; package info.nightscout.androidaps.events;
import android.support.annotation.Nullable;
import info.nightscout.androidaps.plugins.Treatments.Treatment;
/** /**
* Created by mike on 04.06.2016. * Created by mike on 04.06.2016.
*/ */
public class EventTreatmentChange extends EventLoop { public class EventTreatmentChange extends EventLoop {
@Nullable
public final Treatment treatment;
public EventTreatmentChange(Treatment treatment) {
this.treatment = treatment;
}
} }

View file

@ -11,5 +11,5 @@ public interface APSInterface {
public APSResult getLastAPSResult(); public APSResult getLastAPSResult();
public Date getLastAPSRun(); public Date getLastAPSRun();
public void invoke(String initiator); public void invoke(String initiator, boolean tempBasalFallback);
} }

View file

@ -4,4 +4,5 @@ package info.nightscout.androidaps.interfaces;
* Created by mike on 20.06.2016. * Created by mike on 20.06.2016.
*/ */
public interface BgSourceInterface { public interface BgSourceInterface {
boolean advancedFilteringSupported();
} }

View file

@ -0,0 +1,117 @@
package info.nightscout.androidaps.interfaces;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
/**
* Created by mike on 19.03.2018.
*/
public class Constraint<T extends Comparable> {
private static Logger log = LoggerFactory.getLogger(Constraint.class);
T value;
T originalValue;
List<String> reasons = new ArrayList<>();
List<String> mostLimiting = new ArrayList<>();
public Constraint(T value) {
this.value = value;
this.originalValue = value;
}
public T value() {
return value;
}
public T originalValue() {
return originalValue;
}
public Constraint<T> set(T value) {
this.value = value;
this.originalValue = value;
return this;
}
public Constraint<T> set(T value, String reason, Object from) {
this.value = value;
addReason(reason, from);
addMostLimingReason(reason, from);
return this;
}
public Constraint<T> setIfSmaller(T value, String reason, Object from) {
if (value.compareTo(this.value) < 0) {
this.value = value;
mostLimiting.clear();
addMostLimingReason(reason, from);
}
if (value.compareTo(this.originalValue) < 0) {
addReason(reason, from);
}
return this;
}
public Constraint<T> setIfGreater(T value, String reason, Object from) {
if (value.compareTo(this.value) > 0) {
this.value = value;
mostLimiting.clear();
addMostLimingReason(reason, from);
}
if (value.compareTo(this.originalValue) > 0) {
addReason(reason, from);
}
return this;
}
public Constraint addReason(String reason, Object from) {
reasons.add(from.getClass().getSimpleName().replace("Plugin", "") + ": " + reason);
return this;
}
public Constraint addMostLimingReason(String reason, Object from) {
mostLimiting.add(from.getClass().getSimpleName().replace("Plugin", "") + ": " + reason);
return this;
}
public String getReasons() {
StringBuilder sb = new StringBuilder();
int count = 0;
for (String r : reasons) {
if (count++ != 0) sb.append("\n");
sb.append(r);
}
log.debug("Limiting origial value: " + originalValue + " to " + value + ". Reason: " + sb.toString());
return sb.toString();
}
public List<String> getReasonList() {
return reasons;
}
public String getMostLimitedReasons() {
StringBuilder sb = new StringBuilder();
int count = 0;
for (String r : mostLimiting) {
if (count++ != 0) sb.append("\n");
sb.append(r);
}
log.debug("Limiting origial value: " + originalValue + " to " + value + ". Reason: " + sb.toString());
return sb.toString();
}
public List<String> getMostLimitedReasonList() {
return mostLimiting;
}
public void copyReasons(Constraint<?> another) {
for (String s: another.getReasonList()) {
reasons.add(s);
}
}
}

View file

@ -1,28 +1,54 @@
package info.nightscout.androidaps.interfaces; package info.nightscout.androidaps.interfaces;
import info.nightscout.androidaps.plugins.Loop.APSResult; import info.nightscout.androidaps.data.Profile;
/** /**
* Created by mike on 15.06.2016. * Created by mike on 15.06.2016.
*/ */
public interface ConstraintsInterface { public interface ConstraintsInterface {
boolean isLoopEnabled(); default Constraint<Boolean> isLoopInvokationAllowed(Constraint<Boolean> value) {
return value;
}
boolean isClosedModeEnabled(); default Constraint<Boolean> isClosedLoopAllowed(Constraint<Boolean> value) {
return value;
}
boolean isAutosensModeEnabled(); default Constraint<Boolean> isAutosensModeEnabled(Constraint<Boolean> value) {
return value;
}
boolean isAMAModeEnabled(); default Constraint<Boolean> isAMAModeEnabled(Constraint<Boolean> value) {
return value;
}
Double applyBasalConstraints(Double absoluteRate); default Constraint<Boolean> isSMBModeEnabled(Constraint<Boolean> value) {
return value;
}
Integer applyBasalConstraints(Integer percentRate); default Constraint<Boolean> isAdvancedFilteringEnabled(Constraint<Boolean> value) {
return value;
}
Double applyBolusConstraints(Double insulin); default Constraint<Double> applyBasalConstraints(Constraint<Double> absoluteRate, Profile profile) {
return absoluteRate;
}
Integer applyCarbsConstraints(Integer carbs); default Constraint<Integer> applyBasalPercentConstraints(Constraint<Integer> percentRate, Profile profile) {
return percentRate;
}
Double applyMaxIOBConstraints(Double maxIob); default Constraint<Double> applyBolusConstraints(Constraint<Double> insulin) {
return insulin;
}
default Constraint<Integer> applyCarbsConstraints(Constraint<Integer> carbs) {
return carbs;
}
default Constraint<Double> applyMaxIOBConstraints(Constraint<Double> maxIob) {
return maxIob;
};
} }

View file

@ -1,25 +1,23 @@
package info.nightscout.androidaps.interfaces; package info.nightscout.androidaps.interfaces;
import java.util.Date;
import info.nightscout.androidaps.data.Iob; import info.nightscout.androidaps.data.Iob;
import info.nightscout.androidaps.db.Treatment; import info.nightscout.androidaps.plugins.Treatments.Treatment;
/** /**
* Created by mike on 17.04.2017. * Created by mike on 17.04.2017.
*/ */
public interface InsulinInterface { public interface InsulinInterface {
final int FASTACTINGINSULIN = 0; int FASTACTINGINSULIN = 0;
final int FASTACTINGINSULINPROLONGED = 1; int FASTACTINGINSULINPROLONGED = 1;
final int OREF_RAPID_ACTING = 2; int OREF_RAPID_ACTING = 2;
final int OREF_ULTRA_RAPID_ACTING = 3; int OREF_ULTRA_RAPID_ACTING = 3;
final int OREF_FREE_PEAK = 4; int OREF_FREE_PEAK = 4;
int getId(); int getId();
String getFriendlyName(); String getFriendlyName();
String getComment(); String getComment();
double getDia(); double getDia();
public Iob iobCalcForTreatment(Treatment treatment, long time, Double dia); Iob iobCalcForTreatment(Treatment treatment, long time, double dia);
} }

View file

@ -21,4 +21,6 @@ public interface Interval {
boolean isInProgress(); boolean isInProgress();
boolean isEndingEvent(); boolean isEndingEvent();
boolean isValid();
} }

View file

@ -1,34 +1,165 @@
package info.nightscout.androidaps.interfaces; package info.nightscout.androidaps.interfaces;
import java.util.Date; import android.os.SystemClock;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
/** /**
* Created by mike on 09.06.2016. * Created by mike on 09.06.2016.
*/ */
public interface PluginBase { public abstract class PluginBase {
int GENERAL = 1; private static Logger log = LoggerFactory.getLogger(PluginBase.class);
int TREATMENT = 2;
int SENSITIVITY = 3;
int PROFILE = 4;
int APS = 5;
int PUMP = 6;
int CONSTRAINTS = 7;
int LOOP = 8;
int BGSOURCE = 9;
int INSULIN = 10;
int LAST = 11; // keep always highest number
int getType(); public enum State {
String getFragmentClass(); NOT_INITIALIZED,
ENABLED,
DISABLED
}
String getName(); private State state = State.NOT_INITIALIZED;
String getNameShort(); private boolean isFragmentVisible = false;
boolean isEnabled(int type); public PluginDescription pluginDescription;
boolean isVisibleInTabs(int type);
boolean canBeHidden(int type);
boolean hasFragment(); // Specific plugin with more Interfaces
boolean showInList(int type); protected boolean isProfileInterfaceEnabled = false;
void setFragmentEnabled(int type, boolean fragmentEnabled);
void setFragmentVisible(int type, boolean fragmentVisible); public PluginBase(PluginDescription pluginDescription) {
int getPreferencesId(); this.pluginDescription = pluginDescription;
}
// public PluginType getType() {
// return mainType;
// }
// public String getFragmentClass() {
// return fragmentClass;
// }
public String getName() {
if (pluginDescription.pluginName == -1)
return "UKNOWN";
else
return MainApp.gs(pluginDescription.pluginName);
}
public String getNameShort() {
if (pluginDescription.shortName == -1)
return getName();
String name = MainApp.gs(pluginDescription.shortName);
if (!name.trim().isEmpty()) //only if translation exists
return name;
// use long name as fallback
return getName();
}
public PluginType getType() {
return pluginDescription.mainType;
}
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;
if (pluginDescription.mainType == PluginType.CONSTRAINTS && type == PluginType.CONSTRAINTS)
return true;
if (type == pluginDescription.mainType)
return state == State.ENABLED && specialEnableCondition();
if (type == PluginType.CONSTRAINTS && pluginDescription.mainType == PluginType.PUMP && isEnabled(PluginType.PUMP))
return true;
if (type == PluginType.PROFILE && pluginDescription.mainType == PluginType.PUMP)
return isProfileInterfaceEnabled;
return false;
}
public boolean hasFragment() {
return pluginDescription.fragmentClass != null;
}
/**
* So far plugin can have it's main type + ConstraintInterface + ProfileInterface
* ConstraintInterface is enabled if main plugin is enabled
* ProfileInterface can be enabled only if main iterface is enable
*/
public void setPluginEnabled(PluginType type, boolean newState) {
if (type == pluginDescription.mainType) {
if (newState == true) { // enabling plugin
if (state != State.ENABLED) {
onStateChange(type, state, State.ENABLED);
state = State.ENABLED;
log.debug("Starting: " + getName());
onStart();
}
} else { // disabling plugin
if (state == State.ENABLED) {
onStateChange(type, state, State.ENABLED);
state = State.DISABLED;
onStop();
log.debug("Stopping: " + getName());
}
}
} else if (type == PluginType.PROFILE) {
isProfileInterfaceEnabled = newState;
}
}
public void setFragmentVisible(PluginType type, boolean fragmentVisible) {
if (type == pluginDescription.mainType) {
isFragmentVisible = fragmentVisible && specialEnableCondition();
}
}
public boolean isFragmentVisible() {
if (pluginDescription.alwayVisible)
return true;
if (pluginDescription.neverVisible)
return false;
return isFragmentVisible;
}
public boolean showInList(PluginType type) {
if (pluginDescription.mainType == type)
return pluginDescription.showInList && specialShowInListCondition();
if (type == PluginType.PROFILE && pluginDescription.mainType == PluginType.PUMP)
return isEnabled(PluginType.PUMP);
return false;
}
public boolean specialEnableCondition() {
return true;
}
public boolean specialShowInListCondition() {
return true;
}
protected void onStart() {
if (getType() == PluginType.PUMP) {
new Thread(() -> {
SystemClock.sleep(3000);
ConfigBuilderPlugin.getCommandQueue().readStatus("Pump driver changed.", null);
}).start();
}
}
protected void onStop() {
}
protected void onStateChange(PluginType type, State oldState, State newState) {
}
} }

View file

@ -0,0 +1,84 @@
package info.nightscout.androidaps.interfaces;
public class PluginDescription {
PluginType mainType = PluginType.GENERAL;
String fragmentClass = null;
public boolean alwayVisible = false;
public boolean neverVisible = false;
public boolean alwaysEnabled = false;
boolean showInList = true;
int pluginName = -1;
int shortName = -1;
int preferencesId = -1;
int advancedPreferencesId = -1;
public boolean enableByDefault = false;
public boolean visibleByDefault = false;
public PluginDescription mainType(PluginType mainType) {
this.mainType = mainType;
return this;
}
public PluginDescription fragmentClass(String fragmentClass) {
this.fragmentClass = fragmentClass;
return this;
}
public PluginDescription alwaysEnabled(boolean alwaysEnabled) {
this.alwaysEnabled = alwaysEnabled;
return this;
}
public PluginDescription alwayVisible(boolean alwayVisible) {
this.alwayVisible = alwayVisible;
return this;
}
public PluginDescription neverVisible(boolean neverVisible) {
this.neverVisible = neverVisible;
return this;
}
public PluginDescription showInList(boolean showInList) {
this.showInList = showInList;
return this;
}
public PluginDescription pluginName(int pluginName) {
this.pluginName = pluginName;
return this;
}
public PluginDescription shortName(int shortName) {
this.shortName = shortName;
return this;
}
public PluginDescription preferencesId(int preferencesId) {
this.preferencesId = preferencesId;
return this;
}
public PluginDescription advancedPreferencesId(int advancedPreferencesId) {
this.advancedPreferencesId = advancedPreferencesId;
return this;
}
public PluginDescription enableByDefault(boolean enableByDefault) {
this.enableByDefault = enableByDefault;
return this;
}
public PluginDescription visibleByDefault(boolean visibleByDefault) {
this.visibleByDefault = visibleByDefault;
return this;
}
public String getFragmentClass() {
return fragmentClass;
}
public PluginType getType() {
return mainType;
}
}

View file

@ -0,0 +1,14 @@
package info.nightscout.androidaps.interfaces;
public enum PluginType {
GENERAL,
TREATMENT,
SENSITIVITY,
PROFILE,
APS,
PUMP,
CONSTRAINTS,
LOOP,
BGSOURCE,
INSULIN
}

View file

@ -27,6 +27,8 @@ public class PumpDescription {
public double tempAbsoluteStep = 0.05d; public double tempAbsoluteStep = 0.05d;
public int tempDurationStep = 60; public int tempDurationStep = 60;
public boolean tempDurationStep15mAllowed = false;
public boolean tempDurationStep30mAllowed = false;
public int tempMaxDuration = 12 * 60; public int tempMaxDuration = 12 * 60;
@ -35,4 +37,11 @@ public class PumpDescription {
public double basalMinimumRate = 0.04d; public double basalMinimumRate = 0.04d;
public boolean isRefillingCapable = false; public boolean isRefillingCapable = false;
public boolean storesCarbInfo = true;
public boolean is30minBasalRatesCapable = false;
public boolean supportsTDDs = false;
public boolean needsManualTDDLoad = true;
} }

View file

@ -5,8 +5,8 @@ import org.json.JSONObject;
import java.util.Date; import java.util.Date;
import info.nightscout.androidaps.data.DetailedBolusInfo; import info.nightscout.androidaps.data.DetailedBolusInfo;
import info.nightscout.androidaps.data.PumpEnactResult;
import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.data.PumpEnactResult;
/** /**
* Created by mike on 04.06.2016. * Created by mike on 04.06.2016.
@ -35,8 +35,8 @@ public interface PumpInterface {
PumpEnactResult deliverTreatment(DetailedBolusInfo detailedBolusInfo); PumpEnactResult deliverTreatment(DetailedBolusInfo detailedBolusInfo);
void stopBolusDelivering(); void stopBolusDelivering();
PumpEnactResult setTempBasalAbsolute(Double absoluteRate, Integer durationInMinutes, boolean enforceNew); PumpEnactResult setTempBasalAbsolute(Double absoluteRate, Integer durationInMinutes, Profile profile, boolean enforceNew);
PumpEnactResult setTempBasalPercent(Integer percent, Integer durationInMinutes); PumpEnactResult setTempBasalPercent(Integer percent, Integer durationInMinutes, Profile profile, boolean enforceNew);
PumpEnactResult setExtendedBolus(Double insulin, Integer durationInMinutes); PumpEnactResult setExtendedBolus(Double insulin, Integer durationInMinutes);
//some pumps might set a very short temp close to 100% as cancelling a temp can be noisy //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 //when the cancel request is requested by the user (forced), the pump should always do a real cancel
@ -44,7 +44,7 @@ public interface PumpInterface {
PumpEnactResult cancelExtendedBolus(); PumpEnactResult cancelExtendedBolus();
// Status to be passed to NS // Status to be passed to NS
JSONObject getJSONStatus(); JSONObject getJSONStatus(Profile profile, String profileName);
String deviceID(); String deviceID();
// Pump capabilities // Pump capabilities
@ -54,4 +54,7 @@ public interface PumpInterface {
String shortStatus(boolean veryShort); String shortStatus(boolean veryShort);
boolean isFakingTempsByExtendedBoluses(); boolean isFakingTempsByExtendedBoluses();
PumpEnactResult loadTDDs();
} }

View file

@ -5,11 +5,12 @@ import java.util.List;
import info.nightscout.androidaps.data.DetailedBolusInfo; import info.nightscout.androidaps.data.DetailedBolusInfo;
import info.nightscout.androidaps.data.IobTotal; import info.nightscout.androidaps.data.IobTotal;
import info.nightscout.androidaps.data.MealData; import info.nightscout.androidaps.data.MealData;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.db.ExtendedBolus; import info.nightscout.androidaps.db.ExtendedBolus;
import info.nightscout.androidaps.db.ProfileSwitch; import info.nightscout.androidaps.db.ProfileSwitch;
import info.nightscout.androidaps.db.TempTarget; import info.nightscout.androidaps.db.TempTarget;
import info.nightscout.androidaps.db.TemporaryBasal; import info.nightscout.androidaps.db.TemporaryBasal;
import info.nightscout.androidaps.db.Treatment; import info.nightscout.androidaps.plugins.Treatments.Treatment;
import info.nightscout.androidaps.data.Intervals; import info.nightscout.androidaps.data.Intervals;
import info.nightscout.androidaps.data.ProfileIntervals; import info.nightscout.androidaps.data.ProfileIntervals;
@ -24,12 +25,13 @@ public interface TreatmentsInterface {
IobTotal getLastCalculationTreatments(); IobTotal getLastCalculationTreatments();
IobTotal getCalculationToTimeTreatments(long time); IobTotal getCalculationToTimeTreatments(long time);
IobTotal getLastCalculationTempBasals(); IobTotal getLastCalculationTempBasals();
IobTotal getCalculationToTimeTempBasals(long time); IobTotal getCalculationToTimeTempBasals(long time, Profile profile);
MealData getMealData(); MealData getMealData();
List<Treatment> getTreatmentsFromHistory(); List<Treatment> getTreatmentsFromHistory();
List<Treatment> getTreatments5MinBackFromHistory(long time); List<Treatment> getTreatments5MinBackFromHistory(long time);
long getLastBolusTime();
// real basals (not faked by extended bolus) // real basals (not faked by extended bolus)
boolean isInHistoryRealTempBasalInProgress(); boolean isInHistoryRealTempBasalInProgress();
@ -40,8 +42,6 @@ public interface TreatmentsInterface {
// basal that can be faked by extended boluses // basal that can be faked by extended boluses
boolean isTempBasalInProgress(); boolean isTempBasalInProgress();
TemporaryBasal getTempBasalFromHistory(long time); TemporaryBasal getTempBasalFromHistory(long time);
double getTempBasalAbsoluteRateHistory();
double getTempBasalRemainingMinutesFromHistory();
Intervals<TemporaryBasal> getTemporaryBasalsFromHistory(); Intervals<TemporaryBasal> getTemporaryBasalsFromHistory();
boolean isInHistoryExtendedBoluslInProgress(); boolean isInHistoryExtendedBoluslInProgress();
@ -55,6 +55,7 @@ public interface TreatmentsInterface {
TempTarget getTempTargetFromHistory(); TempTarget getTempTargetFromHistory();
TempTarget getTempTargetFromHistory(long time); TempTarget getTempTargetFromHistory(long time);
Intervals<TempTarget> getTempTargetsFromHistory(); Intervals<TempTarget> getTempTargetsFromHistory();
void addToHistoryTempTarget(TempTarget tempTarget);
ProfileSwitch getProfileSwitchFromHistory(long time); ProfileSwitch getProfileSwitchFromHistory(long time);
ProfileIntervals<ProfileSwitch> getProfileSwitchesFromHistory(); ProfileIntervals<ProfileSwitch> getProfileSwitchesFromHistory();

View file

@ -2,22 +2,22 @@ package info.nightscout.androidaps.plugins.Actions;
import android.app.Activity; import android.app.Activity;
import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentManager;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.Button;
import com.crashlytics.android.Crashlytics;
import com.crashlytics.android.answers.Answers;
import com.crashlytics.android.answers.CustomEvent; import com.crashlytics.android.answers.CustomEvent;
import com.squareup.otto.Subscribe; import com.squareup.otto.Subscribe;
import info.nightscout.androidaps.Config; import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.HistoryBrowseActivity;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
import info.nightscout.androidaps.TDDStatsActivity;
import info.nightscout.androidaps.db.ExtendedBolus; import info.nightscout.androidaps.db.ExtendedBolus;
import info.nightscout.androidaps.db.TemporaryBasal; import info.nightscout.androidaps.db.TemporaryBasal;
import info.nightscout.androidaps.events.EventExtendedBolusChange; import info.nightscout.androidaps.events.EventExtendedBolusChange;
@ -33,6 +33,9 @@ import info.nightscout.androidaps.plugins.Careportal.Dialogs.NewNSTreatmentDialo
import info.nightscout.androidaps.plugins.Careportal.OptionsToShow; import info.nightscout.androidaps.plugins.Careportal.OptionsToShow;
import info.nightscout.androidaps.plugins.Common.SubscriberFragment; import info.nightscout.androidaps.plugins.Common.SubscriberFragment;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.Treatments.TreatmentsPlugin;
import info.nightscout.utils.FabricPrivacy;
import info.nightscout.utils.SingleClickButton;
/** /**
* A simple {@link Fragment} subclass. * A simple {@link Fragment} subclass.
@ -45,13 +48,15 @@ public class ActionsFragment extends SubscriberFragment implements View.OnClickL
return actionsPlugin; return actionsPlugin;
} }
Button profileSwitch; SingleClickButton profileSwitch;
Button tempTarget; SingleClickButton tempTarget;
Button extendedBolus; SingleClickButton extendedBolus;
Button extendedBolusCancel; SingleClickButton extendedBolusCancel;
Button tempBasal; SingleClickButton tempBasal;
Button tempBasalCancel; SingleClickButton tempBasalCancel;
Button fill; SingleClickButton fill;
SingleClickButton tddStats;
SingleClickButton history;
public ActionsFragment() { public ActionsFragment() {
super(); super();
@ -64,13 +69,15 @@ public class ActionsFragment extends SubscriberFragment implements View.OnClickL
try { try {
View view = inflater.inflate(R.layout.actions_fragment, container, false); View view = inflater.inflate(R.layout.actions_fragment, container, false);
profileSwitch = (Button) view.findViewById(R.id.actions_profileswitch); profileSwitch = (SingleClickButton) view.findViewById(R.id.actions_profileswitch);
tempTarget = (Button) view.findViewById(R.id.actions_temptarget); tempTarget = (SingleClickButton) view.findViewById(R.id.actions_temptarget);
extendedBolus = (Button) view.findViewById(R.id.actions_extendedbolus); extendedBolus = (SingleClickButton) view.findViewById(R.id.actions_extendedbolus);
extendedBolusCancel = (Button) view.findViewById(R.id.actions_extendedbolus_cancel); extendedBolusCancel = (SingleClickButton) view.findViewById(R.id.actions_extendedbolus_cancel);
tempBasal = (Button) view.findViewById(R.id.actions_settempbasal); tempBasal = (SingleClickButton) view.findViewById(R.id.actions_settempbasal);
tempBasalCancel = (Button) view.findViewById(R.id.actions_canceltempbasal); tempBasalCancel = (SingleClickButton) view.findViewById(R.id.actions_canceltempbasal);
fill = (Button) view.findViewById(R.id.actions_fill); 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); profileSwitch.setOnClickListener(this);
tempTarget.setOnClickListener(this); tempTarget.setOnClickListener(this);
@ -79,11 +86,13 @@ public class ActionsFragment extends SubscriberFragment implements View.OnClickL
tempBasal.setOnClickListener(this); tempBasal.setOnClickListener(this);
tempBasalCancel.setOnClickListener(this); tempBasalCancel.setOnClickListener(this);
fill.setOnClickListener(this); fill.setOnClickListener(this);
history.setOnClickListener(this);
tddStats.setOnClickListener(this);
updateGUI(); updateGUI();
return view; return view;
} catch (Exception e) { } catch (Exception e) {
Crashlytics.logException(e); FabricPrivacy.logException(e);
} }
return null; return null;
@ -116,9 +125,14 @@ public class ActionsFragment extends SubscriberFragment implements View.OnClickL
activity.runOnUiThread(new Runnable() { activity.runOnUiThread(new Runnable() {
@Override @Override
public void run() { public void run() {
if (MainApp.getConfigBuilder().getActiveProfileInterface().getProfile() == null) { if (MainApp.getConfigBuilder().getActiveProfileInterface().getProfile() != null) {
tempTarget.setVisibility(View.GONE); profileSwitch.setVisibility(View.VISIBLE);
} else {
profileSwitch.setVisibility(View.GONE); profileSwitch.setVisibility(View.GONE);
}
if (MainApp.getConfigBuilder().getProfile() == null) {
tempTarget.setVisibility(View.GONE);
extendedBolus.setVisibility(View.GONE); extendedBolus.setVisibility(View.GONE);
extendedBolusCancel.setVisibility(View.GONE); extendedBolusCancel.setVisibility(View.GONE);
tempBasal.setVisibility(View.GONE); tempBasal.setVisibility(View.GONE);
@ -126,23 +140,25 @@ public class ActionsFragment extends SubscriberFragment implements View.OnClickL
fill.setVisibility(View.GONE); fill.setVisibility(View.GONE);
return; return;
} }
final PumpInterface pump = ConfigBuilderPlugin.getActivePump(); final PumpInterface pump = ConfigBuilderPlugin.getActivePump();
boolean allowProfileSwitch = MainApp.getConfigBuilder().getActiveProfileInterface().getProfile().getProfileList().size() > 1; final boolean basalprofileEnabled = MainApp.isEngineeringModeOrRelease()
if (!pump.getPumpDescription().isSetBasalProfileCapable || !pump.isInitialized() || pump.isSuspended() || !allowProfileSwitch) && pump.getPumpDescription().isSetBasalProfileCapable;
if (!basalprofileEnabled || !pump.isInitialized() || pump.isSuspended())
profileSwitch.setVisibility(View.GONE); profileSwitch.setVisibility(View.GONE);
else else
profileSwitch.setVisibility(View.VISIBLE); profileSwitch.setVisibility(View.VISIBLE);
if (!pump.getPumpDescription().isExtendedBolusCapable || !pump.isInitialized() || pump.isSuspended() || pump.isFakingTempsByExtendedBoluses()) { if (!pump.getPumpDescription().isExtendedBolusCapable || !pump.isInitialized() || pump.isSuspended() || pump.isFakingTempsByExtendedBoluses()) {
extendedBolus.setVisibility(View.GONE); extendedBolus.setVisibility(View.GONE);
extendedBolusCancel.setVisibility(View.GONE); extendedBolusCancel.setVisibility(View.GONE);
} else { } else {
if (MainApp.getConfigBuilder().isInHistoryExtendedBoluslInProgress()) { ExtendedBolus activeExtendedBolus = TreatmentsPlugin.getPlugin().getExtendedBolusFromHistory(System.currentTimeMillis());
if (activeExtendedBolus != null) {
extendedBolus.setVisibility(View.GONE); extendedBolus.setVisibility(View.GONE);
extendedBolusCancel.setVisibility(View.VISIBLE); extendedBolusCancel.setVisibility(View.VISIBLE);
ExtendedBolus running = MainApp.getConfigBuilder().getExtendedBolusFromHistory(System.currentTimeMillis()); extendedBolusCancel.setText(MainApp.gs(R.string.cancel) + " " + activeExtendedBolus.toString());
extendedBolusCancel.setText(MainApp.instance().getString(R.string.cancel) + " " + running.toString());
} else { } else {
extendedBolus.setVisibility(View.VISIBLE); extendedBolus.setVisibility(View.VISIBLE);
extendedBolusCancel.setVisibility(View.GONE); extendedBolusCancel.setVisibility(View.GONE);
@ -154,11 +170,11 @@ public class ActionsFragment extends SubscriberFragment implements View.OnClickL
tempBasal.setVisibility(View.GONE); tempBasal.setVisibility(View.GONE);
tempBasalCancel.setVisibility(View.GONE); tempBasalCancel.setVisibility(View.GONE);
} else { } else {
if (MainApp.getConfigBuilder().isTempBasalInProgress()) { final TemporaryBasal activeTemp = TreatmentsPlugin.getPlugin().getTempBasalFromHistory(System.currentTimeMillis());
if (activeTemp != null) {
tempBasal.setVisibility(View.GONE); tempBasal.setVisibility(View.GONE);
tempBasalCancel.setVisibility(View.VISIBLE); tempBasalCancel.setVisibility(View.VISIBLE);
final TemporaryBasal activeTemp = MainApp.getConfigBuilder().getTempBasalFromHistory(System.currentTimeMillis()); tempBasalCancel.setText(MainApp.gs(R.string.cancel) + " " + activeTemp.toStringShort());
tempBasalCancel.setText(MainApp.instance().getString(R.string.cancel) + " " + activeTemp.toStringShort());
} else { } else {
tempBasal.setVisibility(View.VISIBLE); tempBasal.setVisibility(View.VISIBLE);
tempBasalCancel.setVisibility(View.GONE); tempBasalCancel.setVisibility(View.GONE);
@ -174,6 +190,9 @@ public class ActionsFragment extends SubscriberFragment implements View.OnClickL
tempTarget.setVisibility(View.GONE); tempTarget.setVisibility(View.GONE);
else else
tempTarget.setVisibility(View.VISIBLE); tempTarget.setVisibility(View.VISIBLE);
if (!ConfigBuilderPlugin.getActivePump().getPumpDescription().supportsTDDs) tddStats.setVisibility(View.GONE);
else tddStats.setVisibility(View.VISIBLE);
} }
}); });
} }
@ -202,15 +221,15 @@ public class ActionsFragment extends SubscriberFragment implements View.OnClickL
newExtendedDialog.show(manager, "NewExtendedDialog"); newExtendedDialog.show(manager, "NewExtendedDialog");
break; break;
case R.id.actions_extendedbolus_cancel: case R.id.actions_extendedbolus_cancel:
if (MainApp.getConfigBuilder().isInHistoryExtendedBoluslInProgress()) { if (TreatmentsPlugin.getPlugin().isInHistoryExtendedBoluslInProgress()) {
ConfigBuilderPlugin.getCommandQueue().cancelExtended(null); ConfigBuilderPlugin.getCommandQueue().cancelExtended(null);
Answers.getInstance().logCustom(new CustomEvent("CancelExtended")); FabricPrivacy.getInstance().logCustom(new CustomEvent("CancelExtended"));
} }
break; break;
case R.id.actions_canceltempbasal: case R.id.actions_canceltempbasal:
if (MainApp.getConfigBuilder().isTempBasalInProgress()) { if (TreatmentsPlugin.getPlugin().isTempBasalInProgress()) {
ConfigBuilderPlugin.getCommandQueue().cancelTempBasal(true, null); ConfigBuilderPlugin.getCommandQueue().cancelTempBasal(true, null);
Answers.getInstance().logCustom(new CustomEvent("CancelTemp")); FabricPrivacy.getInstance().logCustom(new CustomEvent("CancelTemp"));
} }
break; break;
case R.id.actions_settempbasal: case R.id.actions_settempbasal:
@ -221,6 +240,12 @@ public class ActionsFragment extends SubscriberFragment implements View.OnClickL
FillDialog fillDialog = new FillDialog(); FillDialog fillDialog = new FillDialog();
fillDialog.show(manager, "FillDialog"); fillDialog.show(manager, "FillDialog");
break; 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;
} }
} }
} }

View file

@ -1,82 +1,22 @@
package info.nightscout.androidaps.plugins.Actions; package info.nightscout.androidaps.plugins.Actions;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
import info.nightscout.androidaps.interfaces.PluginBase; 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. * Created by mike on 05.11.2016.
*/ */
public class ActionsPlugin implements PluginBase { public class ActionsPlugin extends PluginBase {
private boolean fragmentEnabled = true; public ActionsPlugin() {
private boolean fragmentVisible = true; super(new PluginDescription()
.mainType(PluginType.GENERAL)
@Override .fragmentClass(ActionsFragment.class.getName())
public int getType() { .pluginName(R.string.actions)
return PluginBase.GENERAL; .shortName(R.string.actions_shortname)
);
} }
@Override
public String getFragmentClass() {
return ActionsFragment.class.getName();
}
@Override
public String getName() {
return MainApp.sResources.getString(R.string.actions);
}
@Override
public String getNameShort() {
String name = MainApp.sResources.getString(R.string.actions_shortname);
if (!name.trim().isEmpty()){
//only if translation exists
return name;
}
// use long name as fallback
return getName();
}
@Override
public boolean isEnabled(int type) {
return type == GENERAL && fragmentEnabled;
}
@Override
public boolean isVisibleInTabs(int type) {
return type == GENERAL && fragmentVisible;
}
@Override
public boolean canBeHidden(int type) {
return true;
}
@Override
public boolean hasFragment() {
return true;
}
@Override
public boolean showInList(int type) {
return true;
}
@Override
public void setFragmentEnabled(int type, boolean fragmentEnabled) {
if (type == GENERAL) this.fragmentEnabled = fragmentEnabled;
}
@Override
public void setFragmentVisible(int type, boolean fragmentVisible) {
if (type == GENERAL) this.fragmentVisible = fragmentVisible;
}
@Override
public int getPreferencesId() {
return -1;
}
} }

View file

@ -1,11 +1,13 @@
package info.nightscout.androidaps.plugins.Actions.dialogs; package info.nightscout.androidaps.plugins.Actions.dialogs;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.app.DialogFragment; import android.support.v4.app.DialogFragment;
import android.support.v7.app.AlertDialog; 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.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.View.OnClickListener; import android.view.View.OnClickListener;
@ -13,40 +15,73 @@ import android.view.ViewGroup;
import android.view.Window; import android.view.Window;
import android.view.WindowManager; import android.view.WindowManager;
import android.widget.Button; import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.LinearLayout;
import com.crashlytics.android.answers.Answers;
import com.crashlytics.android.answers.CustomEvent; import com.crashlytics.android.answers.CustomEvent;
import com.google.common.base.Joiner;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.text.DecimalFormat; import java.util.LinkedList;
import java.util.List;
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.DetailedBolusInfo; import info.nightscout.androidaps.data.DetailedBolusInfo;
import info.nightscout.androidaps.db.CareportalEvent;
import info.nightscout.androidaps.db.Source; import info.nightscout.androidaps.db.Source;
import info.nightscout.androidaps.interfaces.Constraint;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.Overview.Dialogs.ErrorHelperActivity; import info.nightscout.androidaps.plugins.Overview.Dialogs.ErrorHelperActivity;
import info.nightscout.androidaps.queue.Callback; import info.nightscout.androidaps.queue.Callback;
import info.nightscout.utils.DecimalFormatter; import info.nightscout.utils.DecimalFormatter;
import info.nightscout.utils.FabricPrivacy;
import info.nightscout.utils.NSUpload;
import info.nightscout.utils.NumberPicker; import info.nightscout.utils.NumberPicker;
import info.nightscout.utils.SP; import info.nightscout.utils.SP;
import info.nightscout.utils.SafeParse; import info.nightscout.utils.SafeParse;
import info.nightscout.utils.ToastUtils;
import static info.nightscout.utils.DateUtil.now;
public class FillDialog extends DialogFragment implements OnClickListener { public class FillDialog extends DialogFragment implements OnClickListener {
private static Logger log = LoggerFactory.getLogger(FillDialog.class); private static Logger log = LoggerFactory.getLogger(FillDialog.class);
Button deliverButton; private CheckBox pumpSiteChangeCheckbox;
private CheckBox insulinCartridgeChangeCheckbox;
private NumberPicker editInsulin;
double amount1 = 0d; double amount1 = 0d;
double amount2 = 0d; double amount2 = 0d;
double amount3 = 0d; double amount3 = 0d;
NumberPicker editInsulin; private EditText notesEdit;
public FillDialog() { 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 @Override
@ -54,107 +89,122 @@ public class FillDialog extends DialogFragment implements OnClickListener {
Bundle savedInstanceState) { Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.actions_fill_dialog, null, false); View view = inflater.inflate(R.layout.actions_fill_dialog, null, false);
deliverButton = (Button) view.findViewById(R.id.treatments_newtreatment_deliverbutton); view.findViewById(R.id.ok).setOnClickListener(this);
view.findViewById(R.id.cancel).setOnClickListener(this);
deliverButton.setOnClickListener(this);
getDialog().getWindow().requestFeature(Window.FEATURE_NO_TITLE); getDialog().getWindow().requestFeature(Window.FEATURE_NO_TITLE);
getDialog().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN); getDialog().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);
Double maxInsulin = MainApp.getConfigBuilder().applyBolusConstraints(Constants.bolusOnlyForCheckLimit); 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.getActivePump().getPumpDescription().bolusStep; double bolusstep = ConfigBuilderPlugin.getActivePump().getPumpDescription().bolusStep;
editInsulin = (NumberPicker) view.findViewById(R.id.treatments_newtreatment_insulinamount); editInsulin = view.findViewById(R.id.fill_insulinamount);
editInsulin.setParams(0d, 0d, maxInsulin, bolusstep, new DecimalFormat("0.00"), false); editInsulin.setParams(0d, 0d, maxInsulin, bolusstep, DecimalFormatter.pumpSupportedBolusFormat(), false, textWatcher);
//setup preset buttons
Button button1 = (Button) view.findViewById(R.id.fill_preset_button1);
Button button2 = (Button) view.findViewById(R.id.fill_preset_button2);
Button button3 = (Button) view.findViewById(R.id.fill_preset_button3);
View divider = view.findViewById(R.id.fill_preset_divider);
Button preset1Button = view.findViewById(R.id.fill_preset_button1);
amount1 = SP.getDouble("fill_button1", 0.3); amount1 = SP.getDouble("fill_button1", 0.3);
amount2 = SP.getDouble("fill_button2", 0d);
amount3 = SP.getDouble("fill_button3", 0d);
if (amount1 > 0) { if (amount1 > 0) {
button1.setVisibility(View.VISIBLE); preset1Button.setVisibility(View.VISIBLE);
button1.setText(DecimalFormatter.to2Decimal(amount1) + "U"); preset1Button.setText(DecimalFormatter.toPumpSupportedBolus(amount1)); // + "U");
button1.setOnClickListener(this); preset1Button.setOnClickListener(this);
} else { } else {
button1.setVisibility(View.GONE); preset1Button.setVisibility(View.GONE);
} }
Button preset2Button = view.findViewById(R.id.fill_preset_button2);
amount2 = SP.getDouble("fill_button2", 0d);
if (amount2 > 0) { if (amount2 > 0) {
button2.setVisibility(View.VISIBLE); preset2Button.setVisibility(View.VISIBLE);
button2.setText(DecimalFormatter.to2Decimal(amount2) + "U"); preset2Button.setText(DecimalFormatter.toPumpSupportedBolus(amount2)); // + "U");
button2.setOnClickListener(this); preset2Button.setOnClickListener(this);
} else { } else {
button2.setVisibility(View.GONE); preset2Button.setVisibility(View.GONE);
} }
Button preset3Button = view.findViewById(R.id.fill_preset_button3);
amount3 = SP.getDouble("fill_button3", 0d);
if (amount3 > 0) { if (amount3 > 0) {
button3.setVisibility(View.VISIBLE); preset3Button.setVisibility(View.VISIBLE);
button3.setText(DecimalFormatter.to2Decimal(amount3) + "U"); preset3Button.setText(DecimalFormatter.toPumpSupportedBolus(amount3)); // + "U");
button3.setOnClickListener(this); preset3Button.setOnClickListener(this);
} else { } else {
button3.setVisibility(View.GONE); preset3Button.setVisibility(View.GONE);
} }
if (button1.getVisibility() == View.GONE && button2.getVisibility() == View.GONE && button3.getVisibility() == View.GONE) { LinearLayout notesLayout = view.findViewById(R.id.fill_notes_layout);
divider.setVisibility(View.GONE); 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; return view;
} }
@Override
public void onResume() {
super.onResume();
if (getDialog() != null)
getDialog().getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
}
@Override @Override
public void onClick(View view) { public void onClick(View view) {
switch (view.getId()) { switch (view.getId()) {
case R.id.treatments_newtreatment_deliverbutton: case R.id.ok:
Double insulin = SafeParse.stringToDouble(editInsulin.getText().toString()); confirmAndDeliver();
confirmAndDeliver(insulin); break;
case R.id.cancel:
dismiss();
break; break;
case R.id.fill_preset_button1: case R.id.fill_preset_button1:
confirmAndDeliver(amount1); editInsulin.setValue(amount1);
break; break;
case R.id.fill_preset_button2: case R.id.fill_preset_button2:
confirmAndDeliver(amount2); editInsulin.setValue(amount2);
break; break;
case R.id.fill_preset_button3: case R.id.fill_preset_button3:
confirmAndDeliver(amount3); editInsulin.setValue(amount3);
break; break;
} }
} }
private void confirmAndDeliver(Double insulin) { private void confirmAndDeliver() {
try { try {
Double insulin = SafeParse.stringToDouble(editInsulin.getText());
String confirmMessage = getString(R.string.fillwarning) + "\n"; List<String> confirmMessage = new LinkedList<>();
Double insulinAfterConstraints = MainApp.getConfigBuilder().applyBolusConstraints(insulin); Double insulinAfterConstraints = MainApp.getConstraintChecker().applyBolusConstraints(new Constraint<>(insulin)).value();
confirmMessage += getString(R.string.bolus) + ": " + insulinAfterConstraints + "U"; if (insulinAfterConstraints > 0) {
if (insulinAfterConstraints - insulin != 0) confirmMessage.add(MainApp.gs(R.string.fillwarning));
confirmMessage += "\n" + getString(R.string.constraintapllied); confirmMessage.add("");
confirmMessage.add(MainApp.gs(R.string.bolus) + ": " + "<font color='" + MainApp.gc(R.color.colorCarbsButton) + "'>" + insulinAfterConstraints + "U" + "</font>");
if (!insulinAfterConstraints.equals(insulin))
confirmMessage.add("<font color='" + MainApp.sResources.getColor(R.color.low) + "'>" + MainApp.gs(R.string.bolusconstraintapplied) + "</font>");
}
if (pumpSiteChangeCheckbox.isChecked())
confirmMessage.add("" + "<font color='" + MainApp.sResources.getColor(R.color.high) + "'>" + MainApp.gs(R.string.record_pump_site_change) + "</font>");
if (insulinCartridgeChangeCheckbox.isChecked())
confirmMessage.add("" + "<font color='" + MainApp.sResources.getColor(R.color.high) + "'>" + MainApp.gs(R.string.record_insulin_cartridge_change) + "</font>");
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 Double finalInsulinAfterConstraints = insulinAfterConstraints;
final Context context = getContext(); final Context context = getContext();
AlertDialog.Builder builder = new AlertDialog.Builder(context); AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle(this.getContext().getString(R.string.confirmation)); builder.setTitle(MainApp.gs(R.string.confirmation));
builder.setMessage(confirmMessage); if (insulinAfterConstraints > 0 || pumpSiteChangeCheckbox.isChecked() || insulinCartridgeChangeCheckbox.isChecked()) {
builder.setPositiveButton(getString(R.string.primefill), new DialogInterface.OnClickListener() { builder.setMessage(Html.fromHtml(Joiner.on("<br/>").join(confirmMessage)));
public void onClick(DialogInterface dialog, int id) { builder.setPositiveButton(MainApp.gs(R.string.primefill), (dialog, id) -> {
if (finalInsulinAfterConstraints > 0) { if (finalInsulinAfterConstraints > 0) {
DetailedBolusInfo detailedBolusInfo = new DetailedBolusInfo(); DetailedBolusInfo detailedBolusInfo = new DetailedBolusInfo();
detailedBolusInfo.insulin = finalInsulinAfterConstraints; detailedBolusInfo.insulin = finalInsulinAfterConstraints;
detailedBolusInfo.context = context; detailedBolusInfo.context = context;
detailedBolusInfo.source = Source.USER; detailedBolusInfo.source = Source.USER;
detailedBolusInfo.isValid = false; // do not count it in IOB (for pump history) detailedBolusInfo.isValid = false; // do not count it in IOB (for pump history)
detailedBolusInfo.notes = notes;
ConfigBuilderPlugin.getCommandQueue().bolus(detailedBolusInfo, new Callback() { ConfigBuilderPlugin.getCommandQueue().bolus(detailedBolusInfo, new Callback() {
@Override @Override
public void run() { public void run() {
@ -162,17 +212,23 @@ public class FillDialog extends DialogFragment implements OnClickListener {
Intent i = new Intent(MainApp.instance(), ErrorHelperActivity.class); Intent i = new Intent(MainApp.instance(), ErrorHelperActivity.class);
i.putExtra("soundid", R.raw.boluserror); i.putExtra("soundid", R.raw.boluserror);
i.putExtra("status", result.comment); i.putExtra("status", result.comment);
i.putExtra("title", MainApp.sResources.getString(R.string.treatmentdeliveryerror)); i.putExtra("title", MainApp.gs(R.string.treatmentdeliveryerror));
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
MainApp.instance().startActivity(i); MainApp.instance().startActivity(i);
} }
} }
}); });
Answers.getInstance().logCustom(new CustomEvent("Fill")); FabricPrivacy.getInstance().logCustom(new CustomEvent("Fill"));
} }
} if (pumpSiteChangeCheckbox.isChecked())
}); NSUpload.uploadEvent(CareportalEvent.SITECHANGE, now(), notes);
builder.setNegativeButton(getString(R.string.cancel), null); 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(); builder.show();
dismiss(); dismiss();
} catch (RuntimeException e) { } catch (RuntimeException e) {

View file

@ -10,20 +10,21 @@ import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import com.crashlytics.android.answers.Answers;
import com.crashlytics.android.answers.CustomEvent; import com.crashlytics.android.answers.CustomEvent;
import org.mozilla.javascript.tools.jsc.Main;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.text.DecimalFormat; import java.text.DecimalFormat;
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
import info.nightscout.androidaps.interfaces.Constraint;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.Overview.Dialogs.ErrorHelperActivity; import info.nightscout.androidaps.plugins.Overview.Dialogs.ErrorHelperActivity;
import info.nightscout.androidaps.queue.Callback; import info.nightscout.androidaps.queue.Callback;
import info.nightscout.utils.FabricPrivacy;
import info.nightscout.utils.NumberPicker; import info.nightscout.utils.NumberPicker;
import info.nightscout.utils.SafeParse; import info.nightscout.utils.SafeParse;
@ -39,11 +40,11 @@ public class NewExtendedBolusDialog extends DialogFragment implements View.OnCli
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) { Bundle savedInstanceState) {
getDialog().setTitle(getString(R.string.overview_extendedbolus_button)); getDialog().setTitle(MainApp.gs(R.string.overview_extendedbolus_button));
View view = inflater.inflate(R.layout.overview_newextendedbolus_dialog, container, false); View view = inflater.inflate(R.layout.overview_newextendedbolus_dialog, container, false);
Double maxInsulin = MainApp.getConfigBuilder().applyBolusConstraints(Constants.bolusOnlyForCheckLimit); Double maxInsulin = MainApp.getConstraintChecker().getMaxBolusAllowed().value();
editInsulin = (NumberPicker) view.findViewById(R.id.overview_newextendedbolus_insulin); editInsulin = (NumberPicker) view.findViewById(R.id.overview_newextendedbolus_insulin);
editInsulin.setParams(0d, 0d, maxInsulin, 0.1d, new DecimalFormat("0.00"), false); editInsulin.setParams(0d, 0d, maxInsulin, 0.1d, new DecimalFormat("0.00"), false);
@ -54,14 +55,10 @@ public class NewExtendedBolusDialog extends DialogFragment implements View.OnCli
view.findViewById(R.id.ok).setOnClickListener(this); view.findViewById(R.id.ok).setOnClickListener(this);
view.findViewById(R.id.cancel).setOnClickListener(this); view.findViewById(R.id.cancel).setOnClickListener(this);
return view;
}
@Override setCancelable(true);
public void onResume() { getDialog().setCanceledOnTouchOutside(false);
super.onResume(); return view;
if (getDialog() != null)
getDialog().getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
} }
@Override @Override
@ -72,13 +69,13 @@ public class NewExtendedBolusDialog extends DialogFragment implements View.OnCli
Double insulin = SafeParse.stringToDouble(editInsulin.getText()); Double insulin = SafeParse.stringToDouble(editInsulin.getText());
int durationInMinutes = SafeParse.stringToInt(editDuration.getText()); int durationInMinutes = SafeParse.stringToInt(editDuration.getText());
String confirmMessage = getString(R.string.setextendedbolusquestion); String confirmMessage = MainApp.gs(R.string.setextendedbolusquestion);
Double insulinAfterConstraint = MainApp.getConfigBuilder().applyBolusConstraints(insulin); Double insulinAfterConstraint = MainApp.getConstraintChecker().applyBolusConstraints(new Constraint<>(insulin)).value();
confirmMessage += " " + insulinAfterConstraint + " U "; confirmMessage += " " + insulinAfterConstraint + " U ";
confirmMessage += getString(R.string.duration) + " " + durationInMinutes + "min ?"; confirmMessage += MainApp.gs(R.string.duration) + " " + durationInMinutes + "min ?";
if (insulinAfterConstraint - insulin != 0d) if (insulinAfterConstraint - insulin != 0d)
confirmMessage += "\n" + getString(R.string.constraintapllied); confirmMessage += "\n" + MainApp.gs(R.string.constraintapllied);
insulin = insulinAfterConstraint; insulin = insulinAfterConstraint;
final Double finalInsulin = insulin; final Double finalInsulin = insulin;
@ -86,9 +83,9 @@ public class NewExtendedBolusDialog extends DialogFragment implements View.OnCli
final Context context = getContext(); final Context context = getContext();
AlertDialog.Builder builder = new AlertDialog.Builder(context); AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle(context.getString(R.string.confirmation)); builder.setTitle(MainApp.gs(R.string.confirmation));
builder.setMessage(confirmMessage); builder.setMessage(confirmMessage);
builder.setPositiveButton(getString(R.string.ok), new DialogInterface.OnClickListener() { builder.setPositiveButton(MainApp.gs(R.string.ok), new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) { public void onClick(DialogInterface dialog, int id) {
ConfigBuilderPlugin.getCommandQueue().extendedBolus(finalInsulin, finalDurationInMinutes, new Callback() { ConfigBuilderPlugin.getCommandQueue().extendedBolus(finalInsulin, finalDurationInMinutes, new Callback() {
@Override @Override
@ -97,16 +94,16 @@ public class NewExtendedBolusDialog extends DialogFragment implements View.OnCli
Intent i = new Intent(MainApp.instance(), ErrorHelperActivity.class); Intent i = new Intent(MainApp.instance(), ErrorHelperActivity.class);
i.putExtra("soundid", R.raw.boluserror); i.putExtra("soundid", R.raw.boluserror);
i.putExtra("status", result.comment); i.putExtra("status", result.comment);
i.putExtra("title", MainApp.sResources.getString(R.string.treatmentdeliveryerror)); i.putExtra("title", MainApp.gs(R.string.treatmentdeliveryerror));
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
MainApp.instance().startActivity(i); MainApp.instance().startActivity(i);
} }
} }
}); });
Answers.getInstance().logCustom(new CustomEvent("ExtendedBolus")); FabricPrivacy.getInstance().logCustom(new CustomEvent("ExtendedBolus"));
} }
}); });
builder.setNegativeButton(getString(R.string.cancel), null); builder.setNegativeButton(MainApp.gs(R.string.cancel), null);
builder.show(); builder.show();
dismiss(); dismiss();

View file

@ -1,6 +1,5 @@
package info.nightscout.androidaps.plugins.Actions.dialogs; package info.nightscout.androidaps.plugins.Actions.dialogs;
import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
@ -13,7 +12,6 @@ import android.widget.LinearLayout;
import android.widget.RadioButton; import android.widget.RadioButton;
import android.widget.RadioGroup; import android.widget.RadioGroup;
import com.crashlytics.android.answers.Answers;
import com.crashlytics.android.answers.CustomEvent; import com.crashlytics.android.answers.CustomEvent;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -24,10 +22,12 @@ import java.text.DecimalFormat;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.interfaces.Constraint;
import info.nightscout.androidaps.interfaces.PumpDescription; import info.nightscout.androidaps.interfaces.PumpDescription;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.Overview.Dialogs.ErrorHelperActivity; import info.nightscout.androidaps.plugins.Overview.Dialogs.ErrorHelperActivity;
import info.nightscout.androidaps.queue.Callback; import info.nightscout.androidaps.queue.Callback;
import info.nightscout.utils.FabricPrivacy;
import info.nightscout.utils.NumberPicker; import info.nightscout.utils.NumberPicker;
import info.nightscout.utils.SafeParse; import info.nightscout.utils.SafeParse;
@ -52,7 +52,7 @@ public class NewTempBasalDialog extends DialogFragment implements View.OnClickLi
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) { Bundle savedInstanceState) {
getDialog().setTitle(getString(R.string.overview_tempbasal_button)); getDialog().setTitle(MainApp.gs(R.string.overview_tempbasal_button));
View view = inflater.inflate(R.layout.overview_newtempbasal_dialog, container, false); View view = inflater.inflate(R.layout.overview_newtempbasal_dialog, container, false);
@ -102,6 +102,9 @@ public class NewTempBasalDialog extends DialogFragment implements View.OnClickLi
view.findViewById(R.id.ok).setOnClickListener(this); view.findViewById(R.id.ok).setOnClickListener(this);
view.findViewById(R.id.cancel).setOnClickListener(this); view.findViewById(R.id.cancel).setOnClickListener(this);
basalTypeRadioGroup.setOnCheckedChangeListener(this); basalTypeRadioGroup.setOnCheckedChangeListener(this);
setCancelable(true);
getDialog().setCanceledOnTouchOutside(false);
return view; return view;
} }
@ -115,21 +118,25 @@ public class NewTempBasalDialog extends DialogFragment implements View.OnClickLi
final boolean setAsPercent = percentRadio.isChecked(); final boolean setAsPercent = percentRadio.isChecked();
int durationInMinutes = SafeParse.stringToInt(duration.getText()); int durationInMinutes = SafeParse.stringToInt(duration.getText());
String confirmMessage = getString(R.string.setbasalquestion); Profile profile = MainApp.getConfigBuilder().getProfile();
if (profile == null)
return;
String confirmMessage = MainApp.gs(R.string.setbasalquestion);
if (setAsPercent) { if (setAsPercent) {
int basalPercentInput = SafeParse.stringToInt(basalPercent.getText()); int basalPercentInput = SafeParse.stringToInt(basalPercent.getText());
percent = MainApp.getConfigBuilder().applyBasalConstraints(basalPercentInput); percent = MainApp.getConstraintChecker().applyBasalPercentConstraints(new Constraint<>(basalPercentInput), profile).value();
confirmMessage += "\n" + percent + "% "; confirmMessage += "\n" + percent + "% ";
confirmMessage += "\n" + getString(R.string.duration) + " " + durationInMinutes + "min ?"; confirmMessage += "\n" + MainApp.gs(R.string.duration) + " " + durationInMinutes + "min ?";
if (percent != basalPercentInput) if (percent != basalPercentInput)
confirmMessage += "\n" + getString(R.string.constraintapllied); confirmMessage += "\n" + MainApp.gs(R.string.constraintapllied);
} else { } else {
Double basalAbsoluteInput = SafeParse.stringToDouble(basalAbsolute.getText()); Double basalAbsoluteInput = SafeParse.stringToDouble(basalAbsolute.getText());
absolute = MainApp.getConfigBuilder().applyBasalConstraints(basalAbsoluteInput); absolute = MainApp.getConstraintChecker().applyBasalConstraints(new Constraint<>(basalAbsoluteInput), profile).value();
confirmMessage += "\n" + absolute + " U/h "; confirmMessage += "\n" + absolute + " U/h ";
confirmMessage += "\n" + getString(R.string.duration) + " " + durationInMinutes + "min ?"; confirmMessage += "\n" + MainApp.gs(R.string.duration) + " " + durationInMinutes + "min ?";
if (absolute - basalAbsoluteInput != 0d) if (absolute - basalAbsoluteInput != 0d)
confirmMessage += "\n" + getString(R.string.constraintapllied); confirmMessage += "\n" + MainApp.gs(R.string.constraintapllied);
} }
final int finalBasalPercent = percent; final int finalBasalPercent = percent;
@ -137,9 +144,9 @@ public class NewTempBasalDialog extends DialogFragment implements View.OnClickLi
final int finalDurationInMinutes = durationInMinutes; final int finalDurationInMinutes = durationInMinutes;
AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setTitle(this.getContext().getString(R.string.confirmation)); builder.setTitle(MainApp.gs(R.string.confirmation));
builder.setMessage(confirmMessage); builder.setMessage(confirmMessage);
builder.setPositiveButton(getString(R.string.ok), new DialogInterface.OnClickListener() { builder.setPositiveButton(MainApp.gs(R.string.ok), new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) { public void onClick(DialogInterface dialog, int id) {
Callback callback = new Callback() { Callback callback = new Callback() {
@Override @Override
@ -148,21 +155,21 @@ public class NewTempBasalDialog extends DialogFragment implements View.OnClickLi
Intent i = new Intent(MainApp.instance(), ErrorHelperActivity.class); Intent i = new Intent(MainApp.instance(), ErrorHelperActivity.class);
i.putExtra("soundid", R.raw.boluserror); i.putExtra("soundid", R.raw.boluserror);
i.putExtra("status", result.comment); i.putExtra("status", result.comment);
i.putExtra("title", MainApp.sResources.getString(R.string.tempbasaldeliveryerror)); i.putExtra("title", MainApp.gs(R.string.tempbasaldeliveryerror));
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
MainApp.instance().startActivity(i); MainApp.instance().startActivity(i);
} }
} }
}; };
if (setAsPercent) { if (setAsPercent) {
ConfigBuilderPlugin.getCommandQueue().tempBasalPercent(finalBasalPercent, finalDurationInMinutes, callback); ConfigBuilderPlugin.getCommandQueue().tempBasalPercent(finalBasalPercent, finalDurationInMinutes, true, profile, callback);
} else { } else {
ConfigBuilderPlugin.getCommandQueue().tempBasalAbsolute(finalBasal, finalDurationInMinutes, true, callback); ConfigBuilderPlugin.getCommandQueue().tempBasalAbsolute(finalBasal, finalDurationInMinutes, true, profile, callback);
} }
Answers.getInstance().logCustom(new CustomEvent("TempBasal")); FabricPrivacy.getInstance().logCustom(new CustomEvent("TempBasal"));
} }
}); });
builder.setNegativeButton(getString(R.string.cancel), null); builder.setNegativeButton(MainApp.gs(R.string.cancel), null);
builder.show(); builder.show();
dismiss(); dismiss();

View file

@ -2,6 +2,7 @@ package info.nightscout.androidaps.plugins.Careportal;
import android.app.Activity; import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentManager;
import android.view.LayoutInflater; import android.view.LayoutInflater;
@ -10,10 +11,11 @@ import android.view.ViewGroup;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.TextView; import android.widget.TextView;
import com.crashlytics.android.Crashlytics;
import com.squareup.otto.Subscribe; import com.squareup.otto.Subscribe;
import info.nightscout.androidaps.BuildConfig; import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.Config; import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
@ -22,10 +24,12 @@ import info.nightscout.androidaps.db.CareportalEvent;
import info.nightscout.androidaps.events.EventCareportalEventChange; import info.nightscout.androidaps.events.EventCareportalEventChange;
import info.nightscout.androidaps.plugins.Careportal.Dialogs.NewNSTreatmentDialog; import info.nightscout.androidaps.plugins.Careportal.Dialogs.NewNSTreatmentDialog;
import info.nightscout.androidaps.plugins.Common.SubscriberFragment; import info.nightscout.androidaps.plugins.Common.SubscriberFragment;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.NSClientInternal.data.NSSettingsStatus;
import info.nightscout.androidaps.plugins.Overview.OverviewFragment; import info.nightscout.androidaps.plugins.Overview.OverviewFragment;
import info.nightscout.utils.FabricPrivacy;
public class CareportalFragment extends SubscriberFragment implements View.OnClickListener { public class CareportalFragment extends SubscriberFragment implements View.OnClickListener {
private static Logger log = LoggerFactory.getLogger(CareportalFragment.class);
TextView iage; TextView iage;
TextView cage; TextView cage;
@ -96,7 +100,7 @@ public class CareportalFragment extends SubscriberFragment implements View.OnCli
noProfileView = view.findViewById(R.id.profileview_noprofile); noProfileView = view.findViewById(R.id.profileview_noprofile);
butonsLayout = (LinearLayout) view.findViewById(R.id.careportal_buttons); butonsLayout = (LinearLayout) view.findViewById(R.id.careportal_buttons);
ProfileStore profileStore = ConfigBuilderPlugin.getActiveProfileInterface().getProfile(); ProfileStore profileStore = MainApp.getConfigBuilder().getActiveProfileInterface().getProfile();
if (profileStore == null) { if (profileStore == null) {
noProfileView.setVisibility(View.VISIBLE); noProfileView.setVisibility(View.VISIBLE);
butonsLayout.setVisibility(View.GONE); butonsLayout.setVisibility(View.GONE);
@ -111,7 +115,7 @@ public class CareportalFragment extends SubscriberFragment implements View.OnCli
updateGUI(); updateGUI();
return view; return view;
} catch (Exception e) { } catch (Exception e) {
Crashlytics.logException(e); FabricPrivacy.logException(e);
} }
return null; return null;
@ -208,26 +212,54 @@ public class CareportalFragment extends SubscriberFragment implements View.OnCli
public static void updateAge(Activity activity, final TextView sage, final TextView iage, final TextView cage, final TextView pbage) { public static void updateAge(Activity activity, final TextView sage, final TextView iage, final TextView cage, final TextView pbage) {
if (activity != null) { if (activity != null) {
activity.runOnUiThread( activity.runOnUiThread(
new Runnable() { () -> {
@Override CareportalEvent careportalEvent;
public void run() { NSSettingsStatus nsSettings = new NSSettingsStatus().getInstance();
CareportalEvent careportalEvent;
String notavailable = OverviewFragment.shorttextmode ? "-" : MainApp.sResources.getString(R.string.notavailable); double iageUrgent = nsSettings.getExtendedWarnValue("iage", "urgent", 96);
if (sage != null) { double iageWarn = nsSettings.getExtendedWarnValue("iage", "warn", 72);
careportalEvent = MainApp.getDbHelper().getLastCareportalEvent(CareportalEvent.SENSORCHANGE); double cageUrgent = nsSettings.getExtendedWarnValue("cage", "urgent", 72);
sage.setText(careportalEvent != null ? careportalEvent.age() : notavailable); double cageWarn = nsSettings.getExtendedWarnValue("cage", "warn", 48);
double sageUrgent = nsSettings.getExtendedWarnValue("sage", "urgent", 166);
double sageWarn = nsSettings.getExtendedWarnValue("sage", "warn", 164);
double pbageUrgent = nsSettings.getExtendedWarnValue("pgage", "urgent", 360);
double pbageWarn = nsSettings.getExtendedWarnValue("pgage", "warn", 240);
String notavailable = OverviewFragment.shorttextmode ? "-" : MainApp.gs(R.string.notavailable);
if (sage != null) {
careportalEvent = MainApp.getDbHelper().getLastCareportalEvent(CareportalEvent.SENSORCHANGE);
if (careportalEvent != null) {
sage.setTextColor(CareportalFragment.determineTextColor(careportalEvent, sageWarn, sageUrgent));
sage.setText(careportalEvent.age());
} else {
sage.setText(notavailable);
} }
if (iage != null) { }
careportalEvent = MainApp.getDbHelper().getLastCareportalEvent(CareportalEvent.INSULINCHANGE); if (iage != null) {
iage.setText(careportalEvent != null ? careportalEvent.age() : notavailable); careportalEvent = MainApp.getDbHelper().getLastCareportalEvent(CareportalEvent.INSULINCHANGE);
if (careportalEvent != null) {
iage.setTextColor(CareportalFragment.determineTextColor(careportalEvent, iageWarn, iageUrgent));
iage.setText(careportalEvent.age());
} else {
iage.setText(notavailable);
} }
if (cage != null) { }
careportalEvent = MainApp.getDbHelper().getLastCareportalEvent(CareportalEvent.SITECHANGE); if (cage != null) {
cage.setText(careportalEvent != null ? careportalEvent.age() : notavailable); careportalEvent = MainApp.getDbHelper().getLastCareportalEvent(CareportalEvent.SITECHANGE);
if (careportalEvent != null) {
cage.setTextColor(CareportalFragment.determineTextColor(careportalEvent, cageWarn, cageUrgent));
cage.setText(careportalEvent.age());
} else {
cage.setText(notavailable);
} }
if (pbage != null) { }
careportalEvent = MainApp.getDbHelper().getLastCareportalEvent(CareportalEvent.PUMPBATTERYCHANGE); if (pbage != null) {
pbage.setText(careportalEvent != null ? careportalEvent.age() : notavailable); careportalEvent = MainApp.getDbHelper().getLastCareportalEvent(CareportalEvent.PUMPBATTERYCHANGE);
if (careportalEvent != null) {
pbage.setTextColor(CareportalFragment.determineTextColor(careportalEvent, pbageWarn, pbageUrgent));
pbage.setText(careportalEvent.age());
} else {
pbage.setText(notavailable);
} }
} }
} }
@ -235,4 +267,15 @@ public class CareportalFragment extends SubscriberFragment implements View.OnCli
} }
} }
public static int determineTextColor(CareportalEvent careportalEvent, double warnThreshold, double urgentThreshold) {
if (careportalEvent.isOlderThan(urgentThreshold)) {
return MainApp.sResources.getColor(R.color.low);
} else if (careportalEvent.isOlderThan(warnThreshold)) {
return MainApp.sResources.getColor(R.color.high);
} else {
return Color.WHITE;
}
}
} }

View file

@ -1,14 +1,12 @@
package info.nightscout.androidaps.plugins.Careportal; package info.nightscout.androidaps.plugins.Careportal;
import info.nightscout.androidaps.Config; import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
import info.nightscout.androidaps.interfaces.PluginBase; import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.PluginDescription;
import info.nightscout.androidaps.interfaces.PluginType;
public class CareportalPlugin implements PluginBase { public class CareportalPlugin extends PluginBase {
private boolean fragmentEnabled = true;
private boolean fragmentVisible = true;
static CareportalPlugin careportalPlugin; static CareportalPlugin careportalPlugin;
@ -19,70 +17,13 @@ public class CareportalPlugin implements PluginBase {
return careportalPlugin; return careportalPlugin;
} }
@Override public CareportalPlugin() {
public int getType() { super(new PluginDescription()
return PluginBase.GENERAL; .mainType(PluginType.GENERAL)
} .fragmentClass(CareportalFragment.class.getName())
.pluginName(R.string.careportal)
@Override .shortName(R.string.careportal_shortname)
public String getFragmentClass() { );
return CareportalFragment.class.getName();
}
@Override
public String getName() {
return MainApp.sResources.getString(R.string.careportal);
}
@Override
public String getNameShort() {
String name = MainApp.sResources.getString(R.string.careportal_shortname);
if (!name.trim().isEmpty()){
//only if translation exists
return name;
}
// use long name as fallback
return getName();
}
@Override
public boolean isEnabled(int type) {
return type == GENERAL && fragmentEnabled;
}
@Override
public boolean isVisibleInTabs(int type) {
return type == GENERAL && fragmentVisible;
}
@Override
public boolean canBeHidden(int type) {
return true;
}
@Override
public boolean hasFragment() {
return true;
}
@Override
public boolean showInList(int type) {
return !Config.NSCLIENT && !Config.G5UPLOADER;
}
@Override
public void setFragmentEnabled(int type, boolean fragmentEnabled) {
if (type == GENERAL) this.fragmentEnabled = fragmentEnabled;
}
@Override
public void setFragmentVisible(int type, boolean fragmentVisible) {
if (type == GENERAL) this.fragmentVisible = fragmentVisible;
}
@Override
public int getPreferencesId() {
return R.xml.pref_careportal;
} }
} }

View file

@ -2,8 +2,6 @@ package info.nightscout.androidaps.plugins.Careportal.Dialogs;
import android.app.Activity; import android.app.Activity;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.app.DialogFragment; import android.support.v4.app.DialogFragment;
import android.support.v7.app.AlertDialog; import android.support.v7.app.AlertDialog;
@ -16,15 +14,14 @@ import android.view.ViewGroup;
import android.widget.AdapterView; import android.widget.AdapterView;
import android.widget.ArrayAdapter; import android.widget.ArrayAdapter;
import android.widget.Button; import android.widget.Button;
import android.widget.CompoundButton;
import android.widget.EditText; import android.widget.EditText;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.RadioButton; import android.widget.RadioButton;
import android.widget.Spinner; import android.widget.Spinner;
import android.widget.TextView; import android.widget.TextView;
import com.crashlytics.android.answers.Answers;
import com.crashlytics.android.answers.CustomEvent; import com.crashlytics.android.answers.CustomEvent;
import com.google.common.collect.Lists;
import com.wdullaer.materialdatetimepicker.date.DatePickerDialog; import com.wdullaer.materialdatetimepicker.date.DatePickerDialog;
import com.wdullaer.materialdatetimepicker.time.RadialPickerLayout; import com.wdullaer.materialdatetimepicker.time.RadialPickerLayout;
import com.wdullaer.materialdatetimepicker.time.TimePickerDialog; import com.wdullaer.materialdatetimepicker.time.TimePickerDialog;
@ -38,6 +35,7 @@ import java.text.DecimalFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Calendar; import java.util.Calendar;
import java.util.Date; import java.util.Date;
import java.util.List;
import info.nightscout.androidaps.Constants; import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
@ -45,16 +43,18 @@ import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.GlucoseStatus; import info.nightscout.androidaps.data.GlucoseStatus;
import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.data.ProfileStore; import info.nightscout.androidaps.data.ProfileStore;
import info.nightscout.androidaps.db.BgReading;
import info.nightscout.androidaps.db.CareportalEvent; import info.nightscout.androidaps.db.CareportalEvent;
import info.nightscout.androidaps.db.ProfileSwitch; import info.nightscout.androidaps.db.ProfileSwitch;
import info.nightscout.androidaps.db.Source; import info.nightscout.androidaps.db.Source;
import info.nightscout.androidaps.db.TempTarget; import info.nightscout.androidaps.db.TempTarget;
import info.nightscout.androidaps.events.EventNewBasalProfile;
import info.nightscout.androidaps.plugins.Careportal.OptionsToShow; import info.nightscout.androidaps.plugins.Careportal.OptionsToShow;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.Treatments.TreatmentsPlugin;
import info.nightscout.androidaps.plugins.Overview.Dialogs.ErrorHelperActivity;
import info.nightscout.androidaps.queue.Callback;
import info.nightscout.utils.DateUtil; import info.nightscout.utils.DateUtil;
import info.nightscout.utils.DefaultValueHelper;
import info.nightscout.utils.FabricPrivacy;
import info.nightscout.utils.HardLimits;
import info.nightscout.utils.JsonHelper;
import info.nightscout.utils.NSUpload; import info.nightscout.utils.NSUpload;
import info.nightscout.utils.NumberPicker; import info.nightscout.utils.NumberPicker;
import info.nightscout.utils.SP; import info.nightscout.utils.SP;
@ -70,8 +70,8 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick
private static String event; private static String event;
Profile profile; Profile profile;
ProfileStore profileStore; public ProfileStore profileStore;
String units; String units = Constants.MGDL;
TextView eventTypeText; TextView eventTypeText;
LinearLayout layoutPercent; LinearLayout layoutPercent;
@ -105,13 +105,19 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick
Date eventTime; Date eventTime;
private static Integer seconds = null;
public void setOptions(OptionsToShow options, int event) { public void setOptions(OptionsToShow options, int event) {
this.options = options; this.options = options;
this.event = MainApp.sResources.getString(event); this.event = MainApp.gs(event);
} }
public NewNSTreatmentDialog() { public NewNSTreatmentDialog() {
super(); super();
if (seconds == null) {
seconds = Double.valueOf(Math.random() * 59).intValue();
}
} }
@Override @Override
@ -130,7 +136,7 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick
public View onCreateView(LayoutInflater inflater, ViewGroup container, public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) { Bundle savedInstanceState) {
if (options == null) return null; if (options == null) return null;
getDialog().setTitle(getString(options.eventName)); getDialog().setTitle(MainApp.gs(options.eventName));
setStyle(DialogFragment.STYLE_NORMAL, getTheme()); setStyle(DialogFragment.STYLE_NORMAL, getTheme());
View view = inflater.inflate(R.layout.careportal_newnstreatment_dialog, container, false); View view = inflater.inflate(R.layout.careportal_newnstreatment_dialog, container, false);
@ -166,52 +172,61 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick
// profile // profile
profile = MainApp.getConfigBuilder().getProfile(); profile = MainApp.getConfigBuilder().getProfile();
profileStore = ConfigBuilderPlugin.getActiveProfileInterface().getProfile(); profileStore = MainApp.getConfigBuilder().getActiveProfileInterface().getProfile();
ArrayList<CharSequence> profileList; if (profileStore == null) {
units = profile != null ? profile.getUnits() : Constants.MGDL; if (options.eventType == R.id.careportal_profileswitch) {
profileList = profileStore.getProfileList(); log.error("Profile switch called but plugin doesn't contain valid profile");
ArrayAdapter<CharSequence> adapter = new ArrayAdapter<CharSequence>(getContext(), }
R.layout.spinner_centered, profileList); } else {
profileSpinner.setAdapter(adapter); ArrayList<CharSequence> profileList;
// set selected to actual profile units = profile != null ? profile.getUnits() : Constants.MGDL;
for (int p = 0; p < profileList.size(); p++) { profileList = profileStore.getProfileList();
if (profileList.get(p).equals(MainApp.getConfigBuilder().getProfileName())) ArrayAdapter<CharSequence> adapter = new ArrayAdapter<>(getContext(),
profileSpinner.setSelection(p); R.layout.spinner_centered, profileList);
profileSpinner.setAdapter(adapter);
// set selected to actual profile
for (int p = 0; p < profileList.size(); p++) {
if (profileList.get(p).equals(MainApp.getConfigBuilder().getProfileName(false)))
profileSpinner.setSelection(p);
}
} }
final Double bg = Profile.fromMgdlToUnits(GlucoseStatus.getGlucoseStatusData() != null ? GlucoseStatus.getGlucoseStatusData().glucose : 0d, units);
final Double bg = Profile.fromMgdlToUnits(GlucoseStatus.getGlucoseStatusData() != null ? GlucoseStatus.getGlucoseStatusData().glucose : 0d, profile != null ? profile.getUnits() : Constants.MGDL);
// temp target // temp target
final ArrayList<CharSequence> reasonList = new ArrayList<CharSequence>(); final List<String> reasonList = Lists.newArrayList(
reasonList.add(MainApp.sResources.getString(R.string.manual)); MainApp.gs(R.string.manual),
reasonList.add(MainApp.sResources.getString(R.string.eatingsoon)); MainApp.gs(R.string.eatingsoon),
reasonList.add(MainApp.sResources.getString(R.string.activity)); MainApp.gs(R.string.activity),
ArrayAdapter<CharSequence> adapterReason = new ArrayAdapter<CharSequence>(getContext(), MainApp.gs(R.string.hypo));
ArrayAdapter<String> adapterReason = new ArrayAdapter<>(getContext(),
R.layout.spinner_centered, reasonList); R.layout.spinner_centered, reasonList);
reasonSpinner.setAdapter(adapterReason); reasonSpinner.setAdapter(adapterReason);
reasonSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { reasonSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override @Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
double defaultDuration = 0; double defaultDuration;
double defaultTarget = 0; double defaultTarget = 0;
if (profile != null) { if (profile != null) {
defaultTarget = bg.doubleValue(); defaultTarget = bg;
} }
boolean erase = false; boolean erase = false;
if (MainApp.sResources.getString(R.string.eatingsoon).equals(reasonList.get(position))) { String units = MainApp.getConfigBuilder().getProfileUnits();
defaultDuration = SP.getDouble(R.string.key_eatingsoon_duration, 0d); DefaultValueHelper helper = new DefaultValueHelper();
defaultTarget = SP.getDouble(R.string.key_eatingsoon_target, 0d); if (MainApp.gs(R.string.eatingsoon).equals(reasonList.get(position))) {
; defaultDuration = helper.determineEatingSoonTTDuration();
} else if (MainApp.sResources.getString(R.string.activity).equals(reasonList.get(position))) { defaultTarget = helper.determineEatingSoonTT(units);
defaultDuration = SP.getDouble(R.string.key_activity_duration, 0d); } else if (MainApp.gs(R.string.activity).equals(reasonList.get(position))) {
; defaultDuration = helper.determineActivityTTDuration();
defaultTarget = SP.getDouble(R.string.key_activity_target, 0d); defaultTarget = helper.determineActivityTT(units);
; } else if (MainApp.gs(R.string.hypo).equals(reasonList.get(position))) {
defaultDuration = helper.determineHypoTTDuration();
defaultTarget = helper.determineHypoTT(units);
} else { } else {
defaultDuration = 0; defaultDuration = 0;
erase = true; erase = true;
} }
if (defaultTarget != 0 || erase) { if (defaultTarget != 0 || erase) {
editTemptarget.setValue(defaultTarget); editTemptarget.setValue(defaultTarget);
} }
@ -256,19 +271,16 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick
editBg.setParams(bg, 0d, 500d, 1d, new DecimalFormat("0"), false, bgTextWatcher); editBg.setParams(bg, 0d, 500d, 1d, new DecimalFormat("0"), false, bgTextWatcher);
editTemptarget.setParams(bg, 0d, 500d, 1d, new DecimalFormat("0"), false); editTemptarget.setParams(bg, 0d, 500d, 1d, new DecimalFormat("0"), false);
} }
sensorRadioButton.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { sensorRadioButton.setOnCheckedChangeListener((buttonView, isChecked) -> {
@Override Double bg1 = Profile.fromMgdlToUnits(GlucoseStatus.getGlucoseStatusData() != null ? GlucoseStatus.getGlucoseStatusData().glucose : 0d, profile.getUnits());
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { editBg.setValue(bg1);
Double bg = Profile.fromMgdlToUnits(GlucoseStatus.getGlucoseStatusData() != null ? GlucoseStatus.getGlucoseStatusData().glucose : 0d, profile.getUnits());
editBg.setValue(bg);
}
}); });
Integer maxCarbs = MainApp.getConfigBuilder().applyCarbsConstraints(Constants.carbsOnlyForCheckLimit); Integer maxCarbs = MainApp.getConstraintChecker().getMaxCarbsAllowed().value();
editCarbs = (NumberPicker) view.findViewById(R.id.careportal_newnstreatment_carbsinput); editCarbs = (NumberPicker) view.findViewById(R.id.careportal_newnstreatment_carbsinput);
editCarbs.setParams(0d, 0d, (double) maxCarbs, 1d, new DecimalFormat("0"), false); editCarbs.setParams(0d, 0d, (double) maxCarbs, 1d, new DecimalFormat("0"), false);
Double maxInsulin = MainApp.getConfigBuilder().applyBolusConstraints(Constants.bolusOnlyForCheckLimit); Double maxInsulin = MainApp.getConstraintChecker().getMaxBolusAllowed().value();
editInsulin = (NumberPicker) view.findViewById(R.id.careportal_newnstreatment_insulininput); editInsulin = (NumberPicker) view.findViewById(R.id.careportal_newnstreatment_insulininput);
editInsulin.setParams(0d, 0d, maxInsulin, 0.05d, new DecimalFormat("0.00"), false); editInsulin.setParams(0d, 0d, maxInsulin, 0.05d, new DecimalFormat("0.00"), false);
@ -295,7 +307,9 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick
} }
}; };
Integer maxPercent = MainApp.getConfigBuilder().applyBasalConstraints(Constants.basalPercentOnlyForCheckLimit); Integer maxPercent = 200;
if (profile != null)
maxPercent = MainApp.getConstraintChecker().getMaxBasalPercentAllowed(profile).value();
editPercent = (NumberPicker) view.findViewById(R.id.careportal_newnstreatment_percentinput); editPercent = (NumberPicker) view.findViewById(R.id.careportal_newnstreatment_percentinput);
editPercent.setParams(0d, 0d, (double) maxPercent, 5d, new DecimalFormat("0"), true, percentTextWatcher); editPercent.setParams(0d, 0d, (double) maxPercent, 5d, new DecimalFormat("0"), true, percentTextWatcher);
@ -317,7 +331,9 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick
} }
}; };
Double maxAbsolute = MainApp.getConfigBuilder().applyBasalConstraints(Constants.basalAbsoluteOnlyForCheckLimit); Double maxAbsolute = HardLimits.maxBasal();
if (profile != null)
maxAbsolute = MainApp.getConstraintChecker().getMaxBasalAllowed(profile).value();
editAbsolute = (NumberPicker) view.findViewById(R.id.careportal_newnstreatment_absoluteinput); editAbsolute = (NumberPicker) view.findViewById(R.id.careportal_newnstreatment_absoluteinput);
editAbsolute.setParams(0d, 0d, maxAbsolute, 0.05d, new DecimalFormat("0.00"), true, absoluteTextWatcher); editAbsolute.setParams(0d, 0d, maxAbsolute, 0.05d, new DecimalFormat("0.00"), true, absoluteTextWatcher);
@ -330,19 +346,19 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick
editTimeshift = (NumberPicker) view.findViewById(R.id.careportal_newnstreatment_timeshift); editTimeshift = (NumberPicker) view.findViewById(R.id.careportal_newnstreatment_timeshift);
editTimeshift.setParams(0d, (double) Constants.CPP_MIN_TIMESHIFT, (double) Constants.CPP_MAX_TIMESHIFT, 1d, new DecimalFormat("0"), false); editTimeshift.setParams(0d, (double) Constants.CPP_MIN_TIMESHIFT, (double) Constants.CPP_MAX_TIMESHIFT, 1d, new DecimalFormat("0"), false);
ProfileSwitch ps = MainApp.getConfigBuilder().getProfileSwitchFromHistory(System.currentTimeMillis()); ProfileSwitch ps = TreatmentsPlugin.getPlugin().getProfileSwitchFromHistory(DateUtil.now());
if (ps != null && ps.isCPP) { if (ps != null && ps.isCPP) {
final int percentage = ps.percentage; final int percentage = ps.percentage;
final int timeshift = ps.timeshift; final int timeshift = ps.timeshift;
reuseButton.setText(reuseButton.getText() + " " + percentage + "% " + timeshift + "h"); reuseButton.setText(reuseButton.getText() + " " + percentage + "% " + timeshift + "h");
reuseButton.setOnClickListener(new View.OnClickListener() { reuseButton.setOnClickListener(v -> {
@Override editPercentage.setValue((double) percentage);
public void onClick(View v) { editTimeshift.setValue((double) timeshift);
editPercentage.setValue((double) percentage);
editTimeshift.setValue((double) timeshift);
}
}); });
} }
if (ps == null) {
options.duration = false;
}
showOrHide((ViewGroup) view.findViewById(R.id.careportal_newnstreatment_eventtime_layout), options.date); showOrHide((ViewGroup) view.findViewById(R.id.careportal_newnstreatment_eventtime_layout), options.date);
showOrHide((ViewGroup) view.findViewById(R.id.careportal_newnstreatment_bg_layout), options.bg); showOrHide((ViewGroup) view.findViewById(R.id.careportal_newnstreatment_bg_layout), options.bg);
@ -360,6 +376,8 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick
showOrHide((ViewGroup) view.findViewById(R.id.careportal_newnstreatment_reuse_layout), options.profile && ps != null && ps.isCPP); showOrHide((ViewGroup) view.findViewById(R.id.careportal_newnstreatment_reuse_layout), options.profile && ps != null && ps.isCPP);
showOrHide((ViewGroup) view.findViewById(R.id.careportal_newnstreatment_temptarget_layout), options.tempTarget); showOrHide((ViewGroup) view.findViewById(R.id.careportal_newnstreatment_temptarget_layout), options.tempTarget);
setCancelable(true);
getDialog().setCanceledOnTouchOutside(false);
return view; return view;
} }
@ -391,7 +409,7 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick
tpd.show(context.getFragmentManager(), "Timepickerdialog"); tpd.show(context.getFragmentManager(), "Timepickerdialog");
break; break;
case R.id.ok: case R.id.ok:
createNSTreatment(); confirmNSTreatmentCreation();
dismiss(); dismiss();
break; break;
case R.id.cancel: case R.id.cancel:
@ -405,20 +423,32 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick
else layout.setVisibility(View.GONE); else layout.setVisibility(View.GONE);
} }
private void updateBGforDateTime() {
long millis = eventTime.getTime() - (150 * 1000L); // 2,5 * 60 * 1000
List<BgReading> data = MainApp.getDbHelper().getBgreadingsDataFromTime(millis, true);
if ((data.size() > 0) &&
(data.get(0).date > millis - 7 * 60 * 1000L) &&
(data.get(0).date < millis + 7 * 60 * 1000L)) {
editBg.setValue(Profile.fromMgdlToUnits(data.get(0).value, profile != null ? profile.getUnits() : Constants.MGDL));
}
}
@Override @Override
public void onDateSet(DatePickerDialog view, int year, int monthOfYear, int dayOfMonth) { public void onDateSet(DatePickerDialog view, int year, int monthOfYear, int dayOfMonth) {
eventTime.setYear(year - 1900); eventTime.setYear(year - 1900);
eventTime.setMonth(monthOfYear); eventTime.setMonth(monthOfYear);
eventTime.setDate(dayOfMonth); eventTime.setDate(dayOfMonth);
dateButton.setText(DateUtil.dateString(eventTime)); dateButton.setText(DateUtil.dateString(eventTime));
updateBGforDateTime();
} }
@Override @Override
public void onTimeSet(RadialPickerLayout view, int hourOfDay, int minute, int second) { public void onTimeSet(RadialPickerLayout view, int hourOfDay, int minute, int second) {
eventTime.setHours(hourOfDay); eventTime.setHours(hourOfDay);
eventTime.setMinutes(minute); eventTime.setMinutes(minute);
eventTime.setSeconds(second); eventTime.setSeconds(this.seconds++); // randomize seconds to prevent creating record of the same time, if user choose time manually
timeButton.setText(DateUtil.timeString(eventTime)); timeButton.setText(DateUtil.timeString(eventTime));
updateBGforDateTime();
} }
@ -532,7 +562,7 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick
if (options.eventType == R.id.careportal_combobolus) { if (options.eventType == R.id.careportal_combobolus) {
Double enteredInsulin = SafeParse.stringToDouble(editInsulin.getText()); Double enteredInsulin = SafeParse.stringToDouble(editInsulin.getText());
data.put("enteredinsulin", enteredInsulin); data.put("enteredinsulin", enteredInsulin);
data.put("insulin", enteredInsulin * SafeParse.stringToDouble(editInsulin.getText()) / 100); data.put("insulin", enteredInsulin * SafeParse.stringToDouble(editSplit.getText()) / 100);
data.put("relative", enteredInsulin * (100 - SafeParse.stringToDouble(editSplit.getText())) / 100 / SafeParse.stringToDouble(editDuration.getText()) * 60); data.put("relative", enteredInsulin * (100 - SafeParse.stringToDouble(editSplit.getText())) / 100 / SafeParse.stringToDouble(editDuration.getText()) * 60);
} }
} catch (JSONException e) { } catch (JSONException e) {
@ -543,221 +573,200 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick
String buildConfirmText(JSONObject data) { String buildConfirmText(JSONObject data) {
String ret = ""; String ret = "";
try { if (data.has("eventType")) {
if (data.has("eventType")) { ret += MainApp.gs(R.string.careportal_newnstreatment_eventtype);
ret += getString(R.string.careportal_newnstreatment_eventtype); ret += ": ";
ret += ": "; ret += Translator.translate(JsonHelper.safeGetString(data, "eventType", ""));
ret += Translator.translate(data.getString("eventType")); ret += "\n";
ret += "\n"; }
} if (data.has("glucose")) {
if (data.has("glucose")) { ret += MainApp.gs(R.string.treatments_wizard_bg_label);
ret += getString(R.string.treatments_wizard_bg_label); ret += ": ";
ret += ": "; ret += JsonHelper.safeGetObject(data, "glucose", "");
ret += data.get("glucose"); ret += " " + units + "\n";
ret += " " + units + "\n"; }
} if (data.has("glucoseType")) {
if (data.has("glucoseType")) { ret += MainApp.gs(R.string.careportal_newnstreatment_glucosetype);
ret += getString(R.string.careportal_newnstreatment_glucosetype); ret += ": ";
ret += ": "; ret += Translator.translate(JsonHelper.safeGetString(data, "glucoseType", ""));
ret += Translator.translate(data.getString("glucoseType")); ret += "\n";
ret += "\n"; }
} if (data.has("carbs")) {
if (data.has("carbs")) { ret += MainApp.gs(R.string.careportal_newnstreatment_carbs_label);
ret += getString(R.string.careportal_newnstreatment_carbs_label); ret += ": ";
ret += ": "; ret += JsonHelper.safeGetObject(data, "carbs", "");
ret += data.get("carbs"); ret += " g\n";
ret += " g\n"; }
} if (data.has("insulin")) {
if (data.has("insulin")) { ret += MainApp.gs(R.string.careportal_newnstreatment_insulin_label);
ret += getString(R.string.careportal_newnstreatment_insulin_label); ret += ": ";
ret += ": "; ret += JsonHelper.safeGetObject(data, "insulin", "");
ret += data.get("insulin"); ret += " U\n";
ret += " U\n"; }
} if (data.has("duration")) {
if (data.has("duration")) { ret += MainApp.gs(R.string.careportal_newnstreatment_duration_label);
ret += getString(R.string.careportal_newnstreatment_duration_label); ret += ": ";
ret += ": "; ret += JsonHelper.safeGetObject(data, "duration", "");
ret += data.get("duration"); ret += " min\n";
ret += " min\n"; }
} if (data.has("percent")) {
if (data.has("percent")) { ret += MainApp.gs(R.string.careportal_newnstreatment_percent_label);
ret += getString(R.string.careportal_newnstreatment_percent_label); ret += ": ";
ret += ": "; ret += JsonHelper.safeGetObject(data, "percent", "");
ret += data.get("percent"); ret += " %\n";
ret += " %\n"; }
} if (data.has("absolute")) {
if (data.has("absolute")) { ret += MainApp.gs(R.string.careportal_newnstreatment_absolute_label);
ret += getString(R.string.careportal_newnstreatment_absolute_label); ret += ": ";
ret += ": "; ret += JsonHelper.safeGetObject(data, "absolute", "");
ret += data.get("absolute"); ret += " U/h\n";
ret += " U/h\n"; }
} if (data.has("preBolus")) {
if (data.has("preBolus")) { ret += MainApp.gs(R.string.careportal_newnstreatment_carbtime_label);
ret += getString(R.string.careportal_newnstreatment_carbtime_label); ret += ": ";
ret += ": "; ret += JsonHelper.safeGetObject(data, "preBolus", "");
ret += data.get("preBolus"); ret += " min\n";
ret += " min\n"; }
} if (data.has("notes")) {
if (data.has("notes")) { ret += MainApp.gs(R.string.careportal_newnstreatment_notes_label);
ret += getString(R.string.careportal_newnstreatment_notes_label); ret += ": ";
ret += ": "; ret += JsonHelper.safeGetObject(data, "notes", "");
ret += data.get("notes"); ret += "\n";
ret += "\n"; }
} if (data.has("profile")) {
if (data.has("profile")) { ret += MainApp.gs(R.string.careportal_newnstreatment_profile_label);
ret += getString(R.string.careportal_newnstreatment_profile_label); ret += ": ";
ret += ": "; ret += JsonHelper.safeGetObject(data, "profile", "");
ret += data.get("profile"); ret += "\n";
ret += "\n"; }
} if (data.has("percentage")) {
if (data.has("percentage")) { ret += MainApp.gs(R.string.careportal_newnstreatment_percentage_label);
ret += getString(R.string.careportal_newnstreatment_percentage_label); ret += ": ";
ret += ": "; ret += JsonHelper.safeGetObject(data, "percentage", "");
ret += data.get("percentage"); ret += " %\n";
ret += " %\n"; }
} if (data.has("timeshift")) {
if (data.has("timeshift")) { ret += MainApp.gs(R.string.careportal_newnstreatment_timeshift_label);
ret += getString(R.string.careportal_newnstreatment_timeshift_label); ret += ": ";
ret += ": "; ret += JsonHelper.safeGetObject(data, "timeshift", "");
ret += data.get("timeshift"); ret += " h\n";
ret += " h\n"; }
} if (data.has("targetBottom") && data.has("targetTop")) {
if (data.has("targetBottom") && data.has("targetTop")) { ret += MainApp.gs(R.string.target_range);
ret += getString(R.string.target_range); ret += " ";
ret += " "; ret += JsonHelper.safeGetObject(data, "targetBottom", "");
ret += data.get("targetBottom"); ret += " - ";
ret += " - "; ret += JsonHelper.safeGetObject(data, "targetTop", "");
ret += data.get("targetTop"); ret += "\n";
ret += "\n"; }
} if (data.has("created_at")) {
if (data.has("created_at")) { ret += MainApp.gs(R.string.careportal_newnstreatment_eventtime_label);
ret += getString(R.string.careportal_newnstreatment_eventtime_label); ret += ": ";
ret += ": "; ret += eventTime.toLocaleString();
ret += eventTime.toLocaleString(); ret += "\n";
ret += "\n"; }
} if (data.has("enteredBy")) {
if (data.has("enteredBy")) { ret += MainApp.gs(R.string.careportal_newnstreatment_enteredby_title);
ret += getString(R.string.careportal_newnstreatment_enteredby_title); ret += ": ";
ret += ": "; ret += JsonHelper.safeGetObject(data, "enteredBy", "");
ret += data.get("enteredBy"); ret += "\n";
ret += "\n";
}
} catch (JSONException e) {
log.error("Unhandled exception", e);
} }
return ret; return ret;
} }
void createNSTreatment() { void confirmNSTreatmentCreation() {
final JSONObject data = gatherData(); if (context != null) {
String confirmText = buildConfirmText(data); final JSONObject data = gatherData();
AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); final String confirmText = buildConfirmText(data);
builder.setTitle(getContext().getString(R.string.confirmation)); AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setMessage(confirmText); builder.setTitle(MainApp.gs(R.string.confirmation));
builder.setPositiveButton(getContext().getString(R.string.ok), new DialogInterface.OnClickListener() { builder.setMessage(confirmText);
public void onClick(DialogInterface dialog, int id) { builder.setPositiveButton(MainApp.gs(R.string.ok), (dialog, id) -> createNSTreatment(data));
if (options.executeProfileSwitch) { builder.setNegativeButton(MainApp.gs(R.string.cancel), null);
if (data.has("profile")) { builder.show();
try { }
doProfileSwitch(profileStore, data.getString("profile"), data.getInt("duration"), data.getInt("percentage"), data.getInt("timeshift"));
} catch (JSONException e) {
log.error("Unhandled exception", e);
}
}
} else if (options.executeTempTarget) {
try {
if ((data.has("targetBottom") && data.has("targetTop")) || (data.has("duration") && data.getInt("duration") == 0)) {
TempTarget tempTarget = new TempTarget();
tempTarget.date = eventTime.getTime();
tempTarget.durationInMinutes = data.getInt("duration");
tempTarget.reason = data.getString("reason");
tempTarget.source = Source.USER;
if (tempTarget.durationInMinutes != 0) {
tempTarget.low = Profile.toMgdl(data.getDouble("targetBottom"), profile.getUnits());
tempTarget.high = Profile.toMgdl(data.getDouble("targetTop"), profile.getUnits());
} else {
tempTarget.low = 0;
tempTarget.high = 0;
}
log.debug("Creating new TempTarget db record: " + tempTarget.toString());
MainApp.getDbHelper().createOrUpdate(tempTarget);
NSUpload.uploadCareportalEntryToNS(data);
Answers.getInstance().logCustom(new CustomEvent("TempTarget"));
}
} catch (JSONException e) {
log.error("Unhandled exception", e);
}
} else {
NSUpload.uploadCareportalEntryToNS(data);
Answers.getInstance().logCustom(new CustomEvent("NSTreatment"));
}
}
});
builder.setNegativeButton(getContext().getString(R.string.cancel), null);
builder.show();
} }
public static void doProfileSwitch(final ProfileStore profileStore, final String profileName, final int duration, final int percentage, final int timeshift) {
public void createNSTreatment(JSONObject data) {
if (options.executeProfileSwitch) {
if (data.has("profile")) {
doProfileSwitch(profileStore, JsonHelper.safeGetString(data, "profile"), JsonHelper.safeGetInt(data, "duration"), JsonHelper.safeGetInt(data, "percentage"), JsonHelper.safeGetInt(data, "timeshift"));
}
} else if (options.executeTempTarget) {
final int duration = JsonHelper.safeGetInt(data, "duration");
final double targetBottom = JsonHelper.safeGetDouble(data, "targetBottom");
final double targetTop = JsonHelper.safeGetDouble(data, "targetTop");
final String reason = JsonHelper.safeGetString(data, "reason", "");
if ((targetBottom != 0d && targetTop != 0d) || duration == 0) {
TempTarget tempTarget = new TempTarget()
.date(eventTime.getTime())
.duration(duration)
.reason(reason)
.source(Source.USER);
if (tempTarget.durationInMinutes != 0) {
tempTarget.low(Profile.toMgdl(targetBottom, profile.getUnits()))
.high(Profile.toMgdl(targetTop, profile.getUnits()));
} else {
tempTarget.low(0).high(0);
}
TreatmentsPlugin.getPlugin().addToHistoryTempTarget(tempTarget);
FabricPrivacy.getInstance().logCustom(new CustomEvent("TempTarget"));
}
} else {
if (JsonHelper.safeGetString(data, "eventType").equals(CareportalEvent.PROFILESWITCH)) {
ProfileSwitch profileSwitch = prepareProfileSwitch(
profileStore,
JsonHelper.safeGetString(data, "profile"),
JsonHelper.safeGetInt(data, "duration"),
JsonHelper.safeGetInt(data, "percentage"),
JsonHelper.safeGetInt(data, "timeshift"),
eventTime.getTime()
);
NSUpload.uploadProfileSwitch(profileSwitch);
} else {
NSUpload.uploadCareportalEntryToNS(data);
}
FabricPrivacy.getInstance().logCustom(new CustomEvent("NSTreatment"));
}
}
public static ProfileSwitch prepareProfileSwitch(final ProfileStore profileStore, final String profileName, final int duration, final int percentage, final int timeshift, long date) {
ProfileSwitch profileSwitch = new ProfileSwitch(); ProfileSwitch profileSwitch = new ProfileSwitch();
profileSwitch.date = System.currentTimeMillis(); profileSwitch.date = date;
profileSwitch.source = Source.USER; profileSwitch.source = Source.USER;
profileSwitch.profileName = profileName; profileSwitch.profileName = profileName;
profileSwitch.profileJson = profileStore.getSpecificProfile(profileName).getData().toString(); profileSwitch.profileJson = profileStore.getSpecificProfile(profileName).getData().toString();
profileSwitch.profilePlugin = ConfigBuilderPlugin.getActiveProfileInterface().getClass().getName(); profileSwitch.profilePlugin = MainApp.getConfigBuilder().getActiveProfileInterface().getClass().getName();
profileSwitch.durationInMinutes = duration; profileSwitch.durationInMinutes = duration;
profileSwitch.isCPP = percentage != 100 || timeshift != 0; profileSwitch.isCPP = percentage != 100 || timeshift != 0;
profileSwitch.timeshift = timeshift; profileSwitch.timeshift = timeshift;
profileSwitch.percentage = percentage; profileSwitch.percentage = percentage;
MainApp.getConfigBuilder().addToHistoryProfileSwitch(profileSwitch); return profileSwitch;
}
ConfigBuilderPlugin.getCommandQueue().setProfile(profileSwitch.getProfileObject(), new Callback() { public static void doProfileSwitch(final ProfileStore profileStore, final String profileName, final int duration, final int percentage, final int timeshift) {
@Override ProfileSwitch profileSwitch = prepareProfileSwitch(profileStore, profileName, duration, percentage, timeshift, System.currentTimeMillis());
public void run() { TreatmentsPlugin.getPlugin().addToHistoryProfileSwitch(profileSwitch);
if (!result.success) { FabricPrivacy.getInstance().logCustom(new CustomEvent("ProfileSwitch"));
Intent i = new Intent(MainApp.instance(), ErrorHelperActivity.class);
i.putExtra("soundid", R.raw.boluserror);
i.putExtra("status", result.comment);
i.putExtra("title", MainApp.sResources.getString(R.string.failedupdatebasalprofile));
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
MainApp.instance().startActivity(i);
}
MainApp.bus().post(new EventNewBasalProfile());
}
});
Answers.getInstance().logCustom(new CustomEvent("ProfileSwitch"));
} }
public static void doProfileSwitch(final int duration, final int percentage, final int timeshift) { public static void doProfileSwitch(final int duration, final int percentage, final int timeshift) {
ProfileSwitch profileSwitch = MainApp.getConfigBuilder().getProfileSwitchFromHistory(System.currentTimeMillis()); ProfileSwitch profileSwitch = TreatmentsPlugin.getPlugin().getProfileSwitchFromHistory(System.currentTimeMillis());
if (profileSwitch != null) { if (profileSwitch != null) {
profileSwitch = new ProfileSwitch(); profileSwitch = new ProfileSwitch();
profileSwitch.date = System.currentTimeMillis(); profileSwitch.date = System.currentTimeMillis();
profileSwitch.source = Source.USER; profileSwitch.source = Source.USER;
profileSwitch.profileName = MainApp.getConfigBuilder().getProfileName(System.currentTimeMillis(), false); profileSwitch.profileName = MainApp.getConfigBuilder().getProfileName(System.currentTimeMillis(), false);
profileSwitch.profileJson = MainApp.getConfigBuilder().getProfile().getData().toString(); profileSwitch.profileJson = MainApp.getConfigBuilder().getProfile().getData().toString();
profileSwitch.profilePlugin = ConfigBuilderPlugin.getActiveProfileInterface().getClass().getName(); profileSwitch.profilePlugin = MainApp.getConfigBuilder().getActiveProfileInterface().getClass().getName();
profileSwitch.durationInMinutes = duration; profileSwitch.durationInMinutes = duration;
profileSwitch.isCPP = percentage != 100 || timeshift != 0; profileSwitch.isCPP = percentage != 100 || timeshift != 0;
profileSwitch.timeshift = timeshift; profileSwitch.timeshift = timeshift;
profileSwitch.percentage = percentage; profileSwitch.percentage = percentage;
MainApp.getConfigBuilder().addToHistoryProfileSwitch(profileSwitch); TreatmentsPlugin.getPlugin().addToHistoryProfileSwitch(profileSwitch);
FabricPrivacy.getInstance().logCustom(new CustomEvent("ProfileSwitch"));
ConfigBuilderPlugin.getCommandQueue().setProfile(profileSwitch.getProfileObject(), 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.sResources.getString(R.string.failedupdatebasalprofile));
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
MainApp.instance().startActivity(i);
}
MainApp.bus().post(new EventNewBasalProfile());
}
});
Answers.getInstance().logCustom(new CustomEvent("ProfileSwitch"));
} else { } else {
log.error("No profile switch existing"); log.error("No profile switch existing");
} }

View file

@ -2,9 +2,12 @@ package info.nightscout.androidaps.plugins.Common;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
import butterknife.Unbinder;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
abstract public class SubscriberFragment extends Fragment { abstract public class SubscriberFragment extends Fragment {
protected Unbinder unbinder;
@Override @Override
public void onPause() { public void onPause() {
super.onPause(); super.onPause();
@ -18,5 +21,12 @@ abstract public class SubscriberFragment extends Fragment {
updateGUI(); updateGUI();
} }
@Override public void onDestroyView() {
super.onDestroyView();
if (unbinder != null)
unbinder.unbind();
}
protected abstract void updateGUI(); protected abstract void updateGUI();
} }

View file

@ -4,7 +4,7 @@ package info.nightscout.androidaps.plugins.ConfigBuilder;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.app.Fragment; import android.support.annotation.NonNull;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
@ -17,12 +17,14 @@ import android.widget.ListAdapter;
import android.widget.ListView; import android.widget.ListView;
import android.widget.TextView; import android.widget.TextView;
import com.crashlytics.android.Crashlytics;
import com.crashlytics.android.answers.Answers;
import com.crashlytics.android.answers.CustomEvent; import com.crashlytics.android.answers.CustomEvent;
import java.util.ArrayList; import java.util.ArrayList;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.PreferencesActivity; import info.nightscout.androidaps.PreferencesActivity;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
@ -33,43 +35,59 @@ import info.nightscout.androidaps.interfaces.BgSourceInterface;
import info.nightscout.androidaps.interfaces.ConstraintsInterface; import info.nightscout.androidaps.interfaces.ConstraintsInterface;
import info.nightscout.androidaps.interfaces.InsulinInterface; import info.nightscout.androidaps.interfaces.InsulinInterface;
import info.nightscout.androidaps.interfaces.PluginBase; import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.PluginType;
import info.nightscout.androidaps.interfaces.ProfileInterface; import info.nightscout.androidaps.interfaces.ProfileInterface;
import info.nightscout.androidaps.interfaces.PumpInterface; import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.interfaces.SensitivityInterface; import info.nightscout.androidaps.interfaces.SensitivityInterface;
import info.nightscout.androidaps.plugins.Insulin.InsulinFastactingPlugin; import info.nightscout.androidaps.plugins.Common.SubscriberFragment;
import info.nightscout.androidaps.plugins.Insulin.InsulinOrefRapidActingPlugin;
import info.nightscout.androidaps.plugins.ProfileNS.NSProfilePlugin; import info.nightscout.androidaps.plugins.ProfileNS.NSProfilePlugin;
import info.nightscout.androidaps.plugins.PumpVirtual.VirtualPumpPlugin; import info.nightscout.androidaps.plugins.PumpVirtual.VirtualPumpPlugin;
import info.nightscout.androidaps.plugins.SensitivityOref0.SensitivityOref0Plugin; import info.nightscout.androidaps.plugins.SensitivityOref0.SensitivityOref0Plugin;
import info.nightscout.utils.FabricPrivacy;
import info.nightscout.utils.PasswordProtection; import info.nightscout.utils.PasswordProtection;
public class ConfigBuilderFragment extends Fragment { public class ConfigBuilderFragment extends SubscriberFragment {
static ConfigBuilderPlugin configBuilderPlugin = new ConfigBuilderPlugin();
static public ConfigBuilderPlugin getPlugin() {
return configBuilderPlugin;
}
@BindView(R.id.configbuilder_insulinlistview)
ListView insulinListView; ListView insulinListView;
@BindView(R.id.configbuilder_sensitivitylistview)
ListView sensitivityListView; ListView sensitivityListView;
@BindView(R.id.configbuilder_bgsourcelistview)
ListView bgsourceListView; ListView bgsourceListView;
@BindView(R.id.configbuilder_bgsourcelabel)
TextView bgsourceLabel; TextView bgsourceLabel;
@BindView(R.id.configbuilder_pumplistview)
ListView pumpListView; ListView pumpListView;
@BindView(R.id.configbuilder_pumplabel)
TextView pumpLabel; TextView pumpLabel;
@BindView(R.id.configbuilder_looplistview)
ListView loopListView; ListView loopListView;
@BindView(R.id.configbuilder_looplabel)
TextView loopLabel; TextView loopLabel;
@BindView(R.id.configbuilder_treatmentslistview)
ListView treatmentsListView; ListView treatmentsListView;
@BindView(R.id.configbuilder_treatmentslabel)
TextView treatmentsLabel; TextView treatmentsLabel;
@BindView(R.id.configbuilder_profilelistview)
ListView profileListView; ListView profileListView;
@BindView(R.id.configbuilder_profilelabel)
TextView profileLabel; TextView profileLabel;
@BindView(R.id.configbuilder_apslistview)
ListView apsListView; ListView apsListView;
@BindView(R.id.configbuilder_apslabel)
TextView apsLabel; TextView apsLabel;
@BindView(R.id.configbuilder_constraintslistview)
ListView constraintsListView; ListView constraintsListView;
@BindView(R.id.configbuilder_constraintslabel)
TextView constraintsLabel; TextView constraintsLabel;
@BindView(R.id.configbuilder_generallistview)
ListView generalListView; ListView generalListView;
@BindView(R.id.configbuilder_mainlayout)
LinearLayout mainLayout; LinearLayout mainLayout;
@BindView(R.id.configbuilder_unlock)
Button unlock; Button unlock;
PluginCustomAdapter insulinDataAdapter = null; PluginCustomAdapter insulinDataAdapter = null;
@ -84,105 +102,83 @@ public class ConfigBuilderFragment extends Fragment {
PluginCustomAdapter generalDataAdapter = null; PluginCustomAdapter generalDataAdapter = null;
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) { Bundle savedInstanceState) {
try { try {
View view = inflater.inflate(R.layout.configbuilder_fragment, container, false); View view = inflater.inflate(R.layout.configbuilder_fragment, container, false);
insulinListView = (ListView) view.findViewById(R.id.configbuilder_insulinlistview); unbinder = ButterKnife.bind(this, view);
sensitivityListView = (ListView) view.findViewById(R.id.configbuilder_sensitivitylistview);
bgsourceListView = (ListView) view.findViewById(R.id.configbuilder_bgsourcelistview);
bgsourceLabel = (TextView) view.findViewById(R.id.configbuilder_bgsourcelabel);
pumpListView = (ListView) view.findViewById(R.id.configbuilder_pumplistview);
pumpLabel = (TextView) view.findViewById(R.id.configbuilder_pumplabel);
loopListView = (ListView) view.findViewById(R.id.configbuilder_looplistview);
loopLabel = (TextView) view.findViewById(R.id.configbuilder_looplabel);
treatmentsListView = (ListView) view.findViewById(R.id.configbuilder_treatmentslistview);
treatmentsLabel = (TextView) view.findViewById(R.id.configbuilder_treatmentslabel);
profileListView = (ListView) view.findViewById(R.id.configbuilder_profilelistview);
profileLabel = (TextView) view.findViewById(R.id.configbuilder_profilelabel);
apsListView = (ListView) view.findViewById(R.id.configbuilder_apslistview);
apsLabel = (TextView) view.findViewById(R.id.configbuilder_apslabel);
constraintsListView = (ListView) view.findViewById(R.id.configbuilder_constraintslistview);
constraintsLabel = (TextView) view.findViewById(R.id.configbuilder_constraintslabel);
generalListView = (ListView) view.findViewById(R.id.configbuilder_generallistview);
mainLayout = (LinearLayout) view.findViewById(R.id.configbuilder_mainlayout); if (PasswordProtection.isLocked("settings_password"))
unlock = (Button) view.findViewById(R.id.configbuilder_unlock);
setViews();
if (PasswordProtection.isLocked("settings_password")) {
mainLayout.setVisibility(View.GONE); mainLayout.setVisibility(View.GONE);
unlock.setOnClickListener(new View.OnClickListener() { else
@Override
public void onClick(View v) {
PasswordProtection.QueryPassword(getContext(), R.string.settings_password, "settings_password", new Runnable() {
@Override
public void run() {
mainLayout.setVisibility(View.VISIBLE);
unlock.setVisibility(View.GONE);
}
}, null);
}
});
} else {
unlock.setVisibility(View.GONE); unlock.setVisibility(View.GONE);
}
return view; return view;
} catch (Exception e) { } catch (Exception e) {
Crashlytics.logException(e); FabricPrivacy.logException(e);
} }
return null; return null;
} }
void setViews() { @OnClick(R.id.configbuilder_unlock)
insulinDataAdapter = new PluginCustomAdapter(getContext(), R.layout.configbuilder_simpleitem, MainApp.getSpecificPluginsVisibleInListByInterface(InsulinInterface.class, PluginBase.INSULIN), PluginBase.INSULIN); public void onClickUnlock() {
PasswordProtection.QueryPassword(getContext(), R.string.settings_password, "settings_password", () -> {
mainLayout.setVisibility(View.VISIBLE);
unlock.setVisibility(View.GONE);
}, null);
}
@Override
protected void updateGUI() {
insulinDataAdapter = new PluginCustomAdapter(getContext(), R.layout.configbuilder_simpleitem, MainApp.getSpecificPluginsVisibleInListByInterface(InsulinInterface.class, PluginType.INSULIN), PluginType.INSULIN);
insulinListView.setAdapter(insulinDataAdapter); insulinListView.setAdapter(insulinDataAdapter);
setListViewHeightBasedOnChildren(insulinListView); setListViewHeightBasedOnChildren(insulinListView);
bgsourceDataAdapter = new PluginCustomAdapter(getContext(), R.layout.configbuilder_simpleitem, MainApp.getSpecificPluginsVisibleInListByInterface(BgSourceInterface.class, PluginBase.BGSOURCE), PluginBase.BGSOURCE); bgsourceDataAdapter = new PluginCustomAdapter(getContext(), R.layout.configbuilder_simpleitem, MainApp.getSpecificPluginsVisibleInListByInterface(BgSourceInterface.class, PluginType.BGSOURCE), PluginType.BGSOURCE);
bgsourceListView.setAdapter(bgsourceDataAdapter); bgsourceListView.setAdapter(bgsourceDataAdapter);
if (MainApp.getSpecificPluginsVisibleInList(PluginBase.BGSOURCE).size() == 0) if (MainApp.getSpecificPluginsVisibleInList(PluginType.BGSOURCE).size() == 0)
bgsourceLabel.setVisibility(View.GONE); bgsourceLabel.setVisibility(View.GONE);
setListViewHeightBasedOnChildren(bgsourceListView); setListViewHeightBasedOnChildren(bgsourceListView);
pumpDataAdapter = new PluginCustomAdapter(getContext(), R.layout.configbuilder_simpleitem, MainApp.getSpecificPluginsVisibleInList(PluginBase.PUMP), PluginBase.PUMP); pumpDataAdapter = new PluginCustomAdapter(getContext(), R.layout.configbuilder_simpleitem, MainApp.getSpecificPluginsVisibleInList(PluginType.PUMP), PluginType.PUMP);
pumpListView.setAdapter(pumpDataAdapter); pumpListView.setAdapter(pumpDataAdapter);
if (MainApp.getSpecificPluginsVisibleInList(PluginBase.PUMP).size() == 0) if (MainApp.getSpecificPluginsVisibleInList(PluginType.PUMP).size() == 0 || Config.NSCLIENT || Config.G5UPLOADER) {
pumpLabel.setVisibility(View.GONE); pumpLabel.setVisibility(View.GONE);
pumpListView.setVisibility(View.GONE);
}
setListViewHeightBasedOnChildren(pumpListView); setListViewHeightBasedOnChildren(pumpListView);
loopDataAdapter = new PluginCustomAdapter(getContext(), R.layout.configbuilder_simpleitem, MainApp.getSpecificPluginsVisibleInList(PluginBase.LOOP), PluginBase.LOOP); loopDataAdapter = new PluginCustomAdapter(getContext(), R.layout.configbuilder_simpleitem, MainApp.getSpecificPluginsVisibleInList(PluginType.LOOP), PluginType.LOOP);
loopListView.setAdapter(loopDataAdapter); loopListView.setAdapter(loopDataAdapter);
setListViewHeightBasedOnChildren(loopListView); setListViewHeightBasedOnChildren(loopListView);
if (MainApp.getSpecificPluginsVisibleInList(PluginBase.LOOP).size() == 0) if (MainApp.getSpecificPluginsVisibleInList(PluginType.LOOP).size() == 0)
loopLabel.setVisibility(View.GONE); loopLabel.setVisibility(View.GONE);
treatmentDataAdapter = new PluginCustomAdapter(getContext(), R.layout.configbuilder_simpleitem, MainApp.getSpecificPluginsVisibleInList(PluginBase.TREATMENT), PluginBase.TREATMENT); treatmentDataAdapter = new PluginCustomAdapter(getContext(), R.layout.configbuilder_simpleitem, MainApp.getSpecificPluginsVisibleInList(PluginType.TREATMENT), PluginType.TREATMENT);
treatmentsListView.setAdapter(treatmentDataAdapter); treatmentsListView.setAdapter(treatmentDataAdapter);
setListViewHeightBasedOnChildren(treatmentsListView); setListViewHeightBasedOnChildren(treatmentsListView);
if (MainApp.getSpecificPluginsVisibleInList(PluginBase.TREATMENT).size() == 0) if (MainApp.getSpecificPluginsVisibleInList(PluginType.TREATMENT).size() == 0)
treatmentsLabel.setVisibility(View.GONE); treatmentsLabel.setVisibility(View.GONE);
profileDataAdapter = new PluginCustomAdapter(getContext(), R.layout.configbuilder_simpleitem, MainApp.getSpecificPluginsVisibleInListByInterface(ProfileInterface.class, PluginBase.PROFILE), PluginBase.PROFILE); profileDataAdapter = new PluginCustomAdapter(getContext(), R.layout.configbuilder_simpleitem, MainApp.getSpecificPluginsVisibleInListByInterface(ProfileInterface.class, PluginType.PROFILE), PluginType.PROFILE);
profileListView.setAdapter(profileDataAdapter); profileListView.setAdapter(profileDataAdapter);
if (MainApp.getSpecificPluginsVisibleInList(PluginBase.PROFILE).size() == 0) if (MainApp.getSpecificPluginsVisibleInList(PluginType.PROFILE).size() == 0)
profileLabel.setVisibility(View.GONE); profileLabel.setVisibility(View.GONE);
setListViewHeightBasedOnChildren(profileListView); setListViewHeightBasedOnChildren(profileListView);
apsDataAdapter = new PluginCustomAdapter(getContext(), R.layout.configbuilder_simpleitem, MainApp.getSpecificPluginsVisibleInList(PluginBase.APS), PluginBase.APS); apsDataAdapter = new PluginCustomAdapter(getContext(), R.layout.configbuilder_simpleitem, MainApp.getSpecificPluginsVisibleInList(PluginType.APS), PluginType.APS);
apsListView.setAdapter(apsDataAdapter); apsListView.setAdapter(apsDataAdapter);
setListViewHeightBasedOnChildren(apsListView); setListViewHeightBasedOnChildren(apsListView);
if (MainApp.getSpecificPluginsVisibleInList(PluginBase.APS).size() == 0) if (MainApp.getSpecificPluginsVisibleInList(PluginType.APS).size() == 0)
apsLabel.setVisibility(View.GONE); apsLabel.setVisibility(View.GONE);
sensivityDataAdapter = new PluginCustomAdapter(getContext(), R.layout.configbuilder_simpleitem, MainApp.getSpecificPluginsVisibleInListByInterface(SensitivityInterface.class, PluginBase.SENSITIVITY), PluginBase.SENSITIVITY); sensivityDataAdapter = new PluginCustomAdapter(getContext(), R.layout.configbuilder_simpleitem, MainApp.getSpecificPluginsVisibleInListByInterface(SensitivityInterface.class, PluginType.SENSITIVITY), PluginType.SENSITIVITY);
sensitivityListView.setAdapter(sensivityDataAdapter); sensitivityListView.setAdapter(sensivityDataAdapter);
setListViewHeightBasedOnChildren(sensitivityListView); setListViewHeightBasedOnChildren(sensitivityListView);
constraintsDataAdapter = new PluginCustomAdapter(getContext(), R.layout.configbuilder_simpleitem, MainApp.getSpecificPluginsVisibleInListByInterface(ConstraintsInterface.class, PluginBase.CONSTRAINTS), PluginBase.CONSTRAINTS); constraintsDataAdapter = new PluginCustomAdapter(getContext(), R.layout.configbuilder_simpleitem, MainApp.getSpecificPluginsVisibleInListByInterface(ConstraintsInterface.class, PluginType.CONSTRAINTS), PluginType.CONSTRAINTS);
constraintsListView.setAdapter(constraintsDataAdapter); constraintsListView.setAdapter(constraintsDataAdapter);
setListViewHeightBasedOnChildren(constraintsListView); setListViewHeightBasedOnChildren(constraintsListView);
if (MainApp.getSpecificPluginsVisibleInList(PluginBase.CONSTRAINTS).size() == 0) if (MainApp.getSpecificPluginsVisibleInList(PluginType.CONSTRAINTS).size() == 0)
constraintsLabel.setVisibility(View.GONE); constraintsLabel.setVisibility(View.GONE);
generalDataAdapter = new PluginCustomAdapter(getContext(), R.layout.configbuilder_simpleitem, MainApp.getSpecificPluginsVisibleInList(PluginBase.GENERAL), PluginBase.GENERAL); generalDataAdapter = new PluginCustomAdapter(getContext(), R.layout.configbuilder_simpleitem, MainApp.getSpecificPluginsVisibleInList(PluginType.GENERAL), PluginType.GENERAL);
generalListView.setAdapter(generalDataAdapter); generalListView.setAdapter(generalDataAdapter);
setListViewHeightBasedOnChildren(generalListView); setListViewHeightBasedOnChildren(generalListView);
} }
/* /*
@ -192,10 +188,10 @@ public class ConfigBuilderFragment extends Fragment {
private class PluginCustomAdapter extends ArrayAdapter<PluginBase> { private class PluginCustomAdapter extends ArrayAdapter<PluginBase> {
private ArrayList<PluginBase> pluginList; private ArrayList<PluginBase> pluginList;
final private int type; final private PluginType type;
public PluginCustomAdapter(Context context, int textViewResourceId, PluginCustomAdapter(Context context, int textViewResourceId,
ArrayList<PluginBase> pluginList, int type) { ArrayList<PluginBase> pluginList, PluginType type) {
super(context, textViewResourceId, pluginList); super(context, textViewResourceId, pluginList);
this.pluginList = new ArrayList<>(); this.pluginList = new ArrayList<>();
this.pluginList.addAll(pluginList); this.pluginList.addAll(pluginList);
@ -209,10 +205,11 @@ public class ConfigBuilderFragment extends Fragment {
ImageView settings; ImageView settings;
} }
@NonNull
@Override @Override
public View getView(int position, View view, ViewGroup parent) { public View getView(int position, View view, @NonNull ViewGroup parent) {
PluginViewHolder holder = null; PluginViewHolder holder;
PluginBase plugin = pluginList.get(position); PluginBase plugin = pluginList.get(position);
if (view == null) { if (view == null) {
@ -231,60 +228,45 @@ public class ConfigBuilderFragment extends Fragment {
view.setTag(holder); view.setTag(holder);
holder.checkboxEnabled.setOnClickListener(new View.OnClickListener() { holder.checkboxEnabled.setOnClickListener(v -> {
public void onClick(View v) { CheckBox cb = (CheckBox) v;
CheckBox cb = (CheckBox) v; PluginBase plugin1 = (PluginBase) cb.getTag();
PluginBase plugin = (PluginBase) cb.getTag(); plugin1.setPluginEnabled(type, cb.isChecked());
plugin.setFragmentEnabled(type, cb.isChecked()); plugin1.setFragmentVisible(type, cb.isChecked());
plugin.setFragmentVisible(type, cb.isChecked()); onEnabledCategoryChanged(plugin1, type);
onEnabledCategoryChanged(plugin, type); ConfigBuilderPlugin.getPlugin().storeSettings("CheckedCheckboxEnabled");
configBuilderPlugin.storeSettings(); MainApp.bus().post(new EventRefreshGui());
MainApp.bus().post(new EventRefreshGui()); MainApp.bus().post(new EventConfigBuilderChange());
MainApp.bus().post(new EventConfigBuilderChange()); ConfigBuilderPlugin.getPlugin().logPluginStatus();
getPlugin().logPluginStatus(); FabricPrivacy.getInstance().logCustom(new CustomEvent("ConfigurationChange"));
Answers.getInstance().logCustom(new CustomEvent("ConfigurationChange"));
}
}); });
holder.checkboxVisible.setOnClickListener(new View.OnClickListener() { holder.checkboxVisible.setOnClickListener(v -> {
public void onClick(View v) { CheckBox cb = (CheckBox) v;
CheckBox cb = (CheckBox) v; PluginBase plugin12 = (PluginBase) cb.getTag();
PluginBase plugin = (PluginBase) cb.getTag(); plugin12.setFragmentVisible(type, cb.isChecked());
plugin.setFragmentVisible(type, cb.isChecked()); ConfigBuilderPlugin.getPlugin().storeSettings("CheckedCheckboxVisible");
configBuilderPlugin.storeSettings(); MainApp.bus().post(new EventRefreshGui());
MainApp.bus().post(new EventRefreshGui()); ConfigBuilderPlugin.getPlugin().logPluginStatus();
getPlugin().logPluginStatus();
}
}); });
holder.settings.setOnClickListener(new View.OnClickListener() { holder.settings.setOnClickListener(v -> {
public void onClick(View v) { final PluginBase plugin13 = (PluginBase) v.getTag();
final PluginBase plugin = (PluginBase) v.getTag(); PasswordProtection.QueryPassword(getContext(), R.string.settings_password, "settings_password", () -> {
PasswordProtection.QueryPassword(getContext(), R.string.settings_password, "settings_password", new Runnable() { Intent i = new Intent(getContext(), PreferencesActivity.class);
@Override i.putExtra("id", plugin13.getPreferencesId());
public void run() { startActivity(i);
Intent i = new Intent(getContext(), PreferencesActivity.class); }, null);
i.putExtra("id", plugin.getPreferencesId());
startActivity(i);
}
}, null);
}
}); });
holder.name.setOnLongClickListener(new View.OnLongClickListener() { holder.name.setOnLongClickListener(v -> {
@Override final PluginBase plugin14 = (PluginBase) v.getTag();
public boolean onLongClick(View v) { PasswordProtection.QueryPassword(getContext(), R.string.settings_password, "settings_password", () -> {
final PluginBase plugin = (PluginBase) v.getTag(); Intent i = new Intent(getContext(), PreferencesActivity.class);
PasswordProtection.QueryPassword(getContext(), R.string.settings_password, "settings_password", new Runnable() { i.putExtra("id", plugin14.getPreferencesId());
@Override startActivity(i);
public void run() { }, null);
Intent i = new Intent(getContext(), PreferencesActivity.class); return false;
i.putExtra("id", plugin.getPreferencesId());
startActivity(i);
}
}, null);
return false;
}
}); });
} else { } else {
@ -293,15 +275,18 @@ public class ConfigBuilderFragment extends Fragment {
holder.name.setText(plugin.getName()); holder.name.setText(plugin.getName());
holder.checkboxEnabled.setChecked(plugin.isEnabled(type)); holder.checkboxEnabled.setChecked(plugin.isEnabled(type));
holder.checkboxVisible.setChecked(plugin.isVisibleInTabs(type)); holder.checkboxVisible.setChecked(plugin.isFragmentVisible());
holder.name.setTag(plugin); holder.name.setTag(plugin);
holder.checkboxEnabled.setTag(plugin); holder.checkboxEnabled.setTag(plugin);
holder.checkboxVisible.setTag(plugin); holder.checkboxVisible.setTag(plugin);
holder.settings.setTag(plugin); holder.settings.setTag(plugin);
if (!plugin.canBeHidden(type)) { if (plugin.pluginDescription.alwaysEnabled) {
holder.checkboxEnabled.setEnabled(false);
}
if (plugin.pluginDescription.alwayVisible) {
holder.checkboxEnabled.setEnabled(false); holder.checkboxEnabled.setEnabled(false);
holder.checkboxVisible.setEnabled(false);
} }
if (!plugin.isEnabled(type)) { if (!plugin.isEnabled(type)) {
@ -313,19 +298,19 @@ public class ConfigBuilderFragment extends Fragment {
} }
// Hide enabled control and force enabled plugin if there is only one plugin available // Hide enabled control and force enabled plugin if there is only one plugin available
if (type == PluginBase.INSULIN || type == PluginBase.PUMP || type == PluginBase.TREATMENT || type == PluginBase.PROFILE || type == PluginBase.SENSITIVITY) if (type == PluginType.INSULIN || type == PluginType.PUMP || type == PluginType.SENSITIVITY)
if (pluginList.size() < 2) { if (pluginList.size() < 2) {
holder.checkboxEnabled.setEnabled(false); holder.checkboxEnabled.setEnabled(false);
plugin.setFragmentEnabled(type, true); plugin.setPluginEnabled(type, true);
getPlugin().storeSettings(); ConfigBuilderPlugin.getPlugin().storeSettings("ForceEnable");
} }
// Constraints cannot be disabled // Constraints cannot be disabled
if (type == PluginBase.CONSTRAINTS) if (type == PluginType.CONSTRAINTS)
holder.checkboxEnabled.setEnabled(false); holder.checkboxEnabled.setEnabled(false);
// Hide disabled profiles by default // Hide disabled profiles by default
if (type == PluginBase.PROFILE) { if (type == PluginType.PROFILE) {
if (!plugin.isEnabled(type)) { if (!plugin.isEnabled(type)) {
holder.checkboxVisible.setEnabled(false); holder.checkboxVisible.setEnabled(false);
holder.checkboxVisible.setChecked(false); holder.checkboxVisible.setChecked(false);
@ -335,9 +320,9 @@ public class ConfigBuilderFragment extends Fragment {
} }
// Disable profile control for pump profiles if pump is not enabled // Disable profile control for pump profiles if pump is not enabled
if (type == PluginBase.PROFILE) { if (type == PluginType.PROFILE) {
if (PumpInterface.class.isAssignableFrom(plugin.getClass())) { if (PumpInterface.class.isAssignableFrom(plugin.getClass())) {
if (!plugin.isEnabled(PluginBase.PUMP)) { if (!plugin.isEnabled(PluginType.PUMP)) {
holder.checkboxEnabled.setEnabled(false); holder.checkboxEnabled.setEnabled(false);
holder.checkboxEnabled.setChecked(false); holder.checkboxEnabled.setChecked(false);
} }
@ -354,32 +339,32 @@ public class ConfigBuilderFragment extends Fragment {
} }
void onEnabledCategoryChanged(PluginBase changedPlugin, int type) { void onEnabledCategoryChanged(PluginBase changedPlugin, PluginType type) {
ArrayList<PluginBase> pluginsInCategory = null; ArrayList<PluginBase> pluginsInCategory = null;
switch (type) { switch (type) {
// Multiple selection allowed // Multiple selection allowed
case PluginBase.GENERAL: case GENERAL:
case PluginBase.CONSTRAINTS: case CONSTRAINTS:
case PluginBase.LOOP: case LOOP:
break; break;
// Single selection allowed // Single selection allowed
case PluginBase.INSULIN: case INSULIN:
pluginsInCategory = MainApp.getSpecificPluginsListByInterface(InsulinInterface.class); pluginsInCategory = MainApp.getSpecificPluginsListByInterface(InsulinInterface.class);
break; break;
case PluginBase.SENSITIVITY: case SENSITIVITY:
pluginsInCategory = MainApp.getSpecificPluginsListByInterface(SensitivityInterface.class); pluginsInCategory = MainApp.getSpecificPluginsListByInterface(SensitivityInterface.class);
break; break;
case PluginBase.APS: case APS:
pluginsInCategory = MainApp.getSpecificPluginsListByInterface(APSInterface.class); pluginsInCategory = MainApp.getSpecificPluginsListByInterface(APSInterface.class);
break; break;
case PluginBase.PROFILE: case PROFILE:
pluginsInCategory = MainApp.getSpecificPluginsListByInterface(ProfileInterface.class); pluginsInCategory = MainApp.getSpecificPluginsListByInterface(ProfileInterface.class);
break; break;
case PluginBase.BGSOURCE: case BGSOURCE:
pluginsInCategory = MainApp.getSpecificPluginsListByInterface(BgSourceInterface.class); pluginsInCategory = MainApp.getSpecificPluginsListByInterface(BgSourceInterface.class);
break; break;
case PluginBase.TREATMENT: case TREATMENT:
case PluginBase.PUMP: case PUMP:
pluginsInCategory = MainApp.getSpecificPluginsListByInterface(PumpInterface.class); pluginsInCategory = MainApp.getSpecificPluginsListByInterface(PumpInterface.class);
break; break;
} }
@ -390,23 +375,23 @@ public class ConfigBuilderFragment extends Fragment {
if (p.getName().equals(changedPlugin.getName())) { if (p.getName().equals(changedPlugin.getName())) {
// this is new selected // this is new selected
} else { } else {
p.setFragmentEnabled(type, false); p.setPluginEnabled(type, false);
p.setFragmentVisible(type, false); p.setFragmentVisible(type, false);
} }
} }
} else { // enable first plugin in list } else { // enable first plugin in list
if (type == PluginBase.PUMP) if (type == PluginType.PUMP)
MainApp.getSpecificPlugin(VirtualPumpPlugin.class).setFragmentEnabled(type, true); VirtualPumpPlugin.getPlugin().setPluginEnabled(type, true);
else if (type == PluginBase.INSULIN) else if (type == PluginType.INSULIN)
MainApp.getSpecificPlugin(InsulinFastactingPlugin.class).setFragmentEnabled(type, true); InsulinOrefRapidActingPlugin.getPlugin().setPluginEnabled(type, true);
else if (type == PluginBase.SENSITIVITY) else if (type == PluginType.SENSITIVITY)
MainApp.getSpecificPlugin(SensitivityOref0Plugin.class).setFragmentEnabled(type, true); SensitivityOref0Plugin.getPlugin().setPluginEnabled(type, true);
else if (type == PluginBase.PROFILE) else if (type == PluginType.PROFILE)
MainApp.getSpecificPlugin(NSProfilePlugin.class).setFragmentEnabled(type, true); NSProfilePlugin.getPlugin().setPluginEnabled(type, true);
else else
pluginsInCategory.get(0).setFragmentEnabled(type, true); pluginsInCategory.get(0).setPluginEnabled(type, true);
} }
setViews(); updateGUI();
} }
} }

View file

@ -19,13 +19,13 @@ public class DetailedBolusInfoStorage {
private static Logger log = LoggerFactory.getLogger(DetailedBolusInfoStorage.class); private static Logger log = LoggerFactory.getLogger(DetailedBolusInfoStorage.class);
private static List<DetailedBolusInfo> store = new ArrayList<>(); private static List<DetailedBolusInfo> store = new ArrayList<>();
public static void add(DetailedBolusInfo detailedBolusInfo) { public static synchronized void add(DetailedBolusInfo detailedBolusInfo) {
log.debug("Stored bolus info: " + detailedBolusInfo); log.debug("Stored bolus info: " + detailedBolusInfo);
store.add(detailedBolusInfo); store.add(detailedBolusInfo);
} }
@Nullable @Nullable
public static DetailedBolusInfo findDetailedBolusInfo(long bolustime) { public static synchronized DetailedBolusInfo findDetailedBolusInfo(long bolustime) {
DetailedBolusInfo found = null; DetailedBolusInfo found = null;
for (int i = 0; i < store.size(); i++) { for (int i = 0; i < store.size(); i++) {
long infoTime = store.get(i).date; long infoTime = store.get(i).date;
@ -38,7 +38,7 @@ public class DetailedBolusInfoStorage {
return found; return found;
} }
public static void remove(long bolustime) { public static synchronized void remove(long bolustime) {
for (int i = 0; i < store.size(); i++) { for (int i = 0; i < store.size(); i++) {
long infoTime = store.get(i).date; long infoTime = store.get(i).date;
if (bolustime > infoTime - 60 * 1000 && bolustime < infoTime + 60 * 1000) { if (bolustime > infoTime - 60 * 1000 && bolustime < infoTime + 60 * 1000) {

View file

@ -15,7 +15,6 @@ import android.widget.CheckBox;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.TextView; import android.widget.TextView;
import com.crashlytics.android.Crashlytics;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -25,8 +24,11 @@ import java.util.List;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
import info.nightscout.androidaps.plugins.Common.SubscriberFragment;
import info.nightscout.utils.FabricPrivacy;
import info.nightscout.utils.T;
public class ObjectivesFragment extends Fragment { public class ObjectivesFragment extends SubscriberFragment {
private static Logger log = LoggerFactory.getLogger(ObjectivesFragment.class); private static Logger log = LoggerFactory.getLogger(ObjectivesFragment.class);
RecyclerView recyclerView; RecyclerView recyclerView;
@ -57,7 +59,7 @@ public class ObjectivesFragment extends Fragment {
holder.position.setText(String.valueOf(position + 1)); holder.position.setText(String.valueOf(position + 1));
holder.objective.setText(o.objective); holder.objective.setText(o.objective);
holder.gate.setText(o.gate); holder.gate.setText(o.gate);
holder.duration.setText(context.getString(R.string.objectives_minimalduration) + " " + o.durationInDays + " " + context.getString(R.string.days)); holder.duration.setText(MainApp.gs(R.string.objectives_minimalduration) + " " + o.durationInDays + " " + MainApp.gs(R.string.days));
holder.progress.setText(requirementsMet.comment); holder.progress.setText(requirementsMet.comment);
holder.started.setText(o.started.toLocaleString()); holder.started.setText(o.started.toLocaleString());
holder.accomplished.setText(o.accomplished.toLocaleString()); holder.accomplished.setText(o.accomplished.toLocaleString());
@ -84,37 +86,52 @@ public class ObjectivesFragment extends Fragment {
} }
}); });
Long now = System.currentTimeMillis(); long prevObjectiveAccomplishedTime = position > 0 ?
if (position > 0 && objectives.get(position - 1).accomplished.getTime() == 0) { objectives.get(position - 1).accomplished.getTime() : -1;
// Phase 0: previous not completed
holder.startedLayout.setVisibility(View.GONE); int phase = modifyVisibility(position, prevObjectiveAccomplishedTime,
holder.durationLayout.setVisibility(View.GONE); o.started.getTime(), o.durationInDays,
holder.progressLayout.setVisibility(View.GONE); o.accomplished.getTime(), requirementsMet.done, enableFake.isChecked());
holder.verifyLayout.setVisibility(View.GONE);
} else if (o.started.getTime() == 0) { switch (phase) {
// Phase 1: not started case 0:
holder.durationLayout.setVisibility(View.GONE); // Phase 0: previous not completed
holder.progressLayout.setVisibility(View.GONE); holder.startedLayout.setVisibility(View.GONE);
holder.verifyLayout.setVisibility(View.GONE); holder.durationLayout.setVisibility(View.GONE);
holder.started.setVisibility(View.GONE); holder.progressLayout.setVisibility(View.GONE);
} else if (o.started.getTime() > 0 && !enableFake.isChecked() && o.accomplished.getTime() == 0 && !(o.started.getTime() + o.durationInDays * 24 * 60 * 60 * 1000 < now && requirementsMet.done)) { holder.verifyLayout.setVisibility(View.GONE);
// Phase 2: started, waiting for duration and met requirements break;
holder.startButton.setEnabled(false); case 1:
holder.verifyLayout.setVisibility(View.GONE); // Phase 1: not started
} else if (o.accomplished.getTime() == 0) { holder.durationLayout.setVisibility(View.GONE);
// Phase 3: started, after duration, requirements met holder.progressLayout.setVisibility(View.GONE);
holder.startButton.setEnabled(false); holder.verifyLayout.setVisibility(View.GONE);
holder.accomplished.setVisibility(View.INVISIBLE); holder.started.setVisibility(View.GONE);
} else { break;
// Phase 4: verified case 2:
holder.gateLayout.setVisibility(View.GONE); // Phase 2: started, waiting for duration and met requirements
holder.startedLayout.setVisibility(View.GONE); holder.startButton.setEnabled(false);
holder.durationLayout.setVisibility(View.GONE); holder.verifyLayout.setVisibility(View.GONE);
holder.progressLayout.setVisibility(View.GONE); break;
holder.verifyButton.setVisibility(View.INVISIBLE); case 3:
// Phase 3: started, after duration, requirements met
holder.startButton.setEnabled(false);
holder.accomplished.setVisibility(View.INVISIBLE);
break;
case 4:
// Phase 4: verified
holder.gateLayout.setVisibility(View.GONE);
holder.startedLayout.setVisibility(View.GONE);
holder.durationLayout.setVisibility(View.GONE);
holder.progressLayout.setVisibility(View.GONE);
holder.verifyButton.setVisibility(View.INVISIBLE);
break;
default:
// should not happen
} }
} }
@Override @Override
public int getItemCount() { public int getItemCount() {
return objectives.size(); return objectives.size();
@ -163,6 +180,40 @@ public class ObjectivesFragment extends Fragment {
} }
} }
/**
* returns an int, which represents the phase the current objective is at.
*
* this is mainly used for unit-testing the conditions
*
* @param currentPosition
* @param prevObjectiveAccomplishedTime
* @param objectiveStartedTime
* @param durationInDays
* @param objectiveAccomplishedTime
* @param requirementsMet
* @return
*/
public int modifyVisibility(int currentPosition,
long prevObjectiveAccomplishedTime,
long objectiveStartedTime, int durationInDays,
long objectiveAccomplishedTime, boolean requirementsMet,
boolean enableFakeValue) {
Long now = System.currentTimeMillis();
if (currentPosition > 0 && prevObjectiveAccomplishedTime == 0) {
return 0;
} else if (objectiveStartedTime == 0) {
return 1;
} else if (objectiveStartedTime > 0 && !enableFakeValue
&& objectiveAccomplishedTime == 0
&& !(objectiveStartedTime + T.days(durationInDays).msecs() < now && requirementsMet)) {
return 2;
} else if (objectiveAccomplishedTime == 0) {
return 3;
} else {
return 4;
}
}
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) { Bundle savedInstanceState) {
@ -190,38 +241,38 @@ public class ObjectivesFragment extends Fragment {
}); });
// Add correct translations to array after app is initialized // Add correct translations to array after app is initialized
ObjectivesPlugin.objectives.get(0).objective = MainApp.sResources.getString(R.string.objectives_0_objective); ObjectivesPlugin.objectives.get(0).objective = MainApp.gs(R.string.objectives_0_objective);
ObjectivesPlugin.objectives.get(1).objective = MainApp.sResources.getString(R.string.objectives_1_objective); ObjectivesPlugin.objectives.get(1).objective = MainApp.gs(R.string.objectives_1_objective);
ObjectivesPlugin.objectives.get(2).objective = MainApp.sResources.getString(R.string.objectives_2_objective); ObjectivesPlugin.objectives.get(2).objective = MainApp.gs(R.string.objectives_2_objective);
ObjectivesPlugin.objectives.get(3).objective = MainApp.sResources.getString(R.string.objectives_3_objective); ObjectivesPlugin.objectives.get(3).objective = MainApp.gs(R.string.objectives_3_objective);
ObjectivesPlugin.objectives.get(4).objective = MainApp.sResources.getString(R.string.objectives_4_objective); ObjectivesPlugin.objectives.get(4).objective = MainApp.gs(R.string.objectives_4_objective);
ObjectivesPlugin.objectives.get(5).objective = MainApp.sResources.getString(R.string.objectives_5_objective); ObjectivesPlugin.objectives.get(5).objective = MainApp.gs(R.string.objectives_5_objective);
ObjectivesPlugin.objectives.get(6).objective = MainApp.sResources.getString(R.string.objectives_6_objective); ObjectivesPlugin.objectives.get(6).objective = MainApp.gs(R.string.objectives_6_objective);
ObjectivesPlugin.objectives.get(0).gate = MainApp.sResources.getString(R.string.objectives_0_gate); ObjectivesPlugin.objectives.get(7).objective = MainApp.gs(R.string.objectives_7_objective);
ObjectivesPlugin.objectives.get(1).gate = MainApp.sResources.getString(R.string.objectives_1_gate); ObjectivesPlugin.objectives.get(0).gate = MainApp.gs(R.string.objectives_0_gate);
ObjectivesPlugin.objectives.get(2).gate = MainApp.sResources.getString(R.string.objectives_2_gate); ObjectivesPlugin.objectives.get(1).gate = MainApp.gs(R.string.objectives_1_gate);
ObjectivesPlugin.objectives.get(3).gate = MainApp.sResources.getString(R.string.objectives_3_gate); ObjectivesPlugin.objectives.get(2).gate = MainApp.gs(R.string.objectives_2_gate);
ObjectivesPlugin.objectives.get(4).gate = MainApp.sResources.getString(R.string.objectives_4_gate); ObjectivesPlugin.objectives.get(3).gate = MainApp.gs(R.string.objectives_3_gate);
ObjectivesPlugin.objectives.get(5).gate = MainApp.sResources.getString(R.string.objectives_5_gate); ObjectivesPlugin.objectives.get(4).gate = MainApp.gs(R.string.objectives_4_gate);
ObjectivesPlugin.objectives.get(5).gate = MainApp.gs(R.string.objectives_5_gate);
updateGUI(); updateGUI();
return view; return view;
} catch (Exception e) { } catch (Exception e) {
Crashlytics.logException(e); FabricPrivacy.logException(e);
} }
return null; return null;
} }
void updateGUI() { @Override
public void updateGUI() {
Activity activity = getActivity(); Activity activity = getActivity();
if (activity != null) if (activity != null)
activity.runOnUiThread(new Runnable() { activity.runOnUiThread(() -> {
@Override RecyclerViewAdapter adapter = new RecyclerViewAdapter(ObjectivesPlugin.objectives);
public void run() { recyclerView.setAdapter(adapter);
RecyclerViewAdapter adapter = new RecyclerViewAdapter(ObjectivesPlugin.objectives);
recyclerView.setAdapter(adapter);
}
}); });
} }

View file

@ -10,19 +10,30 @@ import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import info.nightscout.androidaps.BuildConfig;
import info.nightscout.androidaps.Config; import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
import info.nightscout.androidaps.db.DatabaseHelper;
import info.nightscout.androidaps.interfaces.APSInterface;
import info.nightscout.androidaps.interfaces.Constraint;
import info.nightscout.androidaps.interfaces.ConstraintsInterface; import info.nightscout.androidaps.interfaces.ConstraintsInterface;
import info.nightscout.androidaps.interfaces.PluginBase; 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.plugins.ConfigBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.ConstraintsSafety.SafetyPlugin;
import info.nightscout.androidaps.plugins.Loop.LoopPlugin;
import info.nightscout.androidaps.plugins.NSClientInternal.NSClientPlugin;
import info.nightscout.androidaps.plugins.PumpVirtual.VirtualPumpPlugin;
import info.nightscout.androidaps.plugins.Treatments.TreatmentsPlugin;
import info.nightscout.utils.DateUtil;
import info.nightscout.utils.SP; import info.nightscout.utils.SP;
/** /**
* Created by mike on 05.08.2016. * Created by mike on 05.08.2016.
*/ */
public class ObjectivesPlugin implements PluginBase, ConstraintsInterface { public class ObjectivesPlugin extends PluginBase implements ConstraintsInterface {
private static Logger log = LoggerFactory.getLogger(ObjectivesPlugin.class); private static Logger log = LoggerFactory.getLogger(ObjectivesPlugin.class);
private static ObjectivesPlugin objectivesPlugin; private static ObjectivesPlugin objectivesPlugin;
@ -36,80 +47,26 @@ public class ObjectivesPlugin implements PluginBase, ConstraintsInterface {
public static List<Objective> objectives; public static List<Objective> objectives;
private boolean fragmentVisible = true;
private ObjectivesPlugin() { private ObjectivesPlugin() {
super(new PluginDescription()
.mainType(PluginType.CONSTRAINTS)
.fragmentClass(ObjectivesFragment.class.getName())
.alwaysEnabled(!Config.NSCLIENT && !Config.G5UPLOADER)
.showInList(!Config.NSCLIENT && !Config.G5UPLOADER)
.pluginName(R.string.objectives)
.shortName(R.string.objectives_shortname)
);
initializeData(); initializeData();
loadProgress(); loadProgress();
MainApp.bus().register(this);
} }
@Override @Override
public String getFragmentClass() { public boolean specialEnableCondition() {
return ObjectivesFragment.class.getName(); PumpInterface pump = ConfigBuilderPlugin.getActivePump();
return pump == null || pump.getPumpDescription().isTempBasalCapable;
} }
@Override public class Objective {
public int getType() {
return PluginBase.CONSTRAINTS;
}
@Override
public String getName() {
return MainApp.instance().getString(R.string.objectives);
}
@Override
public String getNameShort() {
String name = MainApp.sResources.getString(R.string.objectives_shortname);
if (!name.trim().isEmpty()) {
//only if translation exists
return name;
}
// use long name as fallback
return getName();
}
@Override
public boolean isEnabled(int type) {
return type == CONSTRAINTS && ConfigBuilderPlugin.getActivePump().getPumpDescription().isTempBasalCapable;
}
@Override
public boolean isVisibleInTabs(int type) {
return type == CONSTRAINTS && fragmentVisible && !Config.NSCLIENT && !Config.G5UPLOADER;
}
@Override
public boolean canBeHidden(int type) {
return true;
}
@Override
public boolean hasFragment() {
return true;
}
@Override
public boolean showInList(int type) {
return true;
}
@Override
public void setFragmentEnabled(int type, boolean fragmentEnabled) {
}
@Override
public void setFragmentVisible(int type, boolean fragmentVisible) {
if (type == CONSTRAINTS) this.fragmentVisible = fragmentVisible;
}
@Override
public int getPreferencesId() {
return -1;
}
class Objective {
Integer num; Integer num;
String objective; String objective;
String gate; String gate;
@ -125,6 +82,18 @@ public class ObjectivesPlugin implements PluginBase, ConstraintsInterface {
this.durationInDays = durationInDays; this.durationInDays = durationInDays;
this.accomplished = accomplished; this.accomplished = accomplished;
} }
public void setStarted(Date started) {
this.started = started;
}
boolean isStarted() {
return started.getTime() > 0;
}
boolean isFinished() {
return accomplished.getTime() != 0;
}
} }
// Objective 0 // Objective 0
@ -152,14 +121,41 @@ public class ObjectivesPlugin implements PluginBase, ConstraintsInterface {
RequirementResult requirementsMet(Integer objNum) { RequirementResult requirementsMet(Integer objNum) {
switch (objNum) { switch (objNum) {
case 0: case 0:
return new RequirementResult(bgIsAvailableInNS && pumpStatusIsAvailableInNS, boolean isVirtualPump = VirtualPumpPlugin.getPlugin().isEnabled(PluginType.PUMP);
MainApp.sResources.getString(R.string.objectives_bgavailableinns) + ": " + yesOrNo(bgIsAvailableInNS) boolean vpUploadEnabled = SP.getBoolean("virtualpump_uploadstatus", false);
+ " " + MainApp.sResources.getString(R.string.objectives_pumpstatusavailableinns) + ": " + yesOrNo(pumpStatusIsAvailableInNS)); boolean vpUploadNeeded = !isVirtualPump || vpUploadEnabled;
boolean hasBGData = DatabaseHelper.lastBg() != null;
boolean apsEnabled = false;
APSInterface usedAPS = ConfigBuilderPlugin.getActiveAPS();
if (usedAPS != null && ((PluginBase) usedAPS).isEnabled(PluginType.APS))
apsEnabled = true;
boolean profileSwitchExists = TreatmentsPlugin.getPlugin().getProfileSwitchFromHistory(DateUtil.now()) != null;
return new RequirementResult(hasBGData && bgIsAvailableInNS && pumpStatusIsAvailableInNS && NSClientPlugin.getPlugin().hasWritePermission() && LoopPlugin.getPlugin().isEnabled(PluginType.LOOP) && apsEnabled && vpUploadNeeded && profileSwitchExists,
MainApp.gs(R.string.objectives_bgavailableinns) + ": " + yesOrNo(bgIsAvailableInNS)
+ "\n" + MainApp.gs(R.string.nsclienthaswritepermission) + ": " + yesOrNo(NSClientPlugin.getPlugin().hasWritePermission())
+ (isVirtualPump ? "\n" + MainApp.gs(R.string.virtualpump_uploadstatus_title) + ": " + yesOrNo(vpUploadEnabled) : "")
+ "\n" + MainApp.gs(R.string.objectives_pumpstatusavailableinns) + ": " + yesOrNo(pumpStatusIsAvailableInNS)
+ "\n" + MainApp.gs(R.string.hasbgdata) + ": " + yesOrNo(hasBGData)
+ "\n" + MainApp.gs(R.string.loopenabled) + ": " + yesOrNo(LoopPlugin.getPlugin().isEnabled(PluginType.LOOP))
+ "\n" + MainApp.gs(R.string.apsselected) + ": " + yesOrNo(apsEnabled)
+ "\n" + MainApp.gs(R.string.activate_profile) + ": " + yesOrNo(profileSwitchExists)
);
case 1: case 1:
return new RequirementResult(manualEnacts >= manualEnactsNeeded, return new RequirementResult(manualEnacts >= manualEnactsNeeded,
MainApp.sResources.getString(R.string.objectives_manualenacts) + ": " + manualEnacts + "/" + manualEnactsNeeded); MainApp.gs(R.string.objectives_manualenacts) + ": " + manualEnacts + "/" + manualEnactsNeeded);
case 2: case 2:
return new RequirementResult(true, ""); return new RequirementResult(true, "");
case 3:
Constraint<Boolean> closedLoopEnabled = new Constraint<>(true);
SafetyPlugin.getPlugin().isClosedLoopAllowed(closedLoopEnabled);
return new RequirementResult(closedLoopEnabled.value(), MainApp.gs(R.string.closedmodeenabled) + ": " + yesOrNo(closedLoopEnabled.value()));
case 4:
double maxIOB = MainApp.getConstraintChecker().getMaxIOBAllowed().value();
boolean maxIobSet = maxIOB > 0;
return new RequirementResult(maxIobSet, MainApp.gs(R.string.maxiobset) + ": " + yesOrNo(maxIobSet));
default: default:
return new RequirementResult(true, ""); return new RequirementResult(true, "");
} }
@ -173,46 +169,52 @@ public class ObjectivesPlugin implements PluginBase, ConstraintsInterface {
objectives = new ArrayList<>(); objectives = new ArrayList<>();
objectives.add(new Objective(0, objectives.add(new Objective(0,
MainApp.sResources.getString(R.string.objectives_0_objective), MainApp.gs(R.string.objectives_0_objective),
MainApp.sResources.getString(R.string.objectives_0_gate), MainApp.gs(R.string.objectives_0_gate),
new Date(0), new Date(0),
0, // 0 day 0, // 0 day
new Date(0))); new Date(0)));
objectives.add(new Objective(1, objectives.add(new Objective(1,
MainApp.sResources.getString(R.string.objectives_1_objective), MainApp.gs(R.string.objectives_1_objective),
MainApp.sResources.getString(R.string.objectives_1_gate), MainApp.gs(R.string.objectives_1_gate),
new Date(0), new Date(0),
7, // 7 days 7, // 7 days
new Date(0))); new Date(0)));
objectives.add(new Objective(2, objectives.add(new Objective(2,
MainApp.sResources.getString(R.string.objectives_2_objective), MainApp.gs(R.string.objectives_2_objective),
MainApp.sResources.getString(R.string.objectives_2_gate), MainApp.gs(R.string.objectives_2_gate),
new Date(0), new Date(0),
0, // 0 days 0, // 0 days
new Date(0))); new Date(0)));
objectives.add(new Objective(3, objectives.add(new Objective(3,
MainApp.sResources.getString(R.string.objectives_3_objective), MainApp.gs(R.string.objectives_3_objective),
MainApp.sResources.getString(R.string.objectives_3_gate), MainApp.gs(R.string.objectives_3_gate),
new Date(0), new Date(0),
5, // 5 days 5, // 5 days
new Date(0))); new Date(0)));
objectives.add(new Objective(4, objectives.add(new Objective(4,
MainApp.sResources.getString(R.string.objectives_4_objective), MainApp.gs(R.string.objectives_4_objective),
MainApp.sResources.getString(R.string.objectives_4_gate), MainApp.gs(R.string.objectives_4_gate),
new Date(0), new Date(0),
1, 1,
new Date(0))); new Date(0)));
objectives.add(new Objective(5, objectives.add(new Objective(5,
MainApp.sResources.getString(R.string.objectives_5_objective), MainApp.gs(R.string.objectives_5_objective),
MainApp.sResources.getString(R.string.objectives_5_gate), MainApp.gs(R.string.objectives_5_gate),
new Date(0), new Date(0),
7, 7,
new Date(0))); new Date(0)));
objectives.add(new Objective(6, objectives.add(new Objective(6,
MainApp.sResources.getString(R.string.objectives_6_objective), MainApp.gs(R.string.objectives_6_objective),
"", "",
new Date(0), new Date(0),
14, 28,
new Date(0)));
objectives.add(new Objective(7,
MainApp.gs(R.string.objectives_7_objective),
"",
new Date(0),
28,
new Date(0))); new Date(0)));
} }
@ -259,55 +261,45 @@ public class ObjectivesPlugin implements PluginBase, ConstraintsInterface {
* Constraints interface * Constraints interface
**/ **/
@Override @Override
public boolean isLoopEnabled() { public Constraint<Boolean> isLoopInvokationAllowed(Constraint<Boolean> value) {
return objectives.get(1).started.getTime() > 0; if (!objectives.get(0).isStarted())
value.set(false, String.format(MainApp.gs(R.string.objectivenotstarted), 1), this);
return value;
} }
@Override @Override
public boolean isClosedModeEnabled() { public Constraint<Boolean> isClosedLoopAllowed(Constraint<Boolean> value) {
return objectives.get(3).started.getTime() > 0; if (!objectives.get(3).isStarted())
value.set(false, String.format(MainApp.gs(R.string.objectivenotstarted), 4), this);
return value;
} }
@Override @Override
public boolean isAutosensModeEnabled() { public Constraint<Boolean> isAutosensModeEnabled(Constraint<Boolean> value) {
return objectives.get(5).started.getTime() > 0; if (!objectives.get(5).isStarted())
value.set(false, String.format(MainApp.gs(R.string.objectivenotstarted), 6), this);
return value;
} }
@Override @Override
public boolean isAMAModeEnabled() { public Constraint<Boolean> isAMAModeEnabled(Constraint<Boolean> value) {
return objectives.get(6).started.getTime() > 0; if (!objectives.get(6).isStarted())
value.set(false, String.format(MainApp.gs(R.string.objectivenotstarted), 7), this);
return value;
} }
@Override @Override
public Double applyMaxIOBConstraints(Double maxIob) { public Constraint<Boolean> isSMBModeEnabled(Constraint<Boolean> value) {
if (objectives.get(4).started.getTime() > 0 || objectives.get(2).accomplished.getTime() == 0) if (!objectives.get(7).isStarted())
return maxIob; value.set(false, String.format(MainApp.gs(R.string.objectivenotstarted), 8), this);
else { return value;
if (Config.logConstraintsChanges)
log.debug("Limiting maxIOB " + maxIob + " to " + 0 + "U");
return 0d;
}
} }
@Override @Override
public Double applyBasalConstraints(Double absoluteRate) { public Constraint<Double> applyMaxIOBConstraints(Constraint<Double> maxIob) {
return absoluteRate; if (objectives.get(3).isStarted() && !objectives.get(3).isFinished())
maxIob.set(0d, String.format(MainApp.gs(R.string.objectivenotfinished), 4), this);
return maxIob;
} }
@Override
public Integer applyBasalConstraints(Integer percentRate) {
return percentRate;
}
@Override
public Double applyBolusConstraints(Double insulin) {
return insulin;
}
@Override
public Integer applyCarbsConstraints(Integer carbs) {
return carbs;
}
} }

View file

@ -1,19 +1,22 @@
package info.nightscout.androidaps.plugins.ConstraintsSafety; package info.nightscout.androidaps.plugins.ConstraintsSafety;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Objects;
import info.nightscout.androidaps.BuildConfig;
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.ConstraintChecker;
import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.interfaces.BgSourceInterface;
import info.nightscout.androidaps.interfaces.Constraint;
import info.nightscout.androidaps.interfaces.ConstraintsInterface; import info.nightscout.androidaps.interfaces.ConstraintsInterface;
import info.nightscout.androidaps.interfaces.PluginBase; import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.PluginDescription;
import info.nightscout.androidaps.interfaces.PluginType;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.OpenAPSAMA.OpenAPSAMAPlugin;
import info.nightscout.androidaps.plugins.OpenAPSMA.OpenAPSMAPlugin;
import info.nightscout.androidaps.plugins.OpenAPSSMB.OpenAPSSMBPlugin;
import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification;
import info.nightscout.androidaps.plugins.Overview.notifications.Notification;
import info.nightscout.utils.DecimalFormatter;
import info.nightscout.utils.HardLimits; import info.nightscout.utils.HardLimits;
import info.nightscout.utils.Round; import info.nightscout.utils.Round;
import info.nightscout.utils.SP; import info.nightscout.utils.SP;
@ -21,8 +24,7 @@ import info.nightscout.utils.SP;
/** /**
* Created by mike on 05.08.2016. * Created by mike on 05.08.2016.
*/ */
public class SafetyPlugin implements PluginBase, ConstraintsInterface { public class SafetyPlugin extends PluginBase implements ConstraintsInterface {
private static Logger log = LoggerFactory.getLogger(SafetyPlugin.class);
static SafetyPlugin plugin = null; static SafetyPlugin plugin = null;
@ -32,196 +34,154 @@ public class SafetyPlugin implements PluginBase, ConstraintsInterface {
return plugin; return plugin;
} }
@Override public SafetyPlugin() {
public String getFragmentClass() { super(new PluginDescription()
return null; .mainType(PluginType.CONSTRAINTS)
} .neverVisible(true)
.alwaysEnabled(true)
@Override .showInList(false)
public int getType() { .pluginName(R.string.safety)
return PluginBase.CONSTRAINTS; .preferencesId(R.xml.pref_safety)
} );
@Override
public String getName() {
return MainApp.instance().getString(R.string.safety);
}
@Override
public String getNameShort() {
// use long name as fallback (no tabs)
return getName();
}
@Override
public boolean isEnabled(int type) {
return type == CONSTRAINTS;
}
@Override
public boolean isVisibleInTabs(int type) {
return false;
}
@Override
public boolean canBeHidden(int type) {
return true;
}
@Override
public boolean hasFragment() {
return false;
}
@Override
public boolean showInList(int type) {
return false;
}
@Override
public void setFragmentEnabled(int type, boolean fragmentEnabled) {
}
@Override
public void setFragmentVisible(int type, boolean fragmentVisible) {
}
@Override
public int getPreferencesId() {
return R.xml.pref_safety;
}
@Override
public boolean isLoopEnabled() {
return ConfigBuilderPlugin.getActivePump().getPumpDescription().isTempBasalCapable;
} }
/** /**
* Constraints interface * Constraints interface
**/ **/
@Override @Override
public boolean isClosedModeEnabled() { public Constraint<Boolean> isLoopInvokationAllowed(Constraint<Boolean> value) {
if (!ConfigBuilderPlugin.getActivePump().getPumpDescription().isTempBasalCapable)
value.set(false, MainApp.gs(R.string.pumpisnottempbasalcapable), this);
return value;
}
@Override
public Constraint<Boolean> isClosedLoopAllowed(Constraint<Boolean> value) {
String mode = SP.getString("aps_mode", "open"); String mode = SP.getString("aps_mode", "open");
return mode.equals("closed") && BuildConfig.CLOSEDLOOP; if (!mode.equals("closed"))
value.set(false, MainApp.gs(R.string.closedmodedisabledinpreferences), this);
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));
}
value.set(false, MainApp.gs(R.string.closed_loop_disabled_on_dev_branch), this);
}
return value;
} }
@Override @Override
public boolean isAutosensModeEnabled() { public Constraint<Boolean> isAutosensModeEnabled(Constraint<Boolean> value) {
return true; boolean enabled = SP.getBoolean(R.string.key_openapsama_useautosens, false);
if (!enabled)
value.set(false, MainApp.gs(R.string.autosensdisabledinpreferences), this);
return value;
} }
@Override @Override
public boolean isAMAModeEnabled() { public Constraint<Boolean> isSMBModeEnabled(Constraint<Boolean> value) {
return true; boolean enabled = SP.getBoolean(R.string.key_use_smb, false);
if (!enabled)
value.set(false, MainApp.gs(R.string.smbdisabledinpreferences), this);
ConstraintChecker constraintChecker = MainApp.getConstraintChecker();
Constraint<Boolean> closedLoop = constraintChecker.isClosedLoopAllowed();
if (!closedLoop.value())
value.set(false, MainApp.gs(R.string.smbnotallowedinopenloopmode), this);
return value;
} }
@Override @Override
public Double applyBasalConstraints(Double absoluteRate) { public Constraint<Boolean> isAdvancedFilteringEnabled(Constraint<Boolean> value) {
Double origAbsoluteRate = absoluteRate; BgSourceInterface bgSource = MainApp.getConfigBuilder().getActiveBgSource();
Double maxBasal = SP.getDouble("openapsma_max_basal", 1d);
Profile profile = MainApp.getConfigBuilder().getProfile(); if (bgSource != null) {
if (profile == null) return absoluteRate; if (!bgSource.advancedFilteringSupported())
if (absoluteRate < 0) absoluteRate = 0d; value.set(false, MainApp.gs(R.string.smbalwaysdisabled), this);
}
return value;
}
@Override
public Constraint<Double> applyBasalConstraints(Constraint<Double> absoluteRate, Profile profile) {
absoluteRate.setIfGreater(0d, String.format(MainApp.gs(R.string.limitingbasalratio), 0d, MainApp.gs(R.string.itmustbepositivevalue)), this);
double maxBasal = SP.getDouble(R.string.key_openapsma_max_basal, 1d);
absoluteRate.setIfSmaller(maxBasal, String.format(MainApp.gs(R.string.limitingbasalratio), maxBasal, MainApp.gs(R.string.maxvalueinpreferences)), this);
Integer maxBasalMult = SP.getInt("openapsama_current_basal_safety_multiplier", 4);
Integer maxBasalFromDaily = SP.getInt("openapsama_max_daily_safety_multiplier", 3);
// Check percentRate but absolute rate too, because we know real current basal in pump // Check percentRate but absolute rate too, because we know real current basal in pump
Double origRate = absoluteRate; Double maxBasalMult = SP.getDouble(R.string.key_openapsama_current_basal_safety_multiplier, 4d);
if (absoluteRate > maxBasal) { double maxFromBasalMult = Math.floor(maxBasalMult * profile.getBasal() * 100) / 100;
absoluteRate = maxBasal; absoluteRate.setIfSmaller(maxFromBasalMult, String.format(MainApp.gs(R.string.limitingbasalratio), maxFromBasalMult, MainApp.gs(R.string.maxbasalmultiplier)), this);
if (Config.logConstraintsChanges && origAbsoluteRate != Constants.basalAbsoluteOnlyForCheckLimit)
log.debug("Limiting rate " + origRate + " by maxBasal preference to " + absoluteRate + "U/h"); Double maxBasalFromDaily = SP.getDouble(R.string.key_openapsama_max_daily_safety_multiplier, 3d);
} double maxFromDaily = Math.floor(profile.getMaxDailyBasal() * maxBasalFromDaily * 100) / 100;
if (absoluteRate > maxBasalMult * profile.getBasal()) { absoluteRate.setIfSmaller(maxFromDaily, String.format(MainApp.gs(R.string.limitingbasalratio), maxFromDaily, MainApp.gs(R.string.maxdailybasalmultiplier)), this);
absoluteRate = Math.floor(maxBasalMult * profile.getBasal() * 100) / 100;
if (Config.logConstraintsChanges && origAbsoluteRate != Constants.basalAbsoluteOnlyForCheckLimit) absoluteRate.setIfSmaller(HardLimits.maxBasal(), String.format(MainApp.gs(R.string.limitingbasalratio), HardLimits.maxBasal(), MainApp.gs(R.string.hardlimit)), this);
log.debug("Limiting rate " + origRate + " by maxBasalMult to " + absoluteRate + "U/h");
}
if (absoluteRate > profile.getMaxDailyBasal() * maxBasalFromDaily) {
absoluteRate = profile.getMaxDailyBasal() * maxBasalFromDaily;
if (Config.logConstraintsChanges && origAbsoluteRate != Constants.basalAbsoluteOnlyForCheckLimit)
log.debug("Limiting rate " + origRate + " by 3 * maxDailyBasal to " + absoluteRate + "U/h");
}
return absoluteRate; return absoluteRate;
} }
@Override @Override
public Integer applyBasalConstraints(Integer percentRate) { public Constraint<Integer> applyBasalPercentConstraints(Constraint<Integer> percentRate, Profile profile) {
Integer origPercentRate = percentRate;
Double maxBasal = SP.getDouble("openapsma_max_basal", 1d);
Profile profile = MainApp.getConfigBuilder().getProfile();
if (profile == null) return percentRate;
Double currentBasal = profile.getBasal(); Double currentBasal = profile.getBasal();
Double absoluteRate = currentBasal * ((double) percentRate.originalValue() / 100);
Double absoluteRate = currentBasal * ((double) percentRate / 100); percentRate.addReason("Percent rate " + percentRate.originalValue() + "% recalculated to " + DecimalFormatter.to2Decimal(absoluteRate) + " U/h with current basal " + DecimalFormatter.to2Decimal(currentBasal) + " U/h", this);
if (Config.logConstraintsChanges) Constraint<Double> absoluteConstraint = new Constraint<>(absoluteRate);
log.debug("Percent rate " + percentRate + "% recalculated to " + absoluteRate + "U/h with current basal " + currentBasal + "U/h"); applyBasalConstraints(absoluteConstraint, profile);
percentRate.copyReasons(absoluteConstraint);
if (absoluteRate < 0) absoluteRate = 0d; Integer percentRateAfterConst = Double.valueOf(absoluteConstraint.value() / currentBasal * 100).intValue();
Integer maxBasalMult = SP.getInt("openapsama_current_basal_safety_multiplier", 4);
Integer maxBasalFromDaily = SP.getInt("openapsama_max_daily_safety_multiplier", 3);
// Check percentRate but absolute rate too, because we know real current basal in pump
Double origRate = absoluteRate;
if (absoluteRate > maxBasal) {
absoluteRate = maxBasal;
if (Config.logConstraintsChanges && !Objects.equals(origPercentRate, Constants.basalPercentOnlyForCheckLimit))
log.debug("Limiting rate " + origRate + " by maxBasal preference to " + absoluteRate + "U/h");
}
if (absoluteRate > maxBasalMult * profile.getBasal()) {
absoluteRate = Math.floor(maxBasalMult * profile.getBasal() * 100) / 100;
if (Config.logConstraintsChanges && !Objects.equals(origPercentRate, Constants.basalPercentOnlyForCheckLimit))
log.debug("Limiting rate " + origRate + " by maxBasalMult to " + absoluteRate + "U/h");
}
if (absoluteRate > profile.getMaxDailyBasal() * maxBasalFromDaily) {
absoluteRate = profile.getMaxDailyBasal() * maxBasalFromDaily;
if (Config.logConstraintsChanges && !Objects.equals(origPercentRate, Constants.basalPercentOnlyForCheckLimit))
log.debug("Limiting rate " + origRate + " by 3 * maxDailyBasal to " + absoluteRate + "U/h");
}
Integer percentRateAfterConst = new Double(absoluteRate / currentBasal * 100).intValue();
if (percentRateAfterConst < 100) if (percentRateAfterConst < 100)
percentRateAfterConst = Round.ceilTo((double) percentRateAfterConst, 10d).intValue(); percentRateAfterConst = Round.ceilTo((double) percentRateAfterConst, 10d).intValue();
else percentRateAfterConst = Round.floorTo((double) percentRateAfterConst, 10d).intValue(); else percentRateAfterConst = Round.floorTo((double) percentRateAfterConst, 10d).intValue();
if (Config.logConstraintsChanges && !Objects.equals(origPercentRate, Constants.basalPercentOnlyForCheckLimit)) percentRate.set(percentRateAfterConst, String.format(MainApp.gs(R.string.limitingpercentrate), percentRateAfterConst, MainApp.gs(R.string.pumplimit)), this);
log.debug("Recalculated percent rate " + percentRate + "% to " + percentRateAfterConst + "%");
return percentRateAfterConst; return percentRate;
} }
@Override @Override
public Double applyBolusConstraints(Double insulin) { public Constraint<Double> applyBolusConstraints(Constraint<Double> insulin) {
try { insulin.setIfGreater(0d, String.format(MainApp.gs(R.string.limitingbolus), 0d, MainApp.gs(R.string.itmustbepositivevalue)), this);
Double maxBolus = SP.getDouble("treatmentssafety_maxbolus", 3d);
if (insulin < 0) insulin = 0d; Double maxBolus = SP.getDouble(R.string.key_treatmentssafety_maxbolus, 3d);
if (insulin > maxBolus) insulin = maxBolus; insulin.setIfSmaller(maxBolus, String.format(MainApp.gs(R.string.limitingbolus), maxBolus, MainApp.gs(R.string.maxvalueinpreferences)), this);
} catch (Exception e) {
insulin = 0d; insulin.setIfSmaller(HardLimits.maxBolus(), String.format(MainApp.gs(R.string.limitingbolus), HardLimits.maxBolus(), MainApp.gs(R.string.hardlimit)), this);
}
if (insulin > HardLimits.maxBolus()) insulin = HardLimits.maxBolus();
return insulin; return insulin;
} }
@Override @Override
public Integer applyCarbsConstraints(Integer carbs) { public Constraint<Integer> applyCarbsConstraints(Constraint<Integer> carbs) {
try { carbs.setIfGreater(0, String.format(MainApp.gs(R.string.limitingcarbs), 0, MainApp.gs(R.string.itmustbepositivevalue)), this);
Integer maxCarbs = SP.getInt("treatmentssafety_maxcarbs", 48);
Integer maxCarbs = SP.getInt(R.string.key_treatmentssafety_maxcarbs, 48);
carbs.setIfSmaller(maxCarbs, String.format(MainApp.gs(R.string.limitingcarbs), maxCarbs, MainApp.gs(R.string.maxvalueinpreferences)), this);
if (carbs < 0) carbs = 0;
if (carbs > maxCarbs) carbs = maxCarbs;
} catch (Exception e) {
carbs = 0;
}
return carbs; return carbs;
} }
@Override @Override
public Double applyMaxIOBConstraints(Double maxIob) { public Constraint<Double> applyMaxIOBConstraints(Constraint<Double> maxIob) {
double maxIobPref;
if (OpenAPSSMBPlugin.getPlugin().isEnabled(PluginType.APS))
maxIobPref = SP.getDouble(R.string.key_openapssmb_max_iob, 3d);
else
maxIobPref = SP.getDouble(R.string.key_openapsma_max_iob, 1.5d);
maxIob.setIfSmaller(maxIobPref, String.format(MainApp.gs(R.string.limitingiob), maxIobPref, MainApp.gs(R.string.maxvalueinpreferences)), this);
if (OpenAPSMAPlugin.getPlugin().isEnabled(PluginType.APS))
maxIob.setIfSmaller(HardLimits.maxIobAMA(), String.format(MainApp.gs(R.string.limitingiob), HardLimits.maxIobAMA(), MainApp.gs(R.string.hardlimit)), this);
if (OpenAPSAMAPlugin.getPlugin().isEnabled(PluginType.APS))
maxIob.setIfSmaller(HardLimits.maxIobAMA(), String.format(MainApp.gs(R.string.limitingiob), HardLimits.maxIobAMA(), MainApp.gs(R.string.hardlimit)), this);
if (OpenAPSSMBPlugin.getPlugin().isEnabled(PluginType.APS))
maxIob.setIfSmaller(HardLimits.maxIobSMB(), String.format(MainApp.gs(R.string.limitingiob), HardLimits.maxIobSMB(), MainApp.gs(R.string.hardlimit)), this);
return maxIob; return maxIob;
} }

View file

@ -1,21 +1,22 @@
package info.nightscout.androidaps.db; package info.nightscout.androidaps.plugins.Food;
import com.j256.ormlite.field.DatabaseField; import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable; import com.j256.ormlite.table.DatabaseTable;
import org.slf4j.Logger; import org.json.JSONException;
import org.slf4j.LoggerFactory; import org.json.JSONObject;
import java.util.Objects; import java.util.Objects;
import info.nightscout.utils.JsonHelper;
/** /**
* Created by mike on 20.09.2017. * Created by mike on 20.09.2017.
*/ */
@DatabaseTable(tableName = Food.TABLE_FOODS)
@DatabaseTable(tableName = DatabaseHelper.DATABASE_FOODS)
public class Food { public class Food {
private static Logger log = LoggerFactory.getLogger(Food.class); static final String TABLE_FOODS = "Foods";
@DatabaseField(id = true) @DatabaseField(id = true)
public long key; public long key;
@ -60,10 +61,29 @@ public class Food {
@DatabaseField @DatabaseField
public int gi; // not used yet public int gi; // not used yet
public Food() { private Food() {
key = System.currentTimeMillis(); key = System.currentTimeMillis();
} }
public static Food createFromJson(JSONObject json) throws JSONException {
Food food = new Food();
if ("food".equals(JsonHelper.safeGetString(json, "type"))) {
food._id = JsonHelper.safeGetString(json, "_id");
food.category = JsonHelper.safeGetString(json, "category");
food.subcategory = JsonHelper.safeGetString(json, "subcategory");
food.name = JsonHelper.safeGetString(json, "name");
food.units = JsonHelper.safeGetString(json, "unit");
food.portion = JsonHelper.safeGetDouble(json, "portion");
food.carbs = JsonHelper.safeGetInt(json, "carbs");
food.gi = JsonHelper.safeGetInt(json, "gi");
food.energy = JsonHelper.safeGetInt(json, "energy");
food.protein = JsonHelper.safeGetInt(json, "protein");
food.fat = JsonHelper.safeGetInt(json, "fat");
}
return food;
}
public boolean isEqual(Food other) { public boolean isEqual(Food other) {
if (portion != other.portion) if (portion != other.portion)
return false; return false;
@ -104,4 +124,22 @@ public class Food {
units = other.units; units = other.units;
gi = other.gi; gi = other.gi;
} }
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("_id=" + _id + ";");
sb.append("isValid=" + isValid + ";");
sb.append("name=" + name + ";");
sb.append("category=" + category + ";");
sb.append("subcategory=" + subcategory + ";");
sb.append("portion=" + portion + ";");
sb.append("carbs=" + carbs + ";");
sb.append("protein=" + protein + ";");
sb.append("energy=" + energy + ";");
sb.append("units=" + units + ";");
sb.append("gi=" + gi + ";");
return sb.toString();
}
} }

View file

@ -18,7 +18,6 @@ import android.widget.EditText;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import com.crashlytics.android.Crashlytics;
import com.squareup.otto.Subscribe; import com.squareup.otto.Subscribe;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -27,12 +26,13 @@ import org.slf4j.LoggerFactory;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
import info.nightscout.androidaps.db.Food;
import info.nightscout.androidaps.events.EventFoodDatabaseChanged; import info.nightscout.androidaps.events.EventFoodDatabaseChanged;
import info.nightscout.androidaps.plugins.Common.SubscriberFragment; import info.nightscout.androidaps.plugins.Common.SubscriberFragment;
import info.nightscout.utils.FabricPrivacy;
import info.nightscout.utils.NSUpload; import info.nightscout.utils.NSUpload;
import info.nightscout.utils.SpinnerHelper; import info.nightscout.utils.SpinnerHelper;
@ -54,14 +54,13 @@ public class FoodFragment extends SubscriberFragment {
ArrayList<CharSequence> categories; ArrayList<CharSequence> categories;
ArrayList<CharSequence> subcategories; ArrayList<CharSequence> subcategories;
final String EMPTY = MainApp.sResources.getString(R.string.none); final String EMPTY = MainApp.gs(R.string.none);
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) { Bundle savedInstanceState) {
try { try {
View view = inflater.inflate(R.layout.food_fragment, container, false); View view = inflater.inflate(R.layout.food_fragment, container, false);
filter = (EditText) view.findViewById(R.id.food_filter); filter = (EditText) view.findViewById(R.id.food_filter);
clearFilter = (ImageView) view.findViewById(R.id.food_clearfilter); clearFilter = (ImageView) view.findViewById(R.id.food_clearfilter);
category = new SpinnerHelper(view.findViewById(R.id.food_category)); category = new SpinnerHelper(view.findViewById(R.id.food_category));
@ -122,7 +121,8 @@ public class FoodFragment extends SubscriberFragment {
} }
}); });
RecyclerViewAdapter adapter = new RecyclerViewAdapter(MainApp.getDbHelper().foodHelper.getFoodData()); RecyclerViewAdapter adapter = new RecyclerViewAdapter(MainApp
.getSpecificPlugin(FoodPlugin.class).getService().getFoodData());
recyclerView.setAdapter(adapter); recyclerView.setAdapter(adapter);
loadData(); loadData();
@ -131,7 +131,7 @@ public class FoodFragment extends SubscriberFragment {
filterData(); filterData();
return view; return view;
} catch (Exception e) { } catch (Exception e) {
Crashlytics.logException(e); FabricPrivacy.logException(e);
} }
return null; return null;
@ -145,21 +145,20 @@ public class FoodFragment extends SubscriberFragment {
} }
void loadData() { void loadData() {
unfiltered = MainApp.getDbHelper().foodHelper.getFoodData(); unfiltered = MainApp.getSpecificPlugin(FoodPlugin.class).getService().getFoodData();
} }
void fillCategories() { void fillCategories() {
categories = new ArrayList<>(); Set<CharSequence> catSet = new HashSet<>();
for (Food f : unfiltered) { for (Food f : unfiltered) {
if (f.category != null && !f.category.equals("")) if (f.category != null && !f.category.equals(""))
categories.add(f.category); catSet.add(f.category);
} }
// make it unique // make it unique
categories = new ArrayList<>(new HashSet<>(categories)); categories = new ArrayList<>(catSet);
categories.add(0, MainApp.gs(R.string.none));
categories.add(0, MainApp.sResources.getString(R.string.none));
ArrayAdapter<CharSequence> adapterCategories = new ArrayAdapter<>(getContext(), ArrayAdapter<CharSequence> adapterCategories = new ArrayAdapter<>(getContext(),
R.layout.spinner_centered, categories); R.layout.spinner_centered, categories);
@ -168,20 +167,20 @@ public class FoodFragment extends SubscriberFragment {
void fillSubcategories() { void fillSubcategories() {
String categoryFilter = category.getSelectedItem().toString(); String categoryFilter = category.getSelectedItem().toString();
subcategories = new ArrayList<>();
Set<CharSequence> subCatSet = new HashSet<>();
if (!categoryFilter.equals(EMPTY)) { if (!categoryFilter.equals(EMPTY)) {
for (Food f : unfiltered) { for (Food f : unfiltered) {
if (f.category != null && f.category.equals(categoryFilter)) if (f.category != null && f.category.equals(categoryFilter))
if (f.subcategory != null && !f.subcategory.equals("")) if (f.subcategory != null && !f.subcategory.equals(""))
subcategories.add(f.subcategory); subCatSet.add(f.subcategory);
} }
} }
// make it unique // make it unique
subcategories = new ArrayList<>(new HashSet<>(subcategories)); subcategories = new ArrayList<>(subCatSet);
subcategories.add(0, MainApp.gs(R.string.none));
subcategories.add(0, MainApp.sResources.getString(R.string.none));
ArrayAdapter<CharSequence> adapterSubcategories = new ArrayAdapter<>(getContext(), ArrayAdapter<CharSequence> adapterSubcategories = new ArrayAdapter<>(getContext(),
R.layout.spinner_centered, subcategories); R.layout.spinner_centered, subcategories);
@ -243,14 +242,14 @@ public class FoodFragment extends SubscriberFragment {
holder.ns.setVisibility(food._id != null ? View.VISIBLE : View.GONE); holder.ns.setVisibility(food._id != null ? View.VISIBLE : View.GONE);
holder.name.setText(food.name); holder.name.setText(food.name);
holder.portion.setText(food.portion + food.units); holder.portion.setText(food.portion + food.units);
holder.carbs.setText(food.carbs + MainApp.sResources.getString(R.string.shortgramm)); holder.carbs.setText(food.carbs + MainApp.gs(R.string.shortgramm));
holder.fat.setText(MainApp.sResources.getString(R.string.shortfat) + ": " + food.fat + MainApp.sResources.getString(R.string.shortgramm)); holder.fat.setText(MainApp.gs(R.string.shortfat) + ": " + food.fat + MainApp.gs(R.string.shortgramm));
if (food.fat == 0) if (food.fat == 0)
holder.fat.setVisibility(View.INVISIBLE); holder.fat.setVisibility(View.INVISIBLE);
holder.protein.setText(MainApp.sResources.getString(R.string.shortprotein) + ": " + food.protein + MainApp.sResources.getString(R.string.shortgramm)); holder.protein.setText(MainApp.gs(R.string.shortprotein) + ": " + food.protein + MainApp.gs(R.string.shortgramm));
if (food.protein == 0) if (food.protein == 0)
holder.protein.setVisibility(View.INVISIBLE); holder.protein.setVisibility(View.INVISIBLE);
holder.energy.setText(MainApp.sResources.getString(R.string.shortenergy) + ": " + food.energy + MainApp.sResources.getString(R.string.shortkilojoul)); holder.energy.setText(MainApp.gs(R.string.shortenergy) + ": " + food.energy + MainApp.gs(R.string.shortkilojoul));
if (food.energy == 0) if (food.energy == 0)
holder.energy.setVisibility(View.INVISIBLE); holder.energy.setVisibility(View.INVISIBLE);
holder.remove.setTag(food); holder.remove.setTag(food);
@ -292,18 +291,18 @@ public class FoodFragment extends SubscriberFragment {
case R.id.food_remove: case R.id.food_remove:
AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setTitle(MainApp.sResources.getString(R.string.confirmation)); builder.setTitle(MainApp.gs(R.string.confirmation));
builder.setMessage(MainApp.sResources.getString(R.string.removerecord) + "\n" + food.name); builder.setMessage(MainApp.gs(R.string.removerecord) + "\n" + food.name);
builder.setPositiveButton(MainApp.sResources.getString(R.string.ok), new DialogInterface.OnClickListener() { builder.setPositiveButton(MainApp.gs(R.string.ok), new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) { public void onClick(DialogInterface dialog, int id) {
final String _id = food._id; final String _id = food._id;
if (_id != null && !_id.equals("")) { if (_id != null && !_id.equals("")) {
NSUpload.removeFoodFromNS(_id); NSUpload.removeFoodFromNS(_id);
} }
MainApp.getDbHelper().foodHelper.delete(food); MainApp.getSpecificPlugin(FoodPlugin.class).getService().delete(food);
} }
}); });
builder.setNegativeButton(MainApp.sResources.getString(R.string.cancel), null); builder.setNegativeButton(MainApp.gs(R.string.cancel), null);
builder.show(); builder.show();
break; break;

View file

@ -1,15 +1,14 @@
package info.nightscout.androidaps.plugins.Food; package info.nightscout.androidaps.plugins.Food;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
import info.nightscout.androidaps.interfaces.PluginBase; import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.PluginDescription;
import info.nightscout.androidaps.interfaces.PluginType;
/** /**
* Created by mike on 05.08.2016. * Created by mike on 05.08.2016.
*/ */
public class FoodPlugin implements PluginBase { public class FoodPlugin extends PluginBase {
private boolean fragmentEnabled = true;
private boolean fragmentVisible = false;
private static FoodPlugin plugin = null; private static FoodPlugin plugin = null;
@ -19,67 +18,20 @@ public class FoodPlugin implements PluginBase {
return plugin; return plugin;
} }
@Override private FoodService service;
public String getFragmentClass() {
return FoodFragment.class.getName(); private FoodPlugin() {
super(new PluginDescription()
.mainType(PluginType.GENERAL)
.fragmentClass(FoodFragment.class.getName())
.pluginName(R.string.food)
.shortName(R.string.food_short)
);
this.service = new FoodService();
} }
@Override public FoodService getService() {
public int getType() { return this.service;
return PluginBase.GENERAL;
} }
@Override
public String getName() {
return MainApp.instance().getString(R.string.food);
}
@Override
public String getNameShort() {
// use long name as fallback (not visible in tabs)
return getName();
}
@Override
public boolean isEnabled(int type) {
return type == GENERAL && fragmentEnabled;
}
@Override
public boolean isVisibleInTabs(int type) {
return type == GENERAL && fragmentVisible;
}
@Override
public boolean canBeHidden(int type) {
return true;
}
@Override
public boolean hasFragment() {
return true;
}
@Override
public boolean showInList(int type) {
return true;
}
@Override
public void setFragmentEnabled(int type, boolean fragmentEnabled) {
if (type == GENERAL) this.fragmentEnabled = fragmentEnabled;
}
@Override
public void setFragmentVisible(int type, boolean fragmentVisible) {
if (type == GENERAL) this.fragmentVisible = fragmentVisible;
}
@Override
public int getPreferencesId() {
return -1;
}
} }

View file

@ -0,0 +1,369 @@
package info.nightscout.androidaps.plugins.Food;
import android.content.Intent;
import android.os.Bundle;
import android.os.IBinder;
import android.support.annotation.Nullable;
import com.j256.ormlite.android.apptools.OpenHelperManager;
import com.j256.ormlite.android.apptools.OrmLiteBaseService;
import com.j256.ormlite.dao.Dao;
import com.j256.ormlite.dao.DaoManager;
import com.j256.ormlite.support.ConnectionSource;
import com.j256.ormlite.table.TableUtils;
import com.squareup.otto.Subscribe;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.db.DatabaseHelper;
import info.nightscout.androidaps.db.ICallback;
import info.nightscout.androidaps.events.Event;
import info.nightscout.androidaps.events.EventFoodDatabaseChanged;
import info.nightscout.androidaps.events.EventNsFood;
/**
* Created by mike on 24.09.2017.
*/
public class FoodService extends OrmLiteBaseService<DatabaseHelper> {
private static Logger log = LoggerFactory.getLogger(FoodService.class);
private static final ScheduledExecutorService foodEventWorker = Executors.newSingleThreadScheduledExecutor();
private static ScheduledFuture<?> scheduledFoodEventPost = null;
public FoodService() {
onCreate();
dbInitialize();
MainApp.bus().register(this);
}
/**
* This method is a simple re-implementation of the database create and up/downgrade functionality
* in SQLiteOpenHelper#getDatabaseLocked method.
* <p>
* It is implemented to be able to late initialize separate plugins of the application.
*/
protected void dbInitialize() {
DatabaseHelper helper = OpenHelperManager.getHelper(this, DatabaseHelper.class);
int newVersion = helper.getNewVersion();
int oldVersion = helper.getOldVersion();
if (oldVersion > newVersion) {
onDowngrade(this.getConnectionSource(), oldVersion, newVersion);
} else {
onUpgrade(this.getConnectionSource(), oldVersion, newVersion);
}
}
public Dao<Food, Long> getDao() {
try {
return DaoManager.createDao(this.getConnectionSource(), Food.class);
} catch (SQLException e) {
log.error("Cannot create Dao for Food.class");
}
return null;
}
@Subscribe
public void handleNsEvent(EventNsFood event) {
int mode = event.getMode();
Bundle payload = event.getPayload();
try {
if (payload.containsKey("food")) {
JSONObject json = new JSONObject(payload.getString("food"));
if (mode == EventNsFood.ADD || mode == EventNsFood.UPDATE) {
this.createFoodFromJsonIfNotExists(json);
} else {
this.deleteNS(json);
}
}
if (payload.containsKey("foods")) {
JSONArray array = new JSONArray(payload.getString("foods"));
if (mode == EventNsFood.ADD || mode == EventNsFood.UPDATE) {
this.createFoodFromJsonIfNotExists(array);
} else {
this.deleteNS(array);
}
}
} catch (JSONException e) {
log.error("Unhandled Exception", e);
}
}
@Override
public void onCreate() {
super.onCreate();
try {
log.info("onCreate");
TableUtils.createTableIfNotExists(this.getConnectionSource(), Food.class);
} catch (SQLException e) {
log.error("Can't create database", e);
throw new RuntimeException(e);
}
}
public void onUpgrade(ConnectionSource connectionSource, int oldVersion, int newVersion) {
if (oldVersion == 7 && newVersion == 8) {
log.debug("Upgrading database from v7 to v8");
} else {
log.info("onUpgrade");
// this.resetFood();
}
}
public void onDowngrade(ConnectionSource connectionSource, int oldVersion, int newVersion) {
// this method is not supported right now
}
public void resetFood() {
try {
TableUtils.dropTable(this.getConnectionSource(), Food.class, true);
TableUtils.createTableIfNotExists(this.getConnectionSource(), Food.class);
} catch (SQLException e) {
log.error("Unhandled exception", e);
}
scheduleFoodChange();
}
/**
* A place to centrally register events to be posted, if any data changed.
* This should be implemented in an abstract service-class.
* <p>
* We do need to make sure, that ICallback is extended to be able to handle multiple
* events, or handle a list of events.
* <p>
* on some methods the earliestDataChange event is handled separatly, in that it is checked if it is
* set to null by another event already (eg. scheduleExtendedBolusChange).
*
* @param event
* @param eventWorker
* @param callback
*/
private void scheduleEvent(final Event event, ScheduledExecutorService eventWorker,
final ICallback callback) {
class PostRunnable implements Runnable {
public void run() {
log.debug("Firing EventFoodChange");
MainApp.bus().post(event);
callback.setPost(null);
}
}
// prepare task for execution in 1 sec
// cancel waiting task to prevent sending multiple posts
if (callback.getPost() != null)
callback.getPost().cancel(false);
Runnable task = new PostRunnable();
final int sec = 1;
callback.setPost(eventWorker.schedule(task, sec, TimeUnit.SECONDS));
}
/**
* Schedule a foodChange Event.
*/
public void scheduleFoodChange() {
this.scheduleEvent(new EventFoodDatabaseChanged(), foodEventWorker, new ICallback() {
@Override
public void setPost(ScheduledFuture<?> post) {
scheduledFoodEventPost = post;
}
@Override
public ScheduledFuture<?> getPost() {
return scheduledFoodEventPost;
}
});
}
public List<Food> getFoodData() {
try {
return this.getDao().queryForAll();
} catch (SQLException e) {
log.error("Unhandled exception", e);
}
return new ArrayList<>();
}
/*
{
"_id": "551ee3ad368e06e80856e6a9",
"type": "food",
"category": "Zakladni",
"subcategory": "Napoje",
"name": "Mleko",
"portion": 250,
"carbs": 12,
"gi": 1,
"created_at": "2015-04-14T06:59:16.500Z",
"unit": "ml"
}
*/
public void createFoodFromJsonIfNotExists(JSONObject json) {
try {
Food food = Food.createFromJson(json);
this.createFoodFromJsonIfNotExists(food);
} catch (JSONException e) {
log.error("Unhandled exception", e);
}
}
public void createFoodFromJsonIfNotExists(JSONArray array) {
try {
for (int n = 0; n < array.length(); n++) {
JSONObject json = array.getJSONObject(n);
Food food = Food.createFromJson(json);
this.createFoodFromJsonIfNotExists(food);
}
} catch (JSONException e) {
log.error("Unhandled exception", e);
}
}
public void createFoodFromJsonIfNotExists(Food food) {
this.createOrUpdateByNS(food);
}
public void deleteNS(JSONObject json) {
try {
String _id = json.getString("_id");
this.deleteByNSId(_id);
} catch (JSONException | SQLException e) {
log.error("Unhandled exception", e);
}
}
public void deleteNS(JSONArray array) {
try {
for (int n = 0; n < array.length(); n++) {
JSONObject json = array.getJSONObject(n);
this.deleteNS(json);
}
} catch (JSONException e) {
log.error("Unhandled exception", e);
}
}
/**
* deletes an entry by its NS Id.
* <p>
* Basically a convenience method for findByNSId and delete.
*
* @param _id
*/
public void deleteByNSId(String _id) throws SQLException {
Food stored = this.findByNSId(_id);
if (stored != null) {
log.debug("FOOD: Removing Food record from database: " + stored.toString());
this.delete(stored);
}
}
/**
* deletes the food and sends the foodChange Event
* <p>
* should be moved ot a Service
*
* @param food
*/
public void delete(Food food) {
try {
this.getDao().delete(food);
this.scheduleFoodChange();
} catch (SQLException e) {
log.error("Unhandled exception", e);
}
}
/**
* Create of update a food record by the NS (Nightscout) Id.
*
* @param food
* @return
*/
public boolean createOrUpdateByNS(Food food) {
// find by NS _id
if (food._id != null && !food._id.equals("")) {
Food old = this.findByNSId(food._id);
if (old != null) {
if (!old.isEqual(food)) {
this.delete(old); // need to delete/create because date may change too
old.copyFrom(food);
this.create(old);
return true;
} else {
return false;
}
} else {
this.createOrUpdate(food);
return true;
}
}
return false;
}
public void createOrUpdate(Food food) {
try {
this.getDao().createOrUpdate(food);
log.debug("FOOD: Created or Updated: " + food.toString());
} catch (SQLException e) {
log.error("Unable to createOrUpdate Food", e);
}
this.scheduleFoodChange();
}
public void create(Food food) {
try {
this.getDao().create(food);
log.debug("FOOD: New record: " + food.toString());
} catch (SQLException e) {
log.error("Unable to create Food", e);
}
this.scheduleFoodChange();
}
/**
* finds food by its NS Id.
*
* @param _id
* @return
*/
@Nullable
public Food findByNSId(String _id) {
try {
List<Food> list = this.getDao().queryForEq("_id", _id);
if (list.size() == 1) { // really? if there are more then one result, then we do not return anything...
return list.get(0);
}
} catch (SQLException e) {
log.error("Unhandled exception", e);
}
return null;
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
}

View file

@ -12,7 +12,7 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import info.nightscout.androidaps.data.Iob; import info.nightscout.androidaps.data.Iob;
import info.nightscout.androidaps.db.Treatment; import info.nightscout.androidaps.plugins.Treatments.Treatment;
import info.nightscout.androidaps.interfaces.InsulinInterface; import info.nightscout.androidaps.interfaces.InsulinInterface;
/** /**

View file

@ -1,136 +0,0 @@
package info.nightscout.androidaps.plugins.Insulin;
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.Iob;
import info.nightscout.androidaps.db.Treatment;
import info.nightscout.androidaps.interfaces.InsulinInterface;
import info.nightscout.androidaps.interfaces.PluginBase;
/**
* Created by mike on 17.04.2017.
*/
public class InsulinFastactingPlugin implements PluginBase, InsulinInterface {
private boolean fragmentEnabled = true;
private boolean fragmentVisible = false;
private static InsulinFastactingPlugin plugin = null;
public static InsulinFastactingPlugin getPlugin() {
if (plugin == null)
plugin = new InsulinFastactingPlugin();
return plugin;
}
@Override
public int getType() {
return INSULIN;
}
@Override
public String getFragmentClass() {
return InsulinFragment.class.getName();
}
@Override
public String getName() {
return MainApp.sResources.getString(R.string.fastactinginsulin);
}
@Override
public String getNameShort() {
return MainApp.sResources.getString(R.string.insulin_shortname);
}
@Override
public boolean isEnabled(int type) {
return type == INSULIN && fragmentEnabled;
}
@Override
public boolean isVisibleInTabs(int type) {
return type == INSULIN && fragmentVisible;
}
@Override
public boolean canBeHidden(int type) {
return true;
}
@Override
public boolean hasFragment() {
return true;
}
@Override
public boolean showInList(int type) {
return true;
}
@Override
public void setFragmentEnabled(int type, boolean fragmentEnabled) {
if (type == INSULIN) this.fragmentEnabled = fragmentEnabled;
}
@Override
public void setFragmentVisible(int type, boolean fragmentVisible) {
if (type == INSULIN) this.fragmentVisible = fragmentVisible;
}
@Override
public int getPreferencesId() {
return -1;
}
// Insulin interface
@Override
public int getId() {
return FASTACTINGINSULIN;
}
@Override
public String getFriendlyName() {
return MainApp.sResources.getString(R.string.fastactinginsulin);
}
@Override
public String getComment() {
return MainApp.sResources.getString(R.string.fastactinginsulincomment);
}
@Override
public double getDia() {
return MainApp.getConfigBuilder().getProfile() != null ? MainApp.getConfigBuilder().getProfile().getDia() : Constants.defaultDIA;
}
@Override
public Iob iobCalcForTreatment(Treatment treatment, long time, Double dia) {
Iob result = new Iob();
double scaleFactor = 3.0 / dia;
double peak = 75d;
double end = 180d;
if (treatment.insulin != 0d) {
long bolusTime = treatment.date;
double minAgo = scaleFactor * (time - bolusTime) / 1000d / 60d;
if (minAgo < peak) {
double x1 = minAgo / 5d + 1;
result.iobContrib = treatment.insulin * (1 - 0.001852 * x1 * x1 + 0.001852 * x1);
// units: BG (mg/dL) = (BG/U) * U insulin * scalar
result.activityContrib = treatment.insulin * (2 / dia / 60 / peak) * minAgo;
} else if (minAgo < end) {
double x2 = (minAgo - 75) / 5;
result.iobContrib = treatment.insulin * (0.001323 * x2 * x2 - 0.054233 * x2 + 0.55556);
result.activityContrib = treatment.insulin * (2 / dia / 60 - (minAgo - peak) * 2 / dia / 60 / (60 * 3 - peak));
}
}
return result;
}
}

View file

@ -1,141 +0,0 @@
package info.nightscout.androidaps.plugins.Insulin;
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.Iob;
import info.nightscout.androidaps.db.Treatment;
import info.nightscout.androidaps.interfaces.InsulinInterface;
import info.nightscout.androidaps.interfaces.PluginBase;
/**
* Created by mike on 17.04.2017.
*/
public class InsulinFastactingProlongedPlugin implements PluginBase, InsulinInterface {
private boolean fragmentEnabled = false;
private boolean fragmentVisible = false;
private static InsulinFastactingProlongedPlugin plugin = null;
public static InsulinFastactingProlongedPlugin getPlugin() {
if (plugin == null)
plugin = new InsulinFastactingProlongedPlugin();
return plugin;
}
@Override
public int getType() {
return INSULIN;
}
@Override
public String getFragmentClass() {
return InsulinFragment.class.getName();
}
@Override
public String getName() {
return MainApp.sResources.getString(R.string.fastactinginsulinprolonged);
}
@Override
public String getNameShort() {
return MainApp.sResources.getString(R.string.insulin_shortname);
}
@Override
public boolean isEnabled(int type) {
return type == INSULIN && fragmentEnabled;
}
@Override
public boolean isVisibleInTabs(int type) {
return type == INSULIN && fragmentVisible;
}
@Override
public boolean canBeHidden(int type) {
return true;
}
@Override
public boolean hasFragment() {
return true;
}
@Override
public boolean showInList(int type) {
return true;
}
@Override
public void setFragmentEnabled(int type, boolean fragmentEnabled) {
if (type == INSULIN) this.fragmentEnabled = fragmentEnabled;
}
@Override
public void setFragmentVisible(int type, boolean fragmentVisible) {
if (type == INSULIN) this.fragmentVisible = fragmentVisible;
}
@Override
public int getPreferencesId() {
return -1;
}
// Insulin interface
@Override
public int getId() {
return FASTACTINGINSULINPROLONGED;
}
@Override
public String getFriendlyName() {
return MainApp.sResources.getString(R.string.fastactinginsulinprolonged);
}
@Override
public String getComment() {
return MainApp.sResources.getString(R.string.fastactinginsulincomment);
}
@Override
public double getDia() {
return MainApp.getConfigBuilder().getProfile() != null ? MainApp.getConfigBuilder().getProfile().getDia() : Constants.defaultDIA;
}
@Override
public Iob iobCalcForTreatment(Treatment treatment, long time, Double dia) {
Iob result = new Iob();
//Double scaleFactor = 3.0 / dia;
double peak = 75d * dia / 6.0;
double tail = 180d * dia / 6.0;
double end = 360d * dia / 6.0;
double Total = 2 * peak + (tail - peak) * 5 / 2 + (end - tail) / 2;
if (treatment.insulin != 0d) {
long bolusTime = treatment.date;
double minAgo = (time - bolusTime) / 1000d / 60d;
if (minAgo < peak) {
double x1 = 6 / dia * minAgo / 5d + 1;
result.iobContrib = treatment.insulin * (1 - 0.0012595 * x1 * x1 + 0.0012595 * x1);
// units: BG (mg/dL) = (BG/U) * U insulin * scalar
result.activityContrib = treatment.insulin * ((2 * peak / Total) * 2 / peak / peak * minAgo);
} else if (minAgo < tail) {
double x2 = (6 / dia * (minAgo - peak)) / 5;
result.iobContrib = treatment.insulin * (0.00074 * x2 * x2 - 0.0403 * x2 + 0.69772);
result.activityContrib = treatment.insulin * (-((2 * peak / Total) * 2 / peak * 3 / 4) / (tail - peak) * (minAgo - peak) + (2 * peak / Total) * 2 / peak);
} else if (minAgo < end) {
double x3 = (6 / dia * (minAgo - tail)) / 5;
result.iobContrib = treatment.insulin * (0.0001323 * x3 * x3 - 0.0097 * x3 + 0.17776);
result.activityContrib = treatment.insulin * (-((2 * peak / Total) * 2 / peak * 1 / 4) / (end - tail) * (minAgo - tail) + (2 * peak / Total) * 2 / peak / 4);
}
}
return result;
}
}

View file

@ -7,11 +7,11 @@ import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.TextView; import android.widget.TextView;
import com.crashlytics.android.Crashlytics;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.utils.FabricPrivacy;
/** /**
* Created by mike on 17.04.2017. * Created by mike on 17.04.2017.
@ -37,7 +37,7 @@ public class InsulinFragment extends Fragment {
return view; return view;
} catch (Exception e) { } catch (Exception e) {
Crashlytics.logException(e); FabricPrivacy.logException(e);
} }
return null; return null;

View file

@ -1,81 +1,84 @@
package info.nightscout.androidaps.plugins.Insulin; package info.nightscout.androidaps.plugins.Insulin;
import com.squareup.otto.Bus;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.Iob; import info.nightscout.androidaps.data.Iob;
import info.nightscout.androidaps.db.Treatment; import info.nightscout.androidaps.plugins.Treatments.Treatment;
import info.nightscout.androidaps.interfaces.InsulinInterface; import info.nightscout.androidaps.interfaces.InsulinInterface;
import info.nightscout.androidaps.interfaces.PluginBase; import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.plugins.Overview.notifications.Notification; import info.nightscout.androidaps.interfaces.PluginDescription;
import info.nightscout.androidaps.interfaces.PluginType;
import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification; import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification;
import info.nightscout.androidaps.plugins.Overview.notifications.Notification;
/** /**
* Created by adrian on 13.08.2017. * Created by adrian on 13.08.2017.
*/ */
public abstract class InsulinOrefBasePlugin implements PluginBase, InsulinInterface { public abstract class InsulinOrefBasePlugin extends PluginBase implements InsulinInterface {
public static double MIN_DIA = 5; public static double MIN_DIA = 5;
long lastWarned = 0; long lastWarned = 0;
@Override public InsulinOrefBasePlugin() {
public int getType() { super(new PluginDescription()
return INSULIN; .mainType(PluginType.INSULIN)
.fragmentClass(InsulinFragment.class.getName())
.pluginName(R.string.fastactinginsulin)
.shortName(R.string.insulin_shortname)
);
} }
@Override public Bus getBus() {
public String getNameShort() { return MainApp.bus();
return MainApp.sResources.getString(R.string.insulin_shortname);
}
@Override
public boolean canBeHidden(int type) {
return true;
}
@Override
public boolean hasFragment() {
return true;
}
@Override
public boolean showInList(int type) {
return true;
} }
@Override @Override
public double getDia() { public double getDia() {
double dia = getUserDefinedDia(); double dia = getUserDefinedDia();
if(dia >= MIN_DIA){ if (dia >= MIN_DIA) {
return dia; return dia;
} else { } else {
if((System.currentTimeMillis() - lastWarned) > 60*1000) { sendShortDiaNotification(dia);
lastWarned = System.currentTimeMillis();
Notification notification = new Notification(Notification.SHORT_DIA, String.format(MainApp.sResources.getString(R.string.dia_too_short), dia, MIN_DIA), Notification.URGENT);
MainApp.bus().post(new EventNewNotification(notification));
}
return MIN_DIA; return MIN_DIA;
} }
} }
void sendShortDiaNotification(double dia) {
if ((System.currentTimeMillis() - lastWarned) > 60 * 1000) {
lastWarned = System.currentTimeMillis();
Notification notification = new Notification(Notification.SHORT_DIA, String.format(this.getNotificationPattern(), dia, MIN_DIA), Notification.URGENT);
this.getBus().post(new EventNewNotification(notification));
}
}
public String getNotificationPattern() {
return MainApp.gs(R.string.dia_too_short);
}
public double getUserDefinedDia() { public double getUserDefinedDia() {
return MainApp.getConfigBuilder().getProfile() != null ? MainApp.getConfigBuilder().getProfile().getDia() : MIN_DIA; return MainApp.getConfigBuilder().getProfile() != null ? MainApp.getConfigBuilder().getProfile().getDia() : MIN_DIA;
} }
public Iob iobCalcForTreatment(Treatment treatment, long time) {
return this.iobCalcForTreatment(treatment, time, 0d);
}
@Override @Override
public Iob iobCalcForTreatment(Treatment treatment, long time, Double dia) { public Iob iobCalcForTreatment(Treatment treatment, long time, double dia) {
Iob result = new Iob(); Iob result = new Iob();
int peak = getPeak(); int peak = getPeak();
if (treatment.insulin != 0d) { if (treatment.insulin != 0d) {
long bolusTime = treatment.date; long bolusTime = treatment.date;
double t = (time - bolusTime) / 1000d / 60d; double t = (time - bolusTime) / 1000d / 60d;
double td = getDia()*60; //getDIA() always > 5 double td = getDia() * 60; //getDIA() always >= MIN_DIA
double tp = peak; double tp = peak;
// force the IOB to 0 if over DIA hours have passed // force the IOB to 0 if over DIA hours have passed
@ -92,10 +95,10 @@ public abstract class InsulinOrefBasePlugin implements PluginBase, InsulinInterf
@Override @Override
public String getComment() { public String getComment() {
String comment = commentStandardText(); String comment = commentStandardText();
double userDia = getUserDefinedDia(); double userDia = getUserDefinedDia();
if(userDia < MIN_DIA){ if (userDia < MIN_DIA) {
comment += "\n" + String.format(MainApp.sResources.getString(R.string.dia_too_short), userDia, MIN_DIA); comment += "\n" + String.format(MainApp.gs(R.string.dia_too_short), userDia, MIN_DIA);
} }
return comment; return comment;
} }

View file

@ -10,9 +10,6 @@ import info.nightscout.utils.SP;
public class InsulinOrefFreePeakPlugin extends InsulinOrefBasePlugin { public class InsulinOrefFreePeakPlugin extends InsulinOrefBasePlugin {
private boolean fragmentEnabled = false;
private boolean fragmentVisible = false;
private static InsulinOrefFreePeakPlugin plugin = null; private static InsulinOrefFreePeakPlugin plugin = null;
public static InsulinOrefFreePeakPlugin getPlugin() { public static InsulinOrefFreePeakPlugin getPlugin() {
@ -21,56 +18,27 @@ public class InsulinOrefFreePeakPlugin extends InsulinOrefBasePlugin {
return plugin; return plugin;
} }
public static final int DEFAULT_PEAK = 75; private static final int DEFAULT_PEAK = 75;
private InsulinOrefFreePeakPlugin() {
super();
pluginDescription
.pluginName(R.string.free_peak_oref)
.preferencesId(R.xml.pref_insulinoreffreepeak);
}
@Override @Override
public int getId() { public int getId() {
return OREF_FREE_PEAK; return OREF_FREE_PEAK;
} }
@Override
public String getName() {
return MainApp.sResources.getString(R.string.free_peak_oref);
}
@Override
public String getFragmentClass() {
return InsulinFragment.class.getName();
}
@Override
public String getFriendlyName() { public String getFriendlyName() {
return MainApp.sResources.getString(R.string.free_peak_oref); return MainApp.gs(R.string.free_peak_oref);
} }
@Override @Override
public String commentStandardText() { public String commentStandardText() {
return MainApp.sResources.getString(R.string.insulin_peak_time) + ": " + getPeak(); return MainApp.gs(R.string.insulin_peak_time) + ": " + getPeak();
}
@Override
public boolean isEnabled(int type) {
return type == INSULIN && fragmentEnabled;
}
@Override
public boolean isVisibleInTabs(int type) {
return type == INSULIN && fragmentVisible;
}
@Override
public void setFragmentEnabled(int type, boolean fragmentEnabled) {
if (type == INSULIN) this.fragmentEnabled = fragmentEnabled;
}
@Override
public void setFragmentVisible(int type, boolean fragmentVisible) {
if (type == INSULIN) this.fragmentVisible = fragmentVisible;
}
@Override
public int getPreferencesId() {
return R.xml.pref_insulinoreffreepeak;
} }
@Override @Override

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