Merge pull request #1 from MilosKozak/dev

Dev
This commit is contained in:
Andreas 2018-11-05 11:24:57 +01:00 committed by GitHub
commit 05fa1f4f87
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
825 changed files with 118199 additions and 20318 deletions

2
.gitignore vendored
View file

@ -11,3 +11,5 @@ app/src/main/jniLibs
full/ full/
debug/ debug/
release/ release/
app/com.crashlytics.settings.json
app/session_analytics.tap

View file

@ -5,7 +5,10 @@
[![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)
[![Crowdin](https://d322cqt584bo4o.cloudfront.net/androidaps/localized.svg)](https://translations.androidaps.org/project/androidaps)
[![Documentation Status](https://readthedocs.org/projects/androidaps/badge/?version=latest)](https://androidaps.readthedocs.io/en/latest/?badge=latest)
[![codecov](https://codecov.io/gh/MilosKozak/AndroidAPS/branch/master/graph/badge.svg)](https://codecov.io/gh/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) dev: [![codecov](https://codecov.io/gh/MilosKozak/AndroidAPS/branch/dev/graph/badge.svg)](https://codecov.io/gh/MilosKozak/AndroidAPS)
[![Donate via PayPal](https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=Y4LHGJJESAVB8) [![Donate via PayPal](https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=Y4LHGJJESAVB8)

View file

@ -29,9 +29,7 @@ repositories {
} }
def generateGitBuild = { -> def generateGitBuild = { ->
StringBuilder stringBuilder = new StringBuilder(); StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append('"')
try { try {
def stdout = new ByteArrayOutputStream() def stdout = new ByteArrayOutputStream()
exec { exec {
@ -43,9 +41,12 @@ def generateGitBuild = { ->
} catch (ignored) { } catch (ignored) {
stringBuilder.append('NoGitSystemAvailable') stringBuilder.append('NoGitSystemAvailable')
} }
stringBuilder.append('-') return stringBuilder.toString()
}
def generateDate = { ->
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append((new Date()).format('yyyy.MM.dd-HH:mm')) stringBuilder.append((new Date()).format('yyyy.MM.dd-HH:mm'))
stringBuilder.append('"')
return stringBuilder.toString() return stringBuilder.toString()
} }
@ -58,14 +59,14 @@ android {
compileSdkVersion 27 compileSdkVersion 27
defaultConfig { defaultConfig {
applicationId "info.nightscout.androidaps"
minSdkVersion 21 minSdkVersion 21
targetSdkVersion 25 targetSdkVersion 25
multiDexEnabled true multiDexEnabled true
versionCode 1500 versionCode 1500
version "1.60e-dev" version "2.0i-dev"
buildConfigField "String", "VERSION", '"' + version + '"' buildConfigField "String", "VERSION", '"' + version + '"'
buildConfigField "String", "BUILDVERSION", generateGitBuild() buildConfigField "String", "BUILDVERSION", '"' + generateGitBuild() + '-' + generateDate() + '"'
buildConfigField "String", "HEAD", '"' + generateGitBuild() + '"'
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
ndk { ndk {
@ -95,56 +96,44 @@ android {
productFlavors { productFlavors {
flavorDimensions "standard" flavorDimensions "standard"
full { full {
applicationId "info.nightscout.androidaps"
dimension "standard" dimension "standard"
resValue "string", "app_name", "AndroidAPS" resValue "string", "app_name", "AndroidAPS"
versionName version versionName version
manifestPlaceholders = [ manifestPlaceholders = [
appIcon: "@mipmap/blueowl" appIcon: "@mipmap/ic_launcher",
appIconRound: "@mipmap/ic_launcher_round"
] ]
buildConfigField "boolean", "APS", "true"
buildConfigField "boolean", "PUMPDRIVERS", "true"
buildConfigField "boolean", "NSCLIENTOLNY", "false"
buildConfigField "boolean", "G5UPLOADER", "false"
buildConfigField "boolean", "PUMPCONTROL", "false"
} }
pumpcontrol { pumpcontrol {
applicationId "info.nightscout.androidaps"
dimension "standard" dimension "standard"
resValue "string", "app_name", "AndroidAPS" resValue "string", "app_name", "AndroidAPS"
versionName version versionName version
manifestPlaceholders = [ manifestPlaceholders = [
appIcon: "@mipmap/blueowl" appIcon: "@mipmap/blueowl",
appIconRound: "@null"
] ]
buildConfigField "boolean", "APS", "false"
buildConfigField "boolean", "PUMPDRIVERS", "true"
buildConfigField "boolean", "NSCLIENTOLNY", "false"
buildConfigField "boolean", "G5UPLOADER", "false"
buildConfigField "boolean", "PUMPCONTROL", "true"
} }
nsclient { nsclient {
applicationId "info.nightscout.nsclient"
dimension "standard" dimension "standard"
resValue "string", "app_name", "NSClient" resValue "string", "app_name", "NSClient"
versionName version + "-nsclient" versionName version + "-nsclient"
manifestPlaceholders = [ manifestPlaceholders = [
appIcon: "@mipmap/yellowowl" appIcon: "@mipmap/yellowowl",
appIconRound: "@null"
] ]
buildConfigField "boolean", "APS", "false"
buildConfigField "boolean", "PUMPDRIVERS", "false"
buildConfigField "boolean", "NSCLIENTOLNY", "true"
buildConfigField "boolean", "G5UPLOADER", "false"
buildConfigField "boolean", "PUMPCONTROL", "false"
} }
g5uploader { nsclient2 {
applicationId "info.nightscout.nsclient2"
dimension "standard" dimension "standard"
resValue "string", "app_name", "NSClient" resValue "string", "app_name", "NSClient2"
versionName version + "-nsclient" versionName version + "-nsclient"
manifestPlaceholders = [ manifestPlaceholders = [
appIcon: "@mipmap/yellowowl" appIcon: "@mipmap/yellowowl",
appIconRound: "@null"
] ]
buildConfigField "boolean", "APS", "false"
buildConfigField "boolean", "PUMPDRIVERS", "false"
buildConfigField "boolean", "NSCLIENTOLNY", "false"
buildConfigField "boolean", "G5UPLOADER", "true"
buildConfigField "boolean", "PUMPCONTROL", "false"
} }
} }
compileOptions { compileOptions {
@ -156,6 +145,8 @@ android {
unitTests.returnDefaultValues = true unitTests.returnDefaultValues = true
unitTests.includeAndroidResources = true unitTests.includeAndroidResources = true
} }
useLibrary "org.apache.http.legacy"
} }
allprojects { allprojects {
@ -184,6 +175,7 @@ dependencies {
libs "MilosKozak:danars-support-lib:master@zip" libs "MilosKozak:danars-support-lib:master@zip"
implementation "com.android.support:appcompat-v7:${supportLibraryVersion}" implementation "com.android.support:appcompat-v7:${supportLibraryVersion}"
implementation "com.android.support:support-v13:${supportLibraryVersion}"
implementation "com.android.support:support-v4:${supportLibraryVersion}" implementation "com.android.support:support-v4:${supportLibraryVersion}"
implementation "com.android.support:cardview-v7:${supportLibraryVersion}" implementation "com.android.support:cardview-v7:${supportLibraryVersion}"
implementation "com.android.support:recyclerview-v7:${supportLibraryVersion}" implementation "com.android.support:recyclerview-v7:${supportLibraryVersion}"

Binary file not shown.

View file

@ -30,26 +30,27 @@
android:name=".MainApp" android:name=".MainApp"
android:allowBackup="true" android:allowBackup="true"
android:icon="${appIcon}" android:icon="${appIcon}"
android:roundIcon="${appIconRound}"
android:label="@string/app_name" android:label="@string/app_name"
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/AppTheme"> android:theme="@style/AppTheme.NoActionBar">
<activity android:name=".MainActivity"> <activity android:name=".MainActivity">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter> </intent-filter>
</activity> </activity>
<activity android:name=".PreferencesActivity" /> <activity android:name=".activities.PreferencesActivity" />
<activity <activity
android:name=".plugins.Overview.Dialogs.BolusProgressHelperActivity" android:name=".plugins.Overview.Dialogs.BolusProgressHelperActivity"
android:theme="@style/Theme.AppCompat.Translucent" /> android:theme="@style/Theme.AppCompat.Translucent" />
<activity <activity
android:name=".plugins.Overview.Dialogs.ErrorHelperActivity" android:name=".plugins.Overview.Dialogs.ErrorHelperActivity"
android:theme="@style/Theme.AppCompat.Translucent" /> android:theme="@style/Theme.AppCompat.Translucent" />
<activity android:name=".AgreementActivity" /> <activity android:name=".activities.AgreementActivity" />
<activity android:name=".plugins.PumpDanaR.activities.DanaRHistoryActivity" /> <activity android:name=".plugins.PumpDanaR.activities.DanaRHistoryActivity" />
<activity android:name=".TDDStatsActivity" /> <activity android:name=".plugins.PumpDanaR.activities.DanaRUserOptionsActivity" />
<activity android:name=".activities.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" />
@ -65,7 +66,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" /> <activity android:name=".activities.HistoryBrowseActivity" />
<receiver <receiver
android:name=".receivers.DataReceiver" android:name=".receivers.DataReceiver"
@ -83,6 +84,8 @@
<action android:name="it.ct.glicemia.ACTION_GLUCOSE_MEASURED" /> <action android:name="it.ct.glicemia.ACTION_GLUCOSE_MEASURED" />
<!-- Receiver from DexcomG5 --> <!-- Receiver from DexcomG5 -->
<action android:name="com.dexcom.cgm.DATA" /> <action android:name="com.dexcom.cgm.DATA" />
<!-- Receiver from Poctech -->
<action android:name="com.china.poctech.data" />
</intent-filter> </intent-filter>
</receiver> </receiver>
<!-- Receiver keepalive, scheduled every 30 min --> <!-- Receiver keepalive, scheduled every 30 min -->
@ -124,9 +127,19 @@
</intent-filter> </intent-filter>
</receiver> </receiver>
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/filepaths" />
</provider>
<!-- Service processing incomming data --> <!-- Service processing incomming data -->
<service <service
android:name=".Services.DataService" android:name=".services.DataService"
android:exported="false" /> android:exported="false" />
<service <service
android:name=".plugins.PumpDanaR.services.DanaRExecutionService" android:name=".plugins.PumpDanaR.services.DanaRExecutionService"
@ -156,13 +169,15 @@
android:enabled="true" android:enabled="true"
android:exported="true" /> android:exported="true" />
<service <service
android:name=".Services.AlarmSoundService" android:name=".services.AlarmSoundService"
android:enabled="true" android:enabled="true"
android:exported="true" /> android:exported="true" />
<service <service
android:name=".plugins.Overview.notifications.DismissNotificationService" android:name=".plugins.Overview.notifications.DismissNotificationService"
android:exported="false" /> android:exported="false" />
<service android:name=".plugins.Persistentnotification.DummyService" />
<meta-data <meta-data
android:name="io.fabric.ApiKey" android:name="io.fabric.ApiKey"
android:value="59d462666c664c57b29e1d79ea123e01f8057cfa" /> android:value="59d462666c664c57b29e1d79ea123e01f8057cfa" />
@ -170,8 +185,12 @@
<activity <activity
android:name=".setupwizard.SetupWizardActivity" android:name=".setupwizard.SetupWizardActivity"
android:configChanges="orientation|keyboardHidden|screenSize" android:configChanges="orientation|keyboardHidden|screenSize"
android:theme="@style/AppTheme.SetupWizard" android:theme="@style/AppTheme.NoActionBar"
android:label="@string/title_activity_setup_wizard"></activity> android:label="@string/title_activity_setup_wizard" />
<activity android:name=".activities.SingleFragmentActivity"
android:theme="@style/AppTheme" />
<activity android:name=".plugins.Maintenance.activities.LogSettingActivity"></activity>
</application> </application>
</manifest> </manifest>

View file

@ -23,19 +23,18 @@ var round_basal = require('./round-basal');
if (rate < 0) { if (rate < 0) {
rate = 0; rate = 0;
} // if >30m @ 0 required, zero temp will be extended to 30m instead } else if (rate > maxSafeBasal) {
else if (rate > maxSafeBasal) {
rate = maxSafeBasal; rate = maxSafeBasal;
} }
var suggestedRate = round_basal(rate, profile); 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) { 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 && duration > 0 ) {
rT.reason += " "+currenttemp.duration+"m left and " + currenttemp.rate + " ~ req " + suggestedRate + "U/hr: no temp required"; rT.reason += " "+currenttemp.duration+"m left and " + currenttemp.rate + " ~ req " + suggestedRate + "U/hr: no temp required";
return rT; return rT;
} }
if (suggestedRate === profile.current_basal) { if (suggestedRate === profile.current_basal) {
if (profile.skip_neutral_temps) { if (profile.skip_neutral_temps === true) {
if (typeof(currenttemp) !== 'undefined' && typeof(currenttemp.duration) !== 'undefined' && currenttemp.duration > 0) { 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'); reason(rT, 'Suggested rate is same as profile rate, a temp basal is active, canceling current temp');
rT.duration = 0; rT.duration = 0;

View file

@ -406,8 +406,8 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
} else { } else {
console.error("SMB disabled (no enableSMB preferences active)"); console.error("SMB disabled (no enableSMB preferences active)");
} }
// enable UAM (if enabled in preferences) if SMB is enabled // enable UAM (if enabled in preferences)
var enableUAM=(profile.enableUAM && enableSMB); var enableUAM=(profile.enableUAM);
//console.error(meal_data); //console.error(meal_data);
@ -942,10 +942,10 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
var durationReq = round(60*worstCaseInsulinReq / profile.current_basal); var durationReq = round(60*worstCaseInsulinReq / profile.current_basal);
if (durationReq < 0) { if (durationReq < 0) {
durationReq = 0; durationReq = 0;
// don't set a temp longer than 120 minutes // don't set an SMB zero temp longer than 60 minutess
} else { } else {
durationReq = round(durationReq/30)*30; durationReq = round(durationReq/30)*30;
durationReq = Math.min(120,Math.max(0,durationReq)); durationReq = Math.min(60,Math.max(0,durationReq));
} }
//console.error(durationReq); //console.error(durationReq);
//rT.reason += "insulinReq " + insulinReq + "; " //rT.reason += "insulinReq " + insulinReq + "; "

View file

@ -1,21 +1,24 @@
<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 scope="context" name="EXT_FILES_DIR" value="${EXT_DIR:-/sdcard}/Android/data/${PACKAGE_NAME}/files"/> <property name="EXT_FILES_DIR" scope="context"
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">
<!-- daily rollover. Make sure the path matches the one in the file element or else <!-- daily rollover. Make sure the path matches the one in the file element or else
the rollover logs are placed in the working directory. --> the rollover logs are placed in the working directory. -->
<fileNamePattern>${EXT_FILES_DIR}/AndroidAPS._%d{yyyy-MM-dd}_%d{HH-mm-ss, aux}_.%i.zip</fileNamePattern> <fileNamePattern>${EXT_FILES_DIR}/AndroidAPS._%d{yyyy-MM-dd}_%d{HH-mm-ss, aux}_.%i.zip
</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <timeBasedFileNamingAndTriggeringPolicy
class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>5MB</maxFileSize> <maxFileSize>5MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy> </timeBasedFileNamingAndTriggeringPolicy>
<!-- keep 30 days' worth of history --> <!-- keep 30 days' worth of history -->
<maxHistory>120</maxHistory> <maxHistory>120</maxHistory>
</rollingPolicy> </rollingPolicy>
<encoder> <encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level [%class:%line]: %msg%n</pattern> <pattern>%d{HH:mm:ss.SSS} [%thread] %.-1level/%logger: [%class{0}.%M\(\):%line]: %msg%n</pattern>
</encoder> </encoder>
</appender> </appender>
@ -24,7 +27,7 @@
<pattern>%logger{0}</pattern> <pattern>%logger{0}</pattern>
</tagEncoder> </tagEncoder>
<encoder> <encoder>
<pattern>[%thread] %-5level [%class:%line]: %msg%n</pattern> <pattern>[%thread] [%class{0}.%M\(\):%line]: %msg%n</pattern>
</encoder> </encoder>
</appender> </appender>

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

View file

@ -5,20 +5,23 @@ import org.slf4j.LoggerFactory;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.ConcurrentModificationException;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import info.nightscout.androidaps.events.Event; import info.nightscout.androidaps.events.Event;
import info.nightscout.androidaps.logging.L;
/** Logs events has they're being posted to and dispatched from the event bus. /**
* * Logs events has they're being posted to and dispatched from the event bus.
* <p>
* A summary of event-receiver calls that occurred so far is logged * A summary of event-receiver calls that occurred so far is logged
* after 10s (after startup) and then again every 60s. * after 10s (after startup) and then again every 60s.
* */ */
public class LoggingBus extends Bus { public class LoggingBus extends Bus {
private static Logger log = LoggerFactory.getLogger(LoggingBus.class); private static Logger log = LoggerFactory.getLogger(L.EVENTS);
private static long everyMinute = System.currentTimeMillis() + 10 * 1000; private static long everyMinute = System.currentTimeMillis() + 10 * 1000;
private Map<String, Set<String>> event2Receiver = new HashMap<>(); private Map<String, Set<String>> event2Receiver = new HashMap<>();
@ -48,7 +51,10 @@ public class LoggingBus extends Bus {
log.debug(" source: <unknown>"); log.debug(" source: <unknown>");
} }
try {
super.post(event); super.post(event);
} catch (IllegalStateException ignored) {
}
} }
@Override @Override
@ -70,6 +76,7 @@ public class LoggingBus extends Bus {
log.debug(" receiver: <unknown>"); log.debug(" receiver: <unknown>");
} }
try {
if (everyMinute < System.currentTimeMillis()) { if (everyMinute < System.currentTimeMillis()) {
log.debug("***************** Event -> receiver pairings seen so far ****************"); log.debug("***************** Event -> receiver pairings seen so far ****************");
for (Map.Entry<String, Set<String>> stringSetEntry : event2Receiver.entrySet()) { for (Map.Entry<String, Set<String>> stringSetEntry : event2Receiver.entrySet()) {
@ -81,6 +88,8 @@ public class LoggingBus extends Bus {
log.debug("*************************************************************************"); log.debug("*************************************************************************");
everyMinute = System.currentTimeMillis() + 60 * 1000; everyMinute = System.currentTimeMillis() + 60 * 1000;
} }
} catch (ConcurrentModificationException ignored) {
}
super.dispatch(event, wrapper); super.dispatch(event, wrapper);
} }

View file

@ -6,39 +6,19 @@ package info.nightscout.androidaps;
public class Config { public class Config {
public static int SUPPORTEDNSVERSION = 1002; // 0.10.00 public static int SUPPORTEDNSVERSION = 1002; // 0.10.00
// MAIN FUCTIONALITY public static final boolean APS = BuildConfig.FLAVOR.equals("full");
public static final boolean APS = BuildConfig.APS;
// PLUGINS
public static final boolean NSCLIENT = BuildConfig.NSCLIENTOLNY;
public static final boolean G5UPLOADER = BuildConfig.G5UPLOADER;
public static final boolean PUMPCONTROL = BuildConfig.PUMPCONTROL;
public static final boolean HWPUMPS = BuildConfig.PUMPDRIVERS; public static final boolean NSCLIENT = BuildConfig.FLAVOR.equals("nsclient") || BuildConfig.FLAVOR.equals("nsclient2");
public static final boolean PUMPCONTROL = BuildConfig.FLAVOR.equals("pumpcontrol");
public static final boolean ACTION = !BuildConfig.NSCLIENTOLNY && !BuildConfig.G5UPLOADER; public static final boolean PUMPDRIVERS = BuildConfig.FLAVOR.equals("full") || BuildConfig.FLAVOR.equals("pumpcontrol");
public static final boolean MDI = !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 SMSCOMMUNICATORENABLED = !BuildConfig.NSCLIENTOLNY && !BuildConfig.G5UPLOADER; public static final boolean ACTION = !NSCLIENT;
public static final boolean MDI = !NSCLIENT;
public static final boolean OTHERPROFILES = !NSCLIENT;
public static final boolean SAFETY = !NSCLIENT;
public static final boolean SMSCOMMUNICATORENABLED = !NSCLIENT;
public static final boolean detailedLog = true;
public static final boolean logFunctionCalls = true;
public static final boolean logIncommingData = true;
public static final boolean logAPSResult = true;
public static final boolean logPumpComm = true;
public static final boolean logPrefsChange = true;
public static final boolean logConfigBuilder = true;
public static final boolean logNSUpload = true;
public static final boolean logPumpActions = true;
public static final boolean logCongigBuilderActions = true;
public static final boolean logAutosensData = false;
public static final boolean logEvents = false;
public static final boolean logProfile = false;
// DanaR specific
public static final boolean logDanaBTComm = true;
public static boolean logDanaMessageDetail = true;
public static final boolean logDanaSerialEngine = true;
} }

View file

@ -67,4 +67,5 @@ public class Constants {
//SMS Communicator //SMS Communicator
public static final long SMS_CONFIRM_TIMEOUT = T.mins(5).msecs(); public static final long SMS_CONFIRM_TIMEOUT = T.mins(5).msecs();
} }

View file

@ -1,404 +0,0 @@
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.gc(R.color.graphgrid));
bgGraph.getGridLabelRenderer().reloadStyles();
iobGraph.getGridLabelRenderer().setGridColor(MainApp.gc(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

@ -1,30 +1,34 @@
package info.nightscout.androidaps; package info.nightscout.androidaps;
import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.graphics.Rect; import android.graphics.Rect;
import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.os.PersistableBundle;
import android.os.PowerManager; import android.os.PowerManager;
import android.support.annotation.Nullable;
import android.support.design.widget.NavigationView;
import android.support.design.widget.TabLayout;
import android.support.v4.app.ActivityCompat; import android.support.v4.app.ActivityCompat;
import android.support.v4.view.ViewPager; import android.support.v4.view.ViewPager;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.AlertDialog; import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity; import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.PopupMenu; import android.support.v7.widget.Toolbar;
import android.text.SpannableString; import android.text.SpannableString;
import android.text.method.LinkMovementMethod; import android.text.method.LinkMovementMethod;
import android.text.util.Linkify; import android.text.util.Linkify;
import android.view.MenuInflater; import android.util.TypedValue;
import android.view.Menu;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.View; import android.view.View;
import android.view.WindowManager; 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.LinearLayout;
import android.widget.TextView; import android.widget.TextView;
import com.joanzapata.iconify.Iconify; import com.joanzapata.iconify.Iconify;
@ -34,59 +38,105 @@ 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.activities.AgreementActivity;
import info.nightscout.androidaps.activities.HistoryBrowseActivity;
import info.nightscout.androidaps.activities.PreferencesActivity;
import info.nightscout.androidaps.activities.SingleFragmentActivity;
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.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.logging.L;
import info.nightscout.androidaps.plugins.Food.FoodPlugin; import info.nightscout.androidaps.plugins.ConfigBuilder.ProfileFunctions;
import info.nightscout.androidaps.plugins.Overview.events.EventSetWakeLock; import info.nightscout.androidaps.plugins.NSClientInternal.data.NSSettingsStatus;
import info.nightscout.androidaps.plugins.Treatments.TreatmentsPlugin;
import info.nightscout.androidaps.setupwizard.SetupWizardActivity; import info.nightscout.androidaps.setupwizard.SetupWizardActivity;
import info.nightscout.androidaps.tabs.SlidingTabLayout;
import info.nightscout.androidaps.tabs.TabPageAdapter; import info.nightscout.androidaps.tabs.TabPageAdapter;
import info.nightscout.utils.AndroidPermission; import info.nightscout.utils.AndroidPermission;
import info.nightscout.utils.ImportExportPrefs;
import info.nightscout.utils.LocaleHelper; import info.nightscout.utils.LocaleHelper;
import info.nightscout.utils.LogDialog;
import info.nightscout.utils.OKDialog; import info.nightscout.utils.OKDialog;
import info.nightscout.utils.PasswordProtection; import info.nightscout.utils.PasswordProtection;
import info.nightscout.utils.SP; import info.nightscout.utils.SP;
import info.nightscout.utils.VersionChecker;
public class MainActivity extends AppCompatActivity implements View.OnClickListener { public class MainActivity extends AppCompatActivity {
private static Logger log = LoggerFactory.getLogger(MainActivity.class); private static Logger log = LoggerFactory.getLogger(L.CORE);
ImageButton menuButton;
protected PowerManager.WakeLock mWakeLock; protected PowerManager.WakeLock mWakeLock;
private ActionBarDrawerToggle actionBarDrawerToggle;
private MenuItem pluginPreferencesMenuItem;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
if (Config.logFunctionCalls) if (L.isEnabled(L.CORE))
log.debug("onCreate"); log.debug("onCreate");
Iconify.with(new FontAwesomeModule()); Iconify.with(new FontAwesomeModule());
LocaleHelper.onCreate(this, "en"); LocaleHelper.onCreate(this, "en");
setContentView(R.layout.activity_main);
menuButton = (ImageButton) findViewById(R.id.overview_menuButton);
menuButton.setOnClickListener(this);
onStatusEvent(new EventSetWakeLock(SP.getBoolean("lockscreen", false))); setContentView(R.layout.activity_main);
setSupportActionBar(findViewById(R.id.toolbar));
getSupportActionBar().setDisplayShowTitleEnabled(false);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setHomeButtonEnabled(true);
DrawerLayout drawerLayout = findViewById(R.id.drawer_layout);
actionBarDrawerToggle = new ActionBarDrawerToggle(this, drawerLayout, R.string.open_navigation, R.string.close_navigation);
drawerLayout.addDrawerListener(actionBarDrawerToggle);
actionBarDrawerToggle.syncState();
// initialize screen wake lock
onEventPreferenceChange(new EventPreferenceChange(R.string.key_keep_screen_on));
doMigrations(); doMigrations();
registerBus(); registerBus();
setUpTabs(false); setupTabs();
setupViews(false);
final ViewPager viewPager = findViewById(R.id.pager);
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
checkPluginPreferences(viewPager);
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
VersionChecker.check();
}
private void checkPluginPreferences(ViewPager viewPager) {
if (pluginPreferencesMenuItem == null) return;
if (((TabPageAdapter) viewPager.getAdapter()).getPluginAt(viewPager.getCurrentItem()).getPreferencesId() != -1)
pluginPreferencesMenuItem.setEnabled(true);
else pluginPreferencesMenuItem.setEnabled(false);
}
@Override
public void onPostCreate(@Nullable Bundle savedInstanceState, @Nullable PersistableBundle persistentState) {
super.onPostCreate(savedInstanceState, persistentState);
actionBarDrawerToggle.syncState();
} }
@Override @Override
protected void onResume() { protected void onResume() {
super.onResume(); super.onResume();
if (L.isEnabled(L.CORE))
log.debug("onResume");
if (!SP.getBoolean(R.string.key_setupwizard_processed, false)) { if (!SP.getBoolean(R.string.key_setupwizard_processed, false)) {
Intent intent = new Intent(this, SetupWizardActivity.class); Intent intent = new Intent(this, SetupWizardActivity.class);
startActivity(intent); startActivity(intent);
@ -96,14 +146,18 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
AndroidPermission.notifyForStoragePermission(this); AndroidPermission.notifyForStoragePermission(this);
AndroidPermission.notifyForBatteryOptimizationPermission(this); AndroidPermission.notifyForBatteryOptimizationPermission(this);
if (Config.PUMPDRIVERS) {
AndroidPermission.notifyForLocationPermissions(this); AndroidPermission.notifyForLocationPermissions(this);
AndroidPermission.notifyForSMSPermissions(this); AndroidPermission.notifyForSMSPermissions(this);
}
MainApp.bus().post(new EventFeatureRunning(EventFeatureRunning.Feature.MAIN)); MainApp.bus().post(new EventFeatureRunning(EventFeatureRunning.Feature.MAIN));
} }
@Override @Override
public void onDestroy() { public void onDestroy() {
if (L.isEnabled(L.CORE))
log.debug("onDestroy");
if (mWakeLock != null) if (mWakeLock != null)
if (mWakeLock.isHeld()) if (mWakeLock.isHeld())
mWakeLock.release(); mWakeLock.release();
@ -111,9 +165,11 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
} }
@Subscribe @Subscribe
public void onStatusEvent(final EventSetWakeLock ev) { public void onEventPreferenceChange(final EventPreferenceChange ev) {
if (ev.isChanged(R.string.key_keep_screen_on)) {
boolean keepScreenOn = SP.getBoolean(R.string.key_keep_screen_on, false);
final PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); final PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
if (ev.lock) { if (keepScreenOn) {
mWakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "AAPS"); mWakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "AAPS");
if (!mWakeLock.isHeld()) if (!mWakeLock.isHeld())
mWakeLock.acquire(); mWakeLock.acquire();
@ -122,44 +178,81 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
mWakeLock.release(); mWakeLock.release();
} }
} }
}
@Subscribe @Subscribe
public void onStatusEvent(final EventRefreshGui ev) { public void onStatusEvent(final EventRefreshGui ev) {
String lang = SP.getString("language", "en"); String lang = SP.getString(R.string.key_language, "en");
LocaleHelper.setLocale(getApplicationContext(), lang); LocaleHelper.setLocale(getApplicationContext(), lang);
runOnUiThread(new Runnable() { runOnUiThread(() -> {
@Override
public void run() {
if (ev.recreate) { if (ev.recreate) {
recreate(); recreate();
} else { } else {
try { // activity may be destroyed try { // activity may be destroyed
setUpTabs(true); setupTabs();
setupViews(true);
} catch (IllegalStateException e) { } catch (IllegalStateException e) {
log.error("Unhandled exception", e); log.error("Unhandled exception", e);
} }
} }
boolean lockScreen = BuildConfig.NSCLIENTOLNY && SP.getBoolean("lockscreen", false); boolean keepScreenOn = Config.NSCLIENT && SP.getBoolean(R.string.key_keep_screen_on, false);
if (lockScreen) if (keepScreenOn)
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
else else
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
}); });
} }
private void setUpTabs(boolean switchToLast) { private void setupViews(boolean switchToLast) {
TabPageAdapter pageAdapter = new TabPageAdapter(getSupportFragmentManager(), this); TabPageAdapter pageAdapter = new TabPageAdapter(getSupportFragmentManager(), this);
NavigationView navigationView = findViewById(R.id.navigation_view);
navigationView.setNavigationItemSelectedListener(menuItem -> {
return true;
});
Menu menu = navigationView.getMenu();
menu.clear();
for (PluginBase p : MainApp.getPluginsList()) { for (PluginBase p : MainApp.getPluginsList()) {
pageAdapter.registerNewFragment(p); pageAdapter.registerNewFragment(p);
if (p.hasFragment() && !p.isFragmentVisible() && p.isEnabled(p.pluginDescription.getType()) && !p.pluginDescription.neverVisible) {
MenuItem menuItem = menu.add(p.getName());
menuItem.setCheckable(true);
menuItem.setOnMenuItemClickListener(item -> {
Intent intent = new Intent(this, SingleFragmentActivity.class);
intent.putExtra("plugin", MainApp.getPluginsList().indexOf(p));
startActivity(intent);
((DrawerLayout) findViewById(R.id.drawer_layout)).closeDrawers();
return true;
});
} }
ViewPager mPager = (ViewPager) findViewById(R.id.pager); }
ViewPager mPager = findViewById(R.id.pager);
mPager.setAdapter(pageAdapter); mPager.setAdapter(pageAdapter);
SlidingTabLayout mTabs = (SlidingTabLayout) findViewById(R.id.tabs);
mTabs.setViewPager(mPager);
if (switchToLast) if (switchToLast)
mPager.setCurrentItem(pageAdapter.getCount() - 1, false); mPager.setCurrentItem(pageAdapter.getCount() - 1, false);
checkPluginPreferences(mPager);
}
private void setupTabs() {
ViewPager viewPager = findViewById(R.id.pager);
TabLayout normalTabs = findViewById(R.id.tabs_normal);
normalTabs.setupWithViewPager(viewPager, true);
TabLayout compactTabs = findViewById(R.id.tabs_compact);
compactTabs.setupWithViewPager(viewPager, true);
Toolbar toolbar = findViewById(R.id.toolbar);
if (SP.getBoolean("short_tabtitles", false)) {
normalTabs.setVisibility(View.GONE);
compactTabs.setVisibility(View.VISIBLE);
toolbar.setLayoutParams(new LinearLayout.LayoutParams(Toolbar.LayoutParams.MATCH_PARENT, (int) getResources().getDimension(R.dimen.compact_height)));
} else {
normalTabs.setVisibility(View.VISIBLE);
compactTabs.setVisibility(View.GONE);
TypedValue typedValue = new TypedValue();
if (getTheme().resolveAttribute(R.attr.actionBarSize, typedValue, true)) {
toolbar.setLayoutParams(new LinearLayout.LayoutParams(Toolbar.LayoutParams.MATCH_PARENT,
TypedValue.complexToDimensionPixelSize(typedValue.data, getResources().getDisplayMetrics())));
}
}
} }
private void registerBus() { private void registerBus() {
@ -197,7 +290,7 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
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) {
Profile profile = MainApp.getConfigBuilder().getProfile(); Profile profile = ProfileFunctions.getInstance().getProfile();
String oldRange = SP.getDouble("openapsma_min_bg", 0d) + " - " + SP.getDouble("openapsma_max_bg", 0d); String oldRange = SP.getDouble("openapsma_min_bg", 0d) + " - " + SP.getDouble("openapsma_max_bg", 0d);
String newRange = ""; String newRange = "";
if (profile != null) { if (profile != null) {
@ -257,73 +350,40 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
} }
@Override @Override
public void onClick(final View v) { public boolean onCreateOptionsMenu(Menu menu) {
final Activity activity = this; getMenuInflater().inflate(R.menu.menu_main, menu);
switch (v.getId()) { pluginPreferencesMenuItem = menu.findItem(R.id.nav_plugin_preferences);
case R.id.overview_menuButton: checkPluginPreferences(findViewById(R.id.pager));
PopupMenu popup = new PopupMenu(v.getContext(), v); return true;
MenuInflater inflater = popup.getMenuInflater(); }
inflater.inflate(R.menu.menu_main, popup.getMenu());
popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override @Override
public boolean onMenuItemClick(MenuItem item) { public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId(); int id = item.getItemId();
switch (id) { switch (id) {
case R.id.nav_preferences: case R.id.nav_preferences:
PasswordProtection.QueryPassword(v.getContext(), R.string.settings_password, "settings_password", new Runnable() { PasswordProtection.QueryPassword(this, R.string.settings_password, "settings_password", () -> {
@Override Intent i = new Intent(this, PreferencesActivity.class);
public void run() {
Intent i = new Intent(v.getContext(), PreferencesActivity.class);
i.putExtra("id", -1); i.putExtra("id", -1);
startActivity(i); startActivity(i);
}
}, null); }, null);
break; return true;
case R.id.nav_historybrowser: case R.id.nav_historybrowser:
startActivity(new Intent(v.getContext(), HistoryBrowseActivity.class)); startActivity(new Intent(this, HistoryBrowseActivity.class));
break; return true;
case R.id.nav_setupwizard: case R.id.nav_setupwizard:
startActivity(new Intent(v.getContext(), SetupWizardActivity.class)); startActivity(new Intent(this, SetupWizardActivity.class));
break; return true;
case R.id.nav_resetdb:
new AlertDialog.Builder(v.getContext())
.setTitle(R.string.nav_resetdb)
.setMessage(R.string.reset_db_confirm)
.setNegativeButton(android.R.string.cancel, null)
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
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()
.show();
break;
case R.id.nav_export:
ImportExportPrefs.verifyStoragePermissions(activity);
ImportExportPrefs.exportSharedPreferences(activity);
break;
case R.id.nav_import:
ImportExportPrefs.verifyStoragePermissions(activity);
ImportExportPrefs.importSharedPreferences(activity);
break;
case R.id.nav_show_logcat:
LogDialog.showLogcat(v.getContext());
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(this);
builder.setTitle(MainApp.gs(R.string.app_name) + " " + BuildConfig.VERSION); builder.setTitle(MainApp.gs(R.string.app_name) + " " + BuildConfig.VERSION);
if (Config.NSCLIENT || Config.G5UPLOADER) if (Config.NSCLIENT)
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 += "Flavor: " + BuildConfig.FLAVOR + BuildConfig.BUILD_TYPE + "\n"; message += "Flavor: " + BuildConfig.FLAVOR + BuildConfig.BUILD_TYPE + "\n";
message += MainApp.gs(R.string.configbuilder_nightscoutversion_label) + " " + ConfigBuilderPlugin.nightscoutVersionName; message += MainApp.gs(R.string.configbuilder_nightscoutversion_label) + " " + NSSettingsStatus.getInstance().nightscoutVersionName;
if (MainApp.engineeringMode) if (MainApp.engineeringMode)
message += "\n" + MainApp.gs(R.string.engineering_mode_enabled); message += "\n" + MainApp.gs(R.string.engineering_mode_enabled);
message += MainApp.gs(R.string.about_link_urls); message += MainApp.gs(R.string.about_link_urls);
@ -334,7 +394,7 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
AlertDialog alertDialog = builder.create(); AlertDialog alertDialog = builder.create();
alertDialog.show(); alertDialog.show();
((TextView) alertDialog.findViewById(android.R.id.message)).setMovementMethod(LinkMovementMethod.getInstance()); ((TextView) alertDialog.findViewById(android.R.id.message)).setMovementMethod(LinkMovementMethod.getInstance());
break; return true;
case R.id.nav_exit: case R.id.nav_exit:
log.debug("Exiting"); log.debug("Exiting");
MainApp.instance().stopKeepAliveService(); MainApp.instance().stopKeepAliveService();
@ -343,13 +403,17 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
finish(); finish();
System.runFinalization(); System.runFinalization();
System.exit(0); System.exit(0);
break; return true;
} case R.id.nav_plugin_preferences:
return false; ViewPager viewPager = findViewById(R.id.pager);
} final PluginBase plugin = ((TabPageAdapter) viewPager.getAdapter()).getPluginAt(viewPager.getCurrentItem());
}); PasswordProtection.QueryPassword(this, R.string.settings_password, "settings_password", () -> {
popup.show(); Intent i = new Intent(this, PreferencesActivity.class);
break; i.putExtra("id", plugin.getPreferencesId());
startActivity(i);
}, null);
return true;
} }
return actionBarDrawerToggle.onOptionsItemSelected(item);
} }
} }

View file

@ -5,11 +5,11 @@ import android.content.IntentFilter;
import android.content.res.Resources; import android.content.res.Resources;
import android.os.SystemClock; import android.os.SystemClock;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.support.annotation.PluralsRes;
import android.support.v4.content.LocalBroadcastManager; import android.support.v4.content.LocalBroadcastManager;
import com.crashlytics.android.Crashlytics; import com.crashlytics.android.Crashlytics;
import com.crashlytics.android.answers.Answers; import com.crashlytics.android.answers.Answers;
import com.crashlytics.android.answers.CustomEvent;
import com.j256.ormlite.android.apptools.OpenHelperManager; import com.j256.ormlite.android.apptools.OpenHelperManager;
import com.squareup.otto.Bus; import com.squareup.otto.Bus;
import com.squareup.otto.LoggingBus; import com.squareup.otto.LoggingBus;
@ -23,13 +23,12 @@ import org.slf4j.LoggerFactory;
import java.io.File; 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.data.ConstraintChecker; import info.nightscout.androidaps.data.ConstraintChecker;
import info.nightscout.androidaps.db.DatabaseHelper; import info.nightscout.androidaps.db.DatabaseHelper;
import info.nightscout.androidaps.interfaces.PluginBase; import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.PluginType; import info.nightscout.androidaps.interfaces.PluginType;
import info.nightscout.androidaps.interfaces.PumpInterface; import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.logging.L;
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.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
@ -40,15 +39,16 @@ 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.Maintenance.MaintenancePlugin;
import info.nightscout.androidaps.plugins.Loop.LoopPlugin; import info.nightscout.androidaps.plugins.Loop.LoopPlugin;
import info.nightscout.androidaps.plugins.NSClientInternal.NSClientPlugin; import info.nightscout.androidaps.plugins.NSClientInternal.NSClientPlugin;
import info.nightscout.androidaps.plugins.NSClientInternal.NSUpload;
import info.nightscout.androidaps.plugins.NSClientInternal.receivers.AckAlarmReceiver; import info.nightscout.androidaps.plugins.NSClientInternal.receivers.AckAlarmReceiver;
import info.nightscout.androidaps.plugins.NSClientInternal.receivers.DBAccessReceiver;
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.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.ProfileLocal.LocalProfilePlugin; import info.nightscout.androidaps.plugins.ProfileLocal.LocalProfilePlugin;
import info.nightscout.androidaps.plugins.ProfileNS.NSProfilePlugin; import info.nightscout.androidaps.plugins.ProfileNS.NSProfilePlugin;
@ -61,14 +61,16 @@ import info.nightscout.androidaps.plugins.PumpDanaRv2.DanaRv2Plugin;
import info.nightscout.androidaps.plugins.PumpInsight.InsightPlugin; 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.Sensitivity.SensitivityAAPSPlugin;
import info.nightscout.androidaps.plugins.SensitivityOref0.SensitivityOref0Plugin; import info.nightscout.androidaps.plugins.Sensitivity.SensitivityOref0Plugin;
import info.nightscout.androidaps.plugins.SensitivityWeightedAverage.SensitivityWeightedAveragePlugin; import info.nightscout.androidaps.plugins.Sensitivity.SensitivityOref1Plugin;
import info.nightscout.androidaps.plugins.Sensitivity.SensitivityWeightedAveragePlugin;
import info.nightscout.androidaps.plugins.SmsCommunicator.SmsCommunicatorPlugin; import info.nightscout.androidaps.plugins.SmsCommunicator.SmsCommunicatorPlugin;
import info.nightscout.androidaps.plugins.Source.SourceDexcomG5Plugin; import info.nightscout.androidaps.plugins.Source.SourceDexcomG5Plugin;
import info.nightscout.androidaps.plugins.Source.SourceGlimpPlugin; import info.nightscout.androidaps.plugins.Source.SourceGlimpPlugin;
import info.nightscout.androidaps.plugins.Source.SourceMM640gPlugin; import info.nightscout.androidaps.plugins.Source.SourceMM640gPlugin;
import info.nightscout.androidaps.plugins.Source.SourceNSClientPlugin; import info.nightscout.androidaps.plugins.Source.SourceNSClientPlugin;
import info.nightscout.androidaps.plugins.Source.SourcePoctechPlugin;
import info.nightscout.androidaps.plugins.Source.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;
@ -76,13 +78,14 @@ 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.androidaps.services.Intents;
import info.nightscout.utils.FabricPrivacy; import info.nightscout.utils.FabricPrivacy;
import info.nightscout.utils.NSUpload; import info.nightscout.androidaps.plugins.Maintenance.LoggerUtils;
import io.fabric.sdk.android.Fabric; import io.fabric.sdk.android.Fabric;
public class MainApp extends Application { public class MainApp extends Application {
private static Logger log = LoggerFactory.getLogger(MainApp.class); private static Logger log = LoggerFactory.getLogger(L.CORE);
private static KeepAliveReceiver keepAliveReceiver; private static KeepAliveReceiver keepAliveReceiver;
private static Bus sBus; private static Bus sBus;
@ -90,7 +93,6 @@ public class MainApp extends Application {
public static Resources sResources; public static Resources sResources;
private static DatabaseHelper sDatabaseHelper = null; private static DatabaseHelper sDatabaseHelper = null;
private static ConfigBuilderPlugin sConfigBuilder = null;
private static ConstraintChecker sConstraintsChecker = null; private static ConstraintChecker sConstraintsChecker = null;
private static ArrayList<PluginBase> pluginsList = null; private static ArrayList<PluginBase> pluginsList = null;
@ -98,6 +100,7 @@ public class MainApp extends Application {
private static DataReceiver dataReceiver = new DataReceiver(); private static DataReceiver dataReceiver = new DataReceiver();
private static NSAlarmReceiver alarmReciever = new NSAlarmReceiver(); private static NSAlarmReceiver alarmReciever = new NSAlarmReceiver();
private static AckAlarmReceiver ackAlarmReciever = new AckAlarmReceiver(); private static AckAlarmReceiver ackAlarmReciever = new AckAlarmReceiver();
private static DBAccessReceiver dbAccessReciever = new DBAccessReceiver();
private LocalBroadcastManager lbm; private LocalBroadcastManager lbm;
public static boolean devBranch; public static boolean devBranch;
@ -106,6 +109,7 @@ public class MainApp extends Application {
@Override @Override
public void onCreate() { public void onCreate() {
super.onCreate(); super.onCreate();
log.debug("onCreate");
sInstance = this; sInstance = this;
sResources = getResources(); sResources = getResources();
sConstraintsChecker = new ConstraintChecker(this); sConstraintsChecker = new ConstraintChecker(this);
@ -118,7 +122,7 @@ public class MainApp extends Application {
Crashlytics.setString("BUILDVERSION", BuildConfig.BUILDVERSION); Crashlytics.setString("BUILDVERSION", BuildConfig.BUILDVERSION);
} }
} catch (Exception e) { } catch (Exception e) {
android.util.Log.e("ANDROIDAPS", "Error with Fabric init! " + e); log.error("Error with Fabric init! " + e);
} }
JodaTimeAndroid.init(this); JodaTimeAndroid.init(this);
@ -126,13 +130,13 @@ public class MainApp extends Application {
log.info("Version: " + BuildConfig.VERSION_NAME); log.info("Version: " + BuildConfig.VERSION_NAME);
log.info("BuildVersion: " + BuildConfig.BUILDVERSION); log.info("BuildVersion: " + BuildConfig.BUILDVERSION);
String extFilesDir = this.getLogDirectory(); String extFilesDir = LoggerUtils.getLogDirectory();
File engineeringModeSemaphore = new File(extFilesDir, "engineering_mode"); File engineeringModeSemaphore = new File(extFilesDir, "engineering_mode");
engineeringMode = engineeringModeSemaphore.exists() && engineeringModeSemaphore.isFile(); engineeringMode = engineeringModeSemaphore.exists() && engineeringModeSemaphore.isFile();
devBranch = BuildConfig.VERSION.contains("dev"); devBranch = BuildConfig.VERSION.contains("dev");
sBus = Config.logEvents ? new LoggingBus(ThreadEnforcer.ANY) : new Bus(ThreadEnforcer.ANY); sBus = L.isEnabled(L.EVENTS) && devBranch ? new LoggingBus(ThreadEnforcer.ANY) : new Bus(ThreadEnforcer.ANY);
registerLocalBroadcastReceiver(); registerLocalBroadcastReceiver();
@ -148,14 +152,15 @@ public class MainApp extends Application {
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.HWPUMPS) pluginsList.add(DanaRPlugin.getPlugin()); pluginsList.add(SensitivityOref1Plugin.getPlugin());
if (Config.HWPUMPS) pluginsList.add(DanaRKoreanPlugin.getPlugin()); if (Config.PUMPDRIVERS) pluginsList.add(DanaRPlugin.getPlugin());
if (Config.HWPUMPS) pluginsList.add(DanaRv2Plugin.getPlugin()); if (Config.PUMPDRIVERS) pluginsList.add(DanaRKoreanPlugin.getPlugin());
if (Config.HWPUMPS) pluginsList.add(DanaRSPlugin.getPlugin()); if (Config.PUMPDRIVERS) pluginsList.add(DanaRv2Plugin.getPlugin());
if (Config.PUMPDRIVERS) pluginsList.add(DanaRSPlugin.getPlugin());
pluginsList.add(CareportalPlugin.getPlugin()); pluginsList.add(CareportalPlugin.getPlugin());
if (Config.HWPUMPS && engineeringMode) if (Config.PUMPDRIVERS && engineeringMode)
pluginsList.add(InsightPlugin.getPlugin()); // <-- Enable Insight plugin here pluginsList.add(InsightPlugin.getPlugin()); // <-- Enable Insight plugin here
if (Config.HWPUMPS) pluginsList.add(ComboPlugin.getPlugin()); if (Config.PUMPDRIVERS) pluginsList.add(ComboPlugin.getPlugin());
if (Config.MDI) pluginsList.add(MDIPlugin.getPlugin()); if (Config.MDI) pluginsList.add(MDIPlugin.getPlugin());
pluginsList.add(VirtualPumpPlugin.getPlugin()); pluginsList.add(VirtualPumpPlugin.getPlugin());
if (Config.APS) pluginsList.add(LoopPlugin.getPlugin()); if (Config.APS) pluginsList.add(LoopPlugin.getPlugin());
@ -168,46 +173,33 @@ public class MainApp extends Application {
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());
if (!Config.NSCLIENT && !Config.G5UPLOADER)
pluginsList.add(SourceXdripPlugin.getPlugin()); pluginsList.add(SourceXdripPlugin.getPlugin());
if (!Config.G5UPLOADER)
pluginsList.add(SourceNSClientPlugin.getPlugin()); pluginsList.add(SourceNSClientPlugin.getPlugin());
if (!Config.NSCLIENT && !Config.G5UPLOADER)
pluginsList.add(SourceMM640gPlugin.getPlugin()); pluginsList.add(SourceMM640gPlugin.getPlugin());
if (!Config.NSCLIENT && !Config.G5UPLOADER)
pluginsList.add(SourceGlimpPlugin.getPlugin()); pluginsList.add(SourceGlimpPlugin.getPlugin());
if (!Config.NSCLIENT)
pluginsList.add(SourceDexcomG5Plugin.getPlugin()); pluginsList.add(SourceDexcomG5Plugin.getPlugin());
pluginsList.add(SourcePoctechPlugin.getPlugin());
if (Config.SMSCOMMUNICATORENABLED) pluginsList.add(SmsCommunicatorPlugin.getPlugin()); if (Config.SMSCOMMUNICATORENABLED) pluginsList.add(SmsCommunicatorPlugin.getPlugin());
pluginsList.add(FoodPlugin.getPlugin()); pluginsList.add(FoodPlugin.getPlugin());
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(PersistentNotificationPlugin.getPlugin());
pluginsList.add(NSClientPlugin.getPlugin()); pluginsList.add(NSClientPlugin.getPlugin());
pluginsList.add(MaintenancePlugin.initPlugin(this));
pluginsList.add(sConfigBuilder = ConfigBuilderPlugin.getPlugin()); pluginsList.add(ConfigBuilderPlugin.getPlugin());
MainApp.getConfigBuilder().initialize(); ConfigBuilderPlugin.getPlugin().initialize();
} }
NSUpload.uploadAppStart(); NSUpload.uploadAppStart();
if (Config.NSCLIENT) final PumpInterface pump = ConfigBuilderPlugin.getPlugin().getActivePump();
FabricPrivacy.getInstance().logCustom(new CustomEvent("AppStart-NSClient"));
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) { if (pump != null) {
new Thread(() -> { new Thread(() -> {
SystemClock.sleep(5000); SystemClock.sleep(5000);
ConfigBuilderPlugin.getCommandQueue().readStatus("Initialization", null); ConfigBuilderPlugin.getPlugin().getCommandQueue().readStatus("Initialization", null);
startKeepAliveService(); startKeepAliveService();
}).start(); }).start();
} }
@ -236,6 +228,9 @@ public class MainApp extends Application {
//register ack alarm //register ack alarm
lbm.registerReceiver(ackAlarmReciever, new IntentFilter(Intents.ACTION_ACK_ALARM)); lbm.registerReceiver(ackAlarmReciever, new IntentFilter(Intents.ACTION_ACK_ALARM));
//register dbaccess
lbm.registerReceiver(dbAccessReciever, new IntentFilter(Intents.ACTION_DATABASE));
} }
private void startKeepAliveService() { private void startKeepAliveService() {
@ -278,6 +273,10 @@ public class MainApp extends Application {
return sResources.getString(id, args); return sResources.getString(id, args);
} }
public static String gq(@PluralsRes int id, int quantity, Object... args) {
return sResources.getQuantityString(id, quantity, args);
}
public static int gc(int id) { public static int gc(int id) {
return sResources.getColor(id); return sResources.getColor(id);
} }
@ -297,10 +296,6 @@ public class MainApp extends Application {
} }
} }
public static ConfigBuilderPlugin getConfigBuilder() {
return sConfigBuilder;
}
public static ConstraintChecker getConstraintChecker() { public static ConstraintChecker getConstraintChecker() {
return sConstraintsChecker; return sConstraintsChecker;
} }
@ -381,7 +376,7 @@ public class MainApp extends Application {
} }
public static boolean isEngineeringModeOrRelease() { public static boolean isEngineeringModeOrRelease() {
if (!BuildConfig.APS) if (!Config.APS)
return true; return true;
return engineeringMode || !devBranch; return engineeringMode || !devBranch;
} }
@ -390,13 +385,10 @@ public class MainApp extends Application {
return devBranch; return devBranch;
} }
public String getLogDirectory() {
LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
return lc.getProperty("EXT_FILES_DIR");
}
@Override @Override
public void onTerminate() { public void onTerminate() {
if (L.isEnabled(L.CORE))
log.debug("onTerminate");
super.onTerminate(); super.onTerminate();
if (sDatabaseHelper != null) { if (sDatabaseHelper != null) {
sDatabaseHelper.close(); sDatabaseHelper.close();

View file

@ -1,558 +0,0 @@
package info.nightscout.androidaps.Services;
import android.app.IntentService;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.provider.Telephony;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.ProfileStore;
import info.nightscout.androidaps.db.BgReading;
import info.nightscout.androidaps.db.CareportalEvent;
import info.nightscout.androidaps.events.EventNsFood;
import info.nightscout.androidaps.events.EventNsTreatment;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
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.NSSettingsStatus;
import info.nightscout.androidaps.plugins.NSClientInternal.data.NSSgv;
import info.nightscout.androidaps.plugins.Overview.OverviewPlugin;
import info.nightscout.androidaps.plugins.Overview.events.EventDismissNotification;
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.events.EventNSProfileUpdateGUI;
import info.nightscout.androidaps.plugins.PumpDanaR.activities.DanaRNSHistorySync;
import info.nightscout.androidaps.plugins.SmsCommunicator.events.EventNewSMS;
import info.nightscout.androidaps.plugins.Source.SourceDexcomG5Plugin;
import info.nightscout.androidaps.plugins.Source.SourceGlimpPlugin;
import info.nightscout.androidaps.plugins.Source.SourceMM640gPlugin;
import info.nightscout.androidaps.plugins.Source.SourceNSClientPlugin;
import info.nightscout.androidaps.plugins.Source.SourceXdripPlugin;
import info.nightscout.androidaps.receivers.DataReceiver;
import info.nightscout.utils.BundleLogger;
import info.nightscout.utils.JsonHelper;
import info.nightscout.utils.NSUpload;
import info.nightscout.utils.SP;
public class DataService extends IntentService {
private static Logger log = LoggerFactory.getLogger(DataService.class);
boolean xDripEnabled = false;
boolean nsClientEnabled = true;
boolean mm640gEnabled = false;
boolean glimpEnabled = false;
boolean dexcomG5Enabled = false;
public DataService() {
super("DataService");
registerBus();
}
@Override
protected void onHandleIntent(final Intent intent) {
if (Config.logFunctionCalls)
log.debug("onHandleIntent " + BundleLogger.log(intent.getExtras()));
if (ConfigBuilderPlugin.getPlugin().getActiveBgSource() == null) {
xDripEnabled = true;
nsClientEnabled = false;
mm640gEnabled = false;
glimpEnabled = false;
dexcomG5Enabled = false;
} 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;
nsClientEnabled = true;
mm640gEnabled = false;
glimpEnabled = false;
dexcomG5Enabled = false;
} else if (ConfigBuilderPlugin.getPlugin().getActiveBgSource().getClass().equals(SourceMM640gPlugin.class)) {
xDripEnabled = false;
nsClientEnabled = false;
mm640gEnabled = true;
glimpEnabled = false;
dexcomG5Enabled = false;
} else if (ConfigBuilderPlugin.getPlugin().getActiveBgSource().getClass().equals(SourceGlimpPlugin.class)) {
xDripEnabled = false;
nsClientEnabled = false;
mm640gEnabled = false;
glimpEnabled = true;
dexcomG5Enabled = false;
} else if (ConfigBuilderPlugin.getPlugin().getActiveBgSource().getClass().equals(SourceDexcomG5Plugin.class)) {
xDripEnabled = false;
nsClientEnabled = false;
mm640gEnabled = false;
glimpEnabled = false;
dexcomG5Enabled = true;
}
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");
}
if (intent != null) {
final String action = intent.getAction();
if (Intents.ACTION_NEW_BG_ESTIMATE.equals(action)) {
if (xDripEnabled) {
handleNewDataFromXDrip(intent);
}
} else if (Intents.NS_EMULATOR.equals(action)) {
if (mm640gEnabled) {
handleNewDataFromMM640g(intent);
}
} else if (Intents.GLIMP_BG.equals(action)) {
if (glimpEnabled) {
handleNewDataFromGlimp(intent);
}
} else if (Intents.DEXCOMG5_BG.equals(action)) {
if (dexcomG5Enabled) {
handleNewDataFromDexcomG5(intent);
}
} else if (Intents.ACTION_NEW_SGV.equals(action)) {
if (nsClientEnabled || SP.getBoolean(R.string.key_ns_autobackfill, true))
handleNewDataFromNSClient(intent);
// Objectives 0
ObjectivesPlugin.bgIsAvailableInNS = true;
ObjectivesPlugin.saveProgress();
} 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
handleNewDataFromNSClient(intent);
} else if (acceptNSData &&
(Intents.ACTION_NEW_TREATMENT.equals(action) ||
Intents.ACTION_CHANGED_TREATMENT.equals(action) ||
Intents.ACTION_REMOVED_TREATMENT.equals(action) ||
Intents.ACTION_NEW_STATUS.equals(action) ||
Intents.ACTION_NEW_DEVICESTATUS.equals(action) ||
Intents.ACTION_NEW_FOOD.equals(action) ||
Intents.ACTION_CHANGED_FOOD.equals(action) ||
Intents.ACTION_REMOVED_FOOD.equals(action) ||
Intents.ACTION_NEW_CAL.equals(action) ||
Intents.ACTION_NEW_MBG.equals(action))
) {
handleNewDataFromNSClient(intent);
} else if (Telephony.Sms.Intents.SMS_RECEIVED_ACTION.equals(action)) {
handleNewSMS(intent);
}
}
if (Config.logFunctionCalls)
log.debug("onHandleIntent exit " + intent);
DataReceiver.completeWakefulIntent(intent);
}
/*
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
if (Config.logFunctionCalls)
log.debug("onStartCommand");
return START_STICKY;
}
*/
@Override
public void onDestroy() {
super.onDestroy();
MainApp.bus().unregister(this);
}
private void registerBus() {
try {
MainApp.bus().unregister(this);
} catch (RuntimeException x) {
// Ignore
}
MainApp.bus().register(this);
}
private void handleNewDataFromXDrip(Intent intent) {
Bundle bundle = intent.getExtras();
if (bundle == null) return;
BgReading bgReading = new BgReading();
bgReading.value = bundle.getDouble(Intents.EXTRA_BG_ESTIMATE);
bgReading.direction = bundle.getString(Intents.EXTRA_BG_SLOPE_NAME);
bgReading.date = bundle.getLong(Intents.EXTRA_TIMESTAMP);
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");
}
private void handleNewDataFromGlimp(Intent intent) {
Bundle bundle = intent.getExtras();
if (bundle == null) return;
BgReading bgReading = new BgReading();
bgReading.value = bundle.getDouble("mySGV");
bgReading.direction = bundle.getString("myTrend");
bgReading.date = bundle.getLong("myTimestamp");
bgReading.raw = 0;
MainApp.getDbHelper().createIfNotExists(bgReading, "GLIMP");
}
private void handleNewDataFromDexcomG5(Intent intent) {
// onHandleIntent Bundle{ data => [{"m_time":1511939180,"m_trend":"NotComputable","m_value":335}]; android.support.content.wakelockid => 95; }Bundle
Bundle bundle = intent.getExtras();
if (bundle == null) return;
BgReading bgReading = new BgReading();
String data = bundle.getString("data");
log.debug("Received Dexcom Data", data);
try {
JSONArray jsonArray = new JSONArray(data);
log.debug("Received Dexcom Data size:" + jsonArray.length());
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject json = jsonArray.getJSONObject(i);
bgReading.value = json.getInt("m_value");
bgReading.direction = json.getString("m_trend");
bgReading.date = json.getLong("m_time") * 1000L;
bgReading.raw = 0;
boolean isNew = MainApp.getDbHelper().createIfNotExists(bgReading, "DexcomG5");
if (isNew && SP.getBoolean(R.string.key_dexcomg5_nsupload, false)) {
NSUpload.uploadBg(bgReading);
}
if (isNew && SP.getBoolean(R.string.key_dexcomg5_xdripupload, false)) {
NSUpload.sendToXdrip(bgReading);
}
}
} catch (JSONException e) {
e.printStackTrace();
}
}
private void handleNewDataFromMM640g(Intent intent) {
Bundle bundle = intent.getExtras();
if (bundle == null) return;
final String collection = bundle.getString("collection");
if (collection == null) return;
if (collection.equals("entries")) {
final String data = bundle.getString("data");
if ((data != null) && (data.length() > 0)) {
try {
final JSONArray json_array = new JSONArray(data);
for (int i = 0; i < json_array.length(); i++) {
final JSONObject json_object = json_array.getJSONObject(i);
final String type = json_object.getString("type");
switch (type) {
case "sgv":
BgReading bgReading = new BgReading();
bgReading.value = json_object.getDouble("sgv");
bgReading.direction = json_object.getString("direction");
bgReading.date = json_object.getLong("date");
bgReading.raw = json_object.getDouble("sgv");
MainApp.getDbHelper().createIfNotExists(bgReading, "MM640g");
break;
default:
log.debug("Unknown entries type: " + type);
}
}
} catch (JSONException e) {
log.error("Got JSON exception: " + e);
}
}
}
}
private void handleNewDataFromNSClient(Intent intent) {
Bundle bundles = intent.getExtras();
if (bundles == null) return;
if (Config.logIncommingData)
log.debug("Got intent: " + intent.getAction());
if (intent.getAction().equals(Intents.ACTION_NEW_STATUS)) {
if (bundles.containsKey("nsclientversioncode")) {
ConfigBuilderPlugin.nightscoutVersionCode = bundles.getInt("nightscoutversioncode"); // for ver 1.2.3 contains 10203
ConfigBuilderPlugin.nightscoutVersionName = bundles.getString("nightscoutversionname");
ConfigBuilderPlugin.nsClientVersionCode = bundles.getInt("nsclientversioncode"); // for ver 1.17 contains 117
ConfigBuilderPlugin.nsClientVersionName = bundles.getString("nsclientversionname");
log.debug("Got versions: NSClient: " + ConfigBuilderPlugin.nsClientVersionName + " Nightscout: " + ConfigBuilderPlugin.nightscoutVersionName);
try {
if (ConfigBuilderPlugin.nsClientVersionCode < MainApp.instance().getPackageManager().getPackageInfo(MainApp.instance().getPackageName(), 0).versionCode) {
Notification notification = new Notification(Notification.OLD_NSCLIENT, MainApp.gs(R.string.unsupportedclientver), Notification.URGENT);
MainApp.bus().post(new EventNewNotification(notification));
} else {
MainApp.bus().post(new EventDismissNotification(Notification.OLD_NSCLIENT));
}
} catch (PackageManager.NameNotFoundException e) {
log.error("Unhandled exception", e);
}
if (ConfigBuilderPlugin.nightscoutVersionCode < Config.SUPPORTEDNSVERSION) {
Notification notification = new Notification(Notification.OLD_NS, MainApp.gs(R.string.unsupportednsversion), Notification.NORMAL);
MainApp.bus().post(new EventNewNotification(notification));
} else {
MainApp.bus().post(new EventDismissNotification(Notification.OLD_NS));
}
} else {
Notification notification = new Notification(Notification.OLD_NSCLIENT, MainApp.gs(R.string.unsupportedclientver), Notification.URGENT);
MainApp.bus().post(new EventNewNotification(notification));
}
if (bundles.containsKey("status")) {
try {
JSONObject statusJson = new JSONObject(bundles.getString("status"));
NSSettingsStatus.getInstance().setData(statusJson);
if (Config.logIncommingData)
log.debug("Received status: " + statusJson.toString());
Double targetHigh = NSSettingsStatus.getInstance().getThreshold("bgTargetTop");
Double targetlow = NSSettingsStatus.getInstance().getThreshold("bgTargetBottom");
if (targetHigh != null)
OverviewPlugin.bgTargetHigh = targetHigh;
if (targetlow != null)
OverviewPlugin.bgTargetLow = targetlow;
} catch (JSONException e) {
log.error("Unhandled exception", e);
}
}
}
if (intent.getAction().equals(Intents.ACTION_NEW_DEVICESTATUS)) {
try {
if (bundles.containsKey("devicestatus")) {
JSONObject devicestatusJson = new JSONObject(bundles.getString("devicestatus"));
NSDeviceStatus.getInstance().setData(devicestatusJson);
if (devicestatusJson.has("pump")) {
// Objectives 0
ObjectivesPlugin.pumpStatusIsAvailableInNS = true;
ObjectivesPlugin.saveProgress();
}
}
if (bundles.containsKey("devicestatuses")) {
String devicestatusesstring = bundles.getString("devicestatuses");
JSONArray jsonArray = new JSONArray(devicestatusesstring);
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject devicestatusJson = jsonArray.getJSONObject(i);
NSDeviceStatus.getInstance().setData(devicestatusJson);
if (devicestatusJson.has("pump")) {
// Objectives 0
ObjectivesPlugin.pumpStatusIsAvailableInNS = true;
ObjectivesPlugin.saveProgress();
}
}
}
} catch (Exception e) {
log.error("Unhandled exception", e);
}
}
// Handle profile
if (intent.getAction().equals(Intents.ACTION_NEW_PROFILE)) {
try {
String activeProfile = bundles.getString("activeprofile");
String profile = bundles.getString("profile");
ProfileStore profileStore = new ProfileStore(new JSONObject(profile));
NSProfilePlugin.getPlugin().storeNewProfile(profileStore);
MainApp.bus().post(new EventNSProfileUpdateGUI());
if (Config.logIncommingData)
log.debug("Received profileStore: " + activeProfile + " " + profile);
} catch (JSONException e) {
log.error("Unhandled exception", e);
}
}
if (intent.getAction().equals(Intents.ACTION_NEW_TREATMENT) || intent.getAction().equals(Intents.ACTION_CHANGED_TREATMENT)) {
try {
if (bundles.containsKey("treatment")) {
JSONObject json = new JSONObject(bundles.getString("treatment"));
handleTreatmentFromNS(json, intent);
}
if (bundles.containsKey("treatments")) {
String trstring = bundles.getString("treatments");
JSONArray jsonArray = new JSONArray(trstring);
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject json = jsonArray.getJSONObject(i);
handleTreatmentFromNS(json, intent);
}
}
} catch (JSONException e) {
log.error("Unhandled exception", e);
}
}
if (intent.getAction().equals(Intents.ACTION_REMOVED_TREATMENT)) {
try {
if (bundles.containsKey("treatment")) {
String trstring = bundles.getString("treatment");
JSONObject json = new JSONObject(trstring);
handleTreatmentFromNS(json);
}
if (bundles.containsKey("treatments")) {
String trstring = bundles.getString("treatments");
JSONArray jsonArray = new JSONArray(trstring);
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject json = jsonArray.getJSONObject(i);
handleTreatmentFromNS(json);
}
}
} catch (JSONException e) {
log.error("Unhandled exception", e);
}
}
if (intent.getAction().equals(Intents.ACTION_NEW_SGV)) {
try {
if (bundles.containsKey("sgv")) {
String sgvstring = bundles.getString("sgv");
JSONObject sgvJson = new JSONObject(sgvstring);
NSSgv nsSgv = new NSSgv(sgvJson);
BgReading bgReading = new BgReading(nsSgv);
MainApp.getDbHelper().createIfNotExists(bgReading, "NS");
}
if (bundles.containsKey("sgvs")) {
String sgvstring = bundles.getString("sgvs");
JSONArray jsonArray = new JSONArray(sgvstring);
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject sgvJson = jsonArray.getJSONObject(i);
NSSgv nsSgv = new NSSgv(sgvJson);
BgReading bgReading = new BgReading(nsSgv);
MainApp.getDbHelper().createIfNotExists(bgReading, "NS");
}
}
} catch (Exception e) {
log.error("Unhandled exception", e);
}
}
if (intent.getAction().equals(Intents.ACTION_NEW_MBG)) {
try {
if (bundles.containsKey("mbg")) {
String mbgstring = bundles.getString("mbg");
JSONObject mbgJson = new JSONObject(mbgstring);
NSMbg nsMbg = new NSMbg(mbgJson);
CareportalEvent careportalEvent = new CareportalEvent(nsMbg);
MainApp.getDbHelper().createOrUpdate(careportalEvent);
if (Config.logIncommingData)
log.debug("Adding/Updating new MBG: " + careportalEvent.log());
}
if (bundles.containsKey("mbgs")) {
String sgvstring = bundles.getString("mbgs");
JSONArray jsonArray = new JSONArray(sgvstring);
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject mbgJson = jsonArray.getJSONObject(i);
NSMbg nsMbg = new NSMbg(mbgJson);
CareportalEvent careportalEvent = new CareportalEvent(nsMbg);
MainApp.getDbHelper().createOrUpdate(careportalEvent);
if (Config.logIncommingData)
log.debug("Adding/Updating new MBG: " + careportalEvent.log());
}
}
} catch (Exception e) {
log.error("Unhandled exception", e);
}
}
if (intent.getAction().equals(Intents.ACTION_NEW_FOOD)
|| intent.getAction().equals(Intents.ACTION_CHANGED_FOOD)) {
int mode = Intents.ACTION_NEW_FOOD.equals(intent.getAction()) ? EventNsFood.ADD : EventNsFood.UPDATE;
EventNsFood evt = new EventNsFood(mode, bundles);
MainApp.bus().post(evt);
}
if (intent.getAction().equals(Intents.ACTION_REMOVED_FOOD)) {
EventNsFood evt = new EventNsFood(EventNsFood.REMOVE, bundles);
MainApp.bus().post(evt);
}
}
private void handleTreatmentFromNS(JSONObject json) {
// new DB model
EventNsTreatment evtTreatment = new EventNsTreatment(EventNsTreatment.REMOVE, json);
MainApp.bus().post(evtTreatment);
// old DB model
String _id = JsonHelper.safeGetString(json, "_id");
MainApp.getDbHelper().deleteTempTargetById(_id);
MainApp.getDbHelper().deleteTempBasalById(_id);
MainApp.getDbHelper().deleteExtendedBolusById(_id);
MainApp.getDbHelper().deleteCareportalEventById(_id);
MainApp.getDbHelper().deleteProfileSwitchById(_id);
}
private void handleTreatmentFromNS(JSONObject json, Intent intent) throws JSONException {
// new DB model
int mode = Intents.ACTION_NEW_TREATMENT.equals(intent.getAction()) ? EventNsTreatment.ADD : EventNsTreatment.UPDATE;
double insulin = JsonHelper.safeGetDouble(json, "insulin");
double carbs = JsonHelper.safeGetDouble(json, "carbs");
String eventType = JsonHelper.safeGetString(json, "eventType");
if (insulin > 0 || carbs > 0) {
EventNsTreatment evtTreatment = new EventNsTreatment(mode, json);
MainApp.bus().post(evtTreatment);
} else if (json.has(DanaRNSHistorySync.DANARSIGNATURE)) {
// old DB model
MainApp.getDbHelper().updateDanaRHistoryRecordId(json);
} else if (eventType.equals(CareportalEvent.TEMPORARYTARGET)) {
MainApp.getDbHelper().createTemptargetFromJsonIfNotExists(json);
} else if (eventType.equals(CareportalEvent.TEMPBASAL)) {
MainApp.getDbHelper().createTempBasalFromJsonIfNotExists(json);
} else if (eventType.equals(CareportalEvent.COMBOBOLUS)) {
MainApp.getDbHelper().createExtendedBolusFromJsonIfNotExists(json);
} else if (eventType.equals(CareportalEvent.PROFILESWITCH)) {
MainApp.getDbHelper().createProfileSwitchFromJsonIfNotExists(json);
} else if (eventType.equals(CareportalEvent.SITECHANGE) ||
eventType.equals(CareportalEvent.INSULINCHANGE) ||
eventType.equals(CareportalEvent.SENSORCHANGE) ||
eventType.equals(CareportalEvent.BGCHECK) ||
eventType.equals(CareportalEvent.NOTE) ||
eventType.equals(CareportalEvent.NONE) ||
eventType.equals(CareportalEvent.ANNOUNCEMENT) ||
eventType.equals(CareportalEvent.QUESTION) ||
eventType.equals(CareportalEvent.EXERCISE) ||
eventType.equals(CareportalEvent.OPENAPSOFFLINE) ||
eventType.equals(CareportalEvent.PUMPBATTERYCHANGE)) {
MainApp.getDbHelper().createCareportalEventFromJsonIfNotExists(json);
}
if (eventType.equals(CareportalEvent.ANNOUNCEMENT)) {
long date = JsonHelper.safeGetLong(json,"mills");
long now = System.currentTimeMillis();
String enteredBy = JsonHelper.safeGetString(json, "enteredBy", "");
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));
}
}
}
private void handleNewSMS(Intent intent) {
Bundle bundle = intent.getExtras();
if (bundle == null) return;
MainApp.bus().post(new EventNewSMS(bundle));
}
}

View file

@ -1,4 +1,4 @@
package info.nightscout.androidaps; package info.nightscout.androidaps.activities;
import android.app.Activity; import android.app.Activity;
import android.content.Intent; import android.content.Intent;
@ -9,6 +9,8 @@ import android.view.View;
import android.widget.Button; import android.widget.Button;
import android.widget.CheckBox; import android.widget.CheckBox;
import info.nightscout.androidaps.MainActivity;
import info.nightscout.androidaps.R;
import info.nightscout.utils.SP; import info.nightscout.utils.SP;
public class AgreementActivity extends Activity { public class AgreementActivity extends Activity {

View file

@ -0,0 +1,435 @@
package info.nightscout.androidaps.activities;
import android.os.Bundle;
import android.os.SystemClock;
import android.support.v4.content.res.ResourcesCompat;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.PopupMenu;
import android.text.SpannableString;
import android.text.style.ForegroundColorSpan;
import android.view.Menu;
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 com.wdullaer.materialdatetimepicker.date.DatePickerDialog;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Calendar;
import java.util.Date;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import butterknife.OnLongClick;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.events.EventCustomCalculationFinished;
import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.ConfigBuilder.ProfileFunctions;
import info.nightscout.androidaps.plugins.IobCobCalculator.IobCobCalculatorPlugin;
import info.nightscout.androidaps.plugins.IobCobCalculator.events.EventAutosensCalculationFinished;
import info.nightscout.androidaps.plugins.IobCobCalculator.events.EventIobCalculationProgress;
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.T;
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;
@BindView(R.id.overview_iobcalculationprogess)
TextView iobCalculationProgressView;
private int rangeToDisplay = 24; // for graph
private long start = 0;
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.gc(R.color.graphgrid));
bgGraph.getGridLabelRenderer().reloadStyles();
iobGraph.getGridLabelRenderer().setGridColor(MainApp.gc(R.color.graphgrid));
iobGraph.getGridLabelRenderer().reloadStyles();
iobGraph.getGridLabelRenderer().setHorizontalLabelsVisible(false);
bgGraph.getGridLabelRenderer().setLabelVerticalWidth(50);
iobGraph.getGridLabelRenderer().setLabelVerticalWidth(50);
iobGraph.getGridLabelRenderer().setNumVerticalLabels(5);
setupChartMenu();
}
@Override
public void onPause() {
super.onPause();
MainApp.bus().unregister(this);
iobCobCalculatorPlugin.stopCalculation("onPause");
}
@Override
public void onResume() {
super.onResume();
MainApp.bus().register(this);
// 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();
runCalculation("onResume");
SystemClock.sleep(1000);
updateGUI("onResume");
}
@OnClick(R.id.historybrowse_left)
void onClickLeft() {
start -= T.hours(rangeToDisplay).msecs();
updateGUI("onClickLeft");
runCalculation("onClickLeft");
}
@OnClick(R.id.historybrowse_right)
void onClickRight() {
start += T.hours(rangeToDisplay).msecs();
updateGUI("onClickRight");
runCalculation("onClickRight");
}
@OnClick(R.id.historybrowse_end)
void onClickEnd() {
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.MILLISECOND, 0);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.HOUR_OF_DAY, 0);
start = calendar.getTimeInMillis();
updateGUI("onClickEnd");
runCalculation("onClickEnd");
}
@OnClick(R.id.historybrowse_zoom)
void onClickZoom() {
rangeToDisplay += 6;
rangeToDisplay = rangeToDisplay > 24 ? 6 : rangeToDisplay;
updateGUI("rangeChange");
}
@OnLongClick(R.id.historybrowse_zoom)
boolean onLongClickZoom() {
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(start);
calendar.set(Calendar.MILLISECOND, 0);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.HOUR_OF_DAY, 0);
start = calendar.getTimeInMillis();
updateGUI("resetToMidnight");
runCalculation("onLongClickZoom");
return true;
}
@OnClick(R.id.historybrowse_date)
void onClickDate() {
Calendar calendar = Calendar.getInstance();
calendar.setTime(new Date(start));
DatePickerDialog dpd = DatePickerDialog.newInstance(
(view, year, monthOfYear, dayOfMonth) -> {
Date date = new Date(0);
date.setYear(year - 1900);
date.setMonth(monthOfYear);
date.setDate(dayOfMonth);
date.setHours(0);
start = date.getTime();
updateGUI("onClickDate");
runCalculation("onClickDate");
},
calendar.get(Calendar.YEAR),
calendar.get(Calendar.MONTH),
calendar.get(Calendar.DAY_OF_MONTH)
);
dpd.setThemeDark(true);
dpd.dismissOnPause(true);
dpd.show(getFragmentManager(), "Datepickerdialog");
}
private void runCalculation(String from) {
long end = start + T.hours(rangeToDisplay).msecs();
iobCobCalculatorPlugin.stopCalculation(from);
iobCobCalculatorPlugin.clearCache();
iobCobCalculatorPlugin.runCalculation(from, end, true, false, eventCustomCalculationFinished);
}
@Subscribe
public void onStatusEvent(final EventAutosensCalculationFinished e) {
if (e.cause == eventCustomCalculationFinished) {
log.debug("EventAutosensCalculationFinished");
runOnUiThread(() -> {
synchronized (HistoryBrowseActivity.this) {
updateGUI("EventAutosensCalculationFinished");
}
});
}
}
@Subscribe
public void onStatusEvent(final EventIobCalculationProgress e) {
runOnUiThread(() -> {
if (iobCalculationProgressView != null)
iobCalculationProgressView.setText(e.progress);
});
}
void updateGUI(String from) {
log.debug("updateGUI from: " + from);
if (noProfile == null || buttonDate == null || buttonZoom == null || bgGraph == null || iobGraph == null || seekBar == null)
return;
final PumpInterface pump = ConfigBuilderPlugin.getPlugin().getActivePump();
final Profile profile = ProfileFunctions.getInstance().getProfile();
if (profile == null) {
noProfile.setVisibility(View.VISIBLE);
return;
} else {
noProfile.setVisibility(View.GONE);
}
final String units = profile.getUnits();
final double lowLine = OverviewPlugin.getPlugin().determineLowLine(units);
final double highLine = OverviewPlugin.getPlugin().determineHighLine(units);
buttonDate.setText(DateUtil.dateAndTimeString(start));
buttonZoom.setText(String.valueOf(rangeToDisplay));
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 + T.secs(100).msecs();
toTime = start + T.hours(rangeToDisplay).msecs();
//}
log.debug("Period: " + DateUtil.dateAndTimeString(fromTime) + " - " + DateUtil.dateAndTimeString(toTime));
final long pointer = System.currentTimeMillis();
// ------------------ 1st graph
final GraphData graphData = new GraphData(bgGraph, iobCobCalculatorPlugin);
// **** 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
new Thread(() -> {
final GraphData secondGraphData = new GraphData(iobGraph, iobCobCalculatorPlugin);
boolean useIobForScale = false;
boolean useCobForScale = false;
boolean useDevForScale = false;
boolean useRatioForScale = false;
boolean useDSForScale = false;
if (showIob) {
useIobForScale = true;
} else if (showCob) {
useCobForScale = true;
} else if (showDev) {
useDevForScale = true;
} else if (showRat) {
useRatioForScale = true;
} else if (showDevslope) {
useDSForScale = 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, useDSForScale, 1d);
// **** NOW line ****
// set manual x bounds to have nice steps
secondGraphData.formatAxis(fromTime, toTime);
secondGraphData.addNowLine(pointer);
// do GUI update
runOnUiThread(() -> {
if (showIob || showCob || showDev || showRat || showDevslope) {
iobGraph.setVisibility(View.VISIBLE);
} else {
iobGraph.setVisibility(View.GONE);
}
// finally enforce drawing of graphs
graphData.performUpdate();
if (showIob || showCob || showDev || showRat || showDevslope)
secondGraphData.performUpdate();
});
}).start();
}
private void setupChartMenu() {
chartButton = (ImageButton) findViewById(R.id.overview_chartMenuButton);
chartButton.setOnClickListener(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(item1 -> {
if (item1.getItemId() == OverviewFragment.CHARTTYPE.BAS.ordinal()) {
showBasal = !item1.isChecked();
} else if (item1.getItemId() == OverviewFragment.CHARTTYPE.IOB.ordinal()) {
showIob = !item1.isChecked();
} else if (item1.getItemId() == OverviewFragment.CHARTTYPE.COB.ordinal()) {
showCob = !item1.isChecked();
} else if (item1.getItemId() == OverviewFragment.CHARTTYPE.DEV.ordinal()) {
showDev = !item1.isChecked();
} else if (item1.getItemId() == OverviewFragment.CHARTTYPE.SEN.ordinal()) {
showRat = !item1.isChecked();
} else if (item1.getItemId() == OverviewFragment.CHARTTYPE.DEVSLOPE.ordinal()) {
showDevslope = !item1.isChecked();
}
updateGUI("onGraphCheckboxesCheckedChanged");
return true;
});
chartButton.setImageResource(R.drawable.ic_arrow_drop_up_white_24dp);
popup.setOnDismissListener(menu -> chartButton.setImageResource(R.drawable.ic_arrow_drop_down_white_24dp));
popup.show();
});
}
}

View file

@ -1,4 +1,4 @@
package info.nightscout.androidaps; package info.nightscout.androidaps.activities;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.os.Bundle; import android.os.Bundle;
@ -11,6 +11,9 @@ import android.preference.PreferenceGroup;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.text.TextUtils; import android.text.TextUtils;
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
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;
@ -30,9 +33,10 @@ 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.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.Sensitivity.SensitivityAAPSPlugin;
import info.nightscout.androidaps.plugins.SensitivityOref0.SensitivityOref0Plugin; import info.nightscout.androidaps.plugins.Sensitivity.SensitivityOref0Plugin;
import info.nightscout.androidaps.plugins.SensitivityWeightedAverage.SensitivityWeightedAveragePlugin; import info.nightscout.androidaps.plugins.Sensitivity.SensitivityOref1Plugin;
import info.nightscout.androidaps.plugins.Sensitivity.SensitivityWeightedAveragePlugin;
import info.nightscout.androidaps.plugins.SmsCommunicator.SmsCommunicatorPlugin; import info.nightscout.androidaps.plugins.SmsCommunicator.SmsCommunicatorPlugin;
import info.nightscout.androidaps.plugins.Source.SourceDexcomG5Plugin; import info.nightscout.androidaps.plugins.Source.SourceDexcomG5Plugin;
import info.nightscout.androidaps.plugins.Wear.WearPlugin; import info.nightscout.androidaps.plugins.Wear.WearPlugin;
@ -85,7 +89,7 @@ public class PreferencesActivity extends PreferenceActivity implements SharedPre
pref.setSummary("******"); pref.setSummary("******");
} else if (pref.getKey().equals(MainApp.gs(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) {
((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())) {
@ -131,7 +135,7 @@ public class PreferencesActivity extends PreferenceActivity implements SharedPre
addPreferencesFromResource(id); addPreferencesFromResource(id);
} else { } else {
if (!Config.NSCLIENT && !Config.G5UPLOADER) { if (!Config.NSCLIENT) {
addPreferencesFromResource(R.xml.pref_password); addPreferencesFromResource(R.xml.pref_password);
} }
addPreferencesFromResource(R.xml.pref_age); addPreferencesFromResource(R.xml.pref_age);
@ -152,8 +156,9 @@ public class PreferencesActivity extends PreferenceActivity implements SharedPre
addPreferencesFromResourceIfEnabled(SensitivityAAPSPlugin.getPlugin(), PluginType.SENSITIVITY); addPreferencesFromResourceIfEnabled(SensitivityAAPSPlugin.getPlugin(), PluginType.SENSITIVITY);
addPreferencesFromResourceIfEnabled(SensitivityWeightedAveragePlugin.getPlugin(), PluginType.SENSITIVITY); addPreferencesFromResourceIfEnabled(SensitivityWeightedAveragePlugin.getPlugin(), PluginType.SENSITIVITY);
addPreferencesFromResourceIfEnabled(SensitivityOref0Plugin.getPlugin(), PluginType.SENSITIVITY); addPreferencesFromResourceIfEnabled(SensitivityOref0Plugin.getPlugin(), PluginType.SENSITIVITY);
addPreferencesFromResourceIfEnabled(SensitivityOref1Plugin.getPlugin(), PluginType.SENSITIVITY);
if (Config.HWPUMPS) { if (Config.PUMPDRIVERS) {
addPreferencesFromResourceIfEnabled(DanaRPlugin.getPlugin(), PluginType.PUMP); addPreferencesFromResourceIfEnabled(DanaRPlugin.getPlugin(), PluginType.PUMP);
addPreferencesFromResourceIfEnabled(DanaRKoreanPlugin.getPlugin(), PluginType.PUMP); addPreferencesFromResourceIfEnabled(DanaRKoreanPlugin.getPlugin(), PluginType.PUMP);
addPreferencesFromResourceIfEnabled(DanaRv2Plugin.getPlugin(), PluginType.PUMP); addPreferencesFromResourceIfEnabled(DanaRv2Plugin.getPlugin(), PluginType.PUMP);
@ -169,7 +174,7 @@ public class PreferencesActivity extends PreferenceActivity implements SharedPre
} }
} }
if (!Config.NSCLIENT && !Config.G5UPLOADER) { if (!Config.NSCLIENT) {
addPreferencesFromResourceIfEnabled(VirtualPumpPlugin.getPlugin(), PluginType.PUMP); addPreferencesFromResourceIfEnabled(VirtualPumpPlugin.getPlugin(), PluginType.PUMP);
} }
@ -178,9 +183,7 @@ public class PreferencesActivity extends PreferenceActivity implements SharedPre
addPreferencesFromResourceIfEnabled(NSClientPlugin.getPlugin(), PluginType.GENERAL); addPreferencesFromResourceIfEnabled(NSClientPlugin.getPlugin(), PluginType.GENERAL);
addPreferencesFromResourceIfEnabled(SmsCommunicatorPlugin.getPlugin(), PluginType.GENERAL); addPreferencesFromResourceIfEnabled(SmsCommunicatorPlugin.getPlugin(), PluginType.GENERAL);
if (!Config.NSCLIENT && !Config.G5UPLOADER) {
addPreferencesFromResource(R.xml.pref_others); addPreferencesFromResource(R.xml.pref_others);
}
addPreferencesFromResource(R.xml.pref_datachoices); addPreferencesFromResource(R.xml.pref_datachoices);
addPreferencesFromResourceIfEnabled(WearPlugin.getPlugin(), PluginType.GENERAL); addPreferencesFromResourceIfEnabled(WearPlugin.getPlugin(), PluginType.GENERAL);

View file

@ -0,0 +1,60 @@
package info.nightscout.androidaps.activities;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v7.app.AppCompatActivity;
import android.view.Menu;
import android.view.MenuItem;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.activities.PreferencesActivity;
import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.utils.PasswordProtection;
public class SingleFragmentActivity extends AppCompatActivity {
private PluginBase plugin;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_single_fragment);
this.plugin = MainApp.getPluginsList().get(getIntent().getIntExtra("plugin", -1));
setTitle(plugin.getName());
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction().replace(R.id.frame_layout,
Fragment.instantiate(this, plugin.pluginDescription.getFragmentClass())).commit();
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
finish();
return true;
}
else if (item.getItemId() == R.id.nav_plugin_preferences) {
PasswordProtection.QueryPassword(this, R.string.settings_password, "settings_password", () -> {
Intent i = new Intent(this, PreferencesActivity.class);
i.putExtra("id", plugin.getPreferencesId());
startActivity(i);
}, null);
return true;
}
return false;
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
if (plugin.getPreferencesId() != -1)
getMenuInflater().inflate(R.menu.menu_single_fragment, menu);
return super.onCreateOptionsMenu(menu);
}
}

View file

@ -1,4 +1,4 @@
package info.nightscout.androidaps; package info.nightscout.androidaps.activities;
import android.app.Activity; import android.app.Activity;
import android.graphics.Color; import android.graphics.Color;
@ -33,14 +33,15 @@ 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.TDD; 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.interfaces.PumpInterface;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.ConfigBuilder.ProfileFunctions;
import info.nightscout.androidaps.plugins.PumpDanaR.DanaRPlugin; import info.nightscout.androidaps.plugins.PumpDanaR.DanaRPlugin;
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.PumpDanaRKorean.DanaRKoreanPlugin;
import info.nightscout.androidaps.plugins.PumpDanaRS.DanaRSPlugin; import info.nightscout.androidaps.plugins.PumpDanaRS.DanaRSPlugin;
@ -121,7 +122,7 @@ public class TDDStatsActivity extends Activity {
TBB = SP.getString("TBB", "10.00"); TBB = SP.getString("TBB", "10.00");
Profile profile = MainApp.getConfigBuilder().getProfile(); Profile profile = ProfileFunctions.getInstance().getProfile();
if (profile != null) { if (profile != null) {
double cppTBB = profile.baseBasalSum(); double cppTBB = profile.baseBasalSum();
TBB = decimalFormat.format(cppTBB); TBB = decimalFormat.format(cppTBB);
@ -129,7 +130,7 @@ public class TDDStatsActivity extends Activity {
} }
totalBaseBasal.setText(TBB); totalBaseBasal.setText(TBB);
if (!ConfigBuilderPlugin.getActivePump().getPumpDescription().needsManualTDDLoad) if (!ConfigBuilderPlugin.getPlugin().getActivePump().getPumpDescription().needsManualTDDLoad)
reloadButton.setVisibility(View.GONE); reloadButton.setVisibility(View.GONE);
// stats table // stats table
@ -238,7 +239,7 @@ public class TDDStatsActivity extends Activity {
statsMessage.setText(MainApp.gs(R.string.danar_stats_warning_Message)); statsMessage.setText(MainApp.gs(R.string.danar_stats_warning_Message));
} }
}); });
ConfigBuilderPlugin.getCommandQueue().loadTDDs( new Callback() { ConfigBuilderPlugin.getPlugin().getCommandQueue().loadTDDs( new Callback() {
@Override @Override
public void run() { public void run() {
loadDataFromDB(); loadDataFromDB();
@ -439,7 +440,7 @@ public class TDDStatsActivity extends Activity {
TableLayout.LayoutParams.WRAP_CONTENT)); TableLayout.LayoutParams.WRAP_CONTENT));
} }
if (isOldData(historyList) && ConfigBuilderPlugin.getActivePump().getPumpDescription().needsManualTDDLoad) { if (isOldData(historyList) && ConfigBuilderPlugin.getPlugin().getActivePump().getPumpDescription().needsManualTDDLoad) {
statsMessage.setVisibility(View.VISIBLE); statsMessage.setVisibility(View.VISIBLE);
statsMessage.setText(MainApp.gs(R.string.danar_stats_olddata_Message)); statsMessage.setText(MainApp.gs(R.string.danar_stats_olddata_Message));
@ -544,7 +545,7 @@ public class TDDStatsActivity extends Activity {
public static boolean isOldData(List<TDD> historyList) { public static boolean isOldData(List<TDD> historyList) {
Object activePump = MainApp.getConfigBuilder().getActivePump(); Object activePump = ConfigBuilderPlugin.getPlugin().getActivePump();
PumpInterface dana = MainApp.getSpecificPlugin(DanaRPlugin.class); PumpInterface dana = MainApp.getSpecificPlugin(DanaRPlugin.class);
PumpInterface danaRS = MainApp.getSpecificPlugin(DanaRSPlugin.class); PumpInterface danaRS = MainApp.getSpecificPlugin(DanaRSPlugin.class);
PumpInterface danaV2 = MainApp.getSpecificPlugin(DanaRv2Plugin.class); PumpInterface danaV2 = MainApp.getSpecificPlugin(DanaRv2Plugin.class);

View file

@ -4,12 +4,10 @@ import java.util.ArrayList;
import info.nightscout.androidaps.Constants; import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.interfaces.BgSourceInterface;
import info.nightscout.androidaps.interfaces.Constraint; 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.PluginType; import info.nightscout.androidaps.interfaces.PluginType;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
/** /**
* Created by mike on 19.03.2018. * Created by mike on 19.03.2018.
@ -25,7 +23,7 @@ public class ConstraintChecker implements ConstraintsInterface {
public Constraint<Boolean> isLoopInvokationAllowed() { public Constraint<Boolean> isLoopInvokationAllowed() {
return isLoopInvokationAllowed(new Constraint<>(true)); return isLoopInvocationAllowed(new Constraint<>(true));
} }
public Constraint<Boolean> isClosedLoopAllowed() { public Constraint<Boolean> isClosedLoopAllowed() {
@ -44,6 +42,10 @@ public class ConstraintChecker implements ConstraintsInterface {
return isSMBModeEnabled(new Constraint<>(true)); return isSMBModeEnabled(new Constraint<>(true));
} }
public Constraint<Boolean> isUAMEnabled() {
return isUAMEnabled(new Constraint<>(true));
}
public Constraint<Boolean> isAdvancedFilteringEnabled() { public Constraint<Boolean> isAdvancedFilteringEnabled() {
return isAdvancedFilteringEnabled(new Constraint<>(true)); return isAdvancedFilteringEnabled(new Constraint<>(true));
} }
@ -60,6 +62,10 @@ public class ConstraintChecker implements ConstraintsInterface {
return applyBolusConstraints(new Constraint<>(Constants.REALLYHIGHBOLUS)); return applyBolusConstraints(new Constraint<>(Constants.REALLYHIGHBOLUS));
} }
public Constraint<Double> getMaxExtendedBolusAllowed() {
return applyExtendedBolusConstraints(new Constraint<>(Constants.REALLYHIGHBOLUS));
}
public Constraint<Integer> getMaxCarbsAllowed() { public Constraint<Integer> getMaxCarbsAllowed() {
return applyCarbsConstraints(new Constraint<>(Constants.REALLYHIGHCARBS)); return applyCarbsConstraints(new Constraint<>(Constants.REALLYHIGHCARBS));
} }
@ -69,13 +75,13 @@ public class ConstraintChecker implements ConstraintsInterface {
} }
@Override @Override
public Constraint<Boolean> isLoopInvokationAllowed(Constraint<Boolean> value) { public Constraint<Boolean> isLoopInvocationAllowed(Constraint<Boolean> value) {
ArrayList<PluginBase> constraintsPlugins = mainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class); ArrayList<PluginBase> constraintsPlugins = mainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class);
for (PluginBase p : constraintsPlugins) { for (PluginBase p : constraintsPlugins) {
ConstraintsInterface constraint = (ConstraintsInterface) p; ConstraintsInterface constraint = (ConstraintsInterface) p;
if (!p.isEnabled(PluginType.CONSTRAINTS)) continue; if (!p.isEnabled(PluginType.CONSTRAINTS)) continue;
constraint.isLoopInvokationAllowed(value); constraint.isLoopInvocationAllowed(value);
} }
return value; return value;
} }
@ -128,6 +134,18 @@ public class ConstraintChecker implements ConstraintsInterface {
return value; return value;
} }
@Override
public Constraint<Boolean> isUAMEnabled(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.isUAMEnabled(value);
}
return value;
}
@Override @Override
public Constraint<Boolean> isAdvancedFilteringEnabled(Constraint<Boolean> value) { public Constraint<Boolean> isAdvancedFilteringEnabled(Constraint<Boolean> value) {
ArrayList<PluginBase> constraintsPlugins = mainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class); ArrayList<PluginBase> constraintsPlugins = mainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class);
@ -172,6 +190,17 @@ public class ConstraintChecker implements ConstraintsInterface {
return insulin; return insulin;
} }
@Override
public Constraint<Double> applyExtendedBolusConstraints(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.applyExtendedBolusConstraints(insulin);
}
return insulin;
}
@Override @Override
public Constraint<Integer> applyCarbsConstraints(Constraint<Integer> carbs) { public Constraint<Integer> applyCarbsConstraints(Constraint<Integer> carbs) {
ArrayList<PluginBase> constraintsPlugins = mainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class); ArrayList<PluginBase> constraintsPlugins = mainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class);

View file

@ -10,6 +10,7 @@ import java.util.Date;
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.plugins.Treatments.TreatmentsPlugin;
/** /**
* Created by mike on 29.05.2017. * Created by mike on 29.05.2017.
@ -17,6 +18,7 @@ import info.nightscout.androidaps.db.Source;
public class DetailedBolusInfo { public class DetailedBolusInfo {
public long date = System.currentTimeMillis(); public long date = System.currentTimeMillis();
public long lastKnownBolusTime;
public String eventType = CareportalEvent.MEALBOLUS; public String eventType = CareportalEvent.MEALBOLUS;
public double insulin = 0; public double insulin = 0;
public double carbs = 0; public double carbs = 0;
@ -55,6 +57,7 @@ public class DetailedBolusInfo {
@Override @Override
public String toString() { public String toString() {
return new Date(date).toLocaleString() + return new Date(date).toLocaleString() +
" date: " + date +
" insulin: " + insulin + " insulin: " + insulin +
" carbs: " + carbs + " carbs: " + carbs +
" isValid: " + isValid + " isValid: " + isValid +

View file

@ -12,17 +12,18 @@ 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.interfaces.PumpDescription; import info.nightscout.androidaps.interfaces.PumpDescription;
import info.nightscout.androidaps.interfaces.PumpInterface; import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
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.Overview.notifications.Notification;
import info.nightscout.utils.DateUtil; import info.nightscout.utils.DateUtil;
import info.nightscout.utils.DecimalFormatter; import info.nightscout.utils.DecimalFormatter;
import info.nightscout.utils.FabricPrivacy; import info.nightscout.utils.FabricPrivacy;
import info.nightscout.utils.MidnightTime;
public class Profile { public class Profile {
private static Logger log = LoggerFactory.getLogger(Profile.class); private static Logger log = LoggerFactory.getLogger(Profile.class);
@ -52,6 +53,14 @@ public class Profile {
protected Profile() { protected Profile() {
} }
@Override
public String toString() {
if (json != null)
return json.toString();
else
return "Profile has no JSON";
}
// Constructor from profileStore JSON // Constructor from profileStore JSON
public Profile(JSONObject json, String units) { public Profile(JSONObject json, String units) {
init(json, 100, 0); init(json, 100, 0);
@ -202,12 +211,18 @@ public class Profile {
if (targetHigh_v == null) if (targetHigh_v == null)
targetHigh_v = convertToSparseArray(targetHigh); targetHigh_v = convertToSparseArray(targetHigh);
validate(targetHigh_v); validate(targetHigh_v);
if (targetHigh_v.size() != targetLow_v.size()) isValid = false;
else for (int i = 0; i < targetHigh_v.size(); i++)
if (targetHigh_v.valueAt(i) < targetLow_v.valueAt(i))
isValid = false;
isValidated = true; isValidated = true;
} }
if (isValid) { if (isValid) {
// Check for hours alignment // Check for hours alignment
PumpInterface pump = MainApp.getConfigBuilder().getActivePump(); PumpInterface pump = ConfigBuilderPlugin.getPlugin().getActivePump();
if (pump != null && !pump.getPumpDescription().is30minBasalRatesCapable) { if (pump != null && !pump.getPumpDescription().is30minBasalRatesCapable) {
for (int index = 0; index < basal_v.size(); index++) { for (int index = 0; index < basal_v.size(); index++) {
long secondsFromMidnight = basal_v.keyAt(index); long secondsFromMidnight = basal_v.keyAt(index);
@ -226,6 +241,10 @@ public class Profile {
basal_v.setValueAt(i, description.basalMinimumRate); basal_v.setValueAt(i, description.basalMinimumRate);
if (notify) if (notify)
sendBelowMinimumNotification(from); sendBelowMinimumNotification(from);
} else if (basal_v.valueAt(i) > description.basalMaximumRate) {
basal_v.setValueAt(i, description.basalMaximumRate);
if (notify)
sendAboveMaximumNotification(from);
} }
} }
} else { } else {
@ -243,6 +262,10 @@ public class Profile {
MainApp.bus().post(new EventNewNotification(new Notification(Notification.MINIMAL_BASAL_VALUE_REPLACED, String.format(MainApp.gs(R.string.minimalbasalvaluereplaced), from), Notification.NORMAL))); MainApp.bus().post(new EventNewNotification(new Notification(Notification.MINIMAL_BASAL_VALUE_REPLACED, String.format(MainApp.gs(R.string.minimalbasalvaluereplaced), from), Notification.NORMAL)));
} }
protected void sendAboveMaximumNotification(String from) {
MainApp.bus().post(new EventNewNotification(new Notification(Notification.MAXIMUM_BASAL_VALUE_REPLACED, String.format(MainApp.gs(R.string.maximumbasalvaluereplaced), from), Notification.NORMAL)));
}
private void validate(LongSparseArray array) { private void validate(LongSparseArray array) {
if (array.size() == 0) { if (array.size() == 0) {
isValid = false; isValid = false;
@ -281,8 +304,6 @@ public class Profile {
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 && Config.logProfile)
log.debug("(Sec) Original time: " + originalTime + " ShiftedTime: " + shiftedTime);
return shiftedTime; return shiftedTime;
} }
@ -361,7 +382,7 @@ public class Profile {
} }
public double getIsf() { public double getIsf() {
return getIsfTimeFromMidnight(secondsFromMidnight(System.currentTimeMillis())); return getIsfTimeFromMidnight(secondsFromMidnight());
} }
public double getIsf(long time) { public double getIsf(long time) {
@ -381,7 +402,7 @@ public class Profile {
} }
public double getIc() { public double getIc() {
return getIcTimeFromMidnight(secondsFromMidnight(System.currentTimeMillis())); return getIcTimeFromMidnight(secondsFromMidnight());
} }
public double getIc(long time) { public double getIc(long time) {
@ -401,7 +422,7 @@ public class Profile {
} }
public double getBasal() { public double getBasal() {
return getBasalTimeFromMidnight(secondsFromMidnight(System.currentTimeMillis())); return getBasalTimeFromMidnight(secondsFromMidnight());
} }
public double getBasal(long time) { public double getBasal(long time) {
@ -445,7 +466,7 @@ public class Profile {
} }
public double getTarget() { public double getTarget() {
return getTarget(secondsFromMidnight(System.currentTimeMillis())); return getTarget(secondsFromMidnight());
} }
protected double getTarget(int timeAsSeconds) { protected double getTarget(int timeAsSeconds) {
@ -453,7 +474,7 @@ public class Profile {
} }
public double getTargetLow() { public double getTargetLow() {
return getTargetLowTimeFromMidnight(secondsFromMidnight(System.currentTimeMillis())); return getTargetLowTimeFromMidnight(secondsFromMidnight());
} }
public double getTargetLow(long time) { public double getTargetLow(long time) {
@ -467,7 +488,7 @@ public class Profile {
} }
public double getTargetHigh() { public double getTargetHigh() {
return getTargetHighTimeFromMidnight(secondsFromMidnight(System.currentTimeMillis())); return getTargetHighTimeFromMidnight(secondsFromMidnight());
} }
public double getTargetHigh(long time) { public double getTargetHigh(long time) {
@ -498,24 +519,13 @@ public class Profile {
} }
public static int secondsFromMidnight() { public static int secondsFromMidnight() {
Calendar c = Calendar.getInstance(); long passed = DateUtil.now() - MidnightTime.calc();
long now = c.getTimeInMillis();
c.set(Calendar.HOUR_OF_DAY, 0);
c.set(Calendar.MINUTE, 0);
c.set(Calendar.SECOND, 0);
c.set(Calendar.MILLISECOND, 0);
long passed = now - c.getTimeInMillis();
return (int) (passed / 1000); return (int) (passed / 1000);
} }
public static int secondsFromMidnight(long date) { public static int secondsFromMidnight(long date) {
Calendar c = Calendar.getInstance(); long midnight = MidnightTime.calc(date);
c.setTimeInMillis(date); long passed = date - midnight;
c.set(Calendar.HOUR_OF_DAY, 0);
c.set(Calendar.MINUTE, 0);
c.set(Calendar.SECOND, 0);
c.set(Calendar.MILLISECOND, 0);
long passed = date - c.getTimeInMillis();
return (int) (passed / 1000); return (int) (passed / 1000);
} }
@ -544,6 +554,12 @@ public class Profile {
else return DecimalFormatter.to1Decimal(valueInMmol); else return DecimalFormatter.to1Decimal(valueInMmol);
} }
public static String toSignedUnitsString(Double valueInMgdl, Double valueInMmol, String units) {
if (units.equals(Constants.MGDL))
return (valueInMgdl > 0 ? "+" : "") + DecimalFormatter.to0Decimal(valueInMgdl);
else return (valueInMmol > 0 ? "+" : "") + DecimalFormatter.to1Decimal(valueInMmol);
}
// targets are stored in mg/dl but profile vary // targets are stored in mg/dl but profile vary
public static String toTargetRangeString(double low, double high, String sourceUnits, String units) { public static String toTargetRangeString(double low, double high, String sourceUnits, String units) {
double lowMgdl = toMgdl(low, sourceUnits); double lowMgdl = toMgdl(low, sourceUnits);

View file

@ -10,11 +10,12 @@ import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
import info.nightscout.androidaps.logging.L;
import info.nightscout.utils.DecimalFormatter; import info.nightscout.utils.DecimalFormatter;
import info.nightscout.utils.Round; import info.nightscout.utils.Round;
public class PumpEnactResult { public class PumpEnactResult {
private static Logger log = LoggerFactory.getLogger(PumpEnactResult.class); private static Logger log = LoggerFactory.getLogger(L.APS);
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)
public boolean enacted = false; // request was processed successfully and change has been made public boolean enacted = false; // request was processed successfully and change has been made
@ -107,7 +108,7 @@ public class PumpEnactResult {
if (bolusDelivered > 0) { if (bolusDelivered > 0) {
ret += "\n" + MainApp.gs(R.string.enacted) + ": " + enacted; ret += "\n" + MainApp.gs(R.string.enacted) + ": " + enacted;
ret += "\n" + MainApp.gs(R.string.comment) + ": " + comment; ret += "\n" + MainApp.gs(R.string.comment) + ": " + comment;
ret += "\n" + MainApp.gs(R.string.smb_shortname) ret += "\n" + MainApp.gs(R.string.configbuilder_insulin)
+ ": " + bolusDelivered + " " + MainApp.gs(R.string.insulin_unit_shortname); + ": " + bolusDelivered + " " + MainApp.gs(R.string.insulin_unit_shortname);
} else if (isTempCancel) { } else if (isTempCancel) {
ret += "\n" + MainApp.gs(R.string.enacted) + ": " + enacted; ret += "\n" + MainApp.gs(R.string.enacted) + ": " + enacted;

View file

@ -15,6 +15,8 @@ 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.Profile; import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.logging.L;
import info.nightscout.androidaps.plugins.ConfigBuilder.ProfileFunctions;
import info.nightscout.androidaps.plugins.NSClientInternal.data.NSSgv; 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;
@ -24,7 +26,7 @@ import info.nightscout.utils.SP;
@DatabaseTable(tableName = DatabaseHelper.DATABASE_BGREADINGS) @DatabaseTable(tableName = DatabaseHelper.DATABASE_BGREADINGS)
public class BgReading implements DataPointWithLabelInterface { public class BgReading implements DataPointWithLabelInterface {
private static Logger log = LoggerFactory.getLogger(BgReading.class); private static Logger log = LoggerFactory.getLogger(L.DATABASE);
@DatabaseField(id = true) @DatabaseField(id = true)
public long date; public long date;
@ -142,7 +144,7 @@ public class BgReading implements DataPointWithLabelInterface {
return false; return false;
if (raw != other.raw) if (raw != other.raw)
return false; return false;
if (!direction.equals(other.direction)) if (!Objects.equals(direction, other.direction))
return false; return false;
if (!Objects.equals(_id, other._id)) if (!Objects.equals(_id, other._id))
return false; return false;
@ -160,6 +162,21 @@ public class BgReading implements DataPointWithLabelInterface {
_id = other._id; _id = other._id;
} }
public BgReading date(long date) {
this.date = date;
return this;
}
public BgReading date(Date date) {
this.date = date.getTime();
return this;
}
public BgReading value(double value) {
this.value = value;
return this;
}
// ------------------ DataPointWithLabelInterface ------------------ // ------------------ DataPointWithLabelInterface ------------------
@Override @Override
public double getX() { public double getX() {
@ -168,7 +185,7 @@ public class BgReading implements DataPointWithLabelInterface {
@Override @Override
public double getY() { public double getY() {
String units = MainApp.getConfigBuilder().getProfileUnits(); String units = ProfileFunctions.getInstance().getProfileUnits();
return valueToUnits(units); return valueToUnits(units);
} }
@ -202,15 +219,9 @@ public class BgReading implements DataPointWithLabelInterface {
@Override @Override
public int getColor() { public int getColor() {
String units = MainApp.getConfigBuilder().getProfileUnits(); String units = ProfileFunctions.getInstance().getProfileUnits();
Double lowLine = SP.getDouble("low_mark", 0d); Double lowLine = OverviewPlugin.getPlugin().determineLowLine(units);
Double highLine = SP.getDouble("high_mark", 0d); Double highLine = OverviewPlugin.getPlugin().determineHighLine(units);
if (lowLine < 1) {
lowLine = Profile.fromMgdlToUnits(OverviewPlugin.bgTargetLow, units);
}
if (highLine < 1) {
highLine = Profile.fromMgdlToUnits(OverviewPlugin.bgTargetHigh, units);
}
int color = MainApp.gc(R.color.inrange); int color = MainApp.gc(R.color.inrange);
if (isPrediction()) if (isPrediction())
return getPredectionColor(); return getPredectionColor();

View file

@ -24,16 +24,20 @@ 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.Profile; import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.interfaces.Interval;
import info.nightscout.androidaps.logging.L;
import info.nightscout.androidaps.plugins.ConfigBuilder.ProfileFunctions;
import info.nightscout.androidaps.plugins.NSClientInternal.data.NSMbg; import info.nightscout.androidaps.plugins.NSClientInternal.data.NSMbg;
import info.nightscout.androidaps.plugins.Overview.OverviewFragment; import info.nightscout.androidaps.plugins.Overview.OverviewFragment;
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.DateUtil;
import info.nightscout.utils.T;
import info.nightscout.utils.Translator; import info.nightscout.utils.Translator;
@DatabaseTable(tableName = DatabaseHelper.DATABASE_CAREPORTALEVENTS) @DatabaseTable(tableName = DatabaseHelper.DATABASE_CAREPORTALEVENTS)
public class CareportalEvent implements DataPointWithLabelInterface { public class CareportalEvent implements DataPointWithLabelInterface, Interval {
private static Logger log = LoggerFactory.getLogger(CareportalEvent.class); private static Logger log = LoggerFactory.getLogger(L.DATABASE);
@DatabaseField(id = true) @DatabaseField(id = true)
public long date; public long date;
@ -87,7 +91,7 @@ public class CareportalEvent implements DataPointWithLabelInterface {
} }
public long getHoursFromStart() { public long getHoursFromStart() {
return (System.currentTimeMillis() - date) / (60 * 1000); return (System.currentTimeMillis() - date) / (60 * 60 * 1000);
} }
public String age() { public String age() {
@ -99,14 +103,11 @@ public class CareportalEvent implements DataPointWithLabelInterface {
} }
public boolean isOlderThan(double hours) { public boolean isOlderThan(double hours) {
Map<TimeUnit, Long> diff = computeDiff(date, System.currentTimeMillis()); return getHoursFromStart() > hours;
if(diff.get(TimeUnit.DAYS)*24 + diff.get(TimeUnit.HOURS) > hours)
return true;
else
return false;
} }
public String log() { @Override
public String toString() {
return "CareportalEvent{" + return "CareportalEvent{" +
"date= " + date + "date= " + date +
", date= " + DateUtil.dateAndTimeString(date) + ", date= " + DateUtil.dateAndTimeString(date) +
@ -133,6 +134,19 @@ public class CareportalEvent implements DataPointWithLabelInterface {
return result; return result;
} }
public static boolean isEvent5minBack(List<CareportalEvent> list, long time) {
for (int i = 0; i < list.size(); i++) {
CareportalEvent event = list.get(i);
if (event.date <= time && event.date > (time - T.mins(5).msecs())) {
if (L.isEnabled(L.DATABASE))
log.debug("Found event for time: " + DateUtil.dateAndTimeFullString(time) + " " + event.toString());
return true;
}
}
return false;
}
// -------- DataPointWithLabelInterface ------- // -------- DataPointWithLabelInterface -------
@Override @Override
@ -144,7 +158,7 @@ public class CareportalEvent implements DataPointWithLabelInterface {
@Override @Override
public double getY() { public double getY() {
String units = MainApp.getConfigBuilder().getProfileUnits(); String units = ProfileFunctions.getInstance().getProfileUnits();
if (eventType.equals(MBG)) { if (eventType.equals(MBG)) {
double mbg = 0d; double mbg = 0d;
try { try {
@ -213,14 +227,7 @@ public class CareportalEvent implements DataPointWithLabelInterface {
@Override @Override
public long getDuration() { public long getDuration() {
try { return end() - start();
JSONObject object = new JSONObject(json);
if (object.has("duration"))
return object.getInt("duration") * 60 * 1000L;
} catch (JSONException e) {
log.error("Unhandled exception", e);
}
return 0;
} }
@Override @Override
@ -259,8 +266,79 @@ public class CareportalEvent implements DataPointWithLabelInterface {
if (eventType.equals(EXERCISE)) if (eventType.equals(EXERCISE))
return Color.BLUE; return Color.BLUE;
if (eventType.equals(OPENAPSOFFLINE)) if (eventType.equals(OPENAPSOFFLINE))
return Color.GRAY; return Color.GRAY & 0x80FFFFFF;
return Color.GRAY; return Color.GRAY;
} }
// Interval interface
Long cuttedEnd = null;
@Override
public long durationInMsec() {
try {
JSONObject object = new JSONObject(json);
if (object.has("duration"))
return object.getInt("duration") * 60 * 1000L;
} catch (JSONException e) {
log.error("Unhandled exception", e);
}
return 0;
}
@Override
public long start() {
return date;
}
@Override
public long originalEnd() {
return date + durationInMsec();
}
@Override
public long end() {
if (cuttedEnd != null)
return cuttedEnd;
return originalEnd();
}
@Override
public void cutEndTo(long end) {
cuttedEnd = end;
}
@Override
public boolean match(long time) {
if (start() <= time && end() >= time)
return true;
return false;
}
public boolean before(long time) {
if (end() < time)
return true;
return false;
}
public boolean after(long time) {
if (start() > time)
return true;
return false;
}
@Override
public boolean isInProgress() {
return match(System.currentTimeMillis());
}
@Override
public boolean isEndingEvent() {
return durationInMsec() == 0;
}
@Override
public boolean isValid() {
return eventType.equals(OPENAPSOFFLINE);
}
} }

View file

@ -27,9 +27,9 @@ import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture; import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
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.OverlappingIntervals;
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.events.EventCareportalEventChange; import info.nightscout.androidaps.events.EventCareportalEventChange;
@ -42,12 +42,16 @@ 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.interfaces.ProfileInterface;
import info.nightscout.androidaps.logging.L;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.ConfigBuilder.ProfileFunctions;
import info.nightscout.androidaps.plugins.IobCobCalculator.events.EventNewHistoryData; import info.nightscout.androidaps.plugins.IobCobCalculator.events.EventNewHistoryData;
import info.nightscout.androidaps.plugins.NSClientInternal.NSUpload;
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.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.JsonHelper;
import info.nightscout.utils.NSUpload;
import info.nightscout.utils.PercentageSplitter; import info.nightscout.utils.PercentageSplitter;
import info.nightscout.utils.ToastUtils; import info.nightscout.utils.ToastUtils;
@ -60,7 +64,7 @@ import info.nightscout.utils.ToastUtils;
* direct calls to the corresponding methods (eg. resetDatabases) should be done by a central service. * 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(L.DATABASE);
public static final String DATABASE_NAME = "AndroidAPSDb"; public static final String DATABASE_NAME = "AndroidAPSDb";
public static final String DATABASE_BGREADINGS = "BgReadings"; public static final String DATABASE_BGREADINGS = "BgReadings";
@ -73,7 +77,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
public static final String DATABASE_PROFILESWITCHES = "ProfileSwitches"; public static final String DATABASE_PROFILESWITCHES = "ProfileSwitches";
public static final String DATABASE_TDDS = "TDDs"; public static final String DATABASE_TDDS = "TDDs";
private static final int DATABASE_VERSION = 8; private static final int DATABASE_VERSION = 9;
public static Long earliestDataChange = null; public static Long earliestDataChange = null;
@ -107,6 +111,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
@Override @Override
public void onCreate(SQLiteDatabase database, ConnectionSource connectionSource) { public void onCreate(SQLiteDatabase database, ConnectionSource connectionSource) {
try { try {
if (L.isEnabled(L.DATABASE))
log.info("onCreate"); log.info("onCreate");
TableUtils.createTableIfNotExists(connectionSource, TempTarget.class); TableUtils.createTableIfNotExists(connectionSource, TempTarget.class);
TableUtils.createTableIfNotExists(connectionSource, BgReading.class); TableUtils.createTableIfNotExists(connectionSource, BgReading.class);
@ -131,6 +136,8 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
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");
} else if (oldVersion == 8 && newVersion == 9) {
log.debug("Upgrading database from v8 to v9");
} 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);
@ -196,7 +203,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
} catch (SQLException e) { } catch (SQLException e) {
log.error("Unhandled exception", e); log.error("Unhandled exception", e);
} }
VirtualPumpPlugin.setFakingStatus(true); VirtualPumpPlugin.getPlugin().setFakingStatus(true);
scheduleBgChange(null); // trigger refresh scheduleBgChange(null); // trigger refresh
scheduleTemporaryBasalChange(); scheduleTemporaryBasalChange();
scheduleExtendedBolusChange(); scheduleExtendedBolusChange();
@ -232,7 +239,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
} catch (SQLException e) { } catch (SQLException e) {
log.error("Unhandled exception", e); log.error("Unhandled exception", e);
} }
VirtualPumpPlugin.setFakingStatus(false); VirtualPumpPlugin.getPlugin().setFakingStatus(false);
scheduleTemporaryBasalChange(); scheduleTemporaryBasalChange();
} }
@ -315,7 +322,11 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
} }
public static long roundDateToSec(long date) { public static long roundDateToSec(long date) {
return date - date % 1000; long rounded = date - date % 1000;
if (rounded != date)
if (L.isEnabled(L.DATABASE))
log.debug("Rounding " + date + " to " + rounded);
return rounded;
} }
// ------------------- BgReading handling ----------------------- // ------------------- BgReading handling -----------------------
@ -325,14 +336,17 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
BgReading old = getDaoBgReadings().queryForId(bgReading.date); BgReading old = getDaoBgReadings().queryForId(bgReading.date);
if (old == null) { if (old == null) {
getDaoBgReadings().create(bgReading); getDaoBgReadings().create(bgReading);
if (L.isEnabled(L.DATABASE))
log.debug("BG: New record from: " + from + " " + bgReading.toString()); log.debug("BG: New record from: " + from + " " + bgReading.toString());
scheduleBgChange(bgReading); scheduleBgChange(bgReading);
return true; return true;
} }
if (!old.isEqual(bgReading)) { if (!old.isEqual(bgReading)) {
if (L.isEnabled(L.DATABASE))
log.debug("BG: Similiar found: " + old.toString()); log.debug("BG: Similiar found: " + old.toString());
old.copyFrom(bgReading); old.copyFrom(bgReading);
getDaoBgReadings().update(old); getDaoBgReadings().update(old);
if (L.isEnabled(L.DATABASE))
log.debug("BG: Updating record from: " + from + " New data: " + old.toString()); log.debug("BG: Updating record from: " + from + " New data: " + old.toString());
scheduleBgChange(bgReading); scheduleBgChange(bgReading);
return false; return false;
@ -355,6 +369,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
private static void scheduleBgChange(@Nullable final BgReading bgReading) { private static void scheduleBgChange(@Nullable final BgReading bgReading) {
class PostRunnable implements Runnable { class PostRunnable implements Runnable {
public void run() { public void run() {
if (L.isEnabled(L.DATABASE))
log.debug("Firing EventNewBg"); log.debug("Firing EventNewBg");
MainApp.bus().post(new EventNewBG(bgReading)); MainApp.bus().post(new EventNewBG(bgReading));
scheduledBgPost = null; scheduledBgPost = null;
@ -382,12 +397,12 @@ 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).and().eq("isValid", true); queryBuilder.where().ge("value", 39).and().eq("isValid", true);
PreparedQuery<BgReading> preparedQuery = queryBuilder.prepare(); PreparedQuery<BgReading> preparedQuery = queryBuilder.prepare();
bgList = daoBgReadings.query(preparedQuery); bgList = daoBgReadings.query(preparedQuery);
} catch (SQLException e) { } catch (SQLException e) {
log.debug(e.getMessage(), e); log.error("Unhandled exception", e);
} }
if (bgList != null && bgList.size() > 0) if (bgList != null && bgList.size() > 0)
return bgList.get(0); return bgList.get(0);
@ -420,7 +435,24 @@ 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).and().eq("isValid", true); where.ge("date", mills).and().ge("value", 39).and().eq("isValid", true);
PreparedQuery<BgReading> preparedQuery = queryBuilder.prepare();
bgReadings = daoBgreadings.query(preparedQuery);
return bgReadings;
} catch (SQLException e) {
log.error("Unhandled exception", e);
}
return new ArrayList<BgReading>();
}
public List<BgReading> getBgreadingsDataFromTime(long start, long end, 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.between("date", start, end).and().ge("value", 39).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;
@ -578,6 +610,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
getDaoTempTargets().delete(old); // need to delete/create because date may change too getDaoTempTargets().delete(old); // need to delete/create because date may change too
old.copyFrom(tempTarget); old.copyFrom(tempTarget);
getDaoTempTargets().create(old); getDaoTempTargets().create(old);
if (L.isEnabled(L.DATABASE))
log.debug("TEMPTARGET: Updating record by date from: " + Source.getString(tempTarget.source) + " " + old.toString()); log.debug("TEMPTARGET: Updating record by date from: " + Source.getString(tempTarget.source) + " " + old.toString());
scheduleTemporaryTargetChange(); scheduleTemporaryTargetChange();
return true; return true;
@ -597,6 +630,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
getDaoTempTargets().delete(old); // need to delete/create because date may change too getDaoTempTargets().delete(old); // need to delete/create because date may change too
old.copyFrom(tempTarget); old.copyFrom(tempTarget);
getDaoTempTargets().create(old); getDaoTempTargets().create(old);
if (L.isEnabled(L.DATABASE))
log.debug("TEMPTARGET: Updating record by _id from: " + Source.getString(tempTarget.source) + " " + old.toString()); log.debug("TEMPTARGET: Updating record by _id from: " + Source.getString(tempTarget.source) + " " + old.toString());
scheduleTemporaryTargetChange(); scheduleTemporaryTargetChange();
return true; return true;
@ -604,12 +638,14 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
} }
} }
getDaoTempTargets().create(tempTarget); getDaoTempTargets().create(tempTarget);
if (L.isEnabled(L.DATABASE))
log.debug("TEMPTARGET: New record from: " + Source.getString(tempTarget.source) + " " + tempTarget.toString()); log.debug("TEMPTARGET: New record from: " + Source.getString(tempTarget.source) + " " + tempTarget.toString());
scheduleTemporaryTargetChange(); scheduleTemporaryTargetChange();
return true; return true;
} }
if (tempTarget.source == Source.USER) { if (tempTarget.source == Source.USER) {
getDaoTempTargets().create(tempTarget); getDaoTempTargets().create(tempTarget);
if (L.isEnabled(L.DATABASE))
log.debug("TEMPTARGET: New record from: " + Source.getString(tempTarget.source) + " " + tempTarget.toString()); log.debug("TEMPTARGET: New record from: " + Source.getString(tempTarget.source) + " " + tempTarget.toString());
scheduleTemporaryTargetChange(); scheduleTemporaryTargetChange();
return true; return true;
@ -632,6 +668,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
private static void scheduleTemporaryTargetChange() { private static void scheduleTemporaryTargetChange() {
class PostRunnable implements Runnable { class PostRunnable implements Runnable {
public void run() { public void run() {
if (L.isEnabled(L.DATABASE))
log.debug("Firing EventTempTargetChange"); log.debug("Firing EventTempTargetChange");
MainApp.bus().post(new EventTempTargetChange()); MainApp.bus().post(new EventTempTargetChange());
scheduledTemTargetPost = null; scheduledTemTargetPost = null;
@ -664,18 +701,18 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
public void createTemptargetFromJsonIfNotExists(JSONObject trJson) { public void createTemptargetFromJsonIfNotExists(JSONObject trJson) {
try { try {
String units = JsonHelper.safeGetString(trJson, "units", MainApp.getConfigBuilder().getProfileUnits()); String units = JsonHelper.safeGetString(trJson, "units", Constants.MGDL);
TempTarget tempTarget = new TempTarget() TempTarget tempTarget = new TempTarget()
.date(trJson.getLong("mills")) .date(trJson.getLong("mills"))
.duration(trJson.getInt("duration")) .duration(trJson.getInt("duration"))
.low(Profile.toMgdl(trJson.getDouble("targetBottom"), units)) .low(Profile.toMgdl(trJson.getDouble("targetBottom"), units))
.high(Profile.toMgdl(trJson.getDouble("targetTop"), units)) .high(Profile.toMgdl(trJson.getDouble("targetTop"), units))
.reason(trJson.getString("reason")) .reason(JsonHelper.safeGetString(trJson, "reason", ""))
._id(trJson.getString("_id")) ._id(trJson.getString("_id"))
.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: " + trJson.toString(), e);
} }
} }
@ -752,7 +789,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
} else if (list.size() == 1) { } else if (list.size() == 1) {
DanaRHistoryRecord record = list.get(0); DanaRHistoryRecord record = list.get(0);
if (record._id == null || !record._id.equals(trJson.getString("_id"))) { if (record._id == null || !record._id.equals(trJson.getString("_id"))) {
if (Config.logIncommingData) if (L.isEnabled(L.DATABASE))
log.debug("Updating _id in DanaR history database: " + trJson.getString("_id")); log.debug("Updating _id in DanaR history database: " + trJson.getString("_id"));
record._id = trJson.getString("_id"); record._id = trJson.getString("_id");
getDaoDanaRHistory().update(record); getDaoDanaRHistory().update(record);
@ -761,7 +798,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
} }
} }
} catch (SQLException | JSONException e) { } catch (SQLException | JSONException e) {
log.error("Unhandled exception", e); log.error("Unhandled exception: " + trJson.toString(), e);
} }
} }
@ -782,10 +819,12 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
List<TemporaryBasal> trList = getDaoTemporaryBasal().query(preparedQuery); List<TemporaryBasal> trList = getDaoTemporaryBasal().query(preparedQuery);
if (trList.size() > 0) { if (trList.size() > 0) {
// do nothing, pump history record cannot be changed // do nothing, pump history record cannot be changed
if (L.isEnabled(L.DATABASE))
log.debug("TEMPBASAL: Already exists from: " + Source.getString(tempBasal.source) + " " + tempBasal.toString()); log.debug("TEMPBASAL: Already exists from: " + Source.getString(tempBasal.source) + " " + tempBasal.toString());
return false; return false;
} }
getDaoTemporaryBasal().create(tempBasal); getDaoTemporaryBasal().create(tempBasal);
if (L.isEnabled(L.DATABASE))
log.debug("TEMPBASAL: New record from: " + Source.getString(tempBasal.source) + " " + tempBasal.toString()); log.debug("TEMPBASAL: New record from: " + Source.getString(tempBasal.source) + " " + tempBasal.toString());
updateEarliestDataChange(tempBasal.date); updateEarliestDataChange(tempBasal.date);
scheduleTemporaryBasalChange(); scheduleTemporaryBasalChange();
@ -803,6 +842,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
getDaoTemporaryBasal().delete(old); // need to delete/create because date may change too getDaoTemporaryBasal().delete(old); // need to delete/create because date may change too
old.copyFrom(tempBasal); old.copyFrom(tempBasal);
getDaoTemporaryBasal().create(old); getDaoTemporaryBasal().create(old);
if (L.isEnabled(L.DATABASE))
log.debug("TEMPBASAL: Updating record by date from: " + Source.getString(tempBasal.source) + " " + old.toString()); log.debug("TEMPBASAL: Updating record by date from: " + Source.getString(tempBasal.source) + " " + old.toString());
updateEarliestDataChange(oldDate); updateEarliestDataChange(oldDate);
updateEarliestDataChange(old.date); updateEarliestDataChange(old.date);
@ -825,6 +865,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
getDaoTemporaryBasal().delete(old); // need to delete/create because date may change too getDaoTemporaryBasal().delete(old); // need to delete/create because date may change too
old.copyFrom(tempBasal); old.copyFrom(tempBasal);
getDaoTemporaryBasal().create(old); getDaoTemporaryBasal().create(old);
if (L.isEnabled(L.DATABASE))
log.debug("TEMPBASAL: Updating record by _id from: " + Source.getString(tempBasal.source) + " " + old.toString()); log.debug("TEMPBASAL: Updating record by _id from: " + Source.getString(tempBasal.source) + " " + old.toString());
updateEarliestDataChange(oldDate); updateEarliestDataChange(oldDate);
updateEarliestDataChange(old.date); updateEarliestDataChange(old.date);
@ -834,6 +875,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
} }
} }
getDaoTemporaryBasal().create(tempBasal); getDaoTemporaryBasal().create(tempBasal);
if (L.isEnabled(L.DATABASE))
log.debug("TEMPBASAL: New record from: " + Source.getString(tempBasal.source) + " " + tempBasal.toString()); log.debug("TEMPBASAL: New record from: " + Source.getString(tempBasal.source) + " " + tempBasal.toString());
updateEarliestDataChange(tempBasal.date); updateEarliestDataChange(tempBasal.date);
scheduleTemporaryBasalChange(); scheduleTemporaryBasalChange();
@ -841,6 +883,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
} }
if (tempBasal.source == Source.USER) { if (tempBasal.source == Source.USER) {
getDaoTemporaryBasal().create(tempBasal); getDaoTemporaryBasal().create(tempBasal);
if (L.isEnabled(L.DATABASE))
log.debug("TEMPBASAL: New record from: " + Source.getString(tempBasal.source) + " " + tempBasal.toString()); log.debug("TEMPBASAL: New record from: " + Source.getString(tempBasal.source) + " " + tempBasal.toString());
updateEarliestDataChange(tempBasal.date); updateEarliestDataChange(tempBasal.date);
scheduleTemporaryBasalChange(); scheduleTemporaryBasalChange();
@ -881,6 +924,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
private static void scheduleTemporaryBasalChange() { private static void scheduleTemporaryBasalChange() {
class PostRunnable implements Runnable { class PostRunnable implements Runnable {
public void run() { public void run() {
if (L.isEnabled(L.DATABASE))
log.debug("Firing EventTempBasalChange"); log.debug("Firing EventTempBasalChange");
MainApp.bus().post(new EventReloadTempBasalData()); MainApp.bus().post(new EventReloadTempBasalData());
MainApp.bus().post(new EventTempBasalChange()); MainApp.bus().post(new EventTempBasalChange());
@ -919,15 +963,16 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
public void createTempBasalFromJsonIfNotExists(JSONObject trJson) { public void createTempBasalFromJsonIfNotExists(JSONObject trJson) {
try { try {
if (trJson.has("originalExtendedAmount")) { // extended bolus uploaded as temp basal if (trJson.has("originalExtendedAmount")) { // extended bolus uploaded as temp basal
ExtendedBolus extendedBolus = new ExtendedBolus(); ExtendedBolus extendedBolus = new ExtendedBolus()
extendedBolus.source = Source.NIGHTSCOUT; .source(Source.NIGHTSCOUT)
extendedBolus.date = trJson.getLong("mills"); .date(trJson.getLong("mills"))
extendedBolus.pumpId = trJson.has("pumpId") ? trJson.getLong("pumpId") : 0; .pumpId(trJson.has("pumpId") ? trJson.getLong("pumpId") : 0)
extendedBolus.durationInMinutes = trJson.getInt("duration"); .durationInMinutes(trJson.getInt("duration"))
extendedBolus.insulin = trJson.getDouble("originalExtendedAmount"); .insulin(trJson.getDouble("originalExtendedAmount"))
extendedBolus._id = trJson.getString("_id"); ._id(trJson.getString("_id"));
if (!VirtualPumpPlugin.getFakingStatus()) { // if faking found in NS, adapt AAPS to use it too
VirtualPumpPlugin.setFakingStatus(true); if (!VirtualPumpPlugin.getPlugin().getFakingStatus()) {
VirtualPumpPlugin.getPlugin().setFakingStatus(true);
updateEarliestDataChange(0); updateEarliestDataChange(0);
scheduleTemporaryBasalChange(); scheduleTemporaryBasalChange();
} }
@ -940,8 +985,9 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
extendedBolus.durationInMinutes = 0; extendedBolus.durationInMinutes = 0;
extendedBolus.insulin = 0; extendedBolus.insulin = 0;
extendedBolus._id = trJson.getString("_id"); extendedBolus._id = trJson.getString("_id");
if (!VirtualPumpPlugin.getFakingStatus()) { // if faking found in NS, adapt AAPS to use it too
VirtualPumpPlugin.setFakingStatus(true); if (!VirtualPumpPlugin.getPlugin().getFakingStatus()) {
VirtualPumpPlugin.getPlugin().setFakingStatus(true);
updateEarliestDataChange(0); updateEarliestDataChange(0);
scheduleTemporaryBasalChange(); scheduleTemporaryBasalChange();
} }
@ -966,13 +1012,14 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
createOrUpdate(tempBasal); createOrUpdate(tempBasal);
} }
} catch (JSONException e) { } catch (JSONException e) {
log.error("Unhandled exception", e); log.error("Unhandled exception: " + trJson.toString(), e);
} }
} }
public void deleteTempBasalById(String _id) { public void deleteTempBasalById(String _id) {
TemporaryBasal stored = findTempBasalById(_id); TemporaryBasal stored = findTempBasalById(_id);
if (stored != null) { if (stored != null) {
if (L.isEnabled(L.DATABASE))
log.debug("TEMPBASAL: Removing TempBasal record from database: " + stored.toString()); log.debug("TEMPBASAL: Removing TempBasal record from database: " + stored.toString());
delete(stored); delete(stored);
updateEarliestDataChange(stored.date); updateEarliestDataChange(stored.date);
@ -1004,22 +1051,33 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
public boolean createOrUpdate(ExtendedBolus extendedBolus) { public boolean createOrUpdate(ExtendedBolus extendedBolus) {
try { try {
if (L.isEnabled(L.DATABASE))
log.debug("EXTENDEDBOLUS: createOrUpdate: " + Source.getString(extendedBolus.source) + " " + extendedBolus.log());
ExtendedBolus old; ExtendedBolus old;
extendedBolus.date = roundDateToSec(extendedBolus.date); extendedBolus.date = roundDateToSec(extendedBolus.date);
if (extendedBolus.source == Source.PUMP) { if (extendedBolus.source == Source.PUMP) {
// check for changed from pump change in NS // if pumpId == 0 do not check for existing pumpId
// used with pumps without history
// and insight where record as added first without pumpId
// and then is record updated with pumpId
if (extendedBolus.pumpId == 0) {
getDaoExtendedBolus().createOrUpdate(extendedBolus);
} else {
QueryBuilder<ExtendedBolus, Long> queryBuilder = getDaoExtendedBolus().queryBuilder(); QueryBuilder<ExtendedBolus, Long> queryBuilder = getDaoExtendedBolus().queryBuilder();
Where where = queryBuilder.where(); Where where = queryBuilder.where();
where.eq("pumpId", extendedBolus.pumpId); where.eq("pumpId", extendedBolus.pumpId);
PreparedQuery<ExtendedBolus> preparedQuery = queryBuilder.prepare(); PreparedQuery<ExtendedBolus> preparedQuery = queryBuilder.prepare();
List<ExtendedBolus> trList = getDaoExtendedBolus().query(preparedQuery); List<ExtendedBolus> trList = getDaoExtendedBolus().query(preparedQuery);
if (trList.size() > 0) { if (trList.size() > 1) {
// do nothing, pump history record cannot be changed log.error("EXTENDEDBOLUS: Multiple records found for pumpId: " + extendedBolus.pumpId);
return false; return false;
} }
getDaoExtendedBolus().create(extendedBolus); getDaoExtendedBolus().createOrUpdate(extendedBolus);
log.debug("EXTENDEDBOLUS: New record from: " + Source.getString(extendedBolus.source) + " " + extendedBolus.toString()); }
if (L.isEnabled(L.DATABASE))
log.debug("EXTENDEDBOLUS: New record from: " + Source.getString(extendedBolus.source) + " " + extendedBolus.log());
updateEarliestDataChange(extendedBolus.date); updateEarliestDataChange(extendedBolus.date);
scheduleExtendedBolusChange(); scheduleExtendedBolusChange();
return true; return true;
@ -1032,7 +1090,8 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
getDaoExtendedBolus().delete(old); // need to delete/create because date may change too getDaoExtendedBolus().delete(old); // need to delete/create because date may change too
old.copyFrom(extendedBolus); old.copyFrom(extendedBolus);
getDaoExtendedBolus().create(old); getDaoExtendedBolus().create(old);
log.debug("EXTENDEDBOLUS: Updating record by date from: " + Source.getString(extendedBolus.source) + " " + old.toString()); if (L.isEnabled(L.DATABASE))
log.debug("EXTENDEDBOLUS: Updating record by date from: " + Source.getString(extendedBolus.source) + " " + old.log());
updateEarliestDataChange(oldDate); updateEarliestDataChange(oldDate);
updateEarliestDataChange(old.date); updateEarliestDataChange(old.date);
scheduleExtendedBolusChange(); scheduleExtendedBolusChange();
@ -1054,7 +1113,8 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
getDaoExtendedBolus().delete(old); // need to delete/create because date may change too getDaoExtendedBolus().delete(old); // need to delete/create because date may change too
old.copyFrom(extendedBolus); old.copyFrom(extendedBolus);
getDaoExtendedBolus().create(old); getDaoExtendedBolus().create(old);
log.debug("EXTENDEDBOLUS: Updating record by _id from: " + Source.getString(extendedBolus.source) + " " + old.toString()); if (L.isEnabled(L.DATABASE))
log.debug("EXTENDEDBOLUS: Updating record by _id from: " + Source.getString(extendedBolus.source) + " " + old.log());
updateEarliestDataChange(oldDate); updateEarliestDataChange(oldDate);
updateEarliestDataChange(old.date); updateEarliestDataChange(old.date);
scheduleExtendedBolusChange(); scheduleExtendedBolusChange();
@ -1063,14 +1123,16 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
} }
} }
getDaoExtendedBolus().create(extendedBolus); getDaoExtendedBolus().create(extendedBolus);
log.debug("EXTENDEDBOLUS: New record from: " + Source.getString(extendedBolus.source) + " " + extendedBolus.toString()); if (L.isEnabled(L.DATABASE))
log.debug("EXTENDEDBOLUS: New record from: " + Source.getString(extendedBolus.source) + " " + extendedBolus.log());
updateEarliestDataChange(extendedBolus.date); updateEarliestDataChange(extendedBolus.date);
scheduleExtendedBolusChange(); scheduleExtendedBolusChange();
return true; return true;
} }
if (extendedBolus.source == Source.USER) { if (extendedBolus.source == Source.USER) {
getDaoExtendedBolus().create(extendedBolus); getDaoExtendedBolus().create(extendedBolus);
log.debug("EXTENDEDBOLUS: New record from: " + Source.getString(extendedBolus.source) + " " + extendedBolus.toString()); if (L.isEnabled(L.DATABASE))
log.debug("EXTENDEDBOLUS: New record from: " + Source.getString(extendedBolus.source) + " " + extendedBolus.log());
updateEarliestDataChange(extendedBolus.date); updateEarliestDataChange(extendedBolus.date);
scheduleExtendedBolusChange(); scheduleExtendedBolusChange();
return true; return true;
@ -1110,6 +1172,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
public void deleteExtendedBolusById(String _id) { public void deleteExtendedBolusById(String _id) {
ExtendedBolus stored = findExtendedBolusById(_id); ExtendedBolus stored = findExtendedBolusById(_id);
if (stored != null) { if (stored != null) {
if (L.isEnabled(L.DATABASE))
log.debug("EXTENDEDBOLUS: Removing ExtendedBolus record from database: " + stored.toString()); log.debug("EXTENDEDBOLUS: Removing ExtendedBolus record from database: " + stored.toString());
delete(stored); delete(stored);
updateEarliestDataChange(stored.date); updateEarliestDataChange(stored.date);
@ -1163,6 +1226,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
private static void scheduleExtendedBolusChange() { private static void scheduleExtendedBolusChange() {
class PostRunnable implements Runnable { class PostRunnable implements Runnable {
public void run() { public void run() {
if (L.isEnabled(L.DATABASE))
log.debug("Firing EventExtendedBolusChange"); log.debug("Firing EventExtendedBolusChange");
MainApp.bus().post(new EventReloadTreatmentData(new EventExtendedBolusChange())); MainApp.bus().post(new EventReloadTreatmentData(new EventExtendedBolusChange()));
if (earliestDataChange != null) if (earliestDataChange != null)
@ -1242,6 +1306,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
where.ge("date", mills); where.ge("date", mills);
PreparedQuery<CareportalEvent> preparedQuery = queryBuilder.prepare(); PreparedQuery<CareportalEvent> preparedQuery = queryBuilder.prepare();
careportalEvents = getDaoCareportalEvents().query(preparedQuery); careportalEvents = getDaoCareportalEvents().query(preparedQuery);
preprocessOpenAPSOfflineEvents(careportalEvents);
return careportalEvents; return careportalEvents;
} catch (SQLException e) { } catch (SQLException e) {
log.error("Unhandled exception", e); log.error("Unhandled exception", e);
@ -1249,13 +1314,41 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
return new ArrayList<>(); return new ArrayList<>();
} }
public List<CareportalEvent> getCareportalEventsFromTime(boolean ascending) { public void preprocessOpenAPSOfflineEvents(List<CareportalEvent> list) {
OverlappingIntervals offlineEvents = new OverlappingIntervals();
for (int i = 0; i < list.size(); i++) {
CareportalEvent event = list.get(i);
if (!event.eventType.equals(CareportalEvent.OPENAPSOFFLINE)) continue;
offlineEvents.add(event);
}
}
public List<CareportalEvent> getCareportalEventsFromTime(long mills, String type, boolean ascending) {
try {
List<CareportalEvent> careportalEvents;
QueryBuilder<CareportalEvent, Long> queryBuilder = getDaoCareportalEvents().queryBuilder();
queryBuilder.orderBy("date", ascending);
Where where = queryBuilder.where();
where.ge("date", mills).and().eq("eventType", type);
PreparedQuery<CareportalEvent> preparedQuery = queryBuilder.prepare();
careportalEvents = getDaoCareportalEvents().query(preparedQuery);
preprocessOpenAPSOfflineEvents(careportalEvents);
return careportalEvents;
} catch (SQLException e) {
log.error("Unhandled exception", e);
}
return new ArrayList<>();
}
public List<CareportalEvent> getCareportalEvents(boolean ascending) {
try { try {
List<CareportalEvent> careportalEvents; List<CareportalEvent> careportalEvents;
QueryBuilder<CareportalEvent, Long> queryBuilder = getDaoCareportalEvents().queryBuilder(); QueryBuilder<CareportalEvent, Long> queryBuilder = getDaoCareportalEvents().queryBuilder();
queryBuilder.orderBy("date", ascending); queryBuilder.orderBy("date", ascending);
PreparedQuery<CareportalEvent> preparedQuery = queryBuilder.prepare(); PreparedQuery<CareportalEvent> preparedQuery = queryBuilder.prepare();
careportalEvents = getDaoCareportalEvents().query(preparedQuery); careportalEvents = getDaoCareportalEvents().query(preparedQuery);
preprocessOpenAPSOfflineEvents(careportalEvents);
return careportalEvents; return careportalEvents;
} catch (SQLException e) { } catch (SQLException e) {
log.error("Unhandled exception", e); log.error("Unhandled exception", e);
@ -1274,11 +1367,11 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
if (list.size() == 1) { if (list.size() == 1) {
CareportalEvent record = list.get(0); CareportalEvent record = list.get(0);
if (Config.logIncommingData) if (L.isEnabled(L.DATABASE))
log.debug("Removing CareportalEvent record from database: " + record.log()); log.debug("Removing CareportalEvent record from database: " + record.toString());
delete(record); delete(record);
} else { } else {
if (Config.logIncommingData) if (L.isEnabled(L.DATABASE))
log.debug("CareportalEvent not found database: " + _id); log.debug("CareportalEvent not found database: " + _id);
} }
} catch (SQLException e) { } catch (SQLException e) {
@ -1298,12 +1391,12 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
if (list.size() == 0) { if (list.size() == 0) {
careportalEvent = new CareportalEvent(); careportalEvent = new CareportalEvent();
careportalEvent.source = Source.NIGHTSCOUT; careportalEvent.source = Source.NIGHTSCOUT;
if (Config.logIncommingData) if (L.isEnabled(L.DATABASE))
log.debug("Adding CareportalEvent record to database: " + trJson.toString()); log.debug("Adding CareportalEvent record to database: " + trJson.toString());
// Record does not exists. add // Record does not exists. add
} else if (list.size() == 1) { } else if (list.size() == 1) {
careportalEvent = list.get(0); careportalEvent = list.get(0);
if (Config.logIncommingData) if (L.isEnabled(L.DATABASE))
log.debug("Updating CareportalEvent record in database: " + trJson.toString()); log.debug("Updating CareportalEvent record in database: " + trJson.toString());
} else { } else {
log.error("Something went wrong"); log.error("Something went wrong");
@ -1315,13 +1408,14 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
careportalEvent._id = trJson.getString("_id"); careportalEvent._id = trJson.getString("_id");
createOrUpdate(careportalEvent); createOrUpdate(careportalEvent);
} catch (SQLException | JSONException e) { } catch (SQLException | JSONException e) {
log.error("Unhandled exception", e); log.error("Unhandled exception: " + trJson.toString(), e);
} }
} }
private static void scheduleCareportalEventChange() { private static void scheduleCareportalEventChange() {
class PostRunnable implements Runnable { class PostRunnable implements Runnable {
public void run() { public void run() {
if (L.isEnabled(L.DATABASE))
log.debug("Firing scheduleCareportalEventChange"); log.debug("Firing scheduleCareportalEventChange");
MainApp.bus().post(new EventCareportalEventChange()); MainApp.bus().post(new EventCareportalEventChange());
scheduledCareportalEventPost = null; scheduledCareportalEventPost = null;
@ -1355,6 +1449,24 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
return new ArrayList<>(); return new ArrayList<>();
} }
public List<ProfileSwitch> getProfileSwitchEventsFromTime(long mills, boolean ascending) {
try {
Dao<ProfileSwitch, Long> daoProfileSwitch = getDaoProfileSwitch();
List<ProfileSwitch> profileSwitches;
QueryBuilder<ProfileSwitch, Long> queryBuilder = daoProfileSwitch.queryBuilder();
queryBuilder.orderBy("date", ascending);
queryBuilder.limit(100L);
Where where = queryBuilder.where();
where.ge("date", mills);
PreparedQuery<ProfileSwitch> preparedQuery = queryBuilder.prepare();
profileSwitches = daoProfileSwitch.query(preparedQuery);
return profileSwitches;
} catch (SQLException e) {
log.error("Unhandled exception", e);
}
return new ArrayList<>();
}
public boolean createOrUpdate(ProfileSwitch profileSwitch) { public boolean createOrUpdate(ProfileSwitch profileSwitch) {
try { try {
ProfileSwitch old; ProfileSwitch old;
@ -1368,6 +1480,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
profileSwitch.profileName = old.profileName; // preserver profileName to prevent multiple CPP extension profileSwitch.profileName = old.profileName; // preserver profileName to prevent multiple CPP extension
getDaoProfileSwitch().delete(old); // need to delete/create because date may change too getDaoProfileSwitch().delete(old); // need to delete/create because date may change too
getDaoProfileSwitch().create(profileSwitch); getDaoProfileSwitch().create(profileSwitch);
if (L.isEnabled(L.DATABASE))
log.debug("PROFILESWITCH: Updating record by date from: " + Source.getString(profileSwitch.source) + " " + old.toString()); log.debug("PROFILESWITCH: Updating record by date from: " + Source.getString(profileSwitch.source) + " " + old.toString());
scheduleProfileSwitchChange(); scheduleProfileSwitchChange();
return true; return true;
@ -1387,6 +1500,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
getDaoProfileSwitch().delete(old); // need to delete/create because date may change too getDaoProfileSwitch().delete(old); // need to delete/create because date may change too
old.copyFrom(profileSwitch); old.copyFrom(profileSwitch);
getDaoProfileSwitch().create(old); getDaoProfileSwitch().create(old);
if (L.isEnabled(L.DATABASE))
log.debug("PROFILESWITCH: Updating record by _id from: " + Source.getString(profileSwitch.source) + " " + old.toString()); log.debug("PROFILESWITCH: Updating record by _id from: " + Source.getString(profileSwitch.source) + " " + old.toString());
scheduleProfileSwitchChange(); scheduleProfileSwitchChange();
return true; return true;
@ -1396,12 +1510,14 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
// look for already added percentage from NS // look for already added percentage from NS
profileSwitch.profileName = PercentageSplitter.pureName(profileSwitch.profileName); profileSwitch.profileName = PercentageSplitter.pureName(profileSwitch.profileName);
getDaoProfileSwitch().create(profileSwitch); getDaoProfileSwitch().create(profileSwitch);
if (L.isEnabled(L.DATABASE))
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();
return true; return true;
} }
if (profileSwitch.source == Source.USER) { if (profileSwitch.source == Source.USER) {
getDaoProfileSwitch().create(profileSwitch); getDaoProfileSwitch().create(profileSwitch);
if (L.isEnabled(L.DATABASE))
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();
return true; return true;
@ -1424,6 +1540,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
private static void scheduleProfileSwitchChange() { private static void scheduleProfileSwitchChange() {
class PostRunnable implements Runnable { class PostRunnable implements Runnable {
public void run() { public void run() {
if (L.isEnabled(L.DATABASE))
log.debug("Firing EventProfileSwitchChange"); log.debug("Firing EventProfileSwitchChange");
MainApp.bus().post(new EventReloadProfileSwitchData()); MainApp.bus().post(new EventReloadProfileSwitchData());
MainApp.bus().post(new EventProfileSwitchChange()); MainApp.bus().post(new EventProfileSwitchChange());
@ -1469,29 +1586,45 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
if (trJson.has("profileJson")) if (trJson.has("profileJson"))
profileSwitch.profileJson = trJson.getString("profileJson"); profileSwitch.profileJson = trJson.getString("profileJson");
else { else {
ProfileStore store = MainApp.getConfigBuilder().getActiveProfileInterface().getProfile(); ProfileInterface profileInterface = ConfigBuilderPlugin.getPlugin().getActiveProfileInterface();
if (profileInterface != null) {
ProfileStore store = profileInterface.getProfile();
if (store != null) {
Profile profile = store.getSpecificProfile(profileSwitch.profileName); Profile profile = store.getSpecificProfile(profileSwitch.profileName);
if (profile != null) { if (profile != null) {
profileSwitch.profileJson = profile.getData().toString(); profileSwitch.profileJson = profile.getData().toString();
if (L.isEnabled(L.DATABASE))
log.debug("Profile switch prefilled with JSON from local store"); log.debug("Profile switch prefilled with JSON from local store");
// Update data in NS // Update data in NS
NSUpload.updateProfileSwitch(profileSwitch); NSUpload.updateProfileSwitch(profileSwitch);
} else { } else {
if (L.isEnabled(L.DATABASE))
log.debug("JSON for profile switch doesn't exist. Ignoring: " + trJson.toString()); log.debug("JSON for profile switch doesn't exist. Ignoring: " + trJson.toString());
return; return;
} }
} else {
if (L.isEnabled(L.DATABASE))
log.debug("Store for profile switch doesn't exist. Ignoring: " + trJson.toString());
return;
}
} else {
if (L.isEnabled(L.DATABASE))
log.debug("No active profile interface. 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);
} catch (JSONException e) { } catch (JSONException e) {
log.error("Unhandled exception", e); log.error("Unhandled exception: " + trJson.toString(), e);
} }
} }
public void deleteProfileSwitchById(String _id) { public void deleteProfileSwitchById(String _id) {
ProfileSwitch stored = findProfileSwitchById(_id); ProfileSwitch stored = findProfileSwitchById(_id);
if (stored != null) { if (stored != null) {
if (L.isEnabled(L.DATABASE))
log.debug("PROFILESWITCH: Removing ProfileSwitch record from database: " + stored.toString()); log.debug("PROFILESWITCH: Removing ProfileSwitch record from database: " + stored.toString());
delete(stored); delete(stored);
scheduleTemporaryTargetChange(); scheduleTemporaryTargetChange();

View file

@ -10,6 +10,8 @@ import org.json.JSONObject;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.logging.L;
/** /**
* Created by mike on 27.02.2016. * Created by mike on 27.02.2016.
* <p> * <p>
@ -17,7 +19,7 @@ import org.slf4j.LoggerFactory;
*/ */
@DatabaseTable(tableName = DatabaseHelper.DATABASE_DBREQUESTS) @DatabaseTable(tableName = DatabaseHelper.DATABASE_DBREQUESTS)
public class DbRequest { public class DbRequest {
private static Logger log = LoggerFactory.getLogger(DbRequest.class); private static Logger log = LoggerFactory.getLogger(L.DATABASE);
@DatabaseField(id = true) @DatabaseField(id = true)
public String nsClientID = null; public String nsClientID = null;

View file

@ -21,6 +21,7 @@ import info.nightscout.androidaps.data.Iob;
import info.nightscout.androidaps.data.IobTotal; import info.nightscout.androidaps.data.IobTotal;
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.logging.L;
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;
@ -36,7 +37,7 @@ import info.nightscout.utils.Round;
@DatabaseTable(tableName = DatabaseHelper.DATABASE_EXTENDEDBOLUSES) @DatabaseTable(tableName = DatabaseHelper.DATABASE_EXTENDEDBOLUSES)
public class ExtendedBolus implements Interval, DataPointWithLabelInterface { public class ExtendedBolus implements Interval, DataPointWithLabelInterface {
private static Logger log = LoggerFactory.getLogger(ExtendedBolus.class); private static Logger log = LoggerFactory.getLogger(L.DATABASE);
@DatabaseField(id = true) @DatabaseField(id = true)
public long date; public long date;
@ -69,6 +70,36 @@ public class ExtendedBolus implements Interval, DataPointWithLabelInterface {
this.date = date; this.date = date;
} }
public ExtendedBolus date(long date) {
this.date = date;
return this;
}
public ExtendedBolus insulin(double insulin) {
this.insulin = insulin;
return this;
}
public ExtendedBolus pumpId(long pumpId) {
this.pumpId = pumpId;
return this;
}
public ExtendedBolus source(int source) {
this.source = source;
return this;
}
public ExtendedBolus durationInMinutes(int durationInMinutes) {
this.durationInMinutes = durationInMinutes;
return this;
}
public ExtendedBolus _id(String _id) {
this._id = _id;
return this;
}
public boolean isEqual(ExtendedBolus other) { public boolean isEqual(ExtendedBolus other) {
if (date != other.date) { if (date != other.date) {
return false; return false;
@ -93,13 +124,13 @@ public class ExtendedBolus implements Interval, DataPointWithLabelInterface {
} }
public static ExtendedBolus createFromJson(JSONObject json) { public static ExtendedBolus createFromJson(JSONObject json) {
ExtendedBolus extendedBolus = new ExtendedBolus(); ExtendedBolus extendedBolus = new ExtendedBolus()
extendedBolus.source = Source.NIGHTSCOUT; .source(Source.NIGHTSCOUT)
extendedBolus.date = JsonHelper.safeGetLong(json, "mills"); .date(JsonHelper.safeGetLong(json, "mills"))
extendedBolus.durationInMinutes = JsonHelper.safeGetInt(json, "duration"); .durationInMinutes(JsonHelper.safeGetInt(json, "duration"))
extendedBolus.insulin = JsonHelper.safeGetDouble(json, "relative") / 60 * extendedBolus.durationInMinutes; .insulin(JsonHelper.safeGetDouble(json, "relative") / 60 * JsonHelper.safeGetInt(json, "duration"))
extendedBolus._id = JsonHelper.safeGetString(json, "_id"); ._id(JsonHelper.safeGetString(json, "_id"))
extendedBolus.pumpId = JsonHelper.safeGetLong(json, "pumpId"); .pumpId(JsonHelper.safeGetLong(json, "pumpId"));
return extendedBolus; return extendedBolus;
} }
// -------- Interval interface --------- // -------- Interval interface ---------
@ -166,7 +197,7 @@ public class ExtendedBolus implements Interval, DataPointWithLabelInterface {
// -------- Interval interface end --------- // -------- Interval interface end ---------
public String log() { public String log() {
return "Bolus{" + return "ExtendedBolus{" +
"date= " + date + "date= " + date +
", date= " + DateUtil.dateAndTimeString(date) + ", date= " + DateUtil.dateAndTimeString(date) +
", isValid=" + isValid + ", isValid=" + isValid +
@ -187,7 +218,7 @@ public class ExtendedBolus implements Interval, DataPointWithLabelInterface {
public IobTotal iobCalc(long time) { public IobTotal iobCalc(long time) {
IobTotal result = new IobTotal(time); IobTotal result = new IobTotal(time);
InsulinInterface insulinInterface = ConfigBuilderPlugin.getActiveInsulin(); InsulinInterface insulinInterface = ConfigBuilderPlugin.getPlugin().getActiveInsulin();
int realDuration = getDurationToTime(time); int realDuration = getDurationToTime(time);

View file

@ -11,12 +11,14 @@ import org.json.JSONObject;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.util.List;
import java.util.Objects; import java.util.Objects;
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.Interval; import info.nightscout.androidaps.interfaces.Interval;
import info.nightscout.androidaps.logging.L;
import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification; 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;
@ -24,10 +26,11 @@ 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;
import info.nightscout.utils.T;
@DatabaseTable(tableName = DatabaseHelper.DATABASE_PROFILESWITCHES) @DatabaseTable(tableName = DatabaseHelper.DATABASE_PROFILESWITCHES)
public class ProfileSwitch implements Interval, DataPointWithLabelInterface { public class ProfileSwitch implements Interval, DataPointWithLabelInterface {
private static Logger log = LoggerFactory.getLogger(ProfileSwitch.class); private static Logger log = LoggerFactory.getLogger(L.DATABASE);
@DatabaseField(id = true) @DatabaseField(id = true)
public long date; public long date;
@ -217,6 +220,26 @@ public class ProfileSwitch implements Interval, DataPointWithLabelInterface {
MainApp.bus().post(new EventNewNotification(notification)); MainApp.bus().post(new EventNewNotification(notification));
} }
public static boolean isEvent5minBack(List<ProfileSwitch> list, long time, boolean zeroDurationOnly) {
for (int i = 0; i < list.size(); i++) {
ProfileSwitch event = list.get(i);
if (event.date <= time && event.date > (time - T.mins(5).msecs())) {
if (zeroDurationOnly) {
if (event.durationInMinutes == 0) {
if (L.isEnabled(L.DATABASE))
log.debug("Found ProfileSwitch event for time: " + DateUtil.dateAndTimeFullString(time) + " " + event.toString());
return true;
}
} else {
if (L.isEnabled(L.DATABASE))
log.debug("Found ProfileSwitch event for time: " + DateUtil.dateAndTimeFullString(time) + " " + event.toString());
return true;
}
}
}
return false;
}
// -------- Interval interface end --------- // -------- Interval interface end ---------
// ----------------- DataPointInterface -------------------- // ----------------- DataPointInterface --------------------

View file

@ -8,6 +8,8 @@ import org.slf4j.LoggerFactory;
import java.util.Objects; import java.util.Objects;
import info.nightscout.androidaps.logging.L;
/** /**
* Created by mike on 20.09.2017. * Created by mike on 20.09.2017.
*/ */
@ -15,7 +17,7 @@ import java.util.Objects;
@DatabaseTable(tableName = DatabaseHelper.DATABASE_TDDS) @DatabaseTable(tableName = DatabaseHelper.DATABASE_TDDS)
public class TDD { public class TDD {
private static Logger log = LoggerFactory.getLogger(TDD.class); private static Logger log = LoggerFactory.getLogger(L.DATABASE);
@DatabaseField(id = true) @DatabaseField(id = true)
public long date; public long date;

View file

@ -11,12 +11,13 @@ import java.util.Objects;
import info.nightscout.androidaps.Constants; import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.interfaces.Interval; import info.nightscout.androidaps.interfaces.Interval;
import info.nightscout.androidaps.logging.L;
import info.nightscout.utils.DateUtil; import info.nightscout.utils.DateUtil;
import info.nightscout.utils.DecimalFormatter; import info.nightscout.utils.DecimalFormatter;
@DatabaseTable(tableName = DatabaseHelper.DATABASE_TEMPTARGETS) @DatabaseTable(tableName = DatabaseHelper.DATABASE_TEMPTARGETS)
public class TempTarget implements Interval { public class TempTarget implements Interval {
private static Logger log = LoggerFactory.getLogger(TempTarget.class); private static Logger log = LoggerFactory.getLogger(L.DATABASE);
@DatabaseField(id = true) @DatabaseField(id = true)
public long date; public long date;

View file

@ -15,7 +15,9 @@ import info.nightscout.androidaps.data.IobTotal;
import info.nightscout.androidaps.data.Profile; 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.logging.L;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.ConfigBuilder.ProfileFunctions;
import info.nightscout.androidaps.plugins.Treatments.Treatment; 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;
@ -27,7 +29,7 @@ import info.nightscout.utils.SP;
@DatabaseTable(tableName = DatabaseHelper.DATABASE_TEMPORARYBASALS) @DatabaseTable(tableName = DatabaseHelper.DATABASE_TEMPORARYBASALS)
public class TemporaryBasal implements Interval { public class TemporaryBasal implements Interval {
private static Logger log = LoggerFactory.getLogger(TemporaryBasal.class); private static Logger log = LoggerFactory.getLogger(L.DATABASE);
@DatabaseField(id = true) @DatabaseField(id = true)
public long date; public long date;
@ -93,7 +95,7 @@ public class TemporaryBasal implements Interval {
} }
public TemporaryBasal(ExtendedBolus extendedBolus) { public TemporaryBasal(ExtendedBolus extendedBolus) {
double basal = MainApp.getConfigBuilder().getProfile(extendedBolus.date).getBasal(extendedBolus.date); double basal = ProfileFunctions.getInstance().getProfile(extendedBolus.date).getBasal(extendedBolus.date);
this.date = extendedBolus.date; this.date = extendedBolus.date;
this.isValid = extendedBolus.isValid; this.isValid = extendedBolus.isValid;
this.source = extendedBolus.source; this.source = extendedBolus.source;
@ -103,6 +105,7 @@ public class TemporaryBasal implements Interval {
this.isFakeExtended = true; this.isFakeExtended = true;
this.netExtendedRate = extendedBolus.absoluteRate(); this.netExtendedRate = extendedBolus.absoluteRate();
this.absoluteRate = basal + extendedBolus.absoluteRate(); this.absoluteRate = basal + extendedBolus.absoluteRate();
this.pumpId = extendedBolus.pumpId;
} }
public TemporaryBasal clone() { public TemporaryBasal clone() {
@ -225,7 +228,7 @@ public class TemporaryBasal implements Interval {
} }
IobTotal result = new IobTotal(time); IobTotal result = new IobTotal(time);
InsulinInterface insulinInterface = ConfigBuilderPlugin.getActiveInsulin(); InsulinInterface insulinInterface = ConfigBuilderPlugin.getPlugin().getActiveInsulin();
int realDuration = getDurationToTime(time); int realDuration = getDurationToTime(time);
double netBasalAmount = 0d; double netBasalAmount = 0d;
@ -299,6 +302,16 @@ public class TemporaryBasal implements Interval {
} }
} }
public int tempBasalConvertedToPercent(long time, Profile profile) {
if (isFakeExtended) {
return (int) ((profile.getBasal(time) + netExtendedRate) / profile.getBasal(time)) * 100;
} else if (isAbsolute) {
return (int) (absoluteRate / profile.getBasal(time)) * 100;
} else {
return percentRate;
}
}
public String toString() { public String toString() {
return "TemporaryBasal{" + return "TemporaryBasal{" +
"date=" + date + "date=" + date +
@ -318,7 +331,7 @@ public class TemporaryBasal implements Interval {
public String toStringFull() { public String toStringFull() {
if (isFakeExtended) { if (isFakeExtended) {
Profile profile = MainApp.getConfigBuilder().getProfile(); Profile profile = ProfileFunctions.getInstance().getProfile();
Double currentBasalRate = profile.getBasal(); Double currentBasalRate = profile.getBasal();
double rate = (currentBasalRate == null) ? 0d : (currentBasalRate + netExtendedRate); double rate = (currentBasalRate == null) ? 0d : (currentBasalRate + netExtendedRate);
return getCalcuatedPercentageIfNeeded() + DecimalFormatter.to2Decimal(rate) + "U/h (" + DecimalFormatter.to2Decimal(netExtendedRate) + "E) @" + return getCalcuatedPercentageIfNeeded() + DecimalFormatter.to2Decimal(rate) + "U/h (" + DecimalFormatter.to2Decimal(netExtendedRate) + "E) @" +
@ -340,7 +353,7 @@ public class TemporaryBasal implements Interval {
double rate = 0d; double rate = 0d;
if (isFakeExtended) { if (isFakeExtended) {
Profile profile = MainApp.getConfigBuilder().getProfile(); Profile profile = ProfileFunctions.getInstance().getProfile();
Double currentBasalRate = profile.getBasal(); Double currentBasalRate = profile.getBasal();
rate = (currentBasalRate == null) ? 0d : (currentBasalRate + netExtendedRate); rate = (currentBasalRate == null) ? 0d : (currentBasalRate + netExtendedRate);
} else if (isAbsolute) { } else if (isAbsolute) {
@ -348,7 +361,7 @@ public class TemporaryBasal implements Interval {
} }
if (SP.getBoolean(R.string.key_danar_visualizeextendedaspercentage, false) && SP.getBoolean(R.string.key_danar_useextended, false)) { if (SP.getBoolean(R.string.key_danar_visualizeextendedaspercentage, false) && SP.getBoolean(R.string.key_danar_useextended, false)) {
Profile profile = MainApp.getConfigBuilder().getProfile(); Profile profile = ProfileFunctions.getInstance().getProfile();
if (profile != null) { if (profile != null) {
double basal = profile.getBasal(); double basal = profile.getBasal();
if (basal != 0) { if (basal != 0) {
@ -367,7 +380,7 @@ public class TemporaryBasal implements Interval {
double rate = 0d; double rate = 0d;
if (isFakeExtended) { if (isFakeExtended) {
Profile profile = MainApp.getConfigBuilder().getProfile(); Profile profile = ProfileFunctions.getInstance().getProfile();
Double currentBasalRate = profile.getBasal(); Double currentBasalRate = profile.getBasal();
rate = (currentBasalRate == null) ? 0d : (currentBasalRate + netExtendedRate); rate = (currentBasalRate == null) ? 0d : (currentBasalRate + netExtendedRate);
} else if (isAbsolute) { } else if (isAbsolute) {
@ -375,7 +388,7 @@ public class TemporaryBasal implements Interval {
} }
if (SP.getBoolean(R.string.key_danar_visualizeextendedaspercentage, false) && SP.getBoolean(R.string.key_danar_useextended, false)) { if (SP.getBoolean(R.string.key_danar_visualizeextendedaspercentage, false) && SP.getBoolean(R.string.key_danar_useextended, false)) {
Profile profile = MainApp.getConfigBuilder().getProfile(); Profile profile = ProfileFunctions.getInstance().getProfile();
if (profile != null) { if (profile != null) {
double basal = profile.getBasal(); double basal = profile.getBasal();
if (basal != 0) { if (basal != 0) {
@ -392,7 +405,7 @@ public class TemporaryBasal implements Interval {
double rate = 0d; double rate = 0d;
if (isFakeExtended) { if (isFakeExtended) {
Profile profile = MainApp.getConfigBuilder().getProfile(); Profile profile = ProfileFunctions.getInstance().getProfile();
Double currentBasalRate = profile.getBasal(); Double currentBasalRate = profile.getBasal();
rate = (currentBasalRate == null) ? 0d : (currentBasalRate + netExtendedRate); rate = (currentBasalRate == null) ? 0d : (currentBasalRate + netExtendedRate);
} else if (isAbsolute) { } else if (isAbsolute) {

View file

@ -0,0 +1,5 @@
package info.nightscout.androidaps.events;
/** Base class for events to update the UI, mostly a specific tab. */
public class EventAcceptOpenLoopChange extends Event {
}

View file

@ -1,5 +1,8 @@
package info.nightscout.androidaps.events; package info.nightscout.androidaps.events;
import info.nightscout.utils.StringUtils;
public class EventNetworkChange extends Event { public class EventNetworkChange extends Event {
public boolean mobileConnected = false; public boolean mobileConnected = false;
@ -9,6 +12,6 @@ public class EventNetworkChange extends Event {
public boolean roaming = false; public boolean roaming = false;
public String getSsid() { public String getSsid() {
return ssid.replace("SSID: ","").replaceAll("\"",""); return StringUtils.removeSurroundingQuotes(ssid);
} }
} }

View file

@ -10,9 +10,10 @@ import info.nightscout.androidaps.R;
public class EventPumpStatusChanged extends Event { public class EventPumpStatusChanged extends Event {
public static final int CONNECTING = 0; public static final int CONNECTING = 0;
public static final int CONNECTED = 1; public static final int CONNECTED = 1;
public static final int PERFORMING = 2; public static final int HANDSHAKING = 2;
public static final int DISCONNECTING = 3; public static final int PERFORMING = 3;
public static final int DISCONNECTED = 4; public static final int DISCONNECTING = 4;
public static final int DISCONNECTED = 5;
public int sStatus = DISCONNECTED; public int sStatus = DISCONNECTED;
public int sSecondsElapsed = 0; public int sSecondsElapsed = 0;
@ -47,6 +48,8 @@ public class EventPumpStatusChanged extends Event {
public String textStatus() { public String textStatus() {
if (sStatus == CONNECTING) if (sStatus == CONNECTING)
return String.format(MainApp.gs(R.string.danar_history_connectingfor), sSecondsElapsed); return String.format(MainApp.gs(R.string.danar_history_connectingfor), sSecondsElapsed);
else if (sStatus == HANDSHAKING)
return MainApp.gs(R.string.handshaking);
else if (sStatus == CONNECTED) else if (sStatus == CONNECTED)
return MainApp.gs(R.string.connected); return MainApp.gs(R.string.connected);
else if (sStatus == PERFORMING) else if (sStatus == PERFORMING)

View file

@ -1,7 +1,5 @@
package info.nightscout.androidaps.interfaces; package info.nightscout.androidaps.interfaces;
import java.util.Date;
import info.nightscout.androidaps.plugins.Loop.APSResult; import info.nightscout.androidaps.plugins.Loop.APSResult;
/** /**
@ -9,7 +7,7 @@ import info.nightscout.androidaps.plugins.Loop.APSResult;
*/ */
public interface APSInterface { public interface APSInterface {
public APSResult getLastAPSResult(); public APSResult getLastAPSResult();
public Date getLastAPSRun(); public long getLastAPSRun();
public void invoke(String initiator, boolean tempBasalFallback); public void invoke(String initiator, boolean tempBasalFallback);
} }

View file

@ -1,8 +1,12 @@
package info.nightscout.androidaps.interfaces; package info.nightscout.androidaps.interfaces;
import android.content.Intent;
/** /**
* Created by mike on 20.06.2016. * Created by mike on 20.06.2016.
*/ */
public interface BgSourceInterface { public interface BgSourceInterface {
boolean advancedFilteringSupported(); boolean advancedFilteringSupported();
void handleNewData(Intent intent);
} }

View file

@ -6,12 +6,14 @@ import org.slf4j.LoggerFactory;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import info.nightscout.androidaps.logging.L;
/** /**
* Created by mike on 19.03.2018. * Created by mike on 19.03.2018.
*/ */
public class Constraint<T extends Comparable> { public class Constraint<T extends Comparable> {
private static Logger log = LoggerFactory.getLogger(Constraint.class); private static Logger log = LoggerFactory.getLogger(L.CONSTRAINTS);
T value; T value;
T originalValue; T originalValue;
@ -35,18 +37,35 @@ public class Constraint<T extends Comparable> {
public Constraint<T> set(T value) { public Constraint<T> set(T value) {
this.value = value; this.value = value;
this.originalValue = value; this.originalValue = value;
if (L.isEnabled(L.CONSTRAINTS))
log.debug("Setting value " + value);
return this; return this;
} }
public Constraint<T> set(T value, String reason, Object from) { public Constraint<T> set(T value, String reason, Object from) {
if (L.isEnabled(L.CONSTRAINTS))
log.debug("Setting value " + this.value + " -> " + value + " (" + reason + ")[" + translateFrom(from) + "]");
this.value = value; this.value = value;
addReason(reason, from); addReason(reason, from);
addMostLimingReason(reason, from); addMostLimingReason(reason, from);
return this; return this;
} }
public Constraint<T> setIfDifferent(T value, String reason, Object from) {
if (!this.value.equals(value)) {
if (L.isEnabled(L.CONSTRAINTS))
log.debug("Setting because of different value " + this.value + " -> " + value + " (" + reason + ")[" + translateFrom(from) + "]");
this.value = value;
addReason(reason, from);
addMostLimingReason(reason, from);
}
return this;
}
public Constraint<T> setIfSmaller(T value, String reason, Object from) { public Constraint<T> setIfSmaller(T value, String reason, Object from) {
if (value.compareTo(this.value) < 0) { if (value.compareTo(this.value) < 0) {
if (L.isEnabled(L.CONSTRAINTS))
log.debug("Setting because of smaller value " + this.value + " -> " + value + " (" + reason + ")[" + translateFrom(from) + "]");
this.value = value; this.value = value;
mostLimiting.clear(); mostLimiting.clear();
addMostLimingReason(reason, from); addMostLimingReason(reason, from);
@ -59,6 +78,8 @@ public class Constraint<T extends Comparable> {
public Constraint<T> setIfGreater(T value, String reason, Object from) { public Constraint<T> setIfGreater(T value, String reason, Object from) {
if (value.compareTo(this.value) > 0) { if (value.compareTo(this.value) > 0) {
if (L.isEnabled(L.CONSTRAINTS))
log.debug("Setting because of greater value " + this.value + " -> " + value + " (" + reason + ")[" + translateFrom(from) + "]");
this.value = value; this.value = value;
mostLimiting.clear(); mostLimiting.clear();
addMostLimingReason(reason, from); addMostLimingReason(reason, from);
@ -69,13 +90,17 @@ public class Constraint<T extends Comparable> {
return this; return this;
} }
private String translateFrom(Object from) {
return from.getClass().getSimpleName().replace("Plugin", "");
}
public Constraint addReason(String reason, Object from) { public Constraint addReason(String reason, Object from) {
reasons.add(from.getClass().getSimpleName().replace("Plugin", "") + ": " + reason); reasons.add(translateFrom(from) + ": " + reason);
return this; return this;
} }
public Constraint addMostLimingReason(String reason, Object from) { public Constraint addMostLimingReason(String reason, Object from) {
mostLimiting.add(from.getClass().getSimpleName().replace("Plugin", "") + ": " + reason); mostLimiting.add(translateFrom(from) + ": " + reason);
return this; return this;
} }
@ -86,6 +111,7 @@ public class Constraint<T extends Comparable> {
if (count++ != 0) sb.append("\n"); if (count++ != 0) sb.append("\n");
sb.append(r); sb.append(r);
} }
if (L.isEnabled(L.CONSTRAINTS))
log.debug("Limiting origial value: " + originalValue + " to " + value + ". Reason: " + sb.toString()); log.debug("Limiting origial value: " + originalValue + " to " + value + ". Reason: " + sb.toString());
return sb.toString(); return sb.toString();
} }
@ -101,6 +127,7 @@ public class Constraint<T extends Comparable> {
if (count++ != 0) sb.append("\n"); if (count++ != 0) sb.append("\n");
sb.append(r); sb.append(r);
} }
if (L.isEnabled(L.CONSTRAINTS))
log.debug("Limiting origial value: " + originalValue + " to " + value + ". Reason: " + sb.toString()); log.debug("Limiting origial value: " + originalValue + " to " + value + ". Reason: " + sb.toString());
return sb.toString(); return sb.toString();
} }

View file

@ -7,7 +7,7 @@ import info.nightscout.androidaps.data.Profile;
*/ */
public interface ConstraintsInterface { public interface ConstraintsInterface {
default Constraint<Boolean> isLoopInvokationAllowed(Constraint<Boolean> value) { default Constraint<Boolean> isLoopInvocationAllowed(Constraint<Boolean> value) {
return value; return value;
} }
@ -27,6 +27,10 @@ public interface ConstraintsInterface {
return value; return value;
} }
default Constraint<Boolean> isUAMEnabled(Constraint<Boolean> value) {
return value;
}
default Constraint<Boolean> isAdvancedFilteringEnabled(Constraint<Boolean> value) { default Constraint<Boolean> isAdvancedFilteringEnabled(Constraint<Boolean> value) {
return value; return value;
} }
@ -43,6 +47,10 @@ public interface ConstraintsInterface {
return insulin; return insulin;
} }
default Constraint<Double> applyExtendedBolusConstraints(Constraint<Double> insulin) {
return insulin;
}
default Constraint<Integer> applyCarbsConstraints(Constraint<Integer> carbs) { default Constraint<Integer> applyCarbsConstraints(Constraint<Integer> carbs) {
return carbs; return carbs;
} }

View file

@ -9,4 +9,5 @@ import info.nightscout.androidaps.data.PumpEnactResult;
public interface DanaRInterface { public interface DanaRInterface {
PumpEnactResult loadHistory(byte type); // for history browser PumpEnactResult loadHistory(byte type); // for history browser
PumpEnactResult loadEvents(); // events history to build treatments from PumpEnactResult loadEvents(); // events history to build treatments from
PumpEnactResult setUserOptions(); // like AnyDana does
} }

View file

@ -1,18 +1,22 @@
package info.nightscout.androidaps.interfaces; package info.nightscout.androidaps.interfaces;
import android.os.SystemClock; import android.os.SystemClock;
import android.support.v4.app.FragmentActivity;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.logging.L;
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.queue.CommandQueue;
/** /**
* Created by mike on 09.06.2016. * Created by mike on 09.06.2016.
*/ */
public abstract class PluginBase { public abstract class PluginBase {
private static Logger log = LoggerFactory.getLogger(PluginBase.class); private static Logger log = LoggerFactory.getLogger(L.CORE);
public enum State { public enum State {
NOT_INITIALIZED, NOT_INITIALIZED,
@ -32,6 +36,12 @@ public abstract class PluginBase {
this.pluginDescription = pluginDescription; this.pluginDescription = pluginDescription;
} }
// Default always calls invoke
// Plugins that have special constraints if they get switched to may override this method
public void switchAllowed(ConfigBuilderFragment.PluginViewHolder.PluginSwitcher pluginSwitcher, FragmentActivity activity) {
pluginSwitcher.invoke();
}
// public PluginType getType() { // public PluginType getType() {
// return mainType; // return mainType;
// } // }
@ -57,6 +67,11 @@ public abstract class PluginBase {
return getName(); return getName();
} }
public String getDescription() {
if (pluginDescription.description == -1) return null;
else return MainApp.gs(pluginDescription.description);
}
public PluginType getType() { public PluginType getType() {
return pluginDescription.mainType; return pluginDescription.mainType;
} }
@ -100,14 +115,16 @@ public abstract class PluginBase {
if (state != State.ENABLED) { if (state != State.ENABLED) {
onStateChange(type, state, State.ENABLED); onStateChange(type, state, State.ENABLED);
state = State.ENABLED; state = State.ENABLED;
if (L.isEnabled(L.CORE))
log.debug("Starting: " + getName()); log.debug("Starting: " + getName());
onStart(); onStart();
} }
} else { // disabling plugin } else { // disabling plugin
if (state == State.ENABLED) { if (state == State.ENABLED) {
onStateChange(type, state, State.ENABLED); onStateChange(type, state, State.DISABLED);
state = State.DISABLED; state = State.DISABLED;
onStop(); onStop();
if (L.isEnabled(L.CORE))
log.debug("Stopping: " + getName()); log.debug("Stopping: " + getName());
} }
} }
@ -152,7 +169,9 @@ public abstract class PluginBase {
if (getType() == PluginType.PUMP) { if (getType() == PluginType.PUMP) {
new Thread(() -> { new Thread(() -> {
SystemClock.sleep(3000); SystemClock.sleep(3000);
ConfigBuilderPlugin.getCommandQueue().readStatus("Pump driver changed.", null); CommandQueue commandQueue = ConfigBuilderPlugin.getPlugin().getCommandQueue();
if (commandQueue != null)
commandQueue.readStatus("Pump driver changed.", null);
}).start(); }).start();
} }
} }

View file

@ -9,6 +9,7 @@ public class PluginDescription {
boolean showInList = true; boolean showInList = true;
int pluginName = -1; int pluginName = -1;
int shortName = -1; int shortName = -1;
int description = -1;
int preferencesId = -1; int preferencesId = -1;
int advancedPreferencesId = -1; int advancedPreferencesId = -1;
public boolean enableByDefault = false; public boolean enableByDefault = false;
@ -74,6 +75,11 @@ public class PluginDescription {
return this; return this;
} }
public PluginDescription description(int description) {
this.description = description;
return this;
}
public String getFragmentClass() { public String getFragmentClass() {
return fragmentClass; return fragmentClass;
} }

View file

@ -1,47 +1,139 @@
package info.nightscout.androidaps.interfaces; package info.nightscout.androidaps.interfaces;
import info.nightscout.androidaps.plugins.PumpCommon.defs.PumpCapability;
import info.nightscout.androidaps.plugins.PumpCommon.defs.PumpTempBasalType;
import info.nightscout.androidaps.plugins.PumpCommon.defs.PumpType;
/** /**
* Created by mike on 08.12.2016. * Created by mike on 08.12.2016.
*/ */
public class PumpDescription { public class PumpDescription {
public PumpType pumpType = PumpType.GenericAAPS;
public PumpDescription () {
resetSettings();
}
public static final int NONE = 0; public static final int NONE = 0;
public static final int PERCENT = 0x01; public static final int PERCENT = 0x01;
public static final int ABSOLUTE = 0x02; public static final int ABSOLUTE = 0x02;
public boolean isBolusCapable = true; public boolean isBolusCapable;
public double bolusStep = 0.1d; public double bolusStep;
public boolean isExtendedBolusCapable = true; public boolean isExtendedBolusCapable;
public double extendedBolusStep = 0.1d; public double extendedBolusStep;
public double extendedBolusDurationStep = 30; public double extendedBolusDurationStep;
public double extendedBolusMaxDuration = 12 * 60; public double extendedBolusMaxDuration;
public boolean isTempBasalCapable = true; public boolean isTempBasalCapable;
public int tempBasalStyle = PERCENT; public int tempBasalStyle;
public int maxTempPercent = 200; public int maxTempPercent;
public int tempPercentStep = 10; public int tempPercentStep;
public double maxTempAbsolute = 10; public double maxTempAbsolute;
public double tempAbsoluteStep = 0.05d; public double tempAbsoluteStep;
public int tempDurationStep = 60; public int tempDurationStep;
public boolean tempDurationStep15mAllowed = false; public boolean tempDurationStep15mAllowed;
public boolean tempDurationStep30mAllowed = false; public boolean tempDurationStep30mAllowed;
public int tempMaxDuration = 12 * 60; public int tempMaxDuration;
public boolean isSetBasalProfileCapable;
public double basalStep;
public double basalMinimumRate;
public double basalMaximumRate;
public boolean isRefillingCapable;
public boolean storesCarbInfo;
public boolean is30minBasalRatesCapable;
public boolean supportsTDDs;
public boolean needsManualTDDLoad;
public boolean isSetBasalProfileCapable = true; public void resetSettings() {
public double basalStep = 0.01d; isBolusCapable = true;
public double basalMinimumRate = 0.04d; bolusStep = 0.1d;
public boolean isRefillingCapable = false; isExtendedBolusCapable = true;
extendedBolusStep = 0.1d;
extendedBolusDurationStep = 30;
extendedBolusMaxDuration = 12 * 60;
public boolean storesCarbInfo = true; isTempBasalCapable = true;
tempBasalStyle = PERCENT;
maxTempPercent = 200;
tempPercentStep = 10;
maxTempAbsolute = 10;
tempAbsoluteStep = 0.05d;
tempDurationStep = 60;
tempMaxDuration = 12 * 60;
tempDurationStep15mAllowed = false;
tempDurationStep30mAllowed = false;
public boolean is30minBasalRatesCapable = false; isSetBasalProfileCapable = true;
basalStep = 0.01d;
basalMinimumRate = 0.04d;
basalMaximumRate = 25d;
is30minBasalRatesCapable = false;
isRefillingCapable = false;
storesCarbInfo = true;
supportsTDDs = false;
needsManualTDDLoad = true;
}
public void setPumpDescription(PumpType pumpType) {
resetSettings();
this.pumpType = pumpType;
PumpCapability pumpCapability = pumpType.getPumpCapability();
isBolusCapable = pumpCapability.hasCapability(PumpCapability.Bolus);
bolusStep = pumpType.getBolusSize();
isExtendedBolusCapable = pumpCapability.hasCapability(PumpCapability.ExtendedBolus);
extendedBolusStep = pumpType.getExtendedBolusSettings().getStep();
extendedBolusDurationStep = pumpType.getExtendedBolusSettings().getDurationStep();
extendedBolusMaxDuration = pumpType.getExtendedBolusSettings().getMaxDuration();
isTempBasalCapable = pumpCapability.hasCapability(PumpCapability.TempBasal);
if (pumpType.getPumpTempBasalType() == PumpTempBasalType.Percent) {
tempBasalStyle = PERCENT;
maxTempPercent = pumpType.getTbrSettings().getMaxDose().intValue();
tempPercentStep = (int) pumpType.getTbrSettings().getStep();
} else {
tempBasalStyle = ABSOLUTE;
maxTempAbsolute = pumpType.getTbrSettings().getMaxDose();
tempAbsoluteStep = pumpType.getTbrSettings().getStep();
}
tempDurationStep = pumpType.getTbrSettings().getDurationStep();
tempMaxDuration = pumpType.getTbrSettings().getMaxDuration();
tempDurationStep15mAllowed = pumpType.getSpecialBasalDurations()
.hasCapability(PumpCapability.BasalRate_Duration15minAllowed);
tempDurationStep30mAllowed = pumpType.getSpecialBasalDurations()
.hasCapability(PumpCapability.BasalRate_Duration30minAllowed);
isSetBasalProfileCapable = pumpCapability.hasCapability(PumpCapability.BasalProfileSet);
basalStep = pumpType.getBaseBasalStep();
basalMinimumRate = pumpType.getBaseBasalMinValue();
isRefillingCapable = pumpCapability.hasCapability(PumpCapability.Refill);
storesCarbInfo = pumpCapability.hasCapability(PumpCapability.StoreCarbInfo);
supportsTDDs = pumpCapability.hasCapability(PumpCapability.TDD);
needsManualTDDLoad = pumpCapability.hasCapability(PumpCapability.ManualTDDLoad);
is30minBasalRatesCapable = pumpCapability.hasCapability(PumpCapability.BasalRate30min);
}
public boolean supportsTDDs = false;
public boolean needsManualTDDLoad = true;
} }

View file

@ -2,8 +2,6 @@ package info.nightscout.androidaps.interfaces;
import org.json.JSONObject; import org.json.JSONObject;
import java.util.Date;
import info.nightscout.androidaps.data.DetailedBolusInfo; import info.nightscout.androidaps.data.DetailedBolusInfo;
import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.data.PumpEnactResult; import info.nightscout.androidaps.data.PumpEnactResult;
@ -13,11 +11,13 @@ import info.nightscout.androidaps.data.PumpEnactResult;
*/ */
public interface PumpInterface { public interface PumpInterface {
boolean isInitialized(); boolean isInitialized(); // true if pump status has been read and is ready to accept commands
boolean isSuspended(); boolean isSuspended(); // true if suspended (not delivering insulin)
boolean isBusy(); boolean isBusy(); // if true pump is not ready to accept commands right now
boolean isConnected(); boolean isConnected(); // true if BT connection is established
boolean isConnecting(); boolean isConnecting(); // true if BT connection is in progress
boolean isHandshakeInProgress(); // true if BT is connected but initial handshake is still in progress
void finishHandshaking(); // set initial handshake completed
void connect(String reason); void connect(String reason);
void disconnect(String reason); void disconnect(String reason);
@ -29,7 +29,7 @@ public interface PumpInterface {
PumpEnactResult setNewBasalProfile(Profile profile); PumpEnactResult setNewBasalProfile(Profile profile);
boolean isThisProfileSet(Profile profile); boolean isThisProfileSet(Profile profile);
Date lastDataTime(); long lastDataTime();
double getBaseBasalRate(); // base basal rate, not temp basal double getBaseBasalRate(); // base basal rate, not temp basal

View file

@ -1,11 +1,17 @@
package info.nightscout.androidaps.interfaces; package info.nightscout.androidaps.interfaces;
import info.nightscout.androidaps.plugins.IobCobCalculator.AutosensResult; import info.nightscout.androidaps.plugins.IobCobCalculator.AutosensResult;
import info.nightscout.androidaps.plugins.IobCobCalculator.IobCobCalculatorPlugin;
/** /**
* Created by mike on 24.06.2017. * Created by mike on 24.06.2017.
*/ */
public interface SensitivityInterface { public interface SensitivityInterface {
AutosensResult detectSensitivity(long fromTime, long toTime);
double MIN_HOURS = 1;
double MIN_HOURS_FULL_AUTOSENS = 4;
AutosensResult detectSensitivity(IobCobCalculatorPlugin plugin, long fromTime, long toTime);
} }

View file

@ -50,7 +50,7 @@ public interface TreatmentsInterface {
boolean addToHistoryExtendedBolus(ExtendedBolus extendedBolus); boolean addToHistoryExtendedBolus(ExtendedBolus extendedBolus);
boolean addToHistoryTreatment(DetailedBolusInfo detailedBolusInfo); boolean addToHistoryTreatment(DetailedBolusInfo detailedBolusInfo, boolean allowUpdate);
TempTarget getTempTargetFromHistory(); TempTarget getTempTargetFromHistory();
TempTarget getTempTargetFromHistory(long time); TempTarget getTempTargetFromHistory(long time);

View file

@ -1,4 +1,4 @@
package info.nightscout.utils; package info.nightscout.androidaps.logging;
import android.os.Bundle; import android.os.Bundle;

View file

@ -0,0 +1,123 @@
package info.nightscout.androidaps.logging;
import java.util.ArrayList;
import java.util.List;
import info.nightscout.utils.SP;
public class L {
public static class LogElement {
public String name;
boolean defaultValue;
public boolean enabled;
boolean requiresRestart = false;
LogElement(String name, boolean defaultValue) {
this.name = name;
this.defaultValue = defaultValue;
enabled = SP.getBoolean(getSPName(), defaultValue);
}
LogElement(String name, boolean defaultValue, boolean requiresRestart) {
this.name = name;
this.defaultValue = defaultValue;
this.requiresRestart = requiresRestart;
enabled = SP.getBoolean(getSPName(), defaultValue);
}
LogElement(boolean defaultValue) {
this.name = "NONEXISTING";
this.defaultValue = defaultValue;
enabled = defaultValue;
}
private String getSPName() {
return "log_" + name;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
SP.putBoolean(getSPName(), enabled);
}
void resetToDefault() {
setEnabled(defaultValue);
}
}
private static List<LogElement> logElements;
static {
initialize();
}
private static LogElement findByName(String name) {
for (LogElement element : logElements) {
if (element.name.equals(name))
return element;
}
return new LogElement(false);
}
public static boolean isEnabled(String name) {
return findByName(name).enabled;
}
public static List<LogElement> getLogElements() {
return logElements;
}
public static void resetToDefaults() {
for (LogElement element : logElements) {
element.resetToDefault();
}
}
public static final String CORE = "CORE";
public static final String AUTOSENS = "AUTOSENS";
public static final String EVENTS = "EVENTS";
public static final String BGSOURCE = "BGSOURCE";
public static final String OVERVIEW = "OVERVIEW";
public static final String NOTIFICATION = "NOTIFICATION";
public static final String DATASERVICE = "DATASERVICE";
public static final String DATABASE = "DATABASE";
public static final String DATAFOOD = "DATAFOOD";
public static final String DATATREATMENTS = "DATATREATMENTS";
public static final String NSCLIENT = "NSCLIENT";
public static final String CONSTRAINTS = "CONSTRAINTS";
public static final String PUMP = "PUMP";
public static final String PUMPQUEUE = "PUMPQUEUE";
public static final String PUMPCOMM = "PUMPCOMM";
public static final String PUMPBTCOMM = "PUMPBTCOMM";
public static final String APS = "APS";
public static final String PROFILE = "PROFILE";
public static final String CONFIGBUILDER = "CONFIGBUILDER";
public static final String UI = "UI";
private static void initialize() {
logElements = new ArrayList<>();
logElements.add(new LogElement(APS, true));
logElements.add(new LogElement(AUTOSENS, true));
logElements.add(new LogElement(BGSOURCE, true));
logElements.add(new LogElement(CONFIGBUILDER, true));
logElements.add(new LogElement(CONSTRAINTS, true));
logElements.add(new LogElement(CORE, true));
logElements.add(new LogElement(DATABASE, true));
logElements.add(new LogElement(DATAFOOD, true));
logElements.add(new LogElement(DATASERVICE, true));
logElements.add(new LogElement(DATATREATMENTS, true));
logElements.add(new LogElement(EVENTS, false, true));
logElements.add(new LogElement(NOTIFICATION, true));
logElements.add(new LogElement(NSCLIENT, true));
logElements.add(new LogElement(OVERVIEW, true));
logElements.add(new LogElement(PROFILE, true));
logElements.add(new LogElement(PUMP, true));
logElements.add(new LogElement(PUMPBTCOMM, false));
logElements.add(new LogElement(PUMPCOMM, true));
logElements.add(new LogElement(PUMPQUEUE, true));
logElements.add(new LogElement(UI, true));
}
}

View file

@ -14,10 +14,10 @@ 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.activities.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.activities.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,7 @@ 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.ConfigBuilder.ProfileFunctions;
import info.nightscout.androidaps.plugins.Treatments.TreatmentsPlugin; import info.nightscout.androidaps.plugins.Treatments.TreatmentsPlugin;
import info.nightscout.utils.FabricPrivacy; import info.nightscout.utils.FabricPrivacy;
import info.nightscout.utils.SingleClickButton; import info.nightscout.utils.SingleClickButton;
@ -125,13 +126,13 @@ 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 (ConfigBuilderPlugin.getPlugin().getActiveProfileInterface() != null && ConfigBuilderPlugin.getPlugin().getActiveProfileInterface().getProfile() != null) {
profileSwitch.setVisibility(View.VISIBLE); profileSwitch.setVisibility(View.VISIBLE);
} else { } else {
profileSwitch.setVisibility(View.GONE); profileSwitch.setVisibility(View.GONE);
} }
if (MainApp.getConfigBuilder().getProfile() == null) { if (ProfileFunctions.getInstance().getProfile() == null) {
tempTarget.setVisibility(View.GONE); tempTarget.setVisibility(View.GONE);
extendedBolus.setVisibility(View.GONE); extendedBolus.setVisibility(View.GONE);
extendedBolusCancel.setVisibility(View.GONE); extendedBolusCancel.setVisibility(View.GONE);
@ -141,7 +142,7 @@ public class ActionsFragment extends SubscriberFragment implements View.OnClickL
return; return;
} }
final PumpInterface pump = ConfigBuilderPlugin.getActivePump(); final PumpInterface pump = ConfigBuilderPlugin.getPlugin().getActivePump();
final boolean basalprofileEnabled = MainApp.isEngineeringModeOrRelease() final boolean basalprofileEnabled = MainApp.isEngineeringModeOrRelease()
&& pump.getPumpDescription().isSetBasalProfileCapable; && pump.getPumpDescription().isSetBasalProfileCapable;
@ -191,7 +192,7 @@ public class ActionsFragment extends SubscriberFragment implements View.OnClickL
else else
tempTarget.setVisibility(View.VISIBLE); tempTarget.setVisibility(View.VISIBLE);
if (!ConfigBuilderPlugin.getActivePump().getPumpDescription().supportsTDDs) tddStats.setVisibility(View.GONE); if (!ConfigBuilderPlugin.getPlugin().getActivePump().getPumpDescription().supportsTDDs) tddStats.setVisibility(View.GONE);
else tddStats.setVisibility(View.VISIBLE); else tddStats.setVisibility(View.VISIBLE);
} }
}); });
@ -222,13 +223,13 @@ public class ActionsFragment extends SubscriberFragment implements View.OnClickL
break; break;
case R.id.actions_extendedbolus_cancel: case R.id.actions_extendedbolus_cancel:
if (TreatmentsPlugin.getPlugin().isInHistoryExtendedBoluslInProgress()) { if (TreatmentsPlugin.getPlugin().isInHistoryExtendedBoluslInProgress()) {
ConfigBuilderPlugin.getCommandQueue().cancelExtended(null); ConfigBuilderPlugin.getPlugin().getCommandQueue().cancelExtended(null);
FabricPrivacy.getInstance().logCustom(new CustomEvent("CancelExtended")); FabricPrivacy.getInstance().logCustom(new CustomEvent("CancelExtended"));
} }
break; break;
case R.id.actions_canceltempbasal: case R.id.actions_canceltempbasal:
if (TreatmentsPlugin.getPlugin().isTempBasalInProgress()) { if (TreatmentsPlugin.getPlugin().isTempBasalInProgress()) {
ConfigBuilderPlugin.getCommandQueue().cancelTempBasal(true, null); ConfigBuilderPlugin.getPlugin().getCommandQueue().cancelTempBasal(true, null);
FabricPrivacy.getInstance().logCustom(new CustomEvent("CancelTemp")); FabricPrivacy.getInstance().logCustom(new CustomEvent("CancelTemp"));
} }
break; break;

View file

@ -17,6 +17,7 @@ public class ActionsPlugin extends PluginBase {
.fragmentClass(ActionsFragment.class.getName()) .fragmentClass(ActionsFragment.class.getName())
.pluginName(R.string.actions) .pluginName(R.string.actions)
.shortName(R.string.actions_shortname) .shortName(R.string.actions_shortname)
.description(R.string.description_actions)
); );
} }
} }

View file

@ -39,7 +39,7 @@ 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.FabricPrivacy;
import info.nightscout.utils.NSUpload; import info.nightscout.androidaps.plugins.NSClientInternal.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;
@ -61,6 +61,10 @@ public class FillDialog extends DialogFragment implements OnClickListener {
private EditText notesEdit; private EditText notesEdit;
//one shot guards
private boolean accepted;
private boolean okClicked;
final private TextWatcher textWatcher = new TextWatcher() { final private TextWatcher textWatcher = new TextWatcher() {
@Override @Override
public void afterTextChanged(Editable s) { public void afterTextChanged(Editable s) {
@ -87,7 +91,7 @@ public class FillDialog extends DialogFragment implements OnClickListener {
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) { Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.actions_fill_dialog, null, false); View view = inflater.inflate(R.layout.actions_fill_dialog, container, false);
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);
@ -99,7 +103,7 @@ public class FillDialog extends DialogFragment implements OnClickListener {
insulinCartridgeChangeCheckbox = view.findViewById(R.id.fill_cartridge_change); insulinCartridgeChangeCheckbox = view.findViewById(R.id.fill_cartridge_change);
Double maxInsulin = MainApp.getConstraintChecker().getMaxBolusAllowed().value(); Double maxInsulin = MainApp.getConstraintChecker().getMaxBolusAllowed().value();
double bolusstep = ConfigBuilderPlugin.getActivePump().getPumpDescription().bolusStep; double bolusstep = ConfigBuilderPlugin.getPlugin().getActivePump().getPumpDescription().bolusStep;
editInsulin = view.findViewById(R.id.fill_insulinamount); editInsulin = view.findViewById(R.id.fill_insulinamount);
editInsulin.setParams(0d, 0d, maxInsulin, bolusstep, DecimalFormatter.pumpSupportedBolusFormat(), false, textWatcher); editInsulin.setParams(0d, 0d, maxInsulin, bolusstep, DecimalFormatter.pumpSupportedBolusFormat(), false, textWatcher);
@ -163,7 +167,14 @@ public class FillDialog extends DialogFragment implements OnClickListener {
} }
private void confirmAndDeliver() { private synchronized void confirmAndDeliver() {
if (okClicked) {
log.debug("guarding: ok already clicked");
dismiss();
return;
}
okClicked = true;
try { try {
Double insulin = SafeParse.stringToDouble(editInsulin.getText()); Double insulin = SafeParse.stringToDouble(editInsulin.getText());
@ -173,8 +184,8 @@ public class FillDialog extends DialogFragment implements OnClickListener {
if (insulinAfterConstraints > 0) { if (insulinAfterConstraints > 0) {
confirmMessage.add(MainApp.gs(R.string.fillwarning)); confirmMessage.add(MainApp.gs(R.string.fillwarning));
confirmMessage.add(""); confirmMessage.add("");
confirmMessage.add(MainApp.gs(R.string.bolus) + ": " + "<font color='" + MainApp.gc(R.color.colorCarbsButton) + "'>" + insulinAfterConstraints + "U" + "</font>"); confirmMessage.add(MainApp.gs(R.string.bolus) + ": " + "<font color='" + MainApp.gc(R.color.colorCarbsButton) + "'>" + DecimalFormatter.toPumpSupportedBolus(insulinAfterConstraints) + "U" + "</font>");
if (!insulinAfterConstraints.equals(insulin)) if (Math.abs(insulinAfterConstraints - insulin) > 0.01d)
confirmMessage.add("<font color='" + MainApp.gc(R.color.low) + "'>" + MainApp.gs(R.string.bolusconstraintapplied) + "</font>"); confirmMessage.add("<font color='" + MainApp.gc(R.color.low) + "'>" + MainApp.gs(R.string.bolusconstraintapplied) + "</font>");
} }
@ -198,6 +209,13 @@ public class FillDialog extends DialogFragment implements OnClickListener {
if (insulinAfterConstraints > 0 || pumpSiteChangeCheckbox.isChecked() || insulinCartridgeChangeCheckbox.isChecked()) { if (insulinAfterConstraints > 0 || pumpSiteChangeCheckbox.isChecked() || insulinCartridgeChangeCheckbox.isChecked()) {
builder.setMessage(Html.fromHtml(Joiner.on("<br/>").join(confirmMessage))); builder.setMessage(Html.fromHtml(Joiner.on("<br/>").join(confirmMessage)));
builder.setPositiveButton(MainApp.gs(R.string.primefill), (dialog, id) -> { builder.setPositiveButton(MainApp.gs(R.string.primefill), (dialog, id) -> {
synchronized (builder) {
if (accepted) {
log.debug("guarding: already accepted");
return;
}
accepted = true;
if (finalInsulinAfterConstraints > 0) { if (finalInsulinAfterConstraints > 0) {
DetailedBolusInfo detailedBolusInfo = new DetailedBolusInfo(); DetailedBolusInfo detailedBolusInfo = new DetailedBolusInfo();
detailedBolusInfo.insulin = finalInsulinAfterConstraints; detailedBolusInfo.insulin = finalInsulinAfterConstraints;
@ -205,7 +223,7 @@ public class FillDialog extends DialogFragment implements OnClickListener {
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; detailedBolusInfo.notes = notes;
ConfigBuilderPlugin.getCommandQueue().bolus(detailedBolusInfo, new Callback() { ConfigBuilderPlugin.getPlugin().getCommandQueue().bolus(detailedBolusInfo, new Callback() {
@Override @Override
public void run() { public void run() {
if (!result.success) { if (!result.success) {
@ -224,6 +242,7 @@ public class FillDialog extends DialogFragment implements OnClickListener {
NSUpload.uploadEvent(CareportalEvent.SITECHANGE, now(), notes); NSUpload.uploadEvent(CareportalEvent.SITECHANGE, now(), notes);
if (insulinCartridgeChangeCheckbox.isChecked()) if (insulinCartridgeChangeCheckbox.isChecked())
NSUpload.uploadEvent(CareportalEvent.INSULINCHANGE, now() + 1000, notes); NSUpload.uploadEvent(CareportalEvent.INSULINCHANGE, now() + 1000, notes);
}
}); });
} else { } else {
builder.setMessage(MainApp.gs(R.string.no_action_selected)); builder.setMessage(MainApp.gs(R.string.no_action_selected));

View file

@ -44,12 +44,12 @@ public class NewExtendedBolusDialog extends DialogFragment implements View.OnCli
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.getConstraintChecker().getMaxBolusAllowed().value(); Double maxInsulin = MainApp.getConstraintChecker().getMaxExtendedBolusAllowed().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);
double extendedDurationStep = ConfigBuilderPlugin.getActivePump().getPumpDescription().extendedBolusDurationStep; double extendedDurationStep = ConfigBuilderPlugin.getPlugin().getActivePump().getPumpDescription().extendedBolusDurationStep;
double extendedMaxDuration = ConfigBuilderPlugin.getActivePump().getPumpDescription().extendedBolusMaxDuration; double extendedMaxDuration = ConfigBuilderPlugin.getPlugin().getActivePump().getPumpDescription().extendedBolusMaxDuration;
editDuration = (NumberPicker) view.findViewById(R.id.overview_newextendedbolus_duration); editDuration = (NumberPicker) view.findViewById(R.id.overview_newextendedbolus_duration);
editDuration.setParams(extendedDurationStep, extendedDurationStep, extendedMaxDuration, extendedDurationStep, new DecimalFormat("0"), false); editDuration.setParams(extendedDurationStep, extendedDurationStep, extendedMaxDuration, extendedDurationStep, new DecimalFormat("0"), false);
@ -71,10 +71,10 @@ public class NewExtendedBolusDialog extends DialogFragment implements View.OnCli
String confirmMessage = MainApp.gs(R.string.setextendedbolusquestion); String confirmMessage = MainApp.gs(R.string.setextendedbolusquestion);
Double insulinAfterConstraint = MainApp.getConstraintChecker().applyBolusConstraints(new Constraint<>(insulin)).value(); Double insulinAfterConstraint = MainApp.getConstraintChecker().applyExtendedBolusConstraints(new Constraint<>(insulin)).value();
confirmMessage += " " + insulinAfterConstraint + " U "; confirmMessage += " " + insulinAfterConstraint + " U ";
confirmMessage += MainApp.gs(R.string.duration) + " " + durationInMinutes + "min ?"; confirmMessage += MainApp.gs(R.string.duration) + " " + durationInMinutes + "min ?";
if (insulinAfterConstraint - insulin != 0d) if (Math.abs(insulinAfterConstraint - insulin) > 0.01d)
confirmMessage += "\n" + MainApp.gs(R.string.constraintapllied); confirmMessage += "\n" + MainApp.gs(R.string.constraintapllied);
insulin = insulinAfterConstraint; insulin = insulinAfterConstraint;
@ -87,7 +87,7 @@ public class NewExtendedBolusDialog extends DialogFragment implements View.OnCli
builder.setMessage(confirmMessage); builder.setMessage(confirmMessage);
builder.setPositiveButton(MainApp.gs(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.getPlugin().getCommandQueue().extendedBolus(finalInsulin, finalDurationInMinutes, new Callback() {
@Override @Override
public void run() { public void run() {
if (!result.success) { if (!result.success) {

View file

@ -25,6 +25,7 @@ import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.interfaces.Constraint; 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.ConfigBuilder.ProfileFunctions;
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.FabricPrivacy;
@ -63,14 +64,14 @@ public class NewTempBasalDialog extends DialogFragment implements View.OnClickLi
absoluteRadio = (RadioButton) view.findViewById(R.id.overview_newtempbasal_absolute_radio); absoluteRadio = (RadioButton) view.findViewById(R.id.overview_newtempbasal_absolute_radio);
typeSelectorLayout = (LinearLayout) view.findViewById(R.id.overview_newtempbasal_typeselector_layout); typeSelectorLayout = (LinearLayout) view.findViewById(R.id.overview_newtempbasal_typeselector_layout);
PumpDescription pumpDescription = ConfigBuilderPlugin.getActivePump().getPumpDescription(); PumpDescription pumpDescription = ConfigBuilderPlugin.getPlugin().getActivePump().getPumpDescription();
basalPercent = (NumberPicker) view.findViewById(R.id.overview_newtempbasal_basalpercentinput); basalPercent = (NumberPicker) view.findViewById(R.id.overview_newtempbasal_basalpercentinput);
double maxTempPercent = pumpDescription.maxTempPercent; double maxTempPercent = pumpDescription.maxTempPercent;
double tempPercentStep = pumpDescription.tempPercentStep; double tempPercentStep = pumpDescription.tempPercentStep;
basalPercent.setParams(100d, 0d, maxTempPercent, tempPercentStep, new DecimalFormat("0"), true); basalPercent.setParams(100d, 0d, maxTempPercent, tempPercentStep, new DecimalFormat("0"), true);
Profile profile = MainApp.getConfigBuilder().getProfile(); Profile profile = ProfileFunctions.getInstance().getProfile();
Double currentBasal = profile != null ? profile.getBasal() : 0d; Double currentBasal = profile != null ? profile.getBasal() : 0d;
basalAbsolute = (NumberPicker) view.findViewById(R.id.overview_newtempbasal_basalabsoluteinput); basalAbsolute = (NumberPicker) view.findViewById(R.id.overview_newtempbasal_basalabsoluteinput);
basalAbsolute.setParams(currentBasal, 0d, pumpDescription.maxTempAbsolute, pumpDescription.tempAbsoluteStep, new DecimalFormat("0.00"), true); basalAbsolute.setParams(currentBasal, 0d, pumpDescription.maxTempAbsolute, pumpDescription.tempAbsoluteStep, new DecimalFormat("0.00"), true);
@ -118,7 +119,7 @@ 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());
Profile profile = MainApp.getConfigBuilder().getProfile(); Profile profile = ProfileFunctions.getInstance().getProfile();
if (profile == null) if (profile == null)
return; return;
@ -135,7 +136,7 @@ public class NewTempBasalDialog extends DialogFragment implements View.OnClickLi
absolute = MainApp.getConstraintChecker().applyBasalConstraints(new Constraint<>(basalAbsoluteInput), profile).value(); absolute = MainApp.getConstraintChecker().applyBasalConstraints(new Constraint<>(basalAbsoluteInput), profile).value();
confirmMessage += "\n" + absolute + " U/h "; confirmMessage += "\n" + absolute + " U/h ";
confirmMessage += "\n" + MainApp.gs(R.string.duration) + " " + durationInMinutes + "min ?"; confirmMessage += "\n" + MainApp.gs(R.string.duration) + " " + durationInMinutes + "min ?";
if (absolute - basalAbsoluteInput != 0d) if (Math.abs(absolute - basalAbsoluteInput) > 0.01d)
confirmMessage += "\n" + MainApp.gs(R.string.constraintapllied); confirmMessage += "\n" + MainApp.gs(R.string.constraintapllied);
} }
@ -162,9 +163,9 @@ public class NewTempBasalDialog extends DialogFragment implements View.OnClickLi
} }
}; };
if (setAsPercent) { if (setAsPercent) {
ConfigBuilderPlugin.getCommandQueue().tempBasalPercent(finalBasalPercent, finalDurationInMinutes, true, profile, callback); ConfigBuilderPlugin.getPlugin().getCommandQueue().tempBasalPercent(finalBasalPercent, finalDurationInMinutes, true, profile, callback);
} else { } else {
ConfigBuilderPlugin.getCommandQueue().tempBasalAbsolute(finalBasal, finalDurationInMinutes, true, profile, callback); ConfigBuilderPlugin.getPlugin().getCommandQueue().tempBasalAbsolute(finalBasal, finalDurationInMinutes, true, profile, callback);
} }
FabricPrivacy.getInstance().logCustom(new CustomEvent("TempBasal")); FabricPrivacy.getInstance().logCustom(new CustomEvent("TempBasal"));
} }

View file

@ -24,6 +24,7 @@ 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.NSClientInternal.data.NSSettingsStatus;
import info.nightscout.androidaps.plugins.Overview.OverviewFragment; import info.nightscout.androidaps.plugins.Overview.OverviewFragment;
import info.nightscout.utils.FabricPrivacy; import info.nightscout.utils.FabricPrivacy;
@ -100,7 +101,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 = MainApp.getConfigBuilder().getActiveProfileInterface().getProfile(); ProfileStore profileStore = ConfigBuilderPlugin.getPlugin().getActiveProfileInterface() != null ? ConfigBuilderPlugin.getPlugin().getActiveProfileInterface().getProfile() : null;
if (profileStore == null) { if (profileStore == null) {
noProfileView.setVisibility(View.VISIBLE); noProfileView.setVisibility(View.VISIBLE);
butonsLayout.setVisibility(View.GONE); butonsLayout.setVisibility(View.GONE);
@ -109,7 +110,7 @@ public class CareportalFragment extends SubscriberFragment implements View.OnCli
butonsLayout.setVisibility(View.VISIBLE); butonsLayout.setVisibility(View.VISIBLE);
} }
if (Config.NSCLIENT || Config.G5UPLOADER) if (Config.NSCLIENT)
statsLayout.setVisibility(View.GONE); // visible on overview statsLayout.setVisibility(View.GONE); // visible on overview
updateGUI(); updateGUI();
@ -218,50 +219,19 @@ public class CareportalFragment extends SubscriberFragment implements View.OnCli
double iageUrgent = nsSettings.getExtendedWarnValue("iage", "urgent", 96); double iageUrgent = nsSettings.getExtendedWarnValue("iage", "urgent", 96);
double iageWarn = nsSettings.getExtendedWarnValue("iage", "warn", 72); double iageWarn = nsSettings.getExtendedWarnValue("iage", "warn", 72);
handleAge(iage, CareportalEvent.INSULINCHANGE, iageWarn, iageUrgent);
double cageUrgent = nsSettings.getExtendedWarnValue("cage", "urgent", 72); double cageUrgent = nsSettings.getExtendedWarnValue("cage", "urgent", 72);
double cageWarn = nsSettings.getExtendedWarnValue("cage", "warn", 48); double cageWarn = nsSettings.getExtendedWarnValue("cage", "warn", 48);
handleAge(cage, CareportalEvent.SITECHANGE, cageWarn, cageUrgent);
double sageUrgent = nsSettings.getExtendedWarnValue("sage", "urgent", 166); double sageUrgent = nsSettings.getExtendedWarnValue("sage", "urgent", 166);
double sageWarn = nsSettings.getExtendedWarnValue("sage", "warn", 164); double sageWarn = nsSettings.getExtendedWarnValue("sage", "warn", 164);
handleAge(sage, CareportalEvent.SENSORCHANGE, sageWarn, sageUrgent);
double pbageUrgent = nsSettings.getExtendedWarnValue("pgage", "urgent", 360); double pbageUrgent = nsSettings.getExtendedWarnValue("pgage", "urgent", 360);
double pbageWarn = nsSettings.getExtendedWarnValue("pgage", "warn", 240); double pbageWarn = nsSettings.getExtendedWarnValue("pgage", "warn", 240);
handleAge(pbage, CareportalEvent.PUMPBATTERYCHANGE, pbageWarn, pbageUrgent);
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 (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 (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 (careportalEvent != null) {
pbage.setTextColor(CareportalFragment.determineTextColor(careportalEvent, pbageWarn, pbageUrgent));
pbage.setText(careportalEvent.age());
} else {
pbage.setText(notavailable);
}
}
} }
); );
} }
@ -277,5 +247,21 @@ public class CareportalFragment extends SubscriberFragment implements View.OnCli
} }
} }
private static TextView handleAge(final TextView age, String eventType, double warnThreshold, double urgentThreshold) {
String notavailable = OverviewFragment.shorttextmode ? "-" : MainApp.gs(R.string.notavailable);
if (age != null) {
CareportalEvent careportalEvent = MainApp.getDbHelper().getLastCareportalEvent(eventType);
if (careportalEvent != null) {
age.setTextColor(CareportalFragment.determineTextColor(careportalEvent, warnThreshold, urgentThreshold));
age.setText(careportalEvent.age());
} else {
age.setText(notavailable);
}
}
return age;
}
} }

View file

@ -23,6 +23,9 @@ public class CareportalPlugin extends PluginBase {
.fragmentClass(CareportalFragment.class.getName()) .fragmentClass(CareportalFragment.class.getName())
.pluginName(R.string.careportal) .pluginName(R.string.careportal)
.shortName(R.string.careportal_shortname) .shortName(R.string.careportal_shortname)
.visibleByDefault(true)
.enableByDefault(true)
.description(R.string.description_careportal)
); );
} }

View file

@ -49,13 +49,15 @@ 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.plugins.Careportal.OptionsToShow; import info.nightscout.androidaps.plugins.Careportal.OptionsToShow;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.ConfigBuilder.ProfileFunctions;
import info.nightscout.androidaps.plugins.NSClientInternal.NSUpload;
import info.nightscout.androidaps.plugins.Treatments.TreatmentsPlugin; import info.nightscout.androidaps.plugins.Treatments.TreatmentsPlugin;
import info.nightscout.utils.DateUtil; import info.nightscout.utils.DateUtil;
import info.nightscout.utils.DefaultValueHelper; import info.nightscout.utils.DefaultValueHelper;
import info.nightscout.utils.FabricPrivacy; import info.nightscout.utils.FabricPrivacy;
import info.nightscout.utils.HardLimits; import info.nightscout.utils.HardLimits;
import info.nightscout.utils.JsonHelper; import info.nightscout.utils.JsonHelper;
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;
@ -171,8 +173,8 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick
view.findViewById(R.id.cancel).setOnClickListener(this); view.findViewById(R.id.cancel).setOnClickListener(this);
// profile // profile
profile = MainApp.getConfigBuilder().getProfile(); profile = ProfileFunctions.getInstance().getProfile();
profileStore = MainApp.getConfigBuilder().getActiveProfileInterface().getProfile(); profileStore = ConfigBuilderPlugin.getPlugin().getActiveProfileInterface().getProfile();
if (profileStore == null) { if (profileStore == null) {
if (options.eventType == R.id.careportal_profileswitch) { if (options.eventType == R.id.careportal_profileswitch) {
log.error("Profile switch called but plugin doesn't contain valid profile"); log.error("Profile switch called but plugin doesn't contain valid profile");
@ -186,7 +188,7 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick
profileSpinner.setAdapter(adapter); profileSpinner.setAdapter(adapter);
// set selected to actual profile // set selected to actual profile
for (int p = 0; p < profileList.size(); p++) { for (int p = 0; p < profileList.size(); p++) {
if (profileList.get(p).equals(MainApp.getConfigBuilder().getProfileName(false))) if (profileList.get(p).equals(ProfileFunctions.getInstance().getProfileName(false)))
profileSpinner.setSelection(p); profileSpinner.setSelection(p);
} }
} }
@ -206,12 +208,15 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
double defaultDuration; double defaultDuration;
double defaultTarget = 0; double defaultTarget = 0;
if (profile != null) { if (profile != null && editTemptarget.getValue() == bg) {
defaultTarget = bg; defaultTarget = bg;
} else {
//prevent changes on screen rotate
defaultTarget = editTemptarget.getValue();
} }
boolean erase = false; boolean erase = false;
String units = MainApp.getConfigBuilder().getProfileUnits(); String units = ProfileFunctions.getInstance().getProfileUnits();
DefaultValueHelper helper = new DefaultValueHelper(); DefaultValueHelper helper = new DefaultValueHelper();
if (MainApp.gs(R.string.eatingsoon).equals(reasonList.get(position))) { if (MainApp.gs(R.string.eatingsoon).equals(reasonList.get(position))) {
defaultDuration = helper.determineEatingSoonTTDuration(); defaultDuration = helper.determineEatingSoonTTDuration();
@ -222,6 +227,8 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick
} else if (MainApp.gs(R.string.hypo).equals(reasonList.get(position))) { } else if (MainApp.gs(R.string.hypo).equals(reasonList.get(position))) {
defaultDuration = helper.determineHypoTTDuration(); defaultDuration = helper.determineHypoTTDuration();
defaultTarget = helper.determineHypoTT(units); defaultTarget = helper.determineHypoTT(units);
} else if (editDuration.getValue() != 0) {
defaultDuration = editDuration.getValue();
} else { } else {
defaultDuration = 0; defaultDuration = 0;
erase = true; erase = true;
@ -258,22 +265,26 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick
if (sensorRadioButton.isChecked()) meterRadioButton.setChecked(true); if (sensorRadioButton.isChecked()) meterRadioButton.setChecked(true);
} }
}; };
editBg = (NumberPicker) view.findViewById(R.id.careportal_newnstreatment_bginput); editBg = (NumberPicker) view.findViewById(R.id.careportal_newnstreatment_bginput);
editTemptarget = (NumberPicker) view.findViewById(R.id.careportal_newnstreatment_temptarget); editTemptarget = (NumberPicker) view.findViewById(R.id.careportal_newnstreatment_temptarget);
if (profile == null) { if (profile == null) {
editBg.setParams(bg, 0d, 500d, 0.1d, new DecimalFormat("0.0"), false, bgTextWatcher); editBg.setParams(bg, 0d, 500d, 0.1d, new DecimalFormat("0.0"), false, bgTextWatcher);
editTemptarget.setParams(bg, 0d, 500d, 0.1d, new DecimalFormat("0.0"), false); editTemptarget.setParams(bg, 0d, 500d, 0.1d, new DecimalFormat("0.0"), false);
} else if (profile.getUnits().equals(Constants.MMOL)) { } else if (units.equals(Constants.MMOL)) {
editBg.setParams(bg, 0d, 30d, 0.1d, new DecimalFormat("0.0"), false, bgTextWatcher); editBg.setParams(bg, 0d, 30d, 0.1d, new DecimalFormat("0.0"), false, bgTextWatcher);
editTemptarget.setParams(bg, 0d, 30d, 0.1d, new DecimalFormat("0.0"), false); editTemptarget.setParams(bg, 0d, 30d, 0.1d, new DecimalFormat("0.0"), false);
} else { } else {
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((buttonView, isChecked) -> { sensorRadioButton.setOnCheckedChangeListener((buttonView, isChecked) -> {
Double bg1 = Profile.fromMgdlToUnits(GlucoseStatus.getGlucoseStatusData() != null ? GlucoseStatus.getGlucoseStatusData().glucose : 0d, profile.getUnits()); Double bg1 = Profile.fromMgdlToUnits(GlucoseStatus.getGlucoseStatusData() != null ? GlucoseStatus.getGlucoseStatusData().glucose : 0d, units);
if (savedInstanceState != null && savedInstanceState.getDouble("editBg") != bg1) {
editBg.setValue(savedInstanceState.getDouble("editBg"));
} else {
editBg.setValue(bg1); editBg.setValue(bg1);
}
}); });
Integer maxCarbs = MainApp.getConstraintChecker().getMaxCarbsAllowed().value(); Integer maxCarbs = MainApp.getConstraintChecker().getMaxCarbsAllowed().value();
@ -311,7 +322,7 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick
if (profile != null) if (profile != null)
maxPercent = MainApp.getConstraintChecker().getMaxBasalPercentAllowed(profile).value(); 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, -100d, (double) maxPercent, 5d, new DecimalFormat("0"), true, percentTextWatcher);
TextWatcher absoluteTextWatcher = new TextWatcher() { TextWatcher absoluteTextWatcher = new TextWatcher() {
@Override @Override
@ -378,6 +389,25 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick
setCancelable(true); setCancelable(true);
getDialog().setCanceledOnTouchOutside(false); getDialog().setCanceledOnTouchOutside(false);
//recovering state if there is something
// only numberPickers and editTexts
if (savedInstanceState != null) {
editBg.setValue(savedInstanceState.getDouble("editBg"));
editTemptarget.setValue(savedInstanceState.getDouble("editTemptarget"));
notesEdit.setText(savedInstanceState.getString("notesEdit"));
editCarbs.setValue(savedInstanceState.getDouble("editCarbs"));
editCarbs.setValue(savedInstanceState.getDouble("editCarbs"));
editInsulin.setValue(savedInstanceState.getDouble("editInsulin"));
editDuration.setValue(savedInstanceState.getDouble("editDuration"));
editPercent.setValue(savedInstanceState.getDouble("editPercent"));
editAbsolute.setValue(savedInstanceState.getDouble("editAbsolute"));
editCarbTime.setValue(savedInstanceState.getDouble("editCarbTime"));
editPercentage.setValue(savedInstanceState.getDouble("editPercentage"));
editTimeshift.setValue(savedInstanceState.getDouble("editTimeshift"));
// time and date
dateButton.setText(savedInstanceState.getString("dateButton"));
timeButton.setText(savedInstanceState.getString("timeButton"));
}
return view; return view;
} }
@ -429,7 +459,7 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick
if ((data.size() > 0) && if ((data.size() > 0) &&
(data.get(0).date > millis - 7 * 60 * 1000L) && (data.get(0).date > millis - 7 * 60 * 1000L) &&
(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)); editBg.setValue(Profile.fromMgdlToUnits(data.get(0).value, units));
} }
} }
@ -706,8 +736,8 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick
.reason(reason) .reason(reason)
.source(Source.USER); .source(Source.USER);
if (tempTarget.durationInMinutes != 0) { if (tempTarget.durationInMinutes != 0) {
tempTarget.low(Profile.toMgdl(targetBottom, profile.getUnits())) tempTarget.low(Profile.toMgdl(targetBottom, units))
.high(Profile.toMgdl(targetTop, profile.getUnits())); .high(Profile.toMgdl(targetTop, units));
} else { } else {
tempTarget.low(0).high(0); tempTarget.low(0).high(0);
} }
@ -738,7 +768,7 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick
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 = MainApp.getConfigBuilder().getActiveProfileInterface().getClass().getName(); profileSwitch.profilePlugin = ConfigBuilderPlugin.getPlugin().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;
@ -758,9 +788,9 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick
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 = ProfileFunctions.getInstance().getProfileName(System.currentTimeMillis(), false);
profileSwitch.profileJson = MainApp.getConfigBuilder().getProfile().getData().toString(); profileSwitch.profileJson = ProfileFunctions.getInstance().getProfile().getData().toString();
profileSwitch.profilePlugin = MainApp.getConfigBuilder().getActiveProfileInterface().getClass().getName(); profileSwitch.profilePlugin = ConfigBuilderPlugin.getPlugin().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;
@ -772,4 +802,22 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick
} }
} }
@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
savedInstanceState.putString("notesEdit", notesEdit.getText().toString());
savedInstanceState.putString("dateButton", dateButton.getText().toString());
savedInstanceState.putString("timeButton", timeButton.getText().toString());
savedInstanceState.putDouble("editBg", editBg.getValue());
savedInstanceState.putDouble("editCarbs", editCarbs.getValue());
savedInstanceState.putDouble("editInsulin", editInsulin.getValue());
savedInstanceState.putDouble("editDuration", editDuration.getValue());
savedInstanceState.putDouble("editPercent", editPercent.getValue());
savedInstanceState.putDouble("editAbsolute", editAbsolute.getValue());
savedInstanceState.putDouble("editCarbTime", editCarbTime.getValue());
savedInstanceState.putDouble("editTemptarget", editTemptarget.getValue());
savedInstanceState.putDouble("editPercentage", editPercentage.getValue());
savedInstanceState.putDouble("editTimeshift", editTimeshift.getValue());
super.onSaveInstanceState(savedInstanceState);
}
} }

View file

@ -21,7 +21,7 @@ abstract public class SubscriberFragment extends Fragment {
updateGUI(); updateGUI();
} }
@Override public void onDestroyView() { @Override public synchronized void onDestroyView() {
super.onDestroyView(); super.onDestroyView();
if (unbinder != null) if (unbinder != null)
unbinder.unbind(); unbinder.unbind();

View file

@ -1,32 +1,32 @@
package info.nightscout.androidaps.plugins.ConfigBuilder; package info.nightscout.androidaps.plugins.ConfigBuilder;
import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.StringRes;
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.ArrayAdapter;
import android.widget.Button; import android.widget.Button;
import android.widget.CheckBox; import android.widget.CheckBox;
import android.widget.ImageView; import android.widget.ImageButton;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.ListAdapter; import android.widget.RadioButton;
import android.widget.ListView; import android.widget.ScrollView;
import android.widget.TextView; import android.widget.TextView;
import com.crashlytics.android.answers.CustomEvent; import com.crashlytics.android.answers.CustomEvent;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List;
import butterknife.BindView; import butterknife.BindView;
import butterknife.ButterKnife; import butterknife.ButterKnife;
import butterknife.OnClick; import butterknife.OnClick;
import info.nightscout.androidaps.Config; import butterknife.Unbinder;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.PreferencesActivity; import info.nightscout.androidaps.activities.PreferencesActivity;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
import info.nightscout.androidaps.events.EventConfigBuilderChange; import info.nightscout.androidaps.events.EventConfigBuilderChange;
import info.nightscout.androidaps.events.EventRefreshGui; import info.nightscout.androidaps.events.EventRefreshGui;
@ -43,76 +43,36 @@ import info.nightscout.androidaps.plugins.Common.SubscriberFragment;
import info.nightscout.androidaps.plugins.Insulin.InsulinOrefRapidActingPlugin; 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.Sensitivity.SensitivityOref0Plugin;
import info.nightscout.utils.FabricPrivacy; import info.nightscout.utils.FabricPrivacy;
import info.nightscout.utils.PasswordProtection; import info.nightscout.utils.PasswordProtection;
public class ConfigBuilderFragment extends SubscriberFragment { public class ConfigBuilderFragment extends SubscriberFragment {
@BindView(R.id.configbuilder_insulinlistview) private List<PluginViewHolder> pluginViewHolders = new ArrayList<>();
ListView insulinListView;
@BindView(R.id.configbuilder_sensitivitylistview)
ListView sensitivityListView;
@BindView(R.id.configbuilder_bgsourcelistview)
ListView bgsourceListView;
@BindView(R.id.configbuilder_bgsourcelabel)
TextView bgsourceLabel;
@BindView(R.id.configbuilder_pumplistview)
ListView pumpListView;
@BindView(R.id.configbuilder_pumplabel)
TextView pumpLabel;
@BindView(R.id.configbuilder_looplistview)
ListView loopListView;
@BindView(R.id.configbuilder_looplabel)
TextView loopLabel;
@BindView(R.id.configbuilder_treatmentslistview)
ListView treatmentsListView;
@BindView(R.id.configbuilder_treatmentslabel)
TextView treatmentsLabel;
@BindView(R.id.configbuilder_profilelistview)
ListView profileListView;
@BindView(R.id.configbuilder_profilelabel)
TextView profileLabel;
@BindView(R.id.configbuilder_apslistview)
ListView apsListView;
@BindView(R.id.configbuilder_apslabel)
TextView apsLabel;
@BindView(R.id.configbuilder_constraintslistview)
ListView constraintsListView;
@BindView(R.id.configbuilder_constraintslabel)
TextView constraintsLabel;
@BindView(R.id.configbuilder_generallistview)
ListView generalListView;
@BindView(R.id.configbuilder_mainlayout) @BindView(R.id.categories)
LinearLayout mainLayout; LinearLayout categories;
@BindView(R.id.configbuilder_unlock)
@BindView(R.id.main_layout)
ScrollView mainLayout;
@BindView(R.id.unlock)
Button unlock; Button unlock;
PluginCustomAdapter insulinDataAdapter = null;
PluginCustomAdapter sensivityDataAdapter = null;
PluginCustomAdapter bgsourceDataAdapter = null;
PluginCustomAdapter pumpDataAdapter = null;
PluginCustomAdapter loopDataAdapter = null;
PluginCustomAdapter treatmentDataAdapter = null;
PluginCustomAdapter profileDataAdapter = null;
PluginCustomAdapter apsDataAdapter = null;
PluginCustomAdapter constraintsDataAdapter = null;
PluginCustomAdapter generalDataAdapter = null;
@Override @Override
public View onCreateView(@NonNull 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);
unbinder = ButterKnife.bind(this, view); unbinder = ButterKnife.bind(this, view);
if (PasswordProtection.isLocked("settings_password")) if (PasswordProtection.isLocked("settings_password"))
mainLayout.setVisibility(View.GONE); mainLayout.setVisibility(View.GONE);
else else unlock.setVisibility(View.GONE);
unlock.setVisibility(View.GONE);
createViews();
return view; return view;
} catch (Exception e) { } catch (Exception e) {
FabricPrivacy.logException(e); FabricPrivacy.logException(e);
@ -121,222 +81,55 @@ public class ConfigBuilderFragment extends SubscriberFragment {
return null; return null;
} }
@OnClick(R.id.configbuilder_unlock) @OnClick(R.id.unlock)
public void onClickUnlock() { void onClickUnlock() {
PasswordProtection.QueryPassword(getContext(), R.string.settings_password, "settings_password", () -> { PasswordProtection.QueryPassword(getContext(), R.string.settings_password, "settings_password", () -> {
mainLayout.setVisibility(View.VISIBLE); mainLayout.setVisibility(View.VISIBLE);
unlock.setVisibility(View.GONE); unlock.setVisibility(View.GONE);
}, null); }, null);
} }
@Override
public void onDestroyView() {
super.onDestroyView();
for (PluginViewHolder pluginViewHolder : pluginViewHolders) pluginViewHolder.unbind();
pluginViewHolders.clear();
}
@Override @Override
protected void updateGUI() { protected void updateGUI() {
for (PluginViewHolder pluginViewHolder : pluginViewHolders) pluginViewHolder.update();
insulinDataAdapter = new PluginCustomAdapter(getContext(), R.layout.configbuilder_simpleitem, MainApp.getSpecificPluginsVisibleInListByInterface(InsulinInterface.class, PluginType.INSULIN), PluginType.INSULIN);
insulinListView.setAdapter(insulinDataAdapter);
setListViewHeightBasedOnChildren(insulinListView);
bgsourceDataAdapter = new PluginCustomAdapter(getContext(), R.layout.configbuilder_simpleitem, MainApp.getSpecificPluginsVisibleInListByInterface(BgSourceInterface.class, PluginType.BGSOURCE), PluginType.BGSOURCE);
bgsourceListView.setAdapter(bgsourceDataAdapter);
if (MainApp.getSpecificPluginsVisibleInList(PluginType.BGSOURCE).size() == 0)
bgsourceLabel.setVisibility(View.GONE);
setListViewHeightBasedOnChildren(bgsourceListView);
pumpDataAdapter = new PluginCustomAdapter(getContext(), R.layout.configbuilder_simpleitem, MainApp.getSpecificPluginsVisibleInList(PluginType.PUMP), PluginType.PUMP);
pumpListView.setAdapter(pumpDataAdapter);
if (MainApp.getSpecificPluginsVisibleInList(PluginType.PUMP).size() == 0 || Config.NSCLIENT || Config.G5UPLOADER) {
pumpLabel.setVisibility(View.GONE);
pumpListView.setVisibility(View.GONE);
}
setListViewHeightBasedOnChildren(pumpListView);
loopDataAdapter = new PluginCustomAdapter(getContext(), R.layout.configbuilder_simpleitem, MainApp.getSpecificPluginsVisibleInList(PluginType.LOOP), PluginType.LOOP);
loopListView.setAdapter(loopDataAdapter);
setListViewHeightBasedOnChildren(loopListView);
if (MainApp.getSpecificPluginsVisibleInList(PluginType.LOOP).size() == 0)
loopLabel.setVisibility(View.GONE);
treatmentDataAdapter = new PluginCustomAdapter(getContext(), R.layout.configbuilder_simpleitem, MainApp.getSpecificPluginsVisibleInList(PluginType.TREATMENT), PluginType.TREATMENT);
treatmentsListView.setAdapter(treatmentDataAdapter);
setListViewHeightBasedOnChildren(treatmentsListView);
if (MainApp.getSpecificPluginsVisibleInList(PluginType.TREATMENT).size() == 0)
treatmentsLabel.setVisibility(View.GONE);
profileDataAdapter = new PluginCustomAdapter(getContext(), R.layout.configbuilder_simpleitem, MainApp.getSpecificPluginsVisibleInListByInterface(ProfileInterface.class, PluginType.PROFILE), PluginType.PROFILE);
profileListView.setAdapter(profileDataAdapter);
if (MainApp.getSpecificPluginsVisibleInList(PluginType.PROFILE).size() == 0)
profileLabel.setVisibility(View.GONE);
setListViewHeightBasedOnChildren(profileListView);
apsDataAdapter = new PluginCustomAdapter(getContext(), R.layout.configbuilder_simpleitem, MainApp.getSpecificPluginsVisibleInList(PluginType.APS), PluginType.APS);
apsListView.setAdapter(apsDataAdapter);
setListViewHeightBasedOnChildren(apsListView);
if (MainApp.getSpecificPluginsVisibleInList(PluginType.APS).size() == 0)
apsLabel.setVisibility(View.GONE);
sensivityDataAdapter = new PluginCustomAdapter(getContext(), R.layout.configbuilder_simpleitem, MainApp.getSpecificPluginsVisibleInListByInterface(SensitivityInterface.class, PluginType.SENSITIVITY), PluginType.SENSITIVITY);
sensitivityListView.setAdapter(sensivityDataAdapter);
setListViewHeightBasedOnChildren(sensitivityListView);
constraintsDataAdapter = new PluginCustomAdapter(getContext(), R.layout.configbuilder_simpleitem, MainApp.getSpecificPluginsVisibleInListByInterface(ConstraintsInterface.class, PluginType.CONSTRAINTS), PluginType.CONSTRAINTS);
constraintsListView.setAdapter(constraintsDataAdapter);
setListViewHeightBasedOnChildren(constraintsListView);
if (MainApp.getSpecificPluginsVisibleInList(PluginType.CONSTRAINTS).size() == 0)
constraintsLabel.setVisibility(View.GONE);
generalDataAdapter = new PluginCustomAdapter(getContext(), R.layout.configbuilder_simpleitem, MainApp.getSpecificPluginsVisibleInList(PluginType.GENERAL), PluginType.GENERAL);
generalListView.setAdapter(generalDataAdapter);
setListViewHeightBasedOnChildren(generalListView);
} }
/* private void createViews() {
* ConfigBuilderFragment code createViewsForPlugins(R.string.configbuilder_profile, R.string.configbuilder_profile_description, PluginType.PROFILE, MainApp.getSpecificPluginsVisibleInListByInterface(ProfileInterface.class, PluginType.PROFILE));
*/ createViewsForPlugins(R.string.configbuilder_insulin, R.string.configbuilder_insulin_description, PluginType.INSULIN, MainApp.getSpecificPluginsVisibleInListByInterface(InsulinInterface.class, PluginType.INSULIN));
createViewsForPlugins(R.string.configbuilder_bgsource, R.string.configbuilder_bgsource_description, PluginType.BGSOURCE, MainApp.getSpecificPluginsVisibleInListByInterface(BgSourceInterface.class, PluginType.BGSOURCE));
private class PluginCustomAdapter extends ArrayAdapter<PluginBase> { createViewsForPlugins(R.string.configbuilder_pump, R.string.configbuilder_pump_description, PluginType.PUMP, MainApp.getSpecificPluginsVisibleInList(PluginType.PUMP));
createViewsForPlugins(R.string.configbuilder_sensitivity, R.string.configbuilder_sensitivity_description, PluginType.SENSITIVITY, MainApp.getSpecificPluginsVisibleInListByInterface(SensitivityInterface.class, PluginType.SENSITIVITY));
private ArrayList<PluginBase> pluginList; createViewsForPlugins(R.string.configbuilder_aps, R.string.configbuilder_aps_description, PluginType.APS, MainApp.getSpecificPluginsVisibleInList(PluginType.APS));
final private PluginType type; createViewsForPlugins(R.string.configbuilder_loop, R.string.configbuilder_loop_description, PluginType.LOOP, MainApp.getSpecificPluginsVisibleInList(PluginType.LOOP));
createViewsForPlugins(R.string.constraints, R.string.configbuilder_constraints_description, PluginType.CONSTRAINTS, MainApp.getSpecificPluginsVisibleInListByInterface(ConstraintsInterface.class, PluginType.CONSTRAINTS));
PluginCustomAdapter(Context context, int textViewResourceId, createViewsForPlugins(R.string.configbuilder_treatments, R.string.configbuilder_treatments_description, PluginType.TREATMENT, MainApp.getSpecificPluginsVisibleInList(PluginType.TREATMENT));
ArrayList<PluginBase> pluginList, PluginType type) { createViewsForPlugins(R.string.configbuilder_general, R.string.configbuilder_general_description, PluginType.GENERAL, MainApp.getSpecificPluginsVisibleInList(PluginType.GENERAL));
super(context, textViewResourceId, pluginList);
this.pluginList = new ArrayList<>();
this.pluginList.addAll(pluginList);
this.type = type;
} }
private class PluginViewHolder { private void createViewsForPlugins(@StringRes int title, @StringRes int description, PluginType pluginType, List<PluginBase> plugins) {
TextView name; if (plugins.size() == 0) return;
CheckBox checkboxEnabled; LinearLayout parent = (LinearLayout) getLayoutInflater().inflate(R.layout.configbuilder_single_category, null);
CheckBox checkboxVisible; ((TextView) parent.findViewById(R.id.category_title)).setText(MainApp.gs(title));
ImageView settings; ((TextView) parent.findViewById(R.id.category_description)).setText(MainApp.gs(description));
} LinearLayout pluginContainer = parent.findViewById(R.id.category_plugins);
for (PluginBase plugin: plugins) {
@NonNull PluginViewHolder pluginViewHolder = new PluginViewHolder(pluginType, plugin);
@Override pluginContainer.addView(pluginViewHolder.getBaseView());
public View getView(int position, View view, @NonNull ViewGroup parent) { pluginViewHolders.add(pluginViewHolder);
}
PluginViewHolder holder; categories.addView(parent);
PluginBase plugin = pluginList.get(position);
if (view == null) {
view = LayoutInflater.from(parent.getContext()).inflate(R.layout.configbuilder_simpleitem, null);
holder = new PluginViewHolder();
holder.name = (TextView) view.findViewById(R.id.configbuilder_simpleitem_name);
holder.checkboxEnabled = (CheckBox) view.findViewById(R.id.configbuilder_simpleitem_checkboxenabled);
holder.checkboxVisible = (CheckBox) view.findViewById(R.id.configbuilder_simpleitem_checkboxvisible);
holder.settings = (ImageView) view.findViewById(R.id.configbuilder_simpleitem_settings);
if (plugin.isEnabled(type) && plugin.getPreferencesId() != -1)
holder.settings.setVisibility(View.VISIBLE);
else
holder.settings.setVisibility(View.INVISIBLE);
view.setTag(holder);
holder.checkboxEnabled.setOnClickListener(v -> {
CheckBox cb = (CheckBox) v;
PluginBase plugin1 = (PluginBase) cb.getTag();
plugin1.setPluginEnabled(type, cb.isChecked());
plugin1.setFragmentVisible(type, cb.isChecked());
onEnabledCategoryChanged(plugin1, type);
ConfigBuilderPlugin.getPlugin().storeSettings("CheckedCheckboxEnabled");
MainApp.bus().post(new EventRefreshGui());
MainApp.bus().post(new EventConfigBuilderChange());
ConfigBuilderPlugin.getPlugin().logPluginStatus();
FabricPrivacy.getInstance().logCustom(new CustomEvent("ConfigurationChange"));
});
holder.checkboxVisible.setOnClickListener(v -> {
CheckBox cb = (CheckBox) v;
PluginBase plugin12 = (PluginBase) cb.getTag();
plugin12.setFragmentVisible(type, cb.isChecked());
ConfigBuilderPlugin.getPlugin().storeSettings("CheckedCheckboxVisible");
MainApp.bus().post(new EventRefreshGui());
ConfigBuilderPlugin.getPlugin().logPluginStatus();
});
holder.settings.setOnClickListener(v -> {
final PluginBase plugin13 = (PluginBase) v.getTag();
PasswordProtection.QueryPassword(getContext(), R.string.settings_password, "settings_password", () -> {
Intent i = new Intent(getContext(), PreferencesActivity.class);
i.putExtra("id", plugin13.getPreferencesId());
startActivity(i);
}, null);
});
holder.name.setOnLongClickListener(v -> {
final PluginBase plugin14 = (PluginBase) v.getTag();
PasswordProtection.QueryPassword(getContext(), R.string.settings_password, "settings_password", () -> {
Intent i = new Intent(getContext(), PreferencesActivity.class);
i.putExtra("id", plugin14.getPreferencesId());
startActivity(i);
}, null);
return false;
});
} else {
holder = (PluginViewHolder) view.getTag();
}
holder.name.setText(plugin.getName());
holder.checkboxEnabled.setChecked(plugin.isEnabled(type));
holder.checkboxVisible.setChecked(plugin.isFragmentVisible());
holder.name.setTag(plugin);
holder.checkboxEnabled.setTag(plugin);
holder.checkboxVisible.setTag(plugin);
holder.settings.setTag(plugin);
if (plugin.pluginDescription.alwaysEnabled) {
holder.checkboxEnabled.setEnabled(false);
}
if (plugin.pluginDescription.alwayVisible) {
holder.checkboxEnabled.setEnabled(false);
}
if (!plugin.isEnabled(type)) {
holder.checkboxVisible.setEnabled(false);
}
if (!plugin.hasFragment()) {
holder.checkboxVisible.setVisibility(View.INVISIBLE);
}
// Hide enabled control and force enabled plugin if there is only one plugin available
if (type == PluginType.INSULIN || type == PluginType.PUMP || type == PluginType.SENSITIVITY)
if (pluginList.size() < 2) {
holder.checkboxEnabled.setEnabled(false);
plugin.setPluginEnabled(type, true);
ConfigBuilderPlugin.getPlugin().storeSettings("ForceEnable");
}
// Constraints cannot be disabled
if (type == PluginType.CONSTRAINTS)
holder.checkboxEnabled.setEnabled(false);
// Hide disabled profiles by default
if (type == PluginType.PROFILE) {
if (!plugin.isEnabled(type)) {
holder.checkboxVisible.setEnabled(false);
holder.checkboxVisible.setChecked(false);
} else {
holder.checkboxVisible.setEnabled(true);
}
}
// Disable profile control for pump profiles if pump is not enabled
if (type == PluginType.PROFILE) {
if (PumpInterface.class.isAssignableFrom(plugin.getClass())) {
if (!plugin.isEnabled(PluginType.PUMP)) {
holder.checkboxEnabled.setEnabled(false);
holder.checkboxEnabled.setChecked(false);
}
}
}
if (plugin.isEnabled(type)) {
view.setBackgroundColor(MainApp.gc(R.color.configBuilderSelectedBackground));
}
return view;
} }
private boolean areMultipleSelectionsAllowed(PluginType type) {
return type == PluginType.GENERAL || type == PluginType.CONSTRAINTS ||type == PluginType.LOOP;
} }
public static void processOnEnabledCategoryChanged(PluginBase changedPlugin, PluginType type) { public static void processOnEnabledCategoryChanged(PluginBase changedPlugin, PluginType type) {
@ -394,35 +187,100 @@ public class ConfigBuilderFragment extends SubscriberFragment {
} }
} }
void onEnabledCategoryChanged(PluginBase changedPlugin, PluginType type) { public class PluginViewHolder {
processOnEnabledCategoryChanged(changedPlugin, type);
private Unbinder unbinder;
private PluginType pluginType;
private PluginBase plugin;
LinearLayout baseView;
@BindView(R.id.plugin_enabled_exclusive)
RadioButton enabledExclusive;
@BindView(R.id.plugin_enabled_inclusive)
CheckBox enabledInclusive;
@BindView(R.id.plugin_name)
TextView pluginName;
@BindView(R.id.plugin_description)
TextView pluginDescription;
@BindView(R.id.plugin_preferences)
ImageButton pluginPreferences;
@BindView(R.id.plugin_visibility)
CheckBox pluginVisibility;
public PluginViewHolder(PluginType pluginType, PluginBase plugin) {
this.pluginType = pluginType;
this.plugin = plugin;
baseView = (LinearLayout) getLayoutInflater().inflate(R.layout.configbuilder_single_plugin, null);
unbinder = ButterKnife.bind(this, baseView);
update();
}
public LinearLayout getBaseView() {
return baseView;
}
public void update() {
enabledExclusive.setVisibility(areMultipleSelectionsAllowed(pluginType) ? View.GONE : View.VISIBLE);
enabledInclusive.setVisibility(areMultipleSelectionsAllowed(pluginType) ? View.VISIBLE : View.GONE);
enabledExclusive.setChecked(plugin.isEnabled(pluginType));
enabledInclusive.setChecked(plugin.isEnabled(pluginType));
enabledInclusive.setEnabled(!plugin.pluginDescription.alwaysEnabled);
enabledExclusive.setEnabled(!plugin.pluginDescription.alwaysEnabled);
pluginName.setText(plugin.getName());
if (plugin.getDescription() == null) pluginDescription.setVisibility(View.GONE);
else {
pluginDescription.setVisibility(View.VISIBLE);
pluginDescription.setText(plugin.getDescription());
}
pluginPreferences.setVisibility(plugin.getPreferencesId() == -1 || !plugin.isEnabled(pluginType) ? View.INVISIBLE : View.VISIBLE);
pluginVisibility.setVisibility(plugin.hasFragment() ? View.VISIBLE : View.INVISIBLE);
pluginVisibility.setEnabled(!(plugin.pluginDescription.neverVisible || plugin.pluginDescription.alwayVisible) && plugin.isEnabled(pluginType));
pluginVisibility.setChecked(plugin.isFragmentVisible());
}
@OnClick(R.id.plugin_visibility)
void onVisibilityChanged() {
plugin.setFragmentVisible(pluginType, pluginVisibility.isChecked());
ConfigBuilderPlugin.getPlugin().storeSettings("CheckedCheckboxVisible");
MainApp.bus().post(new EventRefreshGui());
ConfigBuilderPlugin.getPlugin().logPluginStatus();
}
@OnClick({R.id.plugin_enabled_exclusive, R.id.plugin_enabled_inclusive})
void onEnabledChanged() {
plugin.switchAllowed(new PluginSwitcher(), getActivity());
}
@OnClick(R.id.plugin_preferences)
void onPluginPreferencesClicked() {
PasswordProtection.QueryPassword(getContext(), R.string.settings_password, "settings_password", () -> {
Intent i = new Intent(getContext(), PreferencesActivity.class);
i.putExtra("id", plugin.getPreferencesId());
startActivity(i);
}, null);
}
public void unbind() {
unbinder.unbind();
}
public class PluginSwitcher {
public void invoke() {
boolean enabled = enabledExclusive.getVisibility() == View.VISIBLE ? enabledExclusive.isChecked() : enabledInclusive.isChecked();
plugin.setPluginEnabled(pluginType, enabled);
plugin.setFragmentVisible(pluginType, enabled);
processOnEnabledCategoryChanged(plugin, pluginType);
updateGUI();
ConfigBuilderPlugin.getPlugin().storeSettings("CheckedCheckboxEnabled");
MainApp.bus().post(new EventRefreshGui());
MainApp.bus().post(new EventConfigBuilderChange());
ConfigBuilderPlugin.getPlugin().logPluginStatus();
FabricPrivacy.getInstance().logCustom(new CustomEvent("ConfigurationChange"));
}
public void cancel(){
updateGUI(); updateGUI();
} }
/****
* Method for Setting the Height of the ListView dynamically.
* *** Hack to fix the issue of not showing all the items of the ListView
* *** when placed inside a ScrollView
****/
public static void setListViewHeightBasedOnChildren(ListView listView) {
ListAdapter listAdapter = listView.getAdapter();
if (listAdapter == null)
return;
int desiredWidth = View.MeasureSpec.makeMeasureSpec(listView.getWidth(), View.MeasureSpec.UNSPECIFIED);
int totalHeight = 0;
View view = null;
for (int i = 0; i < listAdapter.getCount(); i++) {
view = listAdapter.getView(i, view, listView);
if (i == 0)
view.setLayoutParams(new ViewGroup.LayoutParams(desiredWidth, ViewGroup.LayoutParams.WRAP_CONTENT));
view.measure(desiredWidth, View.MeasureSpec.UNSPECIFIED);
totalHeight += view.getMeasuredHeight();
} }
ViewGroup.LayoutParams params = listView.getLayoutParams();
params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1));
listView.setLayoutParams(params);
} }
} }

View file

@ -1,35 +1,17 @@
package info.nightscout.androidaps.plugins.ConfigBuilder; package info.nightscout.androidaps.plugins.ConfigBuilder;
import android.content.Intent;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import com.crashlytics.android.answers.CustomEvent;
import com.squareup.otto.Subscribe;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.util.ArrayList; import java.util.ArrayList;
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.DetailedBolusInfo;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.data.ProfileStore;
import info.nightscout.androidaps.data.PumpEnactResult;
import info.nightscout.androidaps.db.CareportalEvent;
import info.nightscout.androidaps.db.ProfileSwitch;
import info.nightscout.androidaps.db.Source;
import info.nightscout.androidaps.db.TemporaryBasal;
import info.nightscout.androidaps.events.EventAppInitialized; import info.nightscout.androidaps.events.EventAppInitialized;
import info.nightscout.androidaps.events.EventNewBasalProfile;
import info.nightscout.androidaps.events.EventProfileSwitchChange;
import info.nightscout.androidaps.interfaces.APSInterface; import info.nightscout.androidaps.interfaces.APSInterface;
import info.nightscout.androidaps.interfaces.BgSourceInterface; import info.nightscout.androidaps.interfaces.BgSourceInterface;
import info.nightscout.androidaps.interfaces.Constraint;
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.PluginDescription; import info.nightscout.androidaps.interfaces.PluginDescription;
@ -37,25 +19,18 @@ 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.interfaces.TreatmentsInterface; import info.nightscout.androidaps.logging.L;
import info.nightscout.androidaps.plugins.Insulin.InsulinOrefRapidActingPlugin; import info.nightscout.androidaps.plugins.Insulin.InsulinOrefRapidActingPlugin;
import info.nightscout.androidaps.plugins.Loop.APSResult;
import info.nightscout.androidaps.plugins.Loop.LoopPlugin;
import info.nightscout.androidaps.plugins.Overview.Dialogs.ErrorHelperActivity;
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.Sensitivity.SensitivityOref0Plugin;
import info.nightscout.androidaps.queue.Callback;
import info.nightscout.androidaps.queue.CommandQueue; import info.nightscout.androidaps.queue.CommandQueue;
import info.nightscout.utils.FabricPrivacy;
import info.nightscout.utils.NSUpload;
import info.nightscout.utils.SP; import info.nightscout.utils.SP;
import info.nightscout.utils.ToastUtils;
/** /**
* Created by mike on 05.08.2016. * Created by mike on 05.08.2016.
*/ */
public class ConfigBuilderPlugin extends PluginBase { public class ConfigBuilderPlugin extends PluginBase {
private static Logger log = LoggerFactory.getLogger(ConfigBuilderPlugin.class); private Logger log = LoggerFactory.getLogger(L.CONFIGBUILDER);
private static ConfigBuilderPlugin configBuilderPlugin; private static ConfigBuilderPlugin configBuilderPlugin;
@ -66,32 +41,26 @@ public class ConfigBuilderPlugin extends PluginBase {
} }
private BgSourceInterface activeBgSource; private BgSourceInterface activeBgSource;
private static PumpInterface activePump; private PumpInterface activePump;
private static ProfileInterface activeProfile; private ProfileInterface activeProfile;
private static TreatmentsInterface activeTreatments; private APSInterface activeAPS;
private static APSInterface activeAPS; private InsulinInterface activeInsulin;
private static LoopPlugin activeLoop; private SensitivityInterface activeSensitivity;
private static InsulinInterface activeInsulin;
private static SensitivityInterface activeSensitivity;
static public String nightscoutVersionName = ""; private ArrayList<PluginBase> pluginList;
static public Integer nightscoutVersionCode = 0;
static public String nsClientVersionName = "";
static public Integer nsClientVersionCode = 0;
private static ArrayList<PluginBase> pluginList; private CommandQueue commandQueue = new CommandQueue();
private static CommandQueue commandQueue = new CommandQueue();
public ConfigBuilderPlugin() { public ConfigBuilderPlugin() {
super(new PluginDescription() super(new PluginDescription()
.mainType(PluginType.GENERAL) .mainType(PluginType.GENERAL)
.fragmentClass(ConfigBuilderFragment.class.getName()) .fragmentClass(ConfigBuilderFragment.class.getName())
.showInList(false) .showInList(true)
.alwaysEnabled(true) .alwaysEnabled(true)
.alwayVisible(true) .alwayVisible(false)
.pluginName(R.string.configbuilder) .pluginName(R.string.configbuilder)
.shortName(R.string.configbuilder_shortname) .shortName(R.string.configbuilder_shortname)
.description(R.string.description_config_builder)
); );
} }
@ -112,14 +81,25 @@ public class ConfigBuilderPlugin extends PluginBase {
pluginList = MainApp.getPluginsList(); pluginList = MainApp.getPluginsList();
upgradeSettings(); upgradeSettings();
loadSettings(); loadSettings();
setAlwaysEnabledPluginsEnabled();
MainApp.bus().post(new EventAppInitialized()); MainApp.bus().post(new EventAppInitialized());
} }
private void setAlwaysEnabledPluginsEnabled() {
for (PluginBase plugin : pluginList) {
if (plugin.pluginDescription.alwaysEnabled)
plugin.setPluginEnabled(plugin.getType(), true);
}
storeSettings("setAlwaysEnabledPluginsEnabled");
}
public void storeSettings(String from) { public void storeSettings(String from) {
if (pluginList != null) { if (pluginList != null) {
if (Config.logPrefsChange) if (L.isEnabled(L.CONFIGBUILDER))
log.debug("Storing settings from: " + from); log.debug("Storing settings from: " + from);
verifySelectionInCategories();
for (PluginBase p : pluginList) { for (PluginBase p : pluginList) {
PluginType type = p.getType(); PluginType type = p.getType();
if (p.pluginDescription.alwaysEnabled && p.pluginDescription.alwayVisible) if (p.pluginDescription.alwaysEnabled && p.pluginDescription.alwayVisible)
@ -133,23 +113,24 @@ public class ConfigBuilderPlugin extends PluginBase {
} }
} }
} }
verifySelectionInCategories();
} }
} }
private void savePref(PluginBase p, PluginType type, boolean storeVisible) { private void savePref(PluginBase p, PluginType type, boolean storeVisible) {
String settingEnabled = "ConfigBuilder_" + type.name() + "_" + p.getClass().getSimpleName() + "_Enabled"; String settingEnabled = "ConfigBuilder_" + type.name() + "_" + p.getClass().getSimpleName() + "_Enabled";
SP.putBoolean(settingEnabled, p.isEnabled(type)); SP.putBoolean(settingEnabled, p.isEnabled(type));
if (L.isEnabled(L.CONFIGBUILDER))
log.debug("Storing: " + settingEnabled + ":" + p.isEnabled(type)); log.debug("Storing: " + settingEnabled + ":" + p.isEnabled(type));
if (storeVisible) { if (storeVisible) {
String settingVisible = "ConfigBuilder_" + type.name() + "_" + p.getClass().getSimpleName() + "_Visible"; String settingVisible = "ConfigBuilder_" + type.name() + "_" + p.getClass().getSimpleName() + "_Visible";
SP.putBoolean(settingVisible, p.isFragmentVisible()); SP.putBoolean(settingVisible, p.isFragmentVisible());
if (L.isEnabled(L.CONFIGBUILDER))
log.debug("Storing: " + settingVisible + ":" + p.isFragmentVisible()); log.debug("Storing: " + settingVisible + ":" + p.isFragmentVisible());
} }
} }
private void loadSettings() { private void loadSettings() {
if (Config.logPrefsChange) if (L.isEnabled(L.CONFIGBUILDER))
log.debug("Loading stored settings"); log.debug("Loading stored settings");
for (PluginBase p : pluginList) { for (PluginBase p : pluginList) {
PluginType type = p.getType(); PluginType type = p.getType();
@ -170,6 +151,7 @@ public class ConfigBuilderPlugin extends PluginBase {
else if (p.getType() == type && (p.pluginDescription.enableByDefault || p.pluginDescription.alwaysEnabled)) { else if (p.getType() == type && (p.pluginDescription.enableByDefault || p.pluginDescription.alwaysEnabled)) {
p.setPluginEnabled(type, true); p.setPluginEnabled(type, true);
} }
if (L.isEnabled(L.CONFIGBUILDER))
log.debug("Loaded: " + settingEnabled + ":" + p.isEnabled(type)); log.debug("Loaded: " + settingEnabled + ":" + p.isEnabled(type));
if (loadVisible) { if (loadVisible) {
String settingVisible = "ConfigBuilder_" + type.name() + "_" + p.getClass().getSimpleName() + "_Visible"; String settingVisible = "ConfigBuilder_" + type.name() + "_" + p.getClass().getSimpleName() + "_Visible";
@ -178,6 +160,7 @@ public class ConfigBuilderPlugin extends PluginBase {
else if (p.getType() == type && p.pluginDescription.visibleByDefault) { else if (p.getType() == type && p.pluginDescription.visibleByDefault) {
p.setFragmentVisible(type, true); p.setFragmentVisible(type, true);
} }
if (L.isEnabled(L.CONFIGBUILDER))
log.debug("Loaded: " + settingVisible + ":" + p.isFragmentVisible()); log.debug("Loaded: " + settingVisible + ":" + p.isFragmentVisible());
} }
} }
@ -186,9 +169,10 @@ public class ConfigBuilderPlugin extends PluginBase {
private void upgradeSettings() { private void upgradeSettings() {
if (!SP.contains("ConfigBuilder_1_NSProfilePlugin_Enabled")) if (!SP.contains("ConfigBuilder_1_NSProfilePlugin_Enabled"))
return; return;
if (Config.logPrefsChange) if (L.isEnabled(L.CONFIGBUILDER))
log.debug("Upgrading stored settings"); log.debug("Upgrading stored settings");
for (PluginBase p : pluginList) { for (PluginBase p : pluginList) {
if (L.isEnabled(L.CONFIGBUILDER))
log.debug("Processing " + p.getName()); log.debug("Processing " + p.getName());
for (int type = 1; type < 11; type++) { for (int type = 1; type < 11; type++) {
PluginType newType; PluginType newType;
@ -244,7 +228,7 @@ public class ConfigBuilderPlugin extends PluginBase {
} }
} }
public static CommandQueue getCommandQueue() { public CommandQueue getCommandQueue() {
return commandQueue; return commandQueue;
} }
@ -256,23 +240,24 @@ public class ConfigBuilderPlugin extends PluginBase {
return activeProfile; return activeProfile;
} }
public static InsulinInterface getActiveInsulin() { public InsulinInterface getActiveInsulin() {
return activeInsulin; return activeInsulin;
} }
public static APSInterface getActiveAPS() { public APSInterface getActiveAPS() {
return activeAPS; return activeAPS;
} }
public static PumpInterface getActivePump() { public PumpInterface getActivePump() {
return activePump; return activePump;
} }
public static SensitivityInterface getActiveSensitivity() { public SensitivityInterface getActiveSensitivity() {
return activeSensitivity; return activeSensitivity;
} }
void logPluginStatus() { void logPluginStatus() {
if (L.isEnabled(L.CONFIGBUILDER))
for (PluginBase p : pluginList) { for (PluginBase p : pluginList) {
log.debug(p.getName() + ":" + log.debug(p.getName() + ":" +
(p.isEnabled(PluginType.GENERAL) ? " GENERAL" : "") + (p.isEnabled(PluginType.GENERAL) ? " GENERAL" : "") +
@ -301,6 +286,8 @@ public class ConfigBuilderPlugin extends PluginBase {
if (activeInsulin == null) { if (activeInsulin == null) {
activeInsulin = InsulinOrefRapidActingPlugin.getPlugin(); activeInsulin = InsulinOrefRapidActingPlugin.getPlugin();
InsulinOrefRapidActingPlugin.getPlugin().setPluginEnabled(PluginType.INSULIN, true); InsulinOrefRapidActingPlugin.getPlugin().setPluginEnabled(PluginType.INSULIN, true);
if (L.isEnabled(L.CONFIGBUILDER))
log.debug("Defaulting InsulinOrefRapidActingPlugin");
} }
this.setFragmentVisiblities(((PluginBase) activeInsulin).getName(), pluginsInCategory, PluginType.INSULIN); this.setFragmentVisiblities(((PluginBase) activeInsulin).getName(), pluginsInCategory, PluginType.INSULIN);
@ -310,6 +297,8 @@ public class ConfigBuilderPlugin extends PluginBase {
if (activeSensitivity == null) { if (activeSensitivity == null) {
activeSensitivity = SensitivityOref0Plugin.getPlugin(); activeSensitivity = SensitivityOref0Plugin.getPlugin();
SensitivityOref0Plugin.getPlugin().setPluginEnabled(PluginType.SENSITIVITY, true); SensitivityOref0Plugin.getPlugin().setPluginEnabled(PluginType.SENSITIVITY, true);
if (L.isEnabled(L.CONFIGBUILDER))
log.debug("Defaulting SensitivityOref0Plugin");
} }
this.setFragmentVisiblities(((PluginBase) activeSensitivity).getName(), pluginsInCategory, PluginType.SENSITIVITY); this.setFragmentVisiblities(((PluginBase) activeSensitivity).getName(), pluginsInCategory, PluginType.SENSITIVITY);
@ -325,14 +314,12 @@ public class ConfigBuilderPlugin extends PluginBase {
if (activePump == null) { if (activePump == null) {
activePump = VirtualPumpPlugin.getPlugin(); activePump = VirtualPumpPlugin.getPlugin();
VirtualPumpPlugin.getPlugin().setPluginEnabled(PluginType.PUMP, true); VirtualPumpPlugin.getPlugin().setPluginEnabled(PluginType.PUMP, true);
if (L.isEnabled(L.CONFIGBUILDER))
log.debug("Defaulting VirtualPumpPlugin");
} }
this.setFragmentVisiblities(((PluginBase) activePump).getName(), pluginsInCategory, PluginType.PUMP); this.setFragmentVisiblities(((PluginBase) activePump).getName(), pluginsInCategory, PluginType.PUMP);
// PluginType.LOOP
activeLoop = this.determineActivePlugin(PluginType.LOOP);
// PluginType.TREATMENT // PluginType.TREATMENT
activeTreatments = this.determineActivePlugin(PluginType.TREATMENT);
} }
/** /**
@ -386,7 +373,7 @@ public class ConfigBuilderPlugin extends PluginBase {
private void setFragmentVisiblities(String activePluginName, ArrayList<PluginBase> pluginsInCategory, private void setFragmentVisiblities(String activePluginName, ArrayList<PluginBase> pluginsInCategory,
PluginType pluginType) { PluginType pluginType) {
if (Config.logConfigBuilder) if (L.isEnabled(L.CONFIGBUILDER))
log.debug("Selected interface: " + activePluginName); log.debug("Selected interface: " + activePluginName);
for (PluginBase p : pluginsInCategory) { for (PluginBase p : pluginsInCategory) {
if (!p.getName().equals(activePluginName)) { if (!p.getName().equals(activePluginName)) {
@ -412,246 +399,4 @@ public class ConfigBuilderPlugin extends PluginBase {
return found; return found;
} }
/**
* expect absolute request and allow both absolute and percent response based on pump capabilities
*/
public void applyTBRRequest(APSResult request, Profile profile, Callback callback) {
if (!request.tempBasalRequested) {
if (callback != null) {
callback.result(new PumpEnactResult().enacted(false).success(true).comment(MainApp.gs(R.string.nochangerequested))).run();
}
return;
}
PumpInterface pump = getActivePump();
request.rateConstraint = new Constraint<>(request.rate);
request.rate = MainApp.getConstraintChecker().applyBasalConstraints(request.rateConstraint, profile).value();
if (!pump.isInitialized()) {
log.debug("applyAPSRequest: " + MainApp.gs(R.string.pumpNotInitialized));
if (callback != null) {
callback.result(new PumpEnactResult().comment(MainApp.gs(R.string.pumpNotInitialized)).enacted(false).success(false)).run();
}
return;
}
if (pump.isSuspended()) {
log.debug("applyAPSRequest: " + MainApp.gs(R.string.pumpsuspended));
if (callback != null) {
callback.result(new PumpEnactResult().comment(MainApp.gs(R.string.pumpsuspended)).enacted(false).success(false)).run();
}
return;
}
if (Config.logCongigBuilderActions)
log.debug("applyAPSRequest: " + request.toString());
long now = System.currentTimeMillis();
TemporaryBasal activeTemp = activeTreatments.getTempBasalFromHistory(now);
if ((request.rate == 0 && request.duration == 0) || Math.abs(request.rate - pump.getBaseBasalRate()) < pump.getPumpDescription().basalStep) {
if (activeTemp != null) {
if (Config.logCongigBuilderActions)
log.debug("applyAPSRequest: cancelTempBasal()");
getCommandQueue().cancelTempBasal(false, callback);
} else {
if (Config.logCongigBuilderActions)
log.debug("applyAPSRequest: Basal set correctly");
if (callback != null) {
callback.result(new PumpEnactResult().absolute(request.rate).duration(0)
.enacted(false).success(true).comment(MainApp.gs(R.string.basal_set_correctly))).run();
}
}
} else if (activeTemp != null
&& activeTemp.getPlannedRemainingMinutes() > 5
&& request.duration - activeTemp.getPlannedRemainingMinutes() < 30
&& Math.abs(request.rate - activeTemp.tempBasalConvertedToAbsolute(now, profile)) < pump.getPumpDescription().basalStep) {
if (Config.logCongigBuilderActions)
log.debug("applyAPSRequest: Temp basal set correctly");
if (callback != null) {
callback.result(new PumpEnactResult().absolute(activeTemp.tempBasalConvertedToAbsolute(now, profile))
.enacted(false).success(true).duration(activeTemp.getPlannedRemainingMinutes())
.comment(MainApp.gs(R.string.let_temp_basal_run))).run();
}
} else {
if (Config.logCongigBuilderActions)
log.debug("applyAPSRequest: setTempBasalAbsolute()");
getCommandQueue().tempBasalAbsolute(request.rate, request.duration, false, profile, callback);
}
}
public void applySMBRequest(APSResult request, Callback callback) {
if (!request.bolusRequested) {
return;
}
long lastBolusTime = activeTreatments.getLastBolusTime();
if (lastBolusTime != 0 && lastBolusTime + 3 * 60 * 1000 > System.currentTimeMillis()) {
log.debug("SMB requested but still in 3 min interval");
if (callback != null) {
callback.result(new PumpEnactResult()
.comment(MainApp.gs(R.string.smb_frequency_exceeded))
.enacted(false).success(false)).run();
}
return;
}
PumpInterface pump = getActivePump();
if (!pump.isInitialized()) {
log.debug("applySMBRequest: " + MainApp.gs(R.string.pumpNotInitialized));
if (callback != null) {
callback.result(new PumpEnactResult().comment(MainApp.gs(R.string.pumpNotInitialized)).enacted(false).success(false)).run();
}
return;
}
if (pump.isSuspended()) {
log.debug("applySMBRequest: " + MainApp.gs(R.string.pumpsuspended));
if (callback != null) {
callback.result(new PumpEnactResult().comment(MainApp.gs(R.string.pumpsuspended)).enacted(false).success(false)).run();
}
return;
}
if (Config.logCongigBuilderActions)
log.debug("applySMBRequest: " + request.toString());
// deliver SMB
DetailedBolusInfo detailedBolusInfo = new DetailedBolusInfo();
detailedBolusInfo.eventType = CareportalEvent.CORRECTIONBOLUS;
detailedBolusInfo.insulin = request.smb;
detailedBolusInfo.isSMB = true;
detailedBolusInfo.source = Source.USER;
detailedBolusInfo.deliverAt = request.deliverAt;
if (Config.logCongigBuilderActions)
log.debug("applyAPSRequest: bolus()");
getCommandQueue().bolus(detailedBolusInfo, callback);
}
@Subscribe
public void onProfileSwitch(EventProfileSwitchChange ignored) {
getCommandQueue().setProfile(getProfile(), new Callback() {
@Override
public void run() {
if (!result.success) {
Intent i = new Intent(MainApp.instance(), ErrorHelperActivity.class);
i.putExtra("soundid", R.raw.boluserror);
i.putExtra("status", result.comment);
i.putExtra("title", MainApp.gs(R.string.failedupdatebasalprofile));
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
MainApp.instance().startActivity(i);
}
MainApp.bus().post(new EventNewBasalProfile());
}
});
}
public String getProfileName() {
return getProfileName(System.currentTimeMillis());
}
public String getProfileName(boolean customized) {
return getProfileName(System.currentTimeMillis(), customized);
}
public String getProfileName(long time) {
return getProfileName(time, true);
}
public String getProfileName(long time, boolean customized) {
ProfileSwitch profileSwitch = activeTreatments.getProfileSwitchFromHistory(time);
if (profileSwitch != null) {
if (profileSwitch.profileJson != null) {
return customized ? profileSwitch.getCustomizedName() : profileSwitch.profileName;
} else {
ProfileStore profileStore = activeProfile.getProfile();
if (profileStore != null) {
Profile profile = profileStore.getSpecificProfile(profileSwitch.profileName);
if (profile != null)
return profileSwitch.profileName;
}
}
}
return MainApp.gs(R.string.noprofileselected);
}
public boolean isProfileValid(String from) {
return getProfile() != null && getProfile().isValid(from);
}
@Nullable
public Profile getProfile() {
return getProfile(System.currentTimeMillis());
}
public String getProfileUnits() {
Profile profile = getProfile();
return profile != null ? profile.getUnits() : Constants.MGDL;
}
@Nullable
public Profile getProfile(long time) {
if (activeTreatments == null) {
log.debug("getProfile activeTreatments == null: returning null");
return null; //app not initialized
}
//log.debug("Profile for: " + new Date(time).toLocaleString() + " : " + getProfileName(time));
ProfileSwitch profileSwitch = activeTreatments.getProfileSwitchFromHistory(time);
if (profileSwitch != null) {
if (profileSwitch.profileJson != null) {
return profileSwitch.getProfileObject();
} else if (activeProfile.getProfile() != null) {
Profile profile = activeProfile.getProfile().getSpecificProfile(profileSwitch.profileName);
if (profile != null)
return profile;
}
}
if (activeTreatments.getProfileSwitchesFromHistory().size() > 0) {
FabricPrivacy.getInstance().logCustom(new CustomEvent("CatchedError")
.putCustomAttribute("buildversion", BuildConfig.BUILDVERSION)
.putCustomAttribute("version", BuildConfig.VERSION)
.putCustomAttribute("time", time)
.putCustomAttribute("getProfileSwitchesFromHistory", activeTreatments.getProfileSwitchesFromHistory().toString())
);
}
log.debug("getProfile at the end: returning null");
return null;
}
public void disconnectPump(int durationInMinutes, Profile profile) {
LoopPlugin.getPlugin().disconnectTo(System.currentTimeMillis() + durationInMinutes * 60 * 1000L);
getCommandQueue().tempBasalPercent(0, durationInMinutes, true, profile, new Callback() {
@Override
public void run() {
if (!result.success) {
ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), MainApp.gs(R.string.tempbasaldeliveryerror));
}
}
});
if (getActivePump().getPumpDescription().isExtendedBolusCapable && activeTreatments.isInHistoryExtendedBoluslInProgress()) {
getCommandQueue().cancelExtended(new Callback() {
@Override
public void run() {
if (!result.success) {
ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), MainApp.gs(R.string.extendedbolusdeliveryerror));
}
}
});
}
NSUpload.uploadOpenAPSOffline(durationInMinutes);
}
public void suspendLoop(int durationInMinutes) {
LoopPlugin.getPlugin().suspendTo(System.currentTimeMillis() + durationInMinutes * 60 * 1000);
getCommandQueue().cancelTempBasal(true, new Callback() {
@Override
public void run() {
if (!result.success) {
ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), MainApp.gs(R.string.tempbasaldeliveryerror));
}
}
});
NSUpload.uploadOpenAPSOffline(durationInMinutes);
}
} }

View file

@ -6,17 +6,17 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date;
import java.util.List; import java.util.List;
import info.nightscout.androidaps.data.DetailedBolusInfo; import info.nightscout.androidaps.data.DetailedBolusInfo;
import info.nightscout.androidaps.logging.L;
/** /**
* Created by mike on 08.08.2017. * Created by mike on 08.08.2017.
*/ */
public class DetailedBolusInfoStorage { public class DetailedBolusInfoStorage {
private static Logger log = LoggerFactory.getLogger(DetailedBolusInfoStorage.class); private static Logger log = LoggerFactory.getLogger(L.PUMP);
private static List<DetailedBolusInfo> store = new ArrayList<>(); private static List<DetailedBolusInfo> store = new ArrayList<>();
public static synchronized void add(DetailedBolusInfo detailedBolusInfo) { public static synchronized void add(DetailedBolusInfo detailedBolusInfo) {
@ -29,23 +29,16 @@ public class DetailedBolusInfoStorage {
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;
if (L.isEnabled(L.PUMP))
log.debug("Existing bolus info: " + store.get(i)); log.debug("Existing bolus info: " + store.get(i));
if (bolustime > infoTime - 60 * 1000 && bolustime < infoTime + 60 * 1000) { if (bolustime > infoTime - 60 * 1000 && bolustime < infoTime + 60 * 1000) {
found = store.get(i); found = store.get(i);
if (L.isEnabled(L.PUMP))
log.debug("Using & removing bolus info: " + store.get(i));
store.remove(i);
break; break;
} }
} }
return found; return found;
} }
public static synchronized void remove(long bolustime) {
for (int i = 0; i < store.size(); i++) {
long infoTime = store.get(i).date;
if (bolustime > infoTime - 60 * 1000 && bolustime < infoTime + 60 * 1000) {
log.debug("Removing bolus info: " + store.get(i));
store.remove(i);
break;
}
}
}
} }

View file

@ -0,0 +1,142 @@
package info.nightscout.androidaps.plugins.ConfigBuilder;
import android.content.Intent;
import android.support.annotation.Nullable;
import com.crashlytics.android.answers.CustomEvent;
import com.squareup.otto.Subscribe;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.BuildConfig;
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.data.ProfileStore;
import info.nightscout.androidaps.db.ProfileSwitch;
import info.nightscout.androidaps.events.EventNewBasalProfile;
import info.nightscout.androidaps.events.EventProfileSwitchChange;
import info.nightscout.androidaps.interfaces.ProfileInterface;
import info.nightscout.androidaps.interfaces.TreatmentsInterface;
import info.nightscout.androidaps.logging.L;
import info.nightscout.androidaps.plugins.Overview.Dialogs.ErrorHelperActivity;
import info.nightscout.androidaps.plugins.Treatments.TreatmentsPlugin;
import info.nightscout.androidaps.queue.Callback;
import info.nightscout.utils.FabricPrivacy;
public class ProfileFunctions {
private static Logger log = LoggerFactory.getLogger(L.PROFILE);
private static ProfileFunctions profileFunctions = null;
public static ProfileFunctions getInstance() {
if (profileFunctions == null)
profileFunctions = new ProfileFunctions();
return profileFunctions;
}
static {
ProfileFunctions.getInstance(); // register to bus at start
}
ProfileFunctions() {
MainApp.bus().register(this);
}
@Subscribe
public void onProfileSwitch(EventProfileSwitchChange ignored) {
if (L.isEnabled(L.PROFILE))
log.debug("onProfileSwitch");
ConfigBuilderPlugin.getPlugin().getCommandQueue().setProfile(getProfile(), new Callback() {
@Override
public void run() {
if (!result.success) {
Intent i = new Intent(MainApp.instance(), ErrorHelperActivity.class);
i.putExtra("soundid", R.raw.boluserror);
i.putExtra("status", result.comment);
i.putExtra("title", MainApp.gs(R.string.failedupdatebasalprofile));
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
MainApp.instance().startActivity(i);
}
MainApp.bus().post(new EventNewBasalProfile());
}
});
}
public String getProfileName() {
return getProfileName(System.currentTimeMillis());
}
public String getProfileName(boolean customized) {
return getProfileName(System.currentTimeMillis(), customized);
}
public String getProfileName(long time) {
return getProfileName(time, true);
}
public String getProfileName(long time, boolean customized) {
TreatmentsInterface activeTreatments = TreatmentsPlugin.getPlugin();
ProfileInterface activeProfile = ConfigBuilderPlugin.getPlugin().getActiveProfileInterface();
ProfileSwitch profileSwitch = activeTreatments.getProfileSwitchFromHistory(time);
if (profileSwitch != null) {
if (profileSwitch.profileJson != null) {
return customized ? profileSwitch.getCustomizedName() : profileSwitch.profileName;
} else {
ProfileStore profileStore = activeProfile.getProfile();
if (profileStore != null) {
Profile profile = profileStore.getSpecificProfile(profileSwitch.profileName);
if (profile != null)
return profileSwitch.profileName;
}
}
}
return MainApp.gs(R.string.noprofileselected);
}
public boolean isProfileValid(String from) {
return getProfile() != null && getProfile().isValid(from);
}
@Nullable
public Profile getProfile() {
return getProfile(System.currentTimeMillis());
}
public String getProfileUnits() {
Profile profile = getProfile();
return profile != null ? profile.getUnits() : Constants.MGDL;
}
@Nullable
public Profile getProfile(long time) {
TreatmentsInterface activeTreatments = TreatmentsPlugin.getPlugin();
ProfileInterface activeProfile = ConfigBuilderPlugin.getPlugin().getActiveProfileInterface();
//log.debug("Profile for: " + new Date(time).toLocaleString() + " : " + getProfileName(time));
ProfileSwitch profileSwitch = activeTreatments.getProfileSwitchFromHistory(time);
if (profileSwitch != null) {
if (profileSwitch.profileJson != null) {
return profileSwitch.getProfileObject();
} else if (activeProfile.getProfile() != null) {
Profile profile = activeProfile.getProfile().getSpecificProfile(profileSwitch.profileName);
if (profile != null)
return profile;
}
}
if (activeTreatments.getProfileSwitchesFromHistory().size() > 0) {
FabricPrivacy.getInstance().logCustom(new CustomEvent("CatchedError")
.putCustomAttribute("buildversion", BuildConfig.BUILDVERSION)
.putCustomAttribute("version", BuildConfig.VERSION)
.putCustomAttribute("time", time)
.putCustomAttribute("getProfileSwitchesFromHistory", activeTreatments.getProfileSwitchesFromHistory().toString())
);
}
log.error("getProfile at the end: returning null");
return null;
}
}

View file

@ -1,12 +1,15 @@
package info.nightscout.androidaps.plugins.ConstraintsObjectives; package info.nightscout.androidaps.plugins.ConstraintsObjectives;
import android.app.Activity; import android.app.Activity;
import android.content.Context;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.app.Fragment; import android.os.Handler;
import android.os.Looper;
import android.support.annotation.NonNull;
import android.support.v7.widget.CardView; import android.support.v7.widget.CardView;
import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.LinearSmoothScroller;
import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView;
import android.text.Html;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
@ -15,200 +18,28 @@ import android.widget.CheckBox;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.TextView; import android.widget.TextView;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Date; import java.util.Date;
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.androidaps.plugins.Common.SubscriberFragment;
import info.nightscout.androidaps.plugins.ConstraintsObjectives.objectives.Objective;
import info.nightscout.utils.FabricPrivacy; import info.nightscout.utils.FabricPrivacy;
import info.nightscout.utils.T;
public class ObjectivesFragment extends SubscriberFragment { public class ObjectivesFragment extends SubscriberFragment {
private static Logger log = LoggerFactory.getLogger(ObjectivesFragment.class);
RecyclerView recyclerView; RecyclerView recyclerView;
LinearLayoutManager llm;
CheckBox enableFake; CheckBox enableFake;
LinearLayout fake_layout;
TextView reset; TextView reset;
ObjectivesAdapter objectivesAdapter = new ObjectivesAdapter();
Handler handler = new Handler(Looper.getMainLooper());
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ObjectiveViewHolder> { private Runnable objectiveUpdater = new Runnable() {
List<ObjectivesPlugin.Objective> objectives;
RecyclerViewAdapter(List<ObjectivesPlugin.Objective> objectives) {
this.objectives = objectives;
}
@Override @Override
public ObjectiveViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) { public void run() {
View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.objectives_item, viewGroup, false); handler.postDelayed(this, 60 * 1000);
return new ObjectiveViewHolder(v);
}
@Override
public void onBindViewHolder(ObjectiveViewHolder holder, int position) {
ObjectivesPlugin.Objective o = objectives.get(position);
ObjectivesPlugin.RequirementResult requirementsMet = ObjectivesPlugin.getPlugin().requirementsMet(position);
Context context = MainApp.instance().getApplicationContext();
holder.position.setText(String.valueOf(position + 1));
holder.objective.setText(o.objective);
holder.gate.setText(o.gate);
holder.duration.setText(MainApp.gs(R.string.objectives_minimalduration) + " " + o.durationInDays + " " + MainApp.gs(R.string.days));
holder.progress.setText(requirementsMet.comment);
holder.started.setText(o.started.toLocaleString());
holder.accomplished.setText(o.accomplished.toLocaleString());
holder.startButton.setTag(o);
holder.verifyButton.setTag(o);
holder.startButton.setOnClickListener(v -> {
ObjectivesPlugin.Objective o1 = (ObjectivesPlugin.Objective) v.getTag();
o1.started = new Date();
updateGUI(); updateGUI();
ObjectivesPlugin.saveProgress();
});
holder.verifyButton.setOnClickListener(v -> {
ObjectivesPlugin.Objective o12 = (ObjectivesPlugin.Objective) v.getTag();
if (ObjectivesPlugin.getPlugin().requirementsMet(o12.num).done || enableFake.isChecked()) {
o12.accomplished = new Date();
updateGUI();
ObjectivesPlugin.saveProgress();
}
});
long prevObjectiveAccomplishedTime = position > 0 ?
objectives.get(position - 1).accomplished.getTime() : -1;
int phase = modifyVisibility(position, prevObjectiveAccomplishedTime,
o.started.getTime(), o.durationInDays,
o.accomplished.getTime(), requirementsMet.done, enableFake.isChecked());
switch (phase) {
case 0:
// Phase 0: previous not completed
holder.startedLayout.setVisibility(View.GONE);
holder.durationLayout.setVisibility(View.GONE);
holder.progressLayout.setVisibility(View.GONE);
holder.verifyLayout.setVisibility(View.GONE);
break;
case 1:
// Phase 1: not started
holder.durationLayout.setVisibility(View.GONE);
holder.progressLayout.setVisibility(View.GONE);
holder.verifyLayout.setVisibility(View.GONE);
holder.started.setVisibility(View.GONE);
break;
case 2:
// Phase 2: started, waiting for duration and met requirements
holder.startButton.setEnabled(false);
holder.verifyLayout.setVisibility(View.GONE);
break;
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
public int getItemCount() {
return objectives.size();
}
@Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
}
public class ObjectiveViewHolder extends RecyclerView.ViewHolder {
CardView cv;
TextView position;
TextView objective;
LinearLayout gateLayout;
TextView gate;
TextView duration;
LinearLayout durationLayout;
TextView progress;
LinearLayout progressLayout;
TextView started;
Button startButton;
LinearLayout startedLayout;
TextView accomplished;
Button verifyButton;
LinearLayout verifyLayout;
ObjectiveViewHolder(View itemView) {
super(itemView);
cv = (CardView) itemView.findViewById(R.id.objectives_cardview);
position = (TextView) itemView.findViewById(R.id.objectives_position);
objective = (TextView) itemView.findViewById(R.id.objectives_objective);
durationLayout = (LinearLayout) itemView.findViewById(R.id.objectives_duration_linearlayout);
duration = (TextView) itemView.findViewById(R.id.objectives_duration);
progressLayout = (LinearLayout) itemView.findViewById(R.id.objectives_progresslayout);
progress = (TextView) itemView.findViewById(R.id.objectives_progress);
gateLayout = (LinearLayout) itemView.findViewById(R.id.objectives_gate_linearlayout);
gate = (TextView) itemView.findViewById(R.id.objectives_gate);
startedLayout = (LinearLayout) itemView.findViewById(R.id.objectives_start_linearlayout);
started = (TextView) itemView.findViewById(R.id.objectives_started);
startButton = (Button) itemView.findViewById(R.id.objectives_start);
verifyLayout = (LinearLayout) itemView.findViewById(R.id.objectives_verify_linearlayout);
accomplished = (TextView) itemView.findViewById(R.id.objectives_accomplished);
verifyButton = (Button) itemView.findViewById(R.id.objectives_verify);
}
}
}
/**
* 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,
@ -216,45 +47,20 @@ public class ObjectivesFragment extends SubscriberFragment {
try { try {
View view = inflater.inflate(R.layout.objectives_fragment, container, false); View view = inflater.inflate(R.layout.objectives_fragment, container, false);
recyclerView = (RecyclerView) view.findViewById(R.id.objectives_recyclerview); recyclerView = view.findViewById(R.id.objectives_recyclerview);
recyclerView.setHasFixedSize(true); recyclerView.setLayoutManager(new LinearLayoutManager(view.getContext()));
llm = new LinearLayoutManager(view.getContext()); recyclerView.setAdapter(objectivesAdapter);
recyclerView.setLayoutManager(llm); enableFake = view.findViewById(R.id.objectives_fake);
enableFake = (CheckBox) view.findViewById(R.id.objectives_fake); reset = view.findViewById(R.id.objectives_reset);
fake_layout = (LinearLayout) view.findViewById(R.id.objectives_fake_layout); enableFake.setOnClickListener(v -> updateGUI());
reset = (TextView) view.findViewById(R.id.objectives_reset); reset.setOnClickListener(v -> {
enableFake.setOnClickListener(new View.OnClickListener() { ObjectivesPlugin.getPlugin().reset();
public void onClick(View v) { ObjectivesPlugin.getPlugin().saveProgress();
updateGUI(); recyclerView.getAdapter().notifyDataSetChanged();
} scrollToCurrentObjective();
}); });
reset.setOnClickListener(new View.OnClickListener() { scrollToCurrentObjective();
public void onClick(View v) { startUpdateTimer();
ObjectivesPlugin.getPlugin().initializeData();
ObjectivesPlugin.saveProgress();
updateGUI();
}
});
// Add correct translations to array after app is initialized
ObjectivesPlugin.objectives.get(0).objective = MainApp.gs(R.string.objectives_0_objective);
ObjectivesPlugin.objectives.get(1).objective = MainApp.gs(R.string.objectives_1_objective);
ObjectivesPlugin.objectives.get(2).objective = MainApp.gs(R.string.objectives_2_objective);
ObjectivesPlugin.objectives.get(3).objective = MainApp.gs(R.string.objectives_3_objective);
ObjectivesPlugin.objectives.get(4).objective = MainApp.gs(R.string.objectives_4_objective);
ObjectivesPlugin.objectives.get(5).objective = MainApp.gs(R.string.objectives_5_objective);
ObjectivesPlugin.objectives.get(6).objective = MainApp.gs(R.string.objectives_6_objective);
ObjectivesPlugin.objectives.get(7).objective = MainApp.gs(R.string.objectives_7_objective);
ObjectivesPlugin.objectives.get(0).gate = MainApp.gs(R.string.objectives_0_gate);
ObjectivesPlugin.objectives.get(1).gate = MainApp.gs(R.string.objectives_1_gate);
ObjectivesPlugin.objectives.get(2).gate = MainApp.gs(R.string.objectives_2_gate);
ObjectivesPlugin.objectives.get(3).gate = MainApp.gs(R.string.objectives_3_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);
ObjectivesPlugin.objectives.get(7).gate = MainApp.gs(R.string.objectives_7_gate);
updateGUI();
return view; return view;
} catch (Exception e) { } catch (Exception e) {
FabricPrivacy.logException(e); FabricPrivacy.logException(e);
@ -263,13 +69,142 @@ public class ObjectivesFragment extends SubscriberFragment {
return null; return null;
} }
@Override
public synchronized void onDestroyView() {
super.onDestroyView();
handler.removeCallbacks(objectiveUpdater);
}
private void startUpdateTimer() {
handler.removeCallbacks(objectiveUpdater);
for (Objective objective : ObjectivesPlugin.getPlugin().getObjectives()) {
if (objective.isStarted() && !objective.isAccomplished()) {
long timeTillNextMinute = (System.currentTimeMillis() - objective.getStartedOn().getTime()) % (60 * 1000);
handler.postDelayed(objectiveUpdater, timeTillNextMinute);
break;
}
}
}
private void scrollToCurrentObjective() {
for (int i = 0; i < ObjectivesPlugin.getPlugin().getObjectives().size(); i++) {
Objective objective = ObjectivesPlugin.getPlugin().getObjectives().get(i);
if (!objective.isStarted() || !objective.isAccomplished()) {
RecyclerView.SmoothScroller smoothScroller = new LinearSmoothScroller(getContext()) {
@Override
protected int getVerticalSnapPreference() {
return LinearSmoothScroller.SNAP_TO_START;
}
@Override
protected int calculateTimeForScrolling(int dx) {
return super.calculateTimeForScrolling(dx) * 4;
}
};
smoothScroller.setTargetPosition(i);
recyclerView.getLayoutManager().startSmoothScroll(smoothScroller);
break;
}
}
}
private class ObjectivesAdapter extends RecyclerView.Adapter<ObjectivesAdapter.ViewHolder> {
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new ViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.objectives_item, parent, false));
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
Objective objective = ObjectivesPlugin.getPlugin().getObjectives().get(position);
holder.title.setText(MainApp.gs(R.string.nth_objective, position + 1));
if (objective.getObjective() != 0) {
holder.objective.setVisibility(View.VISIBLE);
holder.objective.setText(MainApp.gs(objective.getObjective()));
} else holder.objective.setVisibility(View.GONE);
if (objective.getGate() != 0) {
holder.gate.setVisibility(View.VISIBLE);
holder.gate.setText(MainApp.gs(objective.getGate()));
} else holder.gate.setVisibility(View.GONE);
if (!objective.isStarted()) {
holder.gate.setTextColor(0xFFFFFFFF);
holder.verify.setVisibility(View.GONE);
holder.progress.setVisibility(View.GONE);
if (position == 0 || ObjectivesPlugin.getPlugin().getObjectives().get(position - 1).isAccomplished())
holder.start.setVisibility(View.VISIBLE);
else holder.start.setVisibility(View.GONE);
} else if (objective.isAccomplished()) {
holder.gate.setTextColor(0xFF4CAF50);
holder.verify.setVisibility(View.GONE);
holder.progress.setVisibility(View.GONE);
holder.start.setVisibility(View.GONE);
} else if (objective.isStarted()) {
holder.gate.setTextColor(0xFFFFFFFF);
holder.verify.setVisibility(View.VISIBLE);
holder.verify.setEnabled(objective.isCompleted() || enableFake.isChecked());
holder.start.setVisibility(View.GONE);
holder.progress.setVisibility(View.VISIBLE);
holder.progress.removeAllViews();
for (Objective.Task task : objective.getTasks()) {
if (task.shouldBeIgnored()) continue;
TextView textView = new TextView(holder.progress.getContext());
textView.setTextColor(0xFFFFFFFF);
String basicHTML = "%2$s: <font color=\"%1$s\"><b>%3$s</b></font>";
String formattedHTML = String.format(basicHTML, task.isCompleted() ? "#4CAF50" : "#FF9800", MainApp.gs(task.getTask()), task.getProgress());
textView.setText(Html.fromHtml(formattedHTML));
holder.progress.addView(textView, LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
}
}
holder.verify.setOnClickListener((view) -> {
objective.setAccomplishedOn(new Date());
notifyDataSetChanged();
scrollToCurrentObjective();
startUpdateTimer();
});
holder.start.setOnClickListener((view) -> {
objective.setStartedOn(new Date());
notifyDataSetChanged();
scrollToCurrentObjective();
startUpdateTimer();
});
}
@Override
public int getItemCount() {
return ObjectivesPlugin.getPlugin().getObjectives().size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
public CardView cardView;
public TextView title;
public TextView objective;
public TextView gate;
public LinearLayout progress;
public Button verify;
public Button start;
public ViewHolder(View itemView) {
super(itemView);
cardView = (CardView) itemView;
title = itemView.findViewById(R.id.objective_title);
objective = itemView.findViewById(R.id.objective_objective);
gate = itemView.findViewById(R.id.objective_gate);
progress = itemView.findViewById(R.id.objective_progress);
verify = itemView.findViewById(R.id.objective_verify);
start = itemView.findViewById(R.id.objective_start);
}
}
}
@Override @Override
public void updateGUI() { public void updateGUI() {
Activity activity = getActivity(); Activity activity = getActivity();
if (activity != null) if (activity != null)
activity.runOnUiThread(() -> { activity.runOnUiThread(() -> {
RecyclerViewAdapter adapter = new RecyclerViewAdapter(ObjectivesPlugin.objectives); objectivesAdapter.notifyDataSetChanged();
recyclerView.setAdapter(adapter);
}); });
} }

View file

@ -1,44 +1,47 @@
package info.nightscout.androidaps.plugins.ConstraintsObjectives; package info.nightscout.androidaps.plugins.ConstraintsObjectives;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date;
import java.util.List; import java.util.List;
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.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.PluginDescription;
import info.nightscout.androidaps.interfaces.PluginType; import info.nightscout.androidaps.interfaces.PluginType;
import info.nightscout.androidaps.interfaces.PumpInterface; import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.logging.L;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.ConstraintsObjectives.events.EventObjectivesSaved; import info.nightscout.androidaps.plugins.ConstraintsObjectives.events.EventObjectivesSaved;
import info.nightscout.androidaps.plugins.ConstraintsSafety.SafetyPlugin; import info.nightscout.androidaps.plugins.ConstraintsObjectives.objectives.Objective;
import info.nightscout.androidaps.plugins.Loop.LoopPlugin; import info.nightscout.androidaps.plugins.ConstraintsObjectives.objectives.Objective1;
import info.nightscout.androidaps.plugins.NSClientInternal.NSClientPlugin; import info.nightscout.androidaps.plugins.ConstraintsObjectives.objectives.Objective2;
import info.nightscout.androidaps.plugins.PumpVirtual.VirtualPumpPlugin; import info.nightscout.androidaps.plugins.ConstraintsObjectives.objectives.Objective3;
import info.nightscout.androidaps.plugins.Treatments.TreatmentsPlugin; import info.nightscout.androidaps.plugins.ConstraintsObjectives.objectives.Objective4;
import info.nightscout.utils.DateUtil; import info.nightscout.androidaps.plugins.ConstraintsObjectives.objectives.Objective5;
import info.nightscout.androidaps.plugins.ConstraintsObjectives.objectives.Objective6;
import info.nightscout.androidaps.plugins.ConstraintsObjectives.objectives.Objective7;
import info.nightscout.androidaps.plugins.ConstraintsObjectives.objectives.Objective8;
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 extends PluginBase implements ConstraintsInterface { public class ObjectivesPlugin extends PluginBase implements ConstraintsInterface {
private static Logger log = LoggerFactory.getLogger(ObjectivesPlugin.class); private static Logger log = LoggerFactory.getLogger(L.CONSTRAINTS);
private static ObjectivesPlugin objectivesPlugin; private static ObjectivesPlugin objectivesPlugin;
public List<Objective> objectives = new ArrayList<>();
public boolean bgIsAvailableInNS = false;
public boolean pumpStatusIsAvailableInNS = false;
public Integer manualEnacts = 0;
public static ObjectivesPlugin getPlugin() { public static ObjectivesPlugin getPlugin() {
if (objectivesPlugin == null) { if (objectivesPlugin == null) {
objectivesPlugin = new ObjectivesPlugin(); objectivesPlugin = new ObjectivesPlugin();
@ -46,208 +49,58 @@ public class ObjectivesPlugin extends PluginBase implements ConstraintsInterface
return objectivesPlugin; return objectivesPlugin;
} }
public static List<Objective> objectives;
private ObjectivesPlugin() { private ObjectivesPlugin() {
super(new PluginDescription() super(new PluginDescription()
.mainType(PluginType.CONSTRAINTS) .mainType(PluginType.CONSTRAINTS)
.fragmentClass(ObjectivesFragment.class.getName()) .fragmentClass(ObjectivesFragment.class.getName())
.alwaysEnabled(!Config.NSCLIENT && !Config.G5UPLOADER) .alwaysEnabled(!Config.NSCLIENT)
.showInList(!Config.NSCLIENT && !Config.G5UPLOADER) .showInList(!Config.NSCLIENT)
.pluginName(R.string.objectives) .pluginName(R.string.objectives)
.shortName(R.string.objectives_shortname) .shortName(R.string.objectives_shortname)
.description(R.string.description_objectives)
); );
initializeData(); setupObjectives();
loadProgress(); loadProgress();
} }
@Override @Override
public boolean specialEnableCondition() { public boolean specialEnableCondition() {
PumpInterface pump = ConfigBuilderPlugin.getActivePump(); PumpInterface pump = ConfigBuilderPlugin.getPlugin().getActivePump();
return pump == null || pump.getPumpDescription().isTempBasalCapable; return pump == null || pump.getPumpDescription().isTempBasalCapable;
} }
public class Objective { private void setupObjectives() {
Integer num; objectives.add(new Objective1());
String objective; objectives.add(new Objective2());
String gate; objectives.add(new Objective3());
Date started; objectives.add(new Objective4());
Integer durationInDays; objectives.add(new Objective5());
Date accomplished; objectives.add(new Objective6());
objectives.add(new Objective7());
Objective(Integer num, String objective, String gate, Date started, Integer durationInDays, Date accomplished) { objectives.add(new Objective8());
this.num = num;
this.objective = objective;
this.gate = gate;
this.started = started;
this.durationInDays = durationInDays;
this.accomplished = accomplished;
} }
public void setStarted(Date started) { public void reset() {
this.started = started; for (Objective objective : objectives) {
objective.setStartedOn(null);
objective.setAccomplishedOn(null);
} }
public boolean isStarted() {
return started.getTime() > 0;
}
boolean isFinished() {
return accomplished.getTime() != 0;
}
}
// Objective 0
public static boolean bgIsAvailableInNS = false;
public static boolean pumpStatusIsAvailableInNS = false;
// Objective 1
public static Integer manualEnacts = 0;
private static final Integer manualEnactsNeeded = 20;
class RequirementResult {
boolean done = false;
String comment = "";
RequirementResult(boolean done, String comment) {
this.done = done;
this.comment = comment;
}
}
private String yesOrNo(boolean yes) {
if (yes) return "";
else return "---";
}
RequirementResult requirementsMet(Integer objNum) {
switch (objNum) {
case 0:
boolean isVirtualPump = VirtualPumpPlugin.getPlugin().isEnabled(PluginType.PUMP);
boolean vpUploadEnabled = SP.getBoolean("virtualpump_uploadstatus", false);
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:
return new RequirementResult(manualEnacts >= manualEnactsNeeded,
MainApp.gs(R.string.objectives_manualenacts) + ": " + manualEnacts + "/" + manualEnactsNeeded);
case 2:
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:
return new RequirementResult(true, "");
}
}
void initializeData() {
bgIsAvailableInNS = false; bgIsAvailableInNS = false;
pumpStatusIsAvailableInNS = false; pumpStatusIsAvailableInNS = false;
manualEnacts = 0; manualEnacts = 0;
saveProgress();
objectives = new ArrayList<>();
objectives.add(new Objective(0,
MainApp.gs(R.string.objectives_0_objective),
MainApp.gs(R.string.objectives_0_gate),
new Date(0),
0, // 0 day
new Date(0)));
objectives.add(new Objective(1,
MainApp.gs(R.string.objectives_1_objective),
MainApp.gs(R.string.objectives_1_gate),
new Date(0),
7, // 7 days
new Date(0)));
objectives.add(new Objective(2,
MainApp.gs(R.string.objectives_2_objective),
MainApp.gs(R.string.objectives_2_gate),
new Date(0),
0, // 0 days
new Date(0)));
objectives.add(new Objective(3,
MainApp.gs(R.string.objectives_3_objective),
MainApp.gs(R.string.objectives_3_gate),
new Date(0),
5, // 5 days
new Date(0)));
objectives.add(new Objective(4,
MainApp.gs(R.string.objectives_4_objective),
MainApp.gs(R.string.objectives_4_gate),
new Date(0),
1,
new Date(0)));
objectives.add(new Objective(5,
MainApp.gs(R.string.objectives_5_objective),
MainApp.gs(R.string.objectives_5_gate),
new Date(0),
7,
new Date(0)));
objectives.add(new Objective(6,
MainApp.gs(R.string.objectives_6_objective),
"",
new Date(0),
28,
new Date(0)));
objectives.add(new Objective(7,
MainApp.gs(R.string.objectives_7_objective),
"",
new Date(0),
28,
new Date(0)));
} }
public static void saveProgress() { public void saveProgress() {
if (objectives != null) { SP.putBoolean("Objectives" + "bgIsAvailableInNS", bgIsAvailableInNS);
SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(MainApp.instance().getApplicationContext()); SP.putBoolean("Objectives" + "pumpStatusIsAvailableInNS", pumpStatusIsAvailableInNS);
SharedPreferences.Editor editor = settings.edit(); SP.putString("Objectives" + "manualEnacts", Integer.toString(manualEnacts));
for (int num = 0; num < objectives.size(); num++) { if (L.isEnabled(L.CONSTRAINTS))
Objective o = objectives.get(num);
editor.putString("Objectives" + num + "started", Long.toString(o.started.getTime()));
editor.putString("Objectives" + num + "accomplished", Long.toString(o.accomplished.getTime()));
}
editor.putBoolean("Objectives" + "bgIsAvailableInNS", bgIsAvailableInNS);
editor.putBoolean("Objectives" + "pumpStatusIsAvailableInNS", pumpStatusIsAvailableInNS);
editor.putString("Objectives" + "manualEnacts", Integer.toString(manualEnacts));
editor.apply();
if (Config.logPrefsChange)
log.debug("Objectives stored"); log.debug("Objectives stored");
MainApp.bus().post(new EventObjectivesSaved()); MainApp.bus().post(new EventObjectivesSaved());
} }
}
private void loadProgress() { private void loadProgress() {
for (int num = 0; num < objectives.size(); num++) {
Objective o = objectives.get(num);
try {
o.started = new Date(SP.getLong("Objectives" + num + "started", 0L));
o.accomplished = new Date(SP.getLong("Objectives" + num + "accomplished", 0L));
} catch (Exception e) {
log.error("Unhandled exception", e);
}
}
bgIsAvailableInNS = SP.getBoolean("Objectives" + "bgIsAvailableInNS", false); bgIsAvailableInNS = SP.getBoolean("Objectives" + "bgIsAvailableInNS", false);
pumpStatusIsAvailableInNS = SP.getBoolean("Objectives" + "pumpStatusIsAvailableInNS", false); pumpStatusIsAvailableInNS = SP.getBoolean("Objectives" + "pumpStatusIsAvailableInNS", false);
try { try {
@ -255,15 +108,19 @@ public class ObjectivesPlugin extends PluginBase implements ConstraintsInterface
} catch (Exception e) { } catch (Exception e) {
log.error("Unhandled exception", e); log.error("Unhandled exception", e);
} }
if (Config.logPrefsChange) if (L.isEnabled(L.CONSTRAINTS))
log.debug("Objectives loaded"); log.debug("Objectives loaded");
} }
public List<Objective> getObjectives() {
return objectives;
}
/** /**
* Constraints interface * Constraints interface
**/ **/
@Override @Override
public Constraint<Boolean> isLoopInvokationAllowed(Constraint<Boolean> value) { public Constraint<Boolean> isLoopInvocationAllowed(Constraint<Boolean> value) {
if (!objectives.get(0).isStarted()) if (!objectives.get(0).isStarted())
value.set(false, String.format(MainApp.gs(R.string.objectivenotstarted), 1), this); value.set(false, String.format(MainApp.gs(R.string.objectivenotstarted), 1), this);
return value; return value;
@ -299,7 +156,7 @@ public class ObjectivesPlugin extends PluginBase implements ConstraintsInterface
@Override @Override
public Constraint<Double> applyMaxIOBConstraints(Constraint<Double> maxIob) { public Constraint<Double> applyMaxIOBConstraints(Constraint<Double> maxIob) {
if (objectives.get(3).isStarted() && !objectives.get(3).isFinished()) if (objectives.get(3).isStarted() && !objectives.get(3).isAccomplished())
maxIob.set(0d, String.format(MainApp.gs(R.string.objectivenotfinished), 4), this); maxIob.set(0d, String.format(MainApp.gs(R.string.objectivenotfinished), 4), this);
return maxIob; return maxIob;
} }

View file

@ -0,0 +1,141 @@
package info.nightscout.androidaps.plugins.ConstraintsObjectives.objectives;
import android.support.annotation.StringRes;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.utils.SP;
import info.nightscout.utils.T;
public abstract class Objective {
private int number;
@StringRes
private int objective;
@StringRes
private int gate;
private Date startedOn;
private Date accomplishedOn;
private List<Task> tasks = new ArrayList<>();
public Objective(int number, @StringRes int objective, @StringRes int gate) {
this.number = number;
this.objective = objective;
this.gate = gate;
startedOn = new Date(SP.getLong("Objectives" + number + "started", 0L));
if (startedOn.getTime() == 0L) startedOn = null;
accomplishedOn = new Date(SP.getLong("Objectives" + number + "accomplished", 0L));
if (accomplishedOn.getTime() == 0L) accomplishedOn = null;
setupTasks(tasks);
for (Task task : tasks) task.objective = this;
}
public boolean isCompleted() {
for (Task task : tasks) {
if (!task.shouldBeIgnored() && !task.isCompleted())
return false;
}
return true;
}
public boolean isAccomplished() {
return accomplishedOn != null;
}
public boolean isStarted() {
return startedOn != null;
}
public Date getStartedOn() {
return startedOn;
}
public int getObjective() {
return objective;
}
public int getGate() {
return gate;
}
public void setStartedOn(Date startedOn) {
this.startedOn = startedOn;
SP.putLong("Objectives" + number + "started", startedOn == null ? 0 : startedOn.getTime());
}
public void setAccomplishedOn(Date accomplishedOn) {
this.accomplishedOn = accomplishedOn;
SP.putLong("Objectives" + number + "accomplished", accomplishedOn == null ? 0 : accomplishedOn.getTime());
}
protected void setupTasks(List<Task> tasks) {
}
public List<Task> getTasks() {
return tasks;
}
public abstract class Task {
@StringRes
private int task;
private Objective objective;
public Task(@StringRes int task) {
this.task = task;
}
public int getTask() {
return task;
}
protected Objective getObjective() {
return objective;
}
public abstract boolean isCompleted();
public String getProgress() {
return MainApp.gs(isCompleted() ? R.string.completed_well_done : R.string.not_completed_yet);
}
public boolean shouldBeIgnored() {
return false;
}
}
public class MinimumDurationTask extends Task {
private long minimumDuration;
public MinimumDurationTask(long minimumDuration) {
super(R.string.time_elapsed);
this.minimumDuration = minimumDuration;
}
@Override
public boolean isCompleted() {
return getObjective().isStarted() && System.currentTimeMillis() - getObjective().getStartedOn().getTime() >= minimumDuration;
}
@Override
public String getProgress() {
return getDurationText(System.currentTimeMillis() - getObjective().getStartedOn().getTime())
+ " / " + getDurationText(minimumDuration);
}
private String getDurationText(long duration) {
int days = (int) Math.floor((double) duration / T.days(1).msecs());
int hours = (int) Math.floor((double) duration / T.hours(1).msecs());
int minutes = (int) Math.floor((double) duration / T.mins(1).msecs());
if (days > 0) return MainApp.gq(R.plurals.objective_days, days, days);
else if (hours > 0) return MainApp.gq(R.plurals.objective_hours, hours, hours);
else return MainApp.gq(R.plurals.objective_minutes, minutes, minutes);
}
}
}

View file

@ -0,0 +1,84 @@
package info.nightscout.androidaps.plugins.ConstraintsObjectives.objectives;
import java.util.List;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.db.DatabaseHelper;
import info.nightscout.androidaps.interfaces.APSInterface;
import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.PluginType;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.ConstraintsObjectives.ObjectivesPlugin;
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;
public class Objective1 extends Objective {
public Objective1() {
super(0, R.string.objectives_0_objective, R.string.objectives_0_gate);
}
@Override
protected void setupTasks(List<Task> tasks) {
tasks.add(new Task(R.string.objectives_bgavailableinns) {
@Override
public boolean isCompleted() {
return ObjectivesPlugin.getPlugin().bgIsAvailableInNS;
}
});
tasks.add(new Task(R.string.nsclienthaswritepermission) {
@Override
public boolean isCompleted() {
return NSClientPlugin.getPlugin().hasWritePermission();
}
});
tasks.add(new Task(R.string.virtualpump_uploadstatus_title) {
@Override
public boolean isCompleted() {
return SP.getBoolean("virtualpump_uploadstatus", false);
}
@Override
public boolean shouldBeIgnored() {
return !VirtualPumpPlugin.getPlugin().isEnabled(PluginType.PUMP);
}
});
tasks.add(new Task(R.string.objectives_pumpstatusavailableinns) {
@Override
public boolean isCompleted() {
return ObjectivesPlugin.getPlugin().pumpStatusIsAvailableInNS;
}
});
tasks.add(new Task(R.string.hasbgdata) {
@Override
public boolean isCompleted() {
return DatabaseHelper.lastBg() != null;
}
});
tasks.add(new Task(R.string.loopenabled) {
@Override
public boolean isCompleted() {
return LoopPlugin.getPlugin().isEnabled(PluginType.LOOP);
}
});
tasks.add(new Task(R.string.apsselected) {
@Override
public boolean isCompleted() {
APSInterface usedAPS = ConfigBuilderPlugin.getPlugin().getActiveAPS();
if (usedAPS != null && ((PluginBase) usedAPS).isEnabled(PluginType.APS))
return true;
return false;
}
});
tasks.add(new Task(R.string.activate_profile) {
@Override
public boolean isCompleted() {
return TreatmentsPlugin.getPlugin().getProfileSwitchFromHistory(DateUtil.now()) != null;
}
});
}
}

View file

@ -0,0 +1,36 @@
package info.nightscout.androidaps.plugins.ConstraintsObjectives.objectives;
import java.util.List;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.plugins.ConstraintsObjectives.ObjectivesPlugin;
import info.nightscout.utils.T;
public class Objective2 extends Objective {
public final int MANUAL_ENACTS_NEEDED = 20;
public Objective2() {
super(1, R.string.objectives_1_objective, R.string.objectives_1_gate);
}
@Override
protected void setupTasks(List<Task> tasks) {
tasks.add(new MinimumDurationTask(T.days(7).msecs()));
tasks.add(new Task(R.string.objectives_manualenacts) {
@Override
public boolean isCompleted() {
return ObjectivesPlugin.getPlugin().manualEnacts >= MANUAL_ENACTS_NEEDED;
}
@Override
public String getProgress() {
if (ObjectivesPlugin.getPlugin().manualEnacts >= MANUAL_ENACTS_NEEDED)
return MainApp.gs(R.string.completed_well_done);
else
return ObjectivesPlugin.getPlugin().manualEnacts + " / " + MANUAL_ENACTS_NEEDED;
}
});
}
}

View file

@ -0,0 +1,10 @@
package info.nightscout.androidaps.plugins.ConstraintsObjectives.objectives;
import info.nightscout.androidaps.R;
public class Objective3 extends Objective {
public Objective3() {
super(2, R.string.objectives_2_objective, R.string.objectives_2_gate);
}
}

View file

@ -0,0 +1,28 @@
package info.nightscout.androidaps.plugins.ConstraintsObjectives.objectives;
import java.util.List;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.interfaces.Constraint;
import info.nightscout.androidaps.plugins.ConstraintsSafety.SafetyPlugin;
import info.nightscout.utils.T;
public class Objective4 extends Objective {
public Objective4() {
super(3, R.string.objectives_3_objective, R.string.objectives_3_gate);
}
@Override
protected void setupTasks(List<Task> tasks) {
tasks.add(new MinimumDurationTask(T.days(5).msecs()));
tasks.add(new Task(R.string.closedmodeenabled) {
@Override
public boolean isCompleted() {
Constraint<Boolean> closedLoopEnabled = new Constraint<>(true);
SafetyPlugin.getPlugin().isClosedLoopAllowed(closedLoopEnabled);
return closedLoopEnabled.value();
}
});
}
}

View file

@ -0,0 +1,26 @@
package info.nightscout.androidaps.plugins.ConstraintsObjectives.objectives;
import java.util.List;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.utils.T;
public class Objective5 extends Objective {
public Objective5() {
super(4, R.string.objectives_4_objective, R.string.objectives_4_gate);
}
@Override
protected void setupTasks(List<Task> tasks) {
tasks.add(new MinimumDurationTask(T.days(1).msecs()));
tasks.add(new Task(R.string.maxiobset) {
@Override
public boolean isCompleted() {
double maxIOB = MainApp.getConstraintChecker().getMaxIOBAllowed().value();
return maxIOB > 0;
}
});
}
}

View file

@ -0,0 +1,18 @@
package info.nightscout.androidaps.plugins.ConstraintsObjectives.objectives;
import java.util.List;
import info.nightscout.androidaps.R;
import info.nightscout.utils.T;
public class Objective6 extends Objective {
public Objective6() {
super(5, R.string.objectives_5_objective, R.string.objectives_5_gate);
}
@Override
protected void setupTasks(List<Task> tasks) {
tasks.add(new MinimumDurationTask(T.days(7).msecs()));
}
}

View file

@ -0,0 +1,18 @@
package info.nightscout.androidaps.plugins.ConstraintsObjectives.objectives;
import java.util.List;
import info.nightscout.androidaps.R;
import info.nightscout.utils.T;
public class Objective7 extends Objective {
public Objective7() {
super(6, R.string.objectives_6_objective, 0);
}
@Override
protected void setupTasks(List<Task> tasks) {
tasks.add(new MinimumDurationTask(T.days(28).msecs()));
}
}

View file

@ -0,0 +1,18 @@
package info.nightscout.androidaps.plugins.ConstraintsObjectives.objectives;
import java.util.List;
import info.nightscout.androidaps.R;
import info.nightscout.utils.T;
public class Objective8 extends Objective {
public Objective8() {
super(7, R.string.objectives_7_objective, R.string.objectives_7_gate);
}
@Override
protected void setupTasks(List<Task> tasks) {
tasks.add(new MinimumDurationTask(T.days(28).msecs()));
}
}

View file

@ -10,12 +10,15 @@ 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.PluginDescription;
import info.nightscout.androidaps.interfaces.PluginType; import info.nightscout.androidaps.interfaces.PluginType;
import info.nightscout.androidaps.interfaces.PumpDescription;
import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
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.OpenAPSSMB.OpenAPSSMBPlugin;
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.Overview.notifications.Notification;
import info.nightscout.androidaps.plugins.Sensitivity.SensitivityOref1Plugin;
import info.nightscout.utils.DecimalFormatter; 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;
@ -49,15 +52,15 @@ public class SafetyPlugin extends PluginBase implements ConstraintsInterface {
* Constraints interface * Constraints interface
**/ **/
@Override @Override
public Constraint<Boolean> isLoopInvokationAllowed(Constraint<Boolean> value) { public Constraint<Boolean> isLoopInvocationAllowed(Constraint<Boolean> value) {
if (!ConfigBuilderPlugin.getActivePump().getPumpDescription().isTempBasalCapable) if (!ConfigBuilderPlugin.getPlugin().getActivePump().getPumpDescription().isTempBasalCapable)
value.set(false, MainApp.gs(R.string.pumpisnottempbasalcapable), this); value.set(false, MainApp.gs(R.string.pumpisnottempbasalcapable), this);
return value; return value;
} }
@Override @Override
public Constraint<Boolean> isClosedLoopAllowed(Constraint<Boolean> value) { public Constraint<Boolean> isClosedLoopAllowed(Constraint<Boolean> value) {
String mode = SP.getString("aps_mode", "open"); String mode = SP.getString(R.string.key_aps_mode, "open");
if (!mode.equals("closed")) if (!mode.equals("closed"))
value.set(false, MainApp.gs(R.string.closedmodedisabledinpreferences), this); value.set(false, MainApp.gs(R.string.closedmodedisabledinpreferences), this);
@ -92,9 +95,20 @@ public class SafetyPlugin extends PluginBase implements ConstraintsInterface {
return value; return value;
} }
@Override
public Constraint<Boolean> isUAMEnabled(Constraint<Boolean> value) {
boolean enabled = SP.getBoolean(R.string.key_use_uam, false);
if (!enabled)
value.set(false, MainApp.gs(R.string.uamdisabledinpreferences), this);
boolean oref1Enabled = SensitivityOref1Plugin.getPlugin().isEnabled(PluginType.SENSITIVITY);
if (!oref1Enabled)
value.set(false, MainApp.gs(R.string.uamdisabledoref1notselected), this);
return value;
}
@Override @Override
public Constraint<Boolean> isAdvancedFilteringEnabled(Constraint<Boolean> value) { public Constraint<Boolean> isAdvancedFilteringEnabled(Constraint<Boolean> value) {
BgSourceInterface bgSource = MainApp.getConfigBuilder().getActiveBgSource(); BgSourceInterface bgSource = ConfigBuilderPlugin.getPlugin().getActiveBgSource();
if (bgSource != null) { if (bgSource != null) {
if (!bgSource.advancedFilteringSupported()) if (!bgSource.advancedFilteringSupported())
@ -121,6 +135,18 @@ public class SafetyPlugin extends PluginBase implements ConstraintsInterface {
absoluteRate.setIfSmaller(maxFromDaily, String.format(MainApp.gs(R.string.limitingbasalratio), maxFromDaily, MainApp.gs(R.string.maxdailybasalmultiplier)), this); absoluteRate.setIfSmaller(maxFromDaily, String.format(MainApp.gs(R.string.limitingbasalratio), maxFromDaily, MainApp.gs(R.string.maxdailybasalmultiplier)), this);
absoluteRate.setIfSmaller(HardLimits.maxBasal(), String.format(MainApp.gs(R.string.limitingbasalratio), HardLimits.maxBasal(), MainApp.gs(R.string.hardlimit)), this); absoluteRate.setIfSmaller(HardLimits.maxBasal(), String.format(MainApp.gs(R.string.limitingbasalratio), HardLimits.maxBasal(), MainApp.gs(R.string.hardlimit)), this);
PumpInterface pump = ConfigBuilderPlugin.getPlugin().getActivePump();
// check for pump max
if (pump != null && pump.getPumpDescription().tempBasalStyle == PumpDescription.ABSOLUTE) {
double pumpLimit = pump.getPumpDescription().pumpType.getTbrSettings().getMaxDose();
absoluteRate.setIfSmaller(pumpLimit, String.format(MainApp.gs(R.string.limitingbasalratio), pumpLimit, MainApp.gs(R.string.pumplimit)), this);
}
// do rounding
if (pump != null && pump.getPumpDescription().tempBasalStyle == PumpDescription.ABSOLUTE) {
absoluteRate.set(Round.roundTo(absoluteRate.value(), pump.getPumpDescription().tempAbsoluteStep));
}
return absoluteRate; return absoluteRate;
} }
@ -136,13 +162,23 @@ public class SafetyPlugin extends PluginBase implements ConstraintsInterface {
applyBasalConstraints(absoluteConstraint, profile); applyBasalConstraints(absoluteConstraint, profile);
percentRate.copyReasons(absoluteConstraint); percentRate.copyReasons(absoluteConstraint);
PumpInterface pump = ConfigBuilderPlugin.getPlugin().getActivePump();
Integer percentRateAfterConst = Double.valueOf(absoluteConstraint.value() / currentBasal * 100).intValue(); Integer percentRateAfterConst = Double.valueOf(absoluteConstraint.value() / currentBasal * 100).intValue();
if (pump != null) {
if (percentRateAfterConst < 100) if (percentRateAfterConst < 100)
percentRateAfterConst = Round.ceilTo((double) percentRateAfterConst, 10d).intValue(); percentRateAfterConst = Round.ceilTo((double) percentRateAfterConst, (double) pump.getPumpDescription().tempPercentStep).intValue();
else percentRateAfterConst = Round.floorTo((double) percentRateAfterConst, 10d).intValue(); else
percentRateAfterConst = Round.floorTo((double) percentRateAfterConst, (double) pump.getPumpDescription().tempPercentStep).intValue();
}
percentRate.set(percentRateAfterConst, String.format(MainApp.gs(R.string.limitingpercentrate), percentRateAfterConst, MainApp.gs(R.string.pumplimit)), this); percentRate.set(percentRateAfterConst, String.format(MainApp.gs(R.string.limitingpercentrate), percentRateAfterConst, MainApp.gs(R.string.pumplimit)), this);
if (pump != null && pump.getPumpDescription().tempBasalStyle == PumpDescription.PERCENT) {
double pumpLimit = pump.getPumpDescription().pumpType.getTbrSettings().getMaxDose();
percentRate.setIfSmaller((int) pumpLimit, String.format(MainApp.gs(R.string.limitingbasalratio), pumpLimit, MainApp.gs(R.string.pumplimit)), this);
}
return percentRate; return percentRate;
} }
@ -154,6 +190,29 @@ public class SafetyPlugin extends PluginBase implements ConstraintsInterface {
insulin.setIfSmaller(maxBolus, String.format(MainApp.gs(R.string.limitingbolus), maxBolus, MainApp.gs(R.string.maxvalueinpreferences)), this); insulin.setIfSmaller(maxBolus, String.format(MainApp.gs(R.string.limitingbolus), maxBolus, MainApp.gs(R.string.maxvalueinpreferences)), this);
insulin.setIfSmaller(HardLimits.maxBolus(), String.format(MainApp.gs(R.string.limitingbolus), HardLimits.maxBolus(), MainApp.gs(R.string.hardlimit)), this); insulin.setIfSmaller(HardLimits.maxBolus(), String.format(MainApp.gs(R.string.limitingbolus), HardLimits.maxBolus(), MainApp.gs(R.string.hardlimit)), this);
PumpInterface pump = ConfigBuilderPlugin.getPlugin().getActivePump();
if (pump != null) {
double rounded = Round.roundTo(insulin.value(), pump.getPumpDescription().pumpType.determineCorrectBolusSize(insulin.value()));
insulin.setIfDifferent(rounded, MainApp.gs(R.string.pumplimit), this);
}
return insulin;
}
@Override
public Constraint<Double> applyExtendedBolusConstraints(Constraint<Double> insulin) {
insulin.setIfGreater(0d, String.format(MainApp.gs(R.string.limitingextendedbolus), 0d, MainApp.gs(R.string.itmustbepositivevalue)), this);
Double maxBolus = SP.getDouble(R.string.key_treatmentssafety_maxbolus, 3d);
insulin.setIfSmaller(maxBolus, String.format(MainApp.gs(R.string.limitingextendedbolus), maxBolus, MainApp.gs(R.string.maxvalueinpreferences)), this);
insulin.setIfSmaller(HardLimits.maxBolus(), String.format(MainApp.gs(R.string.limitingextendedbolus), HardLimits.maxBolus(), MainApp.gs(R.string.hardlimit)), this);
PumpInterface pump = ConfigBuilderPlugin.getPlugin().getActivePump();
if (pump != null) {
double rounded = Round.roundTo(insulin.value(), pump.getPumpDescription().pumpType.determineCorrectExtendedBolusSize(insulin.value()));
insulin.setIfDifferent(rounded, MainApp.gs(R.string.pumplimit), this);
}
return insulin; return insulin;
} }

View file

@ -33,7 +33,7 @@ import info.nightscout.androidaps.R;
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.FabricPrivacy;
import info.nightscout.utils.NSUpload; import info.nightscout.androidaps.plugins.NSClientInternal.NSUpload;
import info.nightscout.utils.SpinnerHelper; import info.nightscout.utils.SpinnerHelper;
/** /**

View file

@ -26,6 +26,7 @@ public class FoodPlugin extends PluginBase {
.fragmentClass(FoodFragment.class.getName()) .fragmentClass(FoodFragment.class.getName())
.pluginName(R.string.food) .pluginName(R.string.food)
.shortName(R.string.food_short) .shortName(R.string.food_short)
.description(R.string.description_food)
); );
this.service = new FoodService(); this.service = new FoodService();
} }

View file

@ -33,13 +33,14 @@ import info.nightscout.androidaps.db.ICallback;
import info.nightscout.androidaps.events.Event; import info.nightscout.androidaps.events.Event;
import info.nightscout.androidaps.events.EventFoodDatabaseChanged; import info.nightscout.androidaps.events.EventFoodDatabaseChanged;
import info.nightscout.androidaps.events.EventNsFood; import info.nightscout.androidaps.events.EventNsFood;
import info.nightscout.androidaps.logging.L;
/** /**
* Created by mike on 24.09.2017. * Created by mike on 24.09.2017.
*/ */
public class FoodService extends OrmLiteBaseService<DatabaseHelper> { public class FoodService extends OrmLiteBaseService<DatabaseHelper> {
private static Logger log = LoggerFactory.getLogger(FoodService.class); private Logger log = LoggerFactory.getLogger(L.DATAFOOD);
private static final ScheduledExecutorService foodEventWorker = Executors.newSingleThreadScheduledExecutor(); private static final ScheduledExecutorService foodEventWorker = Executors.newSingleThreadScheduledExecutor();
private static ScheduledFuture<?> scheduledFoodEventPost = null; private static ScheduledFuture<?> scheduledFoodEventPost = null;
@ -110,6 +111,7 @@ public class FoodService extends OrmLiteBaseService<DatabaseHelper> {
public void onCreate() { public void onCreate() {
super.onCreate(); super.onCreate();
try { try {
if (L.isEnabled(L.DATAFOOD))
log.info("onCreate"); log.info("onCreate");
TableUtils.createTableIfNotExists(this.getConnectionSource(), Food.class); TableUtils.createTableIfNotExists(this.getConnectionSource(), Food.class);
} catch (SQLException e) { } catch (SQLException e) {
@ -119,13 +121,10 @@ public class FoodService extends OrmLiteBaseService<DatabaseHelper> {
} }
public void onUpgrade(ConnectionSource connectionSource, int oldVersion, int newVersion) { public void onUpgrade(ConnectionSource connectionSource, int oldVersion, int newVersion) {
if (oldVersion == 7 && newVersion == 8) { if (L.isEnabled(L.DATAFOOD))
log.debug("Upgrading database from v7 to v8");
} else {
log.info("onUpgrade"); log.info("onUpgrade");
// this.resetFood(); // this.resetFood();
} }
}
public void onDowngrade(ConnectionSource connectionSource, int oldVersion, int newVersion) { public void onDowngrade(ConnectionSource connectionSource, int oldVersion, int newVersion) {
// this method is not supported right now // this method is not supported right now
@ -161,6 +160,7 @@ public class FoodService extends OrmLiteBaseService<DatabaseHelper> {
class PostRunnable implements Runnable { class PostRunnable implements Runnable {
public void run() { public void run() {
if (L.isEnabled(L.DATAFOOD))
log.debug("Firing EventFoodChange"); log.debug("Firing EventFoodChange");
MainApp.bus().post(event); MainApp.bus().post(event);
callback.setPost(null); callback.setPost(null);
@ -271,7 +271,8 @@ public class FoodService extends OrmLiteBaseService<DatabaseHelper> {
public void deleteByNSId(String _id) throws SQLException { public void deleteByNSId(String _id) throws SQLException {
Food stored = this.findByNSId(_id); Food stored = this.findByNSId(_id);
if (stored != null) { if (stored != null) {
log.debug("FOOD: Removing Food record from database: " + stored.toString()); if (L.isEnabled(L.DATAFOOD))
log.debug("Removing Food record from database: " + stored.toString());
this.delete(stored); this.delete(stored);
} }
} }
@ -324,7 +325,8 @@ public class FoodService extends OrmLiteBaseService<DatabaseHelper> {
public void createOrUpdate(Food food) { public void createOrUpdate(Food food) {
try { try {
this.getDao().createOrUpdate(food); this.getDao().createOrUpdate(food);
log.debug("FOOD: Created or Updated: " + food.toString()); if (L.isEnabled(L.DATAFOOD))
log.debug("Created or Updated: " + food.toString());
} catch (SQLException e) { } catch (SQLException e) {
log.error("Unable to createOrUpdate Food", e); log.error("Unable to createOrUpdate Food", e);
} }
@ -334,7 +336,8 @@ public class FoodService extends OrmLiteBaseService<DatabaseHelper> {
public void create(Food food) { public void create(Food food) {
try { try {
this.getDao().create(food); this.getDao().create(food);
log.debug("FOOD: New record: " + food.toString()); if (L.isEnabled(L.DATAFOOD))
log.debug("New record: " + food.toString());
} catch (SQLException e) { } catch (SQLException e) {
log.error("Unable to create Food", e); log.error("Unable to create Food", e);
} }

View file

@ -50,10 +50,10 @@ public class InsulinFragment extends Fragment {
} }
private void updateGUI() { private void updateGUI() {
insulinName.setText(ConfigBuilderPlugin.getActiveInsulin().getFriendlyName()); insulinName.setText(ConfigBuilderPlugin.getPlugin().getActiveInsulin().getFriendlyName());
insulinComment.setText(ConfigBuilderPlugin.getActiveInsulin().getComment()); insulinComment.setText(ConfigBuilderPlugin.getPlugin().getActiveInsulin().getComment());
insulinDia.setText(MainApp.gs(R.string.dia) + " " + Double.toString(ConfigBuilderPlugin.getActiveInsulin().getDia()) + "h"); insulinDia.setText(MainApp.gs(R.string.dia) + " " + Double.toString(ConfigBuilderPlugin.getPlugin().getActiveInsulin().getDia()) + "h");
insulinGraph.show(ConfigBuilderPlugin.getActiveInsulin()); insulinGraph.show(ConfigBuilderPlugin.getPlugin().getActiveInsulin());
} }
} }

View file

@ -5,6 +5,7 @@ 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.plugins.ConfigBuilder.ProfileFunctions;
import info.nightscout.androidaps.plugins.Treatments.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;
@ -29,6 +30,7 @@ public abstract class InsulinOrefBasePlugin extends PluginBase implements Insuli
.fragmentClass(InsulinFragment.class.getName()) .fragmentClass(InsulinFragment.class.getName())
.pluginName(R.string.fastactinginsulin) .pluginName(R.string.fastactinginsulin)
.shortName(R.string.insulin_shortname) .shortName(R.string.insulin_shortname)
.visibleByDefault(false)
); );
} }
@ -60,7 +62,7 @@ public abstract class InsulinOrefBasePlugin extends PluginBase implements Insuli
} }
public double getUserDefinedDia() { public double getUserDefinedDia() {
return MainApp.getConfigBuilder().getProfile() != null ? MainApp.getConfigBuilder().getProfile().getDia() : MIN_DIA; return ProfileFunctions.getInstance().getProfile() != null ? ProfileFunctions.getInstance().getProfile().getDia() : MIN_DIA;
} }
public Iob iobCalcForTreatment(Treatment treatment, long time) { public Iob iobCalcForTreatment(Treatment treatment, long time) {

View file

@ -24,7 +24,8 @@ public class InsulinOrefFreePeakPlugin extends InsulinOrefBasePlugin {
super(); super();
pluginDescription pluginDescription
.pluginName(R.string.free_peak_oref) .pluginName(R.string.free_peak_oref)
.preferencesId(R.xml.pref_insulinoreffreepeak); .preferencesId(R.xml.pref_insulinoreffreepeak)
.description(R.string.description_insulin_free_peak);
} }
@Override @Override

View file

@ -22,7 +22,8 @@ public class InsulinOrefRapidActingPlugin extends InsulinOrefBasePlugin {
private InsulinOrefRapidActingPlugin() { private InsulinOrefRapidActingPlugin() {
super(); super();
pluginDescription pluginDescription
.pluginName(R.string.rapid_acting_oref); .pluginName(R.string.rapid_acting_oref)
.description(R.string.description_insulin_rapid);
} }
@Override @Override

View file

@ -22,7 +22,8 @@ public class InsulinOrefUltraRapidActingPlugin extends InsulinOrefBasePlugin {
private InsulinOrefUltraRapidActingPlugin() { private InsulinOrefUltraRapidActingPlugin() {
super(); super();
pluginDescription pluginDescription
.pluginName(R.string.ultrarapid_oref); .pluginName(R.string.ultrarapid_oref)
.description(R.string.description_insulin_ultra_rapid);
} }
@Override @Override

View file

@ -12,13 +12,16 @@ 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.PluginType; import info.nightscout.androidaps.interfaces.PluginType;
import info.nightscout.androidaps.logging.L;
import info.nightscout.androidaps.plugins.ConfigBuilder.ProfileFunctions;
import info.nightscout.androidaps.plugins.OpenAPSSMB.SMBDefaults; import info.nightscout.androidaps.plugins.OpenAPSSMB.SMBDefaults;
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.graphExtensions.Scale; import info.nightscout.androidaps.plugins.Overview.graphExtensions.Scale;
import info.nightscout.androidaps.plugins.SensitivityAAPS.SensitivityAAPSPlugin; import info.nightscout.androidaps.plugins.Sensitivity.SensitivityAAPSPlugin;
import info.nightscout.androidaps.plugins.SensitivityWeightedAverage.SensitivityWeightedAveragePlugin; import info.nightscout.androidaps.plugins.Sensitivity.SensitivityWeightedAveragePlugin;
import info.nightscout.androidaps.plugins.Treatments.Treatment; import info.nightscout.androidaps.plugins.Treatments.Treatment;
import info.nightscout.utils.DateUtil;
import info.nightscout.utils.SP; import info.nightscout.utils.SP;
/** /**
@ -26,7 +29,7 @@ import info.nightscout.utils.SP;
*/ */
public class AutosensData implements DataPointWithLabelInterface { public class AutosensData implements DataPointWithLabelInterface {
private static Logger log = LoggerFactory.getLogger(AutosensData.class); private static Logger log = LoggerFactory.getLogger(L.AUTOSENS);
public void setChartTime(long chartTime) { public void setChartTime(long chartTime) {
this.chartTime = chartTime; this.chartTime = chartTime;
@ -38,29 +41,42 @@ public class AutosensData implements DataPointWithLabelInterface {
double min5minCarbImpact = 0d; double min5minCarbImpact = 0d;
double remaining = 0d; double remaining = 0d;
public CarbsInPast(Treatment t) { CarbsInPast(Treatment t) {
time = t.date; time = t.date;
carbs = t.carbs; carbs = t.carbs;
remaining = t.carbs; remaining = t.carbs;
if (SensitivityAAPSPlugin.getPlugin().isEnabled(PluginType.SENSITIVITY) || SensitivityWeightedAveragePlugin.getPlugin().isEnabled(PluginType.SENSITIVITY)) { if (SensitivityAAPSPlugin.getPlugin().isEnabled(PluginType.SENSITIVITY) || SensitivityWeightedAveragePlugin.getPlugin().isEnabled(PluginType.SENSITIVITY)) {
double maxAbsorptionHours = SP.getDouble(R.string.key_absorption_maxtime, Constants.DEFAULT_MAX_ABSORPTION_TIME); double maxAbsorptionHours = SP.getDouble(R.string.key_absorption_maxtime, Constants.DEFAULT_MAX_ABSORPTION_TIME);
Profile profile = MainApp.getConfigBuilder().getProfile(t.date); Profile profile = ProfileFunctions.getInstance().getProfile(t.date);
double sens = Profile.toMgdl(profile.getIsf(t.date), profile.getUnits()); double sens = Profile.toMgdl(profile.getIsf(t.date), profile.getUnits());
double ic = profile.getIc(t.date); double ic = profile.getIc(t.date);
min5minCarbImpact = t.carbs / (maxAbsorptionHours * 60 / 5) * sens / ic; min5minCarbImpact = t.carbs / (maxAbsorptionHours * 60 / 5) * sens / ic;
if (L.isEnabled(L.AUTOSENS))
log.debug("Min 5m carbs impact for " + carbs + "g @" + new Date(t.date).toLocaleString() + " for " + maxAbsorptionHours + "h calculated to " + min5minCarbImpact + " ISF: " + sens + " IC: " + ic); log.debug("Min 5m carbs impact for " + carbs + "g @" + new Date(t.date).toLocaleString() + " for " + maxAbsorptionHours + "h calculated to " + min5minCarbImpact + " ISF: " + sens + " IC: " + ic);
} else { } else {
min5minCarbImpact = SP.getDouble(R.string.key_openapsama_min_5m_carbimpact, SMBDefaults.min_5m_carbimpact); min5minCarbImpact = SP.getDouble(R.string.key_openapsama_min_5m_carbimpact, SMBDefaults.min_5m_carbimpact);
} }
} }
CarbsInPast (CarbsInPast other) {
this.time = other.time;
this.carbs = other.carbs;
this.min5minCarbImpact = other.min5minCarbImpact;
this.remaining = other.remaining;
}
@Override
public String toString() {
return String.format("CarbsInPast: time: %s carbs: %.02f min5minCI: %.02f remaining: %.2f", new Date(time).toLocaleString(), carbs, min5minCarbImpact, remaining);
}
} }
public long time = 0L; public long time = 0L;
long chartTime; public double bg = 0; // mgdl
private long chartTime;
public String pastSensitivity = ""; public String pastSensitivity = "";
public double deviation = 0d; public double deviation = 0d;
boolean nonCarbsDeviation = false; public boolean validDeviation = false;
public boolean nonEqualDeviation = false;
List<CarbsInPast> activeCarbsList = new ArrayList<>(); List<CarbsInPast> activeCarbsList = new ArrayList<>();
double absorbed = 0d; double absorbed = 0d;
public double carbsFromBolus = 0d; public double carbsFromBolus = 0d;
@ -70,19 +86,34 @@ public class AutosensData implements DataPointWithLabelInterface {
public double avgDelta = 0d; public double avgDelta = 0d;
public double avgDeviation = 0d; public double avgDeviation = 0d;
public double autosensRatio = 1d; public AutosensResult autosensResult = new AutosensResult();
public double slopeFromMaxDeviation = 0; public double slopeFromMaxDeviation = 0;
public double slopeFromMinDeviation = 999; public double slopeFromMinDeviation = 999;
public double usedMinCarbsImpact = 0d; public double usedMinCarbsImpact = 0d;
public boolean failoverToMinAbsorbtionRate = false; public boolean failoverToMinAbsorbtionRate = false;
// Oref1
public boolean absorbing = false;
public double mealCarbs = 0;
public int mealStartCounter = 999;
public String type = "";
public boolean uam = false;
public List<Double> extraDeviation = new ArrayList<>();
@Override @Override
public String toString() { public String toString() {
return "AutosensData: " + new Date(time).toLocaleString() + " " + pastSensitivity + " Delta=" + delta + " avgDelta=" + avgDelta + " Bgi=" + bgi + " Deviation=" + deviation + " avgDeviation=" + avgDeviation + " Absorbed=" + absorbed + " CarbsFromBolus=" + carbsFromBolus + " COB=" + cob + " autosensRatio=" + autosensRatio + " slopeFromMaxDeviation=" + slopeFromMaxDeviation + " slopeFromMinDeviation =" + slopeFromMinDeviation; return String.format("AutosensData: %s pastSensitivity=%s delta=%.02f avgDelta=%.02f bgi=%.02f deviation=%.02f avgDeviation=%.02f absorbed=%.02f carbsFromBolus=%.02f cob=%.02f autosensRatio=%.02f slopeFromMaxDeviation=%.02f slopeFromMinDeviation=%.02f activeCarbsList=%s",
new Date(time).toLocaleString(), pastSensitivity, delta, avgDelta, bgi, deviation, avgDeviation, absorbed, carbsFromBolus, cob, autosensResult.ratio, slopeFromMaxDeviation, slopeFromMinDeviation, activeCarbsList.toString());
} }
public int minOld() { public List<CarbsInPast> cloneCarbsList() {
return (int) ((System.currentTimeMillis() - time) / 1000 / 60); List<CarbsInPast> newActiveCarbsList = new ArrayList<>();
for(CarbsInPast c: activeCarbsList) {
newActiveCarbsList.add(new CarbsInPast(c));
}
return newActiveCarbsList;
} }
// remove carbs older than timeframe // remove carbs older than timeframe
@ -99,7 +130,8 @@ public class AutosensData implements DataPointWithLabelInterface {
activeCarbsList.remove(i--); activeCarbsList.remove(i--);
if (c.remaining > 0) if (c.remaining > 0)
cob -= c.remaining; cob -= c.remaining;
log.debug("Removing carbs at " + new Date(toTime).toLocaleString() + " + after " + maxAbsorptionHours + "h :" + new Date(c.time).toLocaleString()); if (L.isEnabled(L.AUTOSENS))
log.debug("Removing carbs at " + new Date(toTime).toLocaleString() + " after " + maxAbsorptionHours + "h > " + c.toString());
} }
} }
} }

View file

@ -5,16 +5,18 @@ import org.json.JSONObject;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.logging.L;
/** /**
* Created by mike on 06.01.2017. * Created by mike on 06.01.2017.
*/ */
public class AutosensResult { public class AutosensResult {
private static Logger log = LoggerFactory.getLogger(AutosensResult.class); private static Logger log = LoggerFactory.getLogger(L.AUTOSENS);
//default values to show when autosens algorithm is not called //default values to show when autosens algorithm is not called
public double ratio = 1d; public double ratio = 1d;
public double carbsAbsorbed = 0d; public double carbsAbsorbed = 0d;
public String sensResult = "autosens deactivated"; public String sensResult = "autosens not available";
public String pastSensitivity = ""; public String pastSensitivity = "";
public String ratioLimit = ""; public String ratioLimit = "";
@ -32,4 +34,8 @@ public class AutosensResult {
return ret; return ret;
} }
@Override
public String toString() {
return json().toString();
}
} }

View file

@ -12,10 +12,8 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date;
import java.util.List; import java.util.List;
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;
@ -32,12 +30,16 @@ import info.nightscout.androidaps.events.EventPreferenceChange;
import info.nightscout.androidaps.interfaces.PluginBase; import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.PluginDescription; import info.nightscout.androidaps.interfaces.PluginDescription;
import info.nightscout.androidaps.interfaces.PluginType; import info.nightscout.androidaps.interfaces.PluginType;
import info.nightscout.androidaps.logging.L;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.ConfigBuilder.ProfileFunctions;
import info.nightscout.androidaps.plugins.IobCobCalculator.events.EventNewHistoryData; import info.nightscout.androidaps.plugins.IobCobCalculator.events.EventNewHistoryData;
import info.nightscout.androidaps.plugins.OpenAPSSMB.OpenAPSSMBPlugin; import info.nightscout.androidaps.plugins.OpenAPSSMB.OpenAPSSMBPlugin;
import info.nightscout.androidaps.plugins.Sensitivity.SensitivityOref1Plugin;
import info.nightscout.androidaps.plugins.Treatments.Treatment; import info.nightscout.androidaps.plugins.Treatments.Treatment;
import info.nightscout.androidaps.plugins.Treatments.TreatmentsPlugin; import info.nightscout.androidaps.plugins.Treatments.TreatmentsPlugin;
import info.nightscout.utils.DateUtil; import info.nightscout.utils.DateUtil;
import info.nightscout.utils.T;
import static info.nightscout.utils.DateUtil.now; import static info.nightscout.utils.DateUtil.now;
@ -46,7 +48,7 @@ import static info.nightscout.utils.DateUtil.now;
*/ */
public class IobCobCalculatorPlugin extends PluginBase { public class IobCobCalculatorPlugin extends PluginBase {
private Logger log = LoggerFactory.getLogger(IobCobCalculatorPlugin.class); private Logger log = LoggerFactory.getLogger(L.AUTOSENS);
private static IobCobCalculatorPlugin plugin = null; private static IobCobCalculatorPlugin plugin = null;
@ -68,7 +70,7 @@ public class IobCobCalculatorPlugin extends PluginBase {
final Object dataLock = new Object(); final Object dataLock = new Object();
boolean stopCalculationTrigger = false; boolean stopCalculationTrigger = false;
private IobCobThread thread = null; private Thread thread = null;
public IobCobCalculatorPlugin() { public IobCobCalculatorPlugin() {
super(new PluginDescription() super(new PluginDescription()
@ -96,50 +98,34 @@ public class IobCobCalculatorPlugin extends PluginBase {
return autosensDataTable; return autosensDataTable;
} }
public List<BgReading> getBgReadings() {
return bgReadings;
}
public void setBgReadings(List<BgReading> bgReadings) {
this.bgReadings = bgReadings;
}
public List<BgReading> getBucketedData() { public List<BgReading> getBucketedData() {
return bucketed_data; return bucketed_data;
} }
@Nullable // roundup to whole minute
public List<BgReading> getBucketedData(long fromTime) {
//log.debug("Locking getBucketedData");
synchronized (dataLock) {
if (bucketed_data == null) {
log.debug("No bucketed data available");
return null;
}
int index = indexNewerThan(fromTime);
if (index > -1) {
List<BgReading> part = bucketed_data.subList(0, index);
log.debug("Bucketed data striped off: " + part.size() + "/" + bucketed_data.size());
return part;
}
}
//log.debug("Releasing getBucketedData");
return null;
}
private int indexNewerThan(long time) {
for (int index = 0; index < bucketed_data.size(); index++) {
if (bucketed_data.get(index).date < time)
return index - 1;
}
return -1;
}
public static long roundUpTime(long time) { public static long roundUpTime(long time) {
if (time % 60000 == 0) if (time % 60000 == 0)
return time; return time;
long rouded = (time / 60000 + 1) * 60000; long rounded = (time / 60000 + 1) * 60000;
return rouded; return rounded;
} }
void loadBgData(long start) { void loadBgData(long now) {
bgReadings = MainApp.getDbHelper().getBgreadingsDataFromTime((long) (start - 60 * 60 * 1000L * (24 + dia)), false); long start = (long) (now - 60 * 60 * 1000L * (24 + dia));
log.debug("BG data loaded. Size: " + bgReadings.size() + " Start date: " + DateUtil.dateAndTimeString(start)); bgReadings = MainApp.getDbHelper().getBgreadingsDataFromTime(start, now, false);
if (L.isEnabled(L.AUTOSENS))
log.debug("BG data loaded. Size: " + bgReadings.size() + " Start date: " + DateUtil.dateAndTimeString(start) + " End date: " + DateUtil.dateAndTimeString(now));
} }
private boolean isAbout5minData() { public boolean isAbout5minData() {
synchronized (dataLock) { synchronized (dataLock) {
if (bgReadings == null || bgReadings.size() < 3) { if (bgReadings == null || bgReadings.size() < 3) {
return true; return true;
@ -149,21 +135,26 @@ public class IobCobCalculatorPlugin extends PluginBase {
long bgTime = bgReadings.get(i).date; long bgTime = bgReadings.get(i).date;
long lastbgTime = bgReadings.get(i - 1).date; long lastbgTime = bgReadings.get(i - 1).date;
long diff = lastbgTime - bgTime; long diff = lastbgTime - bgTime;
diff %= T.mins(5).msecs();
if (diff > T.mins(2).plus(T.secs(30)).msecs())
diff = diff - T.mins(5).msecs();
totalDiff += diff; totalDiff += diff;
if (diff > 30 * 1000 && diff < 270 * 1000) { // 0:30 - 4:30 diff = Math.abs(diff);
log.debug("Interval detection: values: " + bgReadings.size() + " diff: " + (diff / 1000) + "sec is5minData: " + false); if (diff > T.secs(30).msecs()) {
if (L.isEnabled(L.AUTOSENS))
log.debug("Interval detection: values: " + bgReadings.size() + " diff: " + (diff / 1000) + "[s] is5minData: " + false);
return false; return false;
} }
} }
double intervals = totalDiff / (5 * 60 * 1000d); long averageDiff = totalDiff / bgReadings.size() / 1000;
double variability = Math.abs(intervals - Math.round(intervals)); boolean is5mindata = averageDiff < 1;
boolean is5mindata = variability < 0.02; if (L.isEnabled(L.AUTOSENS))
log.debug("Interval detection: values: " + bgReadings.size() + " variability: " + variability + " is5minData: " + is5mindata); log.debug("Interval detection: values: " + bgReadings.size() + " averageDiff: " + averageDiff + "[s] is5minData: " + is5mindata);
return is5mindata; return is5mindata;
} }
} }
void createBucketedData() { public void createBucketedData() {
if (isAbout5minData()) if (isAbout5minData())
createBucketedData5min(); createBucketedData5min();
else else
@ -171,24 +162,26 @@ public class IobCobCalculatorPlugin extends PluginBase {
} }
@Nullable @Nullable
private BgReading findNewer(long time) { public BgReading findNewer(long time) {
BgReading lastFound = bgReadings.get(0); BgReading lastFound = bgReadings.get(0);
if (lastFound.date < time) return null; if (lastFound.date < time) return null;
for (int i = 1; i < bgReadings.size(); ++i) { for (int i = 1; i < bgReadings.size(); ++i) {
if (bgReadings.get(i).date == time) return bgReadings.get(i);
if (bgReadings.get(i).date > time) continue; if (bgReadings.get(i).date > time) continue;
lastFound = bgReadings.get(i); lastFound = bgReadings.get(i - 1);
if (bgReadings.get(i).date < time) break; if (bgReadings.get(i).date < time) break;
} }
return lastFound; return lastFound;
} }
@Nullable @Nullable
private BgReading findOlder(long time) { public BgReading findOlder(long time) {
BgReading lastFound = bgReadings.get(bgReadings.size() - 1); BgReading lastFound = bgReadings.get(bgReadings.size() - 1);
if (lastFound.date > time) return null; if (lastFound.date > time) return null;
for (int i = bgReadings.size() - 2; i >= 0; --i) { for (int i = bgReadings.size() - 2; i >= 0; --i) {
if (bgReadings.get(i).date == time) return bgReadings.get(i);
if (bgReadings.get(i).date < time) continue; if (bgReadings.get(i).date < time) continue;
lastFound = bgReadings.get(i); lastFound = bgReadings.get(i + 1);
if (bgReadings.get(i).date > time) break; if (bgReadings.get(i).date > time) break;
} }
return lastFound; return lastFound;
@ -201,7 +194,7 @@ public class IobCobCalculatorPlugin extends PluginBase {
} }
bucketed_data = new ArrayList<>(); bucketed_data = new ArrayList<>();
long currentTime = bgReadings.get(0).date + 5 * 60 * 1000 - bgReadings.get(0).date % (5 * 60 * 1000) - 5 * 60 * 1000L; long currentTime = bgReadings.get(0).date - bgReadings.get(0).date % T.mins(5).msecs();
//log.debug("First reading: " + new Date(currentTime).toLocaleString()); //log.debug("First reading: " + new Date(currentTime).toLocaleString());
while (true) { while (true) {
@ -211,6 +204,9 @@ public class IobCobCalculatorPlugin extends PluginBase {
if (newer == null || older == null) if (newer == null || older == null)
break; break;
if (older.date == newer.date) { // direct hit
bucketed_data.add(newer);
} else {
double bgDelta = newer.value - older.value; double bgDelta = newer.value - older.value;
long timeDiffToNew = newer.date - currentTime; long timeDiffToNew = newer.date - currentTime;
@ -220,7 +216,8 @@ public class IobCobCalculatorPlugin extends PluginBase {
newBgreading.value = Math.round(currentBg); newBgreading.value = Math.round(currentBg);
bucketed_data.add(newBgreading); bucketed_data.add(newBgreading);
//log.debug("BG: " + newBgreading.value + " (" + new Date(newBgreading.date).toLocaleString() + ") Prev: " + older.value + " (" + new Date(older.date).toLocaleString() + ") Newer: " + newer.value + " (" + new Date(newer.date).toLocaleString() + ")"); //log.debug("BG: " + newBgreading.value + " (" + new Date(newBgreading.date).toLocaleString() + ") Prev: " + older.value + " (" + new Date(older.date).toLocaleString() + ") Newer: " + newer.value + " (" + new Date(newer.date).toLocaleString() + ")");
currentTime -= 5 * 60 * 1000L; }
currentTime -= T.mins(5).msecs();
} }
} }
@ -234,13 +231,15 @@ public class IobCobCalculatorPlugin extends PluginBase {
bucketed_data = new ArrayList<>(); bucketed_data = new ArrayList<>();
bucketed_data.add(bgReadings.get(0)); bucketed_data.add(bgReadings.get(0));
if (L.isEnabled(L.AUTOSENS))
log.debug("Adding. bgTime: " + DateUtil.toISOString(bgReadings.get(0).date) + " lastbgTime: " + "none-first-value" + " " + bgReadings.get(0).toString());
int j = 0; int j = 0;
for (int i = 1; i < bgReadings.size(); ++i) { for (int i = 1; i < bgReadings.size(); ++i) {
long bgTime = bgReadings.get(i).date; long bgTime = bgReadings.get(i).date;
long lastbgTime = bgReadings.get(i - 1).date; long lastbgTime = bgReadings.get(i - 1).date;
//log.error("Processing " + i + ": " + new Date(bgTime).toString() + " " + bgReadings.get(i).value + " Previous: " + new Date(lastbgTime).toString() + " " + bgReadings.get(i - 1).value); //log.error("Processing " + i + ": " + new Date(bgTime).toString() + " " + bgReadings.get(i).value + " Previous: " + new Date(lastbgTime).toString() + " " + bgReadings.get(i - 1).value);
if (bgReadings.get(i).value < 39 || bgReadings.get(i - 1).value < 39) { if (bgReadings.get(i).value < 39 || bgReadings.get(i - 1).value < 39) {
continue; throw new IllegalStateException("<39");
} }
long elapsed_minutes = (bgTime - lastbgTime) / (60 * 1000); long elapsed_minutes = (bgTime - lastbgTime) / (60 * 1000);
@ -261,7 +260,8 @@ public class IobCobCalculatorPlugin extends PluginBase {
newBgreading.value = Math.round(nextbg); newBgreading.value = Math.round(nextbg);
//console.error("Interpolated", bucketed_data[j]); //console.error("Interpolated", bucketed_data[j]);
bucketed_data.add(newBgreading); bucketed_data.add(newBgreading);
//log.error("******************************************************************************************************* Adding:" + new Date(newBgreading.date).toString() + " " + newBgreading.value); if (L.isEnabled(L.AUTOSENS))
log.debug("Adding. bgTime: " + DateUtil.toISOString(bgTime) + " lastbgTime: " + DateUtil.toISOString(lastbgTime) + " " + newBgreading.toString());
elapsed_minutes = elapsed_minutes - 5; elapsed_minutes = elapsed_minutes - 5;
lastbg = nextbg; lastbg = nextbg;
@ -272,28 +272,58 @@ public class IobCobCalculatorPlugin extends PluginBase {
newBgreading.value = bgReadings.get(i).value; newBgreading.value = bgReadings.get(i).value;
newBgreading.date = bgTime; newBgreading.date = bgTime;
bucketed_data.add(newBgreading); bucketed_data.add(newBgreading);
//log.error("******************************************************************************************************* Copying:" + new Date(newBgreading.date).toString() + " " + newBgreading.value); if (L.isEnabled(L.AUTOSENS))
log.debug("Adding. bgTime: " + DateUtil.toISOString(bgTime) + " lastbgTime: " + DateUtil.toISOString(lastbgTime) + " " + newBgreading.toString());
} else if (Math.abs(elapsed_minutes) > 2) { } else if (Math.abs(elapsed_minutes) > 2) {
j++; j++;
BgReading newBgreading = new BgReading(); BgReading newBgreading = new BgReading();
newBgreading.value = bgReadings.get(i).value; newBgreading.value = bgReadings.get(i).value;
newBgreading.date = bgTime; newBgreading.date = bgTime;
bucketed_data.add(newBgreading); bucketed_data.add(newBgreading);
//log.error("******************************************************************************************************* Copying:" + new Date(newBgreading.date).toString() + " " + newBgreading.value); if (L.isEnabled(L.AUTOSENS))
log.debug("Adding. bgTime: " + DateUtil.toISOString(bgTime) + " lastbgTime: " + DateUtil.toISOString(lastbgTime) + " " + newBgreading.toString());
} else { } else {
bucketed_data.get(j).value = (bucketed_data.get(j).value + bgReadings.get(i).value) / 2; bucketed_data.get(j).value = (bucketed_data.get(j).value + bgReadings.get(i).value) / 2;
//log.error("***** Average"); //log.error("***** Average");
} }
} }
// Normalize bucketed data
for (int i = bucketed_data.size() - 2; i >= 0; i--) {
BgReading current = bucketed_data.get(i);
BgReading previous = bucketed_data.get(i + 1);
long msecDiff = current.date - previous.date;
long adjusted = (msecDiff - T.mins(5).msecs()) / 1000;
if (L.isEnabled(L.AUTOSENS))
log.debug("Adjusting bucketed data time. Current: " + DateUtil.toISOString(current.date) + " to: " + DateUtil.toISOString(previous.date + T.mins(5).msecs()) + " by " + adjusted + " sec");
if (Math.abs(adjusted) > 90) {
// too big adjustment, fallback to non 5 min data
if (L.isEnabled(L.AUTOSENS))
log.debug("Fallback to non 5 min data");
createBucketedDataRecalculated();
return;
}
current.date = previous.date + T.mins(5).msecs();
}
if (L.isEnabled(L.AUTOSENS))
log.debug("Bucketed data created. Size: " + bucketed_data.size()); log.debug("Bucketed data created. Size: " + bucketed_data.size());
} }
public long oldestDataAvailable() { public long calculateDetectionStart(long from, boolean limitDataToOldestAvailable) {
long now = System.currentTimeMillis(); Profile profile = ProfileFunctions.getInstance().getProfile(from);
double dia = Constants.defaultDIA;
if (profile != null) dia = profile.getDia();
long oldestDataAvailable = TreatmentsPlugin.getPlugin().oldestDataAvailable(); long oldestDataAvailable = TreatmentsPlugin.getPlugin().oldestDataAvailable();
long getBGDataFrom = Math.max(oldestDataAvailable, (long) (now - 60 * 60 * 1000L * (24 + MainApp.getConfigBuilder().getProfile().getDia()))); long getBGDataFrom;
log.debug("Limiting data to oldest available temps: " + new Date(oldestDataAvailable).toString()); if (limitDataToOldestAvailable) {
getBGDataFrom = Math.max(oldestDataAvailable, (long) (from - T.hours(1).msecs() * (24 + dia)));
if (getBGDataFrom == oldestDataAvailable)
if (L.isEnabled(L.AUTOSENS))
log.debug("Limiting data to oldest available temps: " + DateUtil.dateAndTimeFullString(oldestDataAvailable));
} else
getBGDataFrom = (long) (from - T.hours(1).msecs() * (24 + dia));
return getBGDataFrom; return getBGDataFrom;
} }
@ -337,11 +367,11 @@ public class IobCobCalculatorPlugin extends PluginBase {
} }
@Nullable @Nullable
private Long findPreviousTimeFromBucketedData(long time) { public Long findPreviousTimeFromBucketedData(long time) {
if (bucketed_data == null) if (bucketed_data == null)
return null; return null;
for (int index = 0; index < bucketed_data.size(); index++) { for (int index = 0; index < bucketed_data.size(); index++) {
if (bucketed_data.get(index).date < time) if (bucketed_data.get(index).date <= time)
return bucketed_data.get(index).date; return bucketed_data.get(index).date;
} }
return null; return null;
@ -376,22 +406,20 @@ public class IobCobCalculatorPlugin extends PluginBase {
public AutosensData getAutosensData(long time) { public AutosensData getAutosensData(long time) {
synchronized (dataLock) { synchronized (dataLock) {
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
if (time > now) if (time > now) {
return null; return null;
}
Long previous = findPreviousTimeFromBucketedData(time); Long previous = findPreviousTimeFromBucketedData(time);
if (previous == null) if (previous == null) {
return null; return null;
}
time = roundUpTime(previous); time = roundUpTime(previous);
AutosensData data = autosensDataTable.get(time); AutosensData data = autosensDataTable.get(time);
if (data != null) { if (data != null) {
//log.debug(">>> getAutosensData Cache hit " + data.log(time)); //log.debug(">>> AUTOSENSDATA Cache hit " + data.toString());
return data; return data;
} else { } else {
if (time > now) { //log.debug(">>> AUTOSENSDATA Cache miss " + new Date(time).toLocaleString());
// data may not be calculated yet, use last data
return getLastAutosensData("getAutosensData");
}
//log.debug(">>> getAutosensData Cache miss " + new Date(time).toLocaleString());
return null; return null;
} }
} }
@ -399,6 +427,16 @@ public class IobCobCalculatorPlugin extends PluginBase {
@Nullable @Nullable
public AutosensData getLastAutosensDataSynchronized(String reason) { public AutosensData getLastAutosensDataSynchronized(String reason) {
if (thread != null && thread.isAlive()) {
if (L.isEnabled(L.AUTOSENS))
log.debug("AUTOSENSDATA is waiting for calculation thread: " + reason);
try {
thread.join(5000);
} catch (InterruptedException ignored) {
}
if (L.isEnabled(L.AUTOSENS))
log.debug("AUTOSENSDATA finished waiting for calculation thread: " + reason);
}
synchronized (dataLock) { synchronized (dataLock) {
return getLastAutosensData(reason); return getLastAutosensData(reason);
} }
@ -435,6 +473,7 @@ public class IobCobCalculatorPlugin extends PluginBase {
@Nullable @Nullable
public AutosensData getLastAutosensData(String reason) { public AutosensData getLastAutosensData(String reason) {
if (autosensDataTable.size() < 1) { if (autosensDataTable.size() < 1) {
if (L.isEnabled(L.AUTOSENS))
log.debug("AUTOSENSDATA null: autosensDataTable empty (" + reason + ")"); log.debug("AUTOSENSDATA null: autosensDataTable empty (" + reason + ")");
return null; return null;
} }
@ -449,13 +488,23 @@ public class IobCobCalculatorPlugin extends PluginBase {
return null; return null;
} }
if (data.time < System.currentTimeMillis() - 11 * 60 * 1000) { if (data.time < System.currentTimeMillis() - 11 * 60 * 1000) {
if (L.isEnabled(L.AUTOSENS))
log.debug("AUTOSENSDATA null: data is old (" + reason + ") size()=" + autosensDataTable.size() + " lastdata=" + DateUtil.dateAndTimeString(data.time)); log.debug("AUTOSENSDATA null: data is old (" + reason + ") size()=" + autosensDataTable.size() + " lastdata=" + DateUtil.dateAndTimeString(data.time));
return null; return null;
} else { } else {
if (L.isEnabled(L.AUTOSENS))
log.debug("AUTOSENSDATA (" + reason + ") " + data.toString());
return data; return data;
} }
} }
public String lastDataTime() {
if (autosensDataTable.size() > 0)
return DateUtil.dateAndTimeString(autosensDataTable.valueAt(autosensDataTable.size() - 1).time);
else
return "autosensDataTable empty";
}
public IobTotal[] calculateIobArrayInDia(Profile profile) { public IobTotal[] calculateIobArrayInDia(Profile profile) {
// predict IOB out to DIA plus 30m // predict IOB out to DIA plus 30m
long time = System.currentTimeMillis(); long time = System.currentTimeMillis();
@ -490,14 +539,10 @@ public class IobCobCalculatorPlugin extends PluginBase {
public AutosensResult detectSensitivityWithLock(long fromTime, long toTime) { public AutosensResult detectSensitivityWithLock(long fromTime, long toTime) {
synchronized (dataLock) { synchronized (dataLock) {
return detectSensitivity(fromTime, toTime); return ConfigBuilderPlugin.getPlugin().getActiveSensitivity().detectSensitivity(this, fromTime, toTime);
} }
} }
static AutosensResult detectSensitivity(long fromTime, long toTime) {
return ConfigBuilderPlugin.getActiveSensitivity().detectSensitivity(fromTime, toTime);
}
public static JSONArray convertToJSONArray(IobTotal[] iobArray) { public static JSONArray convertToJSONArray(IobTotal[] iobArray) {
JSONArray array = new JSONArray(); JSONArray array = new JSONArray();
for (int i = 0; i < iobArray.length; i++) { for (int i = 0; i < iobArray.length; i++) {
@ -510,38 +555,46 @@ public class IobCobCalculatorPlugin extends PluginBase {
@SuppressWarnings("unused") @SuppressWarnings("unused")
public void onEventAppInitialized(EventAppInitialized ev) { public void onEventAppInitialized(EventAppInitialized ev) {
if (this != getPlugin()) { if (this != getPlugin()) {
if (L.isEnabled(L.AUTOSENS))
log.debug("Ignoring event for non default instance"); log.debug("Ignoring event for non default instance");
return; return;
} }
runCalculation("onEventAppInitialized", System.currentTimeMillis(), true, ev); runCalculation("onEventAppInitialized", System.currentTimeMillis(), true, true, ev);
} }
@Subscribe @Subscribe
@SuppressWarnings("unused") @SuppressWarnings("unused")
public void onEventNewBG(EventNewBG ev) { public void onEventNewBG(EventNewBG ev) {
if (this != getPlugin()) { if (this != getPlugin()) {
if (L.isEnabled(L.AUTOSENS))
log.debug("Ignoring event for non default instance"); log.debug("Ignoring event for non default instance");
return; return;
} }
stopCalculation("onEventNewBG"); stopCalculation("onEventNewBG");
runCalculation("onEventNewBG", System.currentTimeMillis(), true, ev); runCalculation("onEventNewBG", System.currentTimeMillis(), true, true, ev);
} }
private void stopCalculation(String from) { public void stopCalculation(String from) {
if (thread != null && thread.getState() != Thread.State.TERMINATED) { if (thread != null && thread.getState() != Thread.State.TERMINATED) {
stopCalculationTrigger = true; stopCalculationTrigger = true;
if (L.isEnabled(L.AUTOSENS))
log.debug("Stopping calculation thread: " + from); log.debug("Stopping calculation thread: " + from);
while (thread.getState() != Thread.State.TERMINATED) { while (thread.getState() != Thread.State.TERMINATED) {
SystemClock.sleep(100); SystemClock.sleep(100);
} }
if (L.isEnabled(L.AUTOSENS))
log.debug("Calculation thread stopped: " + from); log.debug("Calculation thread stopped: " + from);
} }
} }
public void runCalculation(String from, long start, boolean bgDataReload, Event cause) { public void runCalculation(String from, long end, boolean bgDataReload, boolean limitDataToOldestAvailable, Event cause) {
log.debug("Starting calculation thread: " + from); if (L.isEnabled(L.AUTOSENS))
log.debug("Starting calculation thread: " + from + " to " + DateUtil.dateAndTimeString(end));
if (thread == null || thread.getState() == Thread.State.TERMINATED) { if (thread == null || thread.getState() == Thread.State.TERMINATED) {
thread = new IobCobThread(this, from, start, bgDataReload, cause); if (SensitivityOref1Plugin.getPlugin().isEnabled(PluginType.SENSITIVITY))
thread = new IobCobOref1Thread(this, from, end, bgDataReload, limitDataToOldestAvailable, cause);
else
thread = new IobCobThread(this, from, end, bgDataReload, limitDataToOldestAvailable, cause);
thread.start(); thread.start();
} }
} }
@ -549,12 +602,13 @@ public class IobCobCalculatorPlugin extends PluginBase {
@Subscribe @Subscribe
public void onNewProfile(EventNewBasalProfile ev) { public void onNewProfile(EventNewBasalProfile ev) {
if (this != getPlugin()) { if (this != getPlugin()) {
if (L.isEnabled(L.AUTOSENS))
log.debug("Ignoring event for non default instance"); log.debug("Ignoring event for non default instance");
return; return;
} }
if (MainApp.getConfigBuilder() == null) if (ConfigBuilderPlugin.getPlugin() == null)
return; // app still initializing return; // app still initializing
Profile profile = MainApp.getConfigBuilder().getProfile(); Profile profile = ProfileFunctions.getInstance().getProfile();
if (profile == null) if (profile == null)
return; // app still initializing return; // app still initializing
dia = profile.getDia(); dia = profile.getDia();
@ -563,16 +617,18 @@ public class IobCobCalculatorPlugin extends PluginBase {
} }
stopCalculation("onNewProfile"); stopCalculation("onNewProfile");
synchronized (dataLock) { synchronized (dataLock) {
if (L.isEnabled(L.AUTOSENS))
log.debug("Invalidating cached data because of new profile. IOB: " + iobTable.size() + " Autosens: " + autosensDataTable.size() + " records"); log.debug("Invalidating cached data because of new profile. IOB: " + iobTable.size() + " Autosens: " + autosensDataTable.size() + " records");
iobTable = new LongSparseArray<>(); iobTable = new LongSparseArray<>();
autosensDataTable = new LongSparseArray<>(); autosensDataTable = new LongSparseArray<>();
} }
runCalculation("onNewProfile", System.currentTimeMillis(), false, ev); runCalculation("onNewProfile", System.currentTimeMillis(), false, true, ev);
} }
@Subscribe @Subscribe
public void onEventPreferenceChange(EventPreferenceChange ev) { public void onEventPreferenceChange(EventPreferenceChange ev) {
if (this != getPlugin()) { if (this != getPlugin()) {
if (L.isEnabled(L.AUTOSENS))
log.debug("Ignoring event for non default instance"); log.debug("Ignoring event for non default instance");
return; return;
} }
@ -580,37 +636,43 @@ public class IobCobCalculatorPlugin extends PluginBase {
ev.isChanged(R.string.key_age) || ev.isChanged(R.string.key_age) ||
ev.isChanged(R.string.key_absorption_maxtime) || ev.isChanged(R.string.key_absorption_maxtime) ||
ev.isChanged(R.string.key_openapsama_min_5m_carbimpact) || ev.isChanged(R.string.key_openapsama_min_5m_carbimpact) ||
ev.isChanged(R.string.key_absorption_cutoff) ev.isChanged(R.string.key_absorption_cutoff) ||
ev.isChanged(R.string.key_openapsama_autosens_max) ||
ev.isChanged(R.string.key_openapsama_autosens_min)
) { ) {
stopCalculation("onEventPreferenceChange"); stopCalculation("onEventPreferenceChange");
synchronized (dataLock) { synchronized (dataLock) {
if (L.isEnabled(L.AUTOSENS))
log.debug("Invalidating cached data because of preference change. IOB: " + iobTable.size() + " Autosens: " + autosensDataTable.size() + " records"); log.debug("Invalidating cached data because of preference change. IOB: " + iobTable.size() + " Autosens: " + autosensDataTable.size() + " records");
iobTable = new LongSparseArray<>(); iobTable = new LongSparseArray<>();
autosensDataTable = new LongSparseArray<>(); autosensDataTable = new LongSparseArray<>();
} }
runCalculation("onEventPreferenceChange", System.currentTimeMillis(), false, ev); runCalculation("onEventPreferenceChange", System.currentTimeMillis(), false, true, ev);
} }
} }
@Subscribe @Subscribe
public void onEventConfigBuilderChange(EventConfigBuilderChange ev) { public void onEventConfigBuilderChange(EventConfigBuilderChange ev) {
if (this != getPlugin()) { if (this != getPlugin()) {
if (L.isEnabled(L.AUTOSENS))
log.debug("Ignoring event for non default instance"); log.debug("Ignoring event for non default instance");
return; return;
} }
stopCalculation("onEventConfigBuilderChange"); stopCalculation("onEventConfigBuilderChange");
synchronized (dataLock) { synchronized (dataLock) {
if (L.isEnabled(L.AUTOSENS))
log.debug("Invalidating cached data because of configuration change. IOB: " + iobTable.size() + " Autosens: " + autosensDataTable.size() + " records"); log.debug("Invalidating cached data because of configuration change. IOB: " + iobTable.size() + " Autosens: " + autosensDataTable.size() + " records");
iobTable = new LongSparseArray<>(); iobTable = new LongSparseArray<>();
autosensDataTable = new LongSparseArray<>(); autosensDataTable = new LongSparseArray<>();
} }
runCalculation("onEventConfigBuilderChange", System.currentTimeMillis(), false, ev); runCalculation("onEventConfigBuilderChange", System.currentTimeMillis(), false, true, ev);
} }
// When historical data is changed (comming from NS etc) finished calculations after this date must be invalidated // When historical data is changed (comming from NS etc) finished calculations after this date must be invalidated
@Subscribe @Subscribe
public void onEventNewHistoryData(EventNewHistoryData ev) { public void onEventNewHistoryData(EventNewHistoryData ev) {
if (this != getPlugin()) { if (this != getPlugin()) {
if (L.isEnabled(L.AUTOSENS))
log.debug("Ignoring event for non default instance"); log.debug("Ignoring event for non default instance");
return; return;
} }
@ -619,11 +681,12 @@ public class IobCobCalculatorPlugin extends PluginBase {
synchronized (dataLock) { synchronized (dataLock) {
// clear up 5 min back for proper COB calculation // clear up 5 min back for proper COB calculation
long time = ev.time - 5 * 60 * 1000L; long time = ev.time - 5 * 60 * 1000L;
log.debug("Invalidating cached data to: " + new Date(time).toLocaleString()); if (L.isEnabled(L.AUTOSENS))
log.debug("Invalidating cached data to: " + DateUtil.dateAndTimeFullString(time));
for (int index = iobTable.size() - 1; index >= 0; index--) { for (int index = iobTable.size() - 1; index >= 0; index--) {
if (iobTable.keyAt(index) > time) { if (iobTable.keyAt(index) > time) {
if (Config.logAutosensData) if (L.isEnabled(L.AUTOSENS))
log.debug("Removing from iobTable: " + new Date(iobTable.keyAt(index)).toLocaleString()); log.debug("Removing from iobTable: " + DateUtil.dateAndTimeFullString(iobTable.keyAt(index)));
iobTable.removeAt(index); iobTable.removeAt(index);
} else { } else {
break; break;
@ -631,8 +694,8 @@ public class IobCobCalculatorPlugin extends PluginBase {
} }
for (int index = autosensDataTable.size() - 1; index >= 0; index--) { for (int index = autosensDataTable.size() - 1; index >= 0; index--) {
if (autosensDataTable.keyAt(index) > time) { if (autosensDataTable.keyAt(index) > time) {
if (Config.logAutosensData) if (L.isEnabled(L.AUTOSENS))
log.debug("Removing from autosensDataTable: " + new Date(autosensDataTable.keyAt(index)).toLocaleString()); log.debug("Removing from autosensDataTable: " + DateUtil.dateAndTimeFullString(autosensDataTable.keyAt(index)));
autosensDataTable.removeAt(index); autosensDataTable.removeAt(index);
} else { } else {
break; break;
@ -640,20 +703,21 @@ public class IobCobCalculatorPlugin extends PluginBase {
} }
for (int index = basalDataTable.size() - 1; index >= 0; index--) { for (int index = basalDataTable.size() - 1; index >= 0; index--) {
if (basalDataTable.keyAt(index) > time) { if (basalDataTable.keyAt(index) > time) {
if (Config.logAutosensData) if (L.isEnabled(L.AUTOSENS))
log.debug("Removing from basalDataTable: " + new Date(basalDataTable.keyAt(index)).toLocaleString()); log.debug("Removing from basalDataTable: " + DateUtil.dateAndTimeFullString(basalDataTable.keyAt(index)));
basalDataTable.removeAt(index); basalDataTable.removeAt(index);
} else { } else {
break; break;
} }
} }
} }
runCalculation("onEventNewHistoryData", System.currentTimeMillis(), false, ev); runCalculation("onEventNewHistoryData", System.currentTimeMillis(), false, true, ev);
//log.debug("Releasing onNewHistoryData"); //log.debug("Releasing onNewHistoryData");
} }
public void clearCache() { public void clearCache() {
synchronized (dataLock) { synchronized (dataLock) {
if (L.isEnabled(L.AUTOSENS))
log.debug("Clearing cached data."); log.debug("Clearing cached data.");
iobTable = new LongSparseArray<>(); iobTable = new LongSparseArray<>();
autosensDataTable = new LongSparseArray<>(); autosensDataTable = new LongSparseArray<>();

View file

@ -0,0 +1,407 @@
package info.nightscout.androidaps.plugins.IobCobCalculator;
import android.content.Context;
import android.os.PowerManager;
import android.os.SystemClock;
import android.support.v4.util.LongSparseArray;
import com.crashlytics.android.answers.CustomEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import info.nightscout.androidaps.BuildConfig;
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.IobTotal;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.db.BgReading;
import info.nightscout.androidaps.db.TempTarget;
import info.nightscout.androidaps.events.Event;
import info.nightscout.androidaps.logging.L;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.ConfigBuilder.ProfileFunctions;
import info.nightscout.androidaps.plugins.IobCobCalculator.events.EventAutosensCalculationFinished;
import info.nightscout.androidaps.plugins.IobCobCalculator.events.EventIobCalculationProgress;
import info.nightscout.androidaps.plugins.OpenAPSSMB.SMBDefaults;
import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification;
import info.nightscout.androidaps.plugins.Overview.notifications.Notification;
import info.nightscout.androidaps.plugins.Treatments.Treatment;
import info.nightscout.androidaps.plugins.Treatments.TreatmentsPlugin;
import info.nightscout.utils.DateUtil;
import info.nightscout.utils.DecimalFormatter;
import info.nightscout.utils.FabricPrivacy;
import info.nightscout.utils.MidnightTime;
import info.nightscout.utils.Profiler;
import info.nightscout.utils.SP;
import static info.nightscout.utils.DateUtil.now;
import static java.util.Calendar.MINUTE;
/**
* Created by mike on 23.01.2018.
*/
public class IobCobOref1Thread extends Thread {
private static Logger log = LoggerFactory.getLogger(L.AUTOSENS);
private final Event cause;
private IobCobCalculatorPlugin iobCobCalculatorPlugin;
private boolean bgDataReload;
private boolean limitDataToOldestAvailable;
private String from;
private long end;
private PowerManager.WakeLock mWakeLock;
public IobCobOref1Thread(IobCobCalculatorPlugin plugin, String from, long end, boolean bgDataReload, boolean limitDataToOldestAvailable, Event cause) {
super();
this.iobCobCalculatorPlugin = plugin;
this.bgDataReload = bgDataReload;
this.limitDataToOldestAvailable = limitDataToOldestAvailable;
this.from = from;
this.cause = cause;
this.end = end;
PowerManager powerManager = (PowerManager) MainApp.instance().getApplicationContext().getSystemService(Context.POWER_SERVICE);
mWakeLock = powerManager.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, "iobCobThread");
}
@Override
public final void run() {
long start = DateUtil.now();
mWakeLock.acquire();
try {
if (L.isEnabled(L.AUTOSENS))
log.debug("AUTOSENSDATA thread started: " + from);
if (ConfigBuilderPlugin.getPlugin() == null) {
if (L.isEnabled(L.AUTOSENS))
log.debug("Aborting calculation thread (ConfigBuilder not ready): " + from);
return; // app still initializing
}
if (!ProfileFunctions.getInstance().isProfileValid("IobCobThread")) {
if (L.isEnabled(L.AUTOSENS))
log.debug("Aborting calculation thread (No profile): " + from);
return; // app still initializing
}
//log.debug("Locking calculateSensitivityData");
long oldestTimeWithData = iobCobCalculatorPlugin.calculateDetectionStart(end, limitDataToOldestAvailable);
synchronized (iobCobCalculatorPlugin.dataLock) {
if (bgDataReload) {
iobCobCalculatorPlugin.loadBgData(end);
iobCobCalculatorPlugin.createBucketedData();
}
List<BgReading> bucketed_data = iobCobCalculatorPlugin.getBucketedData();
LongSparseArray<AutosensData> autosensDataTable = iobCobCalculatorPlugin.getAutosensDataTable();
if (bucketed_data == null || bucketed_data.size() < 3) {
if (L.isEnabled(L.AUTOSENS))
log.debug("Aborting calculation thread (No bucketed data available): " + from);
return;
}
long prevDataTime = IobCobCalculatorPlugin.roundUpTime(bucketed_data.get(bucketed_data.size() - 3).date);
if (L.isEnabled(L.AUTOSENS))
log.debug("Prev data time: " + new Date(prevDataTime).toLocaleString());
AutosensData previous = autosensDataTable.get(prevDataTime);
// start from oldest to be able sub cob
for (int i = bucketed_data.size() - 4; i >= 0; i--) {
String progress = i + (MainApp.isDev() ? " (" + from + ")" : "");
MainApp.bus().post(new EventIobCalculationProgress(progress));
if (iobCobCalculatorPlugin.stopCalculationTrigger) {
iobCobCalculatorPlugin.stopCalculationTrigger = false;
if (L.isEnabled(L.AUTOSENS))
log.debug("Aborting calculation thread (trigger): " + from);
return;
}
// check if data already exists
long bgTime = bucketed_data.get(i).date;
bgTime = IobCobCalculatorPlugin.roundUpTime(bgTime);
if (bgTime > IobCobCalculatorPlugin.roundUpTime(now()))
continue;
AutosensData existing;
if ((existing = autosensDataTable.get(bgTime)) != null) {
previous = existing;
continue;
}
Profile profile = ProfileFunctions.getInstance().getProfile(bgTime);
if (profile == null) {
if (L.isEnabled(L.AUTOSENS))
log.debug("Aborting calculation thread (no profile): " + from);
return; // profile not set yet
}
if (L.isEnabled(L.AUTOSENS))
log.debug("Processing calculation thread: " + from + " (" + i + "/" + bucketed_data.size() + ")");
double sens = Profile.toMgdl(profile.getIsf(bgTime), profile.getUnits());
AutosensData autosensData = new AutosensData();
autosensData.time = bgTime;
if (previous != null)
autosensData.activeCarbsList = previous.cloneCarbsList();
else
autosensData.activeCarbsList = new ArrayList<>();
//console.error(bgTime , bucketed_data[i].glucose);
double bg;
double avgDelta;
double delta;
bg = bucketed_data.get(i).value;
if (bg < 39 || bucketed_data.get(i + 3).value < 39) {
log.error("! value < 39");
continue;
}
autosensData.bg = bg;
delta = (bg - bucketed_data.get(i + 1).value);
avgDelta = (bg - bucketed_data.get(i + 3).value) / 3;
IobTotal iob = iobCobCalculatorPlugin.calculateFromTreatmentsAndTemps(bgTime, profile);
double bgi = -iob.activity * sens * 5;
double deviation = delta - bgi;
double avgDeviation = Math.round((avgDelta - bgi) * 1000) / 1000;
double slopeFromMaxDeviation = 0;
double slopeFromMinDeviation = 999;
double maxDeviation = 0;
double minDeviation = 999;
// https://github.com/openaps/oref0/blob/master/lib/determine-basal/cob-autosens.js#L169
if (i < bucketed_data.size() - 16) { // we need 1h of data to calculate minDeviationSlope
long hourago = bgTime + 10 * 1000 - 60 * 60 * 1000L;
AutosensData hourAgoData = iobCobCalculatorPlugin.getAutosensData(hourago);
if (hourAgoData != null) {
int initialIndex = autosensDataTable.indexOfKey(hourAgoData.time);
if (L.isEnabled(L.AUTOSENS))
log.debug(">>>>> bucketed_data.size()=" + bucketed_data.size() + " i=" + i + " hourAgoData=" + hourAgoData.toString());
int past = 1;
try {
for (; past < 12; past++) {
AutosensData ad = autosensDataTable.valueAt(initialIndex + past);
if (L.isEnabled(L.AUTOSENS)) {
log.debug(">>>>> past=" + past + " ad=" + (ad != null ? ad.toString() : null));
if (ad == null) {
log.debug(autosensDataTable.toString());
log.debug(bucketed_data.toString());
log.debug(IobCobCalculatorPlugin.getPlugin().getBgReadings().toString());
Notification notification = new Notification(Notification.SENDLOGFILES, MainApp.gs(R.string.sendlogfiles), Notification.LOW);
MainApp.bus().post(new EventNewNotification(notification));
SP.putBoolean("log_AUTOSENS", true);
break;
}
}
// let it here crash on NPE to get more data as i cannot reproduce this bug
double deviationSlope = (ad.avgDeviation - avgDeviation) / (ad.time - bgTime) * 1000 * 60 * 5;
if (ad.avgDeviation > maxDeviation) {
slopeFromMaxDeviation = Math.min(0, deviationSlope);
maxDeviation = ad.avgDeviation;
}
if (ad.avgDeviation < minDeviation) {
slopeFromMinDeviation = Math.max(0, deviationSlope);
minDeviation = ad.avgDeviation;
}
//if (Config.isEnabled(L.AUTOSENS))
// log.debug("Deviations: " + new Date(bgTime) + new Date(ad.time) + " avgDeviation=" + avgDeviation + " deviationSlope=" + deviationSlope + " slopeFromMaxDeviation=" + slopeFromMaxDeviation + " slopeFromMinDeviation=" + slopeFromMinDeviation);
}
} catch (Exception e) {
log.error("Unhandled exception", e);
FabricPrivacy.logException(e);
FabricPrivacy.getInstance().logCustom(new CustomEvent("CatchedError")
.putCustomAttribute("buildversion", BuildConfig.BUILDVERSION)
.putCustomAttribute("version", BuildConfig.VERSION)
.putCustomAttribute("autosensDataTable", iobCobCalculatorPlugin.getAutosensDataTable().toString())
.putCustomAttribute("for_data", ">>>>> bucketed_data.size()=" + bucketed_data.size() + " i=" + i + "hourAgoData=" + hourAgoData.toString())
.putCustomAttribute("past", past)
);
log.debug(autosensDataTable.toString());
log.debug(bucketed_data.toString());
log.debug(IobCobCalculatorPlugin.getPlugin().getBgReadings().toString());
Notification notification = new Notification(Notification.SENDLOGFILES, MainApp.gs(R.string.sendlogfiles), Notification.LOW);
MainApp.bus().post(new EventNewNotification(notification));
SP.putBoolean("log_AUTOSENS", true);
break;
}
} else {
if (L.isEnabled(L.AUTOSENS))
log.debug(">>>>> bucketed_data.size()=" + bucketed_data.size() + " i=" + i + " hourAgoData=" + "null");
}
}
List<Treatment> recentTreatments = TreatmentsPlugin.getPlugin().getTreatments5MinBackFromHistory(bgTime);
for (int ir = 0; ir < recentTreatments.size(); ir++) {
autosensData.carbsFromBolus += recentTreatments.get(ir).carbs;
autosensData.activeCarbsList.add(new AutosensData.CarbsInPast(recentTreatments.get(ir)));
autosensData.pastSensitivity += "[" + DecimalFormatter.to0Decimal(recentTreatments.get(ir).carbs) + "g]";
}
// if we are absorbing carbs
if (previous != null && previous.cob > 0) {
// calculate sum of min carb impact from all active treatments
double totalMinCarbsImpact = 0d;
// if (SensitivityAAPSPlugin.getPlugin().isEnabled(PluginType.SENSITIVITY) || SensitivityWeightedAveragePlugin.getPlugin().isEnabled(PluginType.SENSITIVITY)) {
//when the impact depends on a max time, sum them up as smaller carb sizes make them smaller
// for (int ii = 0; ii < autosensData.activeCarbsList.size(); ++ii) {
// AutosensData.CarbsInPast c = autosensData.activeCarbsList.get(ii);
// totalMinCarbsImpact += c.min5minCarbImpact;
// }
// } else {
//Oref sensitivity
totalMinCarbsImpact = SP.getDouble(R.string.key_openapsama_min_5m_carbimpact, SMBDefaults.min_5m_carbimpact);
// }
// figure out how many carbs that represents
// but always assume at least 3mg/dL/5m (default) absorption per active treatment
double ci = Math.max(deviation, totalMinCarbsImpact);
if (ci != deviation)
autosensData.failoverToMinAbsorbtionRate = true;
autosensData.absorbed = ci * profile.getIc(bgTime) / sens;
// and add that to the running total carbsAbsorbed
autosensData.cob = Math.max(previous.cob - autosensData.absorbed, 0d);
autosensData.mealCarbs = previous.mealCarbs;
autosensData.substractAbosorbedCarbs();
autosensData.usedMinCarbsImpact = totalMinCarbsImpact;
autosensData.absorbing = previous.absorbing;
autosensData.mealStartCounter = previous.mealStartCounter;
autosensData.type = previous.type;
autosensData.uam = previous.uam;
}
autosensData.removeOldCarbs(bgTime);
autosensData.cob += autosensData.carbsFromBolus;
autosensData.mealCarbs += autosensData.carbsFromBolus;
autosensData.deviation = deviation;
autosensData.bgi = bgi;
autosensData.delta = delta;
autosensData.avgDelta = avgDelta;
autosensData.avgDeviation = avgDeviation;
autosensData.slopeFromMaxDeviation = slopeFromMaxDeviation;
autosensData.slopeFromMinDeviation = slopeFromMinDeviation;
// If mealCOB is zero but all deviations since hitting COB=0 are positive, exclude from autosens
if (autosensData.cob > 0 || autosensData.absorbing || autosensData.mealCarbs > 0) {
if (deviation > 0)
autosensData.absorbing = true;
else
autosensData.absorbing = false;
// stop excluding positive deviations as soon as mealCOB=0 if meal has been absorbing for >5h
if (autosensData.mealStartCounter > 60 && autosensData.cob < 0.5) {
autosensData.absorbing = false;
}
if (!autosensData.absorbing && autosensData.cob < 0.5) {
autosensData.mealCarbs = 0;
}
// check previous "type" value, and if it wasn't csf, set a mealAbsorption start flag
if (!autosensData.type.equals("csf")) {
// process.stderr.write("(");
autosensData.mealStartCounter = 0;
}
autosensData.mealStartCounter++;
autosensData.type = "csf";
} else {
// check previous "type" value, and if it was csf, set a mealAbsorption end flag
if (autosensData.type.equals("csf")) {
// process.stderr.write(")");
}
double currentBasal = profile.getBasal(bgTime);
// always exclude the first 45m after each carb entry
//if (iob.iob > currentBasal || uam ) {
if (iob.iob > 2 * currentBasal || autosensData.uam || autosensData.mealStartCounter < 9) {
autosensData.mealStartCounter++;
if (deviation > 0)
autosensData.uam = true;
else
autosensData.uam = false;
if (!autosensData.type.equals("uam")) {
// process.stderr.write("u(");
}
autosensData.type = "uam";
} else {
if (autosensData.type.equals("uam")) {
// process.stderr.write(")");
}
autosensData.type = "non-meal";
}
}
// Exclude meal-related deviations (carb absorption) from autosens
if (autosensData.type.equals("non-meal")) {
if (Math.abs(deviation) < Constants.DEVIATION_TO_BE_EQUAL) {
autosensData.pastSensitivity += "=";
autosensData.validDeviation = true;
} else if (deviation > 0) {
autosensData.pastSensitivity += "+";
autosensData.validDeviation = true;
} else {
autosensData.pastSensitivity += "-";
autosensData.validDeviation = true;
}
} else if (autosensData.type.equals("uam")) {
autosensData.pastSensitivity += "u";
} else {
autosensData.pastSensitivity += "x";
}
//log.debug("TIME: " + new Date(bgTime).toString() + " BG: " + bg + " SENS: " + sens + " DELTA: " + delta + " AVGDELTA: " + avgDelta + " IOB: " + iob.iob + " ACTIVITY: " + iob.activity + " BGI: " + bgi + " DEVIATION: " + deviation);
// add an extra negative deviation if a high temptarget is running and exercise mode is set
if (SP.getBoolean(R.string.key_high_temptarget_raises_sensitivity, SMBDefaults.high_temptarget_raises_sensitivity)) {
TempTarget tempTarget = TreatmentsPlugin.getPlugin().getTempTargetFromHistory(bgTime);
if (tempTarget != null && tempTarget.target() >= 100) {
autosensData.extraDeviation.add(-(tempTarget.target() - 100) / 20);
}
}
// add one neutral deviation every 2 hours to help decay over long exclusion periods
GregorianCalendar calendar = new GregorianCalendar();
calendar.setTimeInMillis(bgTime);
int min = calendar.get(MINUTE);
int hours = calendar.get(Calendar.HOUR_OF_DAY);
if (min >= 0 && min < 5 && hours % 2 == 0)
autosensData.extraDeviation.add(0d);
previous = autosensData;
if (bgTime < now())
autosensDataTable.put(bgTime, autosensData);
if (L.isEnabled(L.AUTOSENS))
log.debug("Running detectSensitivity from: " + DateUtil.dateAndTimeString(oldestTimeWithData) + " to: " + DateUtil.dateAndTimeString(bgTime) + " lastDataTime:" + iobCobCalculatorPlugin.lastDataTime());
AutosensResult sensitivity = iobCobCalculatorPlugin.detectSensitivityWithLock(oldestTimeWithData, bgTime);
if (L.isEnabled(L.AUTOSENS))
log.debug("Sensitivity result: " + sensitivity.toString());
autosensData.autosensResult = sensitivity;
if (L.isEnabled(L.AUTOSENS))
log.debug(autosensData.toString());
}
}
new Thread(() -> {
SystemClock.sleep(1000);
MainApp.bus().post(new EventAutosensCalculationFinished(cause));
}).start();
} finally {
mWakeLock.release();
MainApp.bus().post(new EventIobCalculationProgress(""));
if (L.isEnabled(L.AUTOSENS)) {
log.debug("AUTOSENSDATA thread ended: " + from);
log.debug("Midnights: " + MidnightTime.log());
}
Profiler.log(log, "IobCobOref1Thread", start);
}
}
}

View file

@ -2,6 +2,7 @@ package info.nightscout.androidaps.plugins.IobCobCalculator;
import android.content.Context; import android.content.Context;
import android.os.PowerManager; import android.os.PowerManager;
import android.os.SystemClock;
import android.support.v4.util.LongSparseArray; import android.support.v4.util.LongSparseArray;
import com.crashlytics.android.answers.CustomEvent; import com.crashlytics.android.answers.CustomEvent;
@ -14,7 +15,6 @@ import java.util.Date;
import java.util.List; import java.util.List;
import info.nightscout.androidaps.BuildConfig; import info.nightscout.androidaps.BuildConfig;
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;
@ -23,15 +23,23 @@ import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.db.BgReading; import info.nightscout.androidaps.db.BgReading;
import info.nightscout.androidaps.events.Event; import info.nightscout.androidaps.events.Event;
import info.nightscout.androidaps.interfaces.PluginType; import info.nightscout.androidaps.interfaces.PluginType;
import info.nightscout.androidaps.logging.L;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.ConfigBuilder.ProfileFunctions;
import info.nightscout.androidaps.plugins.IobCobCalculator.events.EventAutosensCalculationFinished; import info.nightscout.androidaps.plugins.IobCobCalculator.events.EventAutosensCalculationFinished;
import info.nightscout.androidaps.plugins.IobCobCalculator.events.EventIobCalculationProgress; import info.nightscout.androidaps.plugins.IobCobCalculator.events.EventIobCalculationProgress;
import info.nightscout.androidaps.plugins.OpenAPSSMB.SMBDefaults; import info.nightscout.androidaps.plugins.OpenAPSSMB.SMBDefaults;
import info.nightscout.androidaps.plugins.SensitivityAAPS.SensitivityAAPSPlugin; import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification;
import info.nightscout.androidaps.plugins.SensitivityWeightedAverage.SensitivityWeightedAveragePlugin; import info.nightscout.androidaps.plugins.Overview.notifications.Notification;
import info.nightscout.androidaps.plugins.Sensitivity.SensitivityAAPSPlugin;
import info.nightscout.androidaps.plugins.Sensitivity.SensitivityWeightedAveragePlugin;
import info.nightscout.androidaps.plugins.Treatments.Treatment; import info.nightscout.androidaps.plugins.Treatments.Treatment;
import info.nightscout.androidaps.plugins.Treatments.TreatmentsPlugin; import info.nightscout.androidaps.plugins.Treatments.TreatmentsPlugin;
import info.nightscout.utils.DateUtil; import info.nightscout.utils.DateUtil;
import info.nightscout.utils.DecimalFormatter;
import info.nightscout.utils.FabricPrivacy; import info.nightscout.utils.FabricPrivacy;
import info.nightscout.utils.MidnightTime;
import info.nightscout.utils.Profiler;
import info.nightscout.utils.SP; import info.nightscout.utils.SP;
import static info.nightscout.utils.DateUtil.now; import static info.nightscout.utils.DateUtil.now;
@ -41,24 +49,26 @@ import static info.nightscout.utils.DateUtil.now;
*/ */
public class IobCobThread extends Thread { public class IobCobThread extends Thread {
private static Logger log = LoggerFactory.getLogger(IobCobThread.class); private static Logger log = LoggerFactory.getLogger(L.AUTOSENS);
private final Event cause; private final Event cause;
private IobCobCalculatorPlugin iobCobCalculatorPlugin; private IobCobCalculatorPlugin iobCobCalculatorPlugin;
private boolean bgDataReload; private boolean bgDataReload;
private boolean limitDataToOldestAvailable;
private String from; private String from;
private long start; private long end;
private PowerManager.WakeLock mWakeLock; private PowerManager.WakeLock mWakeLock;
public IobCobThread(IobCobCalculatorPlugin plugin, String from, long start, boolean bgDataReload, Event cause) { public IobCobThread(IobCobCalculatorPlugin plugin, String from, long end, boolean bgDataReload, boolean limitDataToOldestAvailable, Event cause) {
super(); super();
this.iobCobCalculatorPlugin = plugin; this.iobCobCalculatorPlugin = plugin;
this.bgDataReload = bgDataReload; this.bgDataReload = bgDataReload;
this.limitDataToOldestAvailable = limitDataToOldestAvailable;
this.from = from; this.from = from;
this.cause = cause; this.cause = cause;
this.start = start; this.end = end;
PowerManager powerManager = (PowerManager) MainApp.instance().getApplicationContext().getSystemService(Context.POWER_SERVICE); PowerManager powerManager = (PowerManager) MainApp.instance().getApplicationContext().getSystemService(Context.POWER_SERVICE);
mWakeLock = powerManager.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, "iobCobThread"); mWakeLock = powerManager.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, "iobCobThread");
@ -66,34 +76,41 @@ public class IobCobThread extends Thread {
@Override @Override
public final void run() { public final void run() {
long start = DateUtil.now();
mWakeLock.acquire(); mWakeLock.acquire();
try { try {
if (MainApp.getConfigBuilder() == null) { if (L.isEnabled(L.AUTOSENS))
log.debug("AUTOSENSDATA thread started: " + from);
if (ConfigBuilderPlugin.getPlugin() == null) {
if (L.isEnabled(L.AUTOSENS))
log.debug("Aborting calculation thread (ConfigBuilder not ready): " + from); log.debug("Aborting calculation thread (ConfigBuilder not ready): " + from);
return; // app still initializing return; // app still initializing
} }
if (!MainApp.getConfigBuilder().isProfileValid("IobCobThread")) { if (!ProfileFunctions.getInstance().isProfileValid("IobCobThread")) {
if (L.isEnabled(L.AUTOSENS))
log.debug("Aborting calculation thread (No profile): " + from); log.debug("Aborting calculation thread (No profile): " + from);
return; // app still initializing return; // app still initializing
} }
//log.debug("Locking calculateSensitivityData"); //log.debug("Locking calculateSensitivityData");
long oldestTimeWithData = iobCobCalculatorPlugin.oldestDataAvailable(); long oldestTimeWithData = iobCobCalculatorPlugin.calculateDetectionStart(end, limitDataToOldestAvailable);
synchronized (iobCobCalculatorPlugin.dataLock) { synchronized (iobCobCalculatorPlugin.dataLock) {
if (bgDataReload) { if (bgDataReload) {
iobCobCalculatorPlugin.loadBgData(start); iobCobCalculatorPlugin.loadBgData(end);
iobCobCalculatorPlugin.createBucketedData(); iobCobCalculatorPlugin.createBucketedData();
} }
List<BgReading> bucketed_data = iobCobCalculatorPlugin.getBucketedData(); List<BgReading> bucketed_data = iobCobCalculatorPlugin.getBucketedData();
LongSparseArray<AutosensData> autosensDataTable = IobCobCalculatorPlugin.getPlugin().getAutosensDataTable(); LongSparseArray<AutosensData> autosensDataTable = iobCobCalculatorPlugin.getAutosensDataTable();
if (bucketed_data == null || bucketed_data.size() < 3) { if (bucketed_data == null || bucketed_data.size() < 3) {
if (L.isEnabled(L.AUTOSENS))
log.debug("Aborting calculation thread (No bucketed data available): " + from); log.debug("Aborting calculation thread (No bucketed data available): " + from);
return; return;
} }
long prevDataTime = IobCobCalculatorPlugin.roundUpTime(bucketed_data.get(bucketed_data.size() - 3).date); long prevDataTime = IobCobCalculatorPlugin.roundUpTime(bucketed_data.get(bucketed_data.size() - 3).date);
if (L.isEnabled(L.AUTOSENS))
log.debug("Prev data time: " + new Date(prevDataTime).toLocaleString()); log.debug("Prev data time: " + new Date(prevDataTime).toLocaleString());
AutosensData previous = autosensDataTable.get(prevDataTime); AutosensData previous = autosensDataTable.get(prevDataTime);
// start from oldest to be able sub cob // start from oldest to be able sub cob
@ -103,6 +120,7 @@ public class IobCobThread extends Thread {
if (iobCobCalculatorPlugin.stopCalculationTrigger) { if (iobCobCalculatorPlugin.stopCalculationTrigger) {
iobCobCalculatorPlugin.stopCalculationTrigger = false; iobCobCalculatorPlugin.stopCalculationTrigger = false;
if (L.isEnabled(L.AUTOSENS))
log.debug("Aborting calculation thread (trigger): " + from); log.debug("Aborting calculation thread (trigger): " + from);
return; return;
} }
@ -118,13 +136,14 @@ public class IobCobThread extends Thread {
continue; continue;
} }
Profile profile = MainApp.getConfigBuilder().getProfile(bgTime); Profile profile = ProfileFunctions.getInstance().getProfile(bgTime);
if (profile == null) { if (profile == null) {
if (L.isEnabled(L.AUTOSENS))
log.debug("Aborting calculation thread (no profile): " + from); log.debug("Aborting calculation thread (no profile): " + from);
return; // profile not set yet return; // profile not set yet
} }
if (Config.logAutosensData) if (L.isEnabled(L.AUTOSENS))
log.debug("Processing calculation thread: " + from + " (" + i + "/" + bucketed_data.size() + ")"); log.debug("Processing calculation thread: " + from + " (" + i + "/" + bucketed_data.size() + ")");
double sens = Profile.toMgdl(profile.getIsf(bgTime), profile.getUnits()); double sens = Profile.toMgdl(profile.getIsf(bgTime), profile.getUnits());
@ -132,7 +151,7 @@ public class IobCobThread extends Thread {
AutosensData autosensData = new AutosensData(); AutosensData autosensData = new AutosensData();
autosensData.time = bgTime; autosensData.time = bgTime;
if (previous != null) if (previous != null)
autosensData.activeCarbsList = new ArrayList<>(previous.activeCarbsList); autosensData.activeCarbsList = previous.cloneCarbsList();
else else
autosensData.activeCarbsList = new ArrayList<>(); autosensData.activeCarbsList = new ArrayList<>();
@ -145,6 +164,7 @@ public class IobCobThread extends Thread {
log.error("! value < 39"); log.error("! value < 39");
continue; continue;
} }
autosensData.bg = bg;
delta = (bg - bucketed_data.get(i + 1).value); delta = (bg - bucketed_data.get(i + 1).value);
avgDelta = (bg - bucketed_data.get(i + 3).value) / 3; avgDelta = (bg - bucketed_data.get(i + 3).value) / 3;
@ -162,15 +182,28 @@ public class IobCobThread extends Thread {
// https://github.com/openaps/oref0/blob/master/lib/determine-basal/cob-autosens.js#L169 // https://github.com/openaps/oref0/blob/master/lib/determine-basal/cob-autosens.js#L169
if (i < bucketed_data.size() - 16) { // we need 1h of data to calculate minDeviationSlope if (i < bucketed_data.size() - 16) { // we need 1h of data to calculate minDeviationSlope
long hourago = bgTime + 10 * 1000 - 60 * 60 * 1000L; long hourago = bgTime + 10 * 1000 - 60 * 60 * 1000L;
AutosensData hourAgoData = IobCobCalculatorPlugin.getPlugin().getAutosensData(hourago); AutosensData hourAgoData = iobCobCalculatorPlugin.getAutosensData(hourago);
if (hourAgoData != null) { if (hourAgoData != null) {
int initialIndex = autosensDataTable.indexOfKey(hourAgoData.time); int initialIndex = autosensDataTable.indexOfKey(hourAgoData.time);
if (Config.logAutosensData) if (L.isEnabled(L.AUTOSENS))
log.debug(">>>>> bucketed_data.size()=" + bucketed_data.size() + " i=" + i + " hourAgoData=" + hourAgoData.toString()); log.debug(">>>>> bucketed_data.size()=" + bucketed_data.size() + " i=" + i + " hourAgoData=" + hourAgoData.toString());
int past = 1; int past = 1;
try { try {
for (; past < 12; past++) { for (; past < 12; past++) {
AutosensData ad = autosensDataTable.valueAt(initialIndex + past); AutosensData ad = autosensDataTable.valueAt(initialIndex + past);
if (L.isEnabled(L.AUTOSENS)) {
log.debug(">>>>> past=" + past + " ad=" + (ad != null ? ad.toString() : null));
if (ad == null) {
log.debug(autosensDataTable.toString());
log.debug(bucketed_data.toString());
log.debug(IobCobCalculatorPlugin.getPlugin().getBgReadings().toString());
Notification notification = new Notification(Notification.SENDLOGFILES, MainApp.gs(R.string.sendlogfiles), Notification.LOW);
MainApp.bus().post(new EventNewNotification(notification));
SP.putBoolean("log_AUTOSENS", true);
break;
}
}
// let it here crash on NPE to get more data as i cannot reproduce this bug
double deviationSlope = (ad.avgDeviation - avgDeviation) / (ad.time - bgTime) * 1000 * 60 * 5; double deviationSlope = (ad.avgDeviation - avgDeviation) / (ad.time - bgTime) * 1000 * 60 * 5;
if (ad.avgDeviation > maxDeviation) { if (ad.avgDeviation > maxDeviation) {
slopeFromMaxDeviation = Math.min(0, deviationSlope); slopeFromMaxDeviation = Math.min(0, deviationSlope);
@ -181,7 +214,7 @@ public class IobCobThread extends Thread {
minDeviation = ad.avgDeviation; minDeviation = ad.avgDeviation;
} }
//if (Config.logAutosensData) //if (Config.isEnabled(L.AUTOSENS))
// log.debug("Deviations: " + new Date(bgTime) + new Date(ad.time) + " avgDeviation=" + avgDeviation + " deviationSlope=" + deviationSlope + " slopeFromMaxDeviation=" + slopeFromMaxDeviation + " slopeFromMinDeviation=" + slopeFromMinDeviation); // log.debug("Deviations: " + new Date(bgTime) + new Date(ad.time) + " avgDeviation=" + avgDeviation + " deviationSlope=" + deviationSlope + " slopeFromMaxDeviation=" + slopeFromMaxDeviation + " slopeFromMinDeviation=" + slopeFromMinDeviation);
} }
} catch (Exception e) { } catch (Exception e) {
@ -194,7 +227,17 @@ public class IobCobThread extends Thread {
.putCustomAttribute("for_data", ">>>>> bucketed_data.size()=" + bucketed_data.size() + " i=" + i + "hourAgoData=" + hourAgoData.toString()) .putCustomAttribute("for_data", ">>>>> bucketed_data.size()=" + bucketed_data.size() + " i=" + i + "hourAgoData=" + hourAgoData.toString())
.putCustomAttribute("past", past) .putCustomAttribute("past", past)
); );
log.debug(autosensDataTable.toString());
log.debug(bucketed_data.toString());
log.debug(IobCobCalculatorPlugin.getPlugin().getBgReadings().toString());
Notification notification = new Notification(Notification.SENDLOGFILES, MainApp.gs(R.string.sendlogfiles), Notification.LOW);
MainApp.bus().post(new EventNewNotification(notification));
SP.putBoolean("log_AUTOSENS", true);
break;
} }
} else {
if (L.isEnabled(L.AUTOSENS))
log.debug(">>>>> bucketed_data.size()=" + bucketed_data.size() + " i=" + i + " hourAgoData=" + "null");
} }
} }
@ -202,6 +245,7 @@ public class IobCobThread extends Thread {
for (int ir = 0; ir < recentTreatments.size(); ir++) { for (int ir = 0; ir < recentTreatments.size(); ir++) {
autosensData.carbsFromBolus += recentTreatments.get(ir).carbs; autosensData.carbsFromBolus += recentTreatments.get(ir).carbs;
autosensData.activeCarbsList.add(new AutosensData.CarbsInPast(recentTreatments.get(ir))); autosensData.activeCarbsList.add(new AutosensData.CarbsInPast(recentTreatments.get(ir)));
autosensData.pastSensitivity += "[" + DecimalFormatter.to0Decimal(recentTreatments.get(ir).carbs) + "g]";
} }
@ -246,34 +290,44 @@ public class IobCobThread extends Thread {
if (autosensData.cob <= 0) { if (autosensData.cob <= 0) {
if (Math.abs(deviation) < Constants.DEVIATION_TO_BE_EQUAL) { if (Math.abs(deviation) < Constants.DEVIATION_TO_BE_EQUAL) {
autosensData.pastSensitivity += "="; autosensData.pastSensitivity += "=";
autosensData.nonEqualDeviation = true; autosensData.validDeviation = true;
} else if (deviation > 0) { } else if (deviation > 0) {
autosensData.pastSensitivity += "+"; autosensData.pastSensitivity += "+";
autosensData.nonEqualDeviation = true; autosensData.validDeviation = true;
} else { } else {
autosensData.pastSensitivity += "-"; autosensData.pastSensitivity += "-";
autosensData.nonEqualDeviation = true; autosensData.validDeviation = true;
} }
autosensData.nonCarbsDeviation = true;
} else { } else {
autosensData.pastSensitivity += "C"; autosensData.pastSensitivity += "C";
} }
//log.debug("TIME: " + new Date(bgTime).toString() + " BG: " + bg + " SENS: " + sens + " DELTA: " + delta + " AVGDELTA: " + avgDelta + " IOB: " + iob.iob + " ACTIVITY: " + iob.activity + " BGI: " + bgi + " DEVIATION: " + deviation); //log.debug("TIME: " + new Date(bgTime).toString() + " BG: " + bg + " SENS: " + sens + " DELTA: " + delta + " AVGDELTA: " + avgDelta + " IOB: " + iob.iob + " ACTIVITY: " + iob.activity + " BGI: " + bgi + " DEVIATION: " + deviation);
previous = autosensData; previous = autosensData;
if (bgTime < now())
autosensDataTable.put(bgTime, autosensData); autosensDataTable.put(bgTime, autosensData);
if (Config.logAutosensData) if (L.isEnabled(L.AUTOSENS))
log.debug("Running detectSensitivity from: " + DateUtil.dateAndTimeString(oldestTimeWithData) + " to: " + DateUtil.dateAndTimeString(bgTime)); log.debug("Running detectSensitivity from: " + DateUtil.dateAndTimeString(oldestTimeWithData) + " to: " + DateUtil.dateAndTimeString(bgTime) + " lastDataTime:" + iobCobCalculatorPlugin.lastDataTime());
autosensData.autosensRatio = iobCobCalculatorPlugin.detectSensitivity(oldestTimeWithData, bgTime).ratio; AutosensResult sensitivity = iobCobCalculatorPlugin.detectSensitivityWithLock(oldestTimeWithData, bgTime);
if (Config.logAutosensData) if (L.isEnabled(L.AUTOSENS))
log.debug("Sensitivity result: " + sensitivity.toString());
autosensData.autosensResult = sensitivity;
if (L.isEnabled(L.AUTOSENS))
log.debug(autosensData.toString()); log.debug(autosensData.toString());
} }
} }
new Thread(() -> {
SystemClock.sleep(1000);
MainApp.bus().post(new EventAutosensCalculationFinished(cause)); MainApp.bus().post(new EventAutosensCalculationFinished(cause));
log.debug("Finishing calculation thread: " + from); }).start();
} finally { } finally {
mWakeLock.release(); mWakeLock.release();
MainApp.bus().post(new EventIobCalculationProgress("")); MainApp.bus().post(new EventIobCalculationProgress(""));
if (L.isEnabled(L.AUTOSENS)) {
log.debug("AUTOSENSDATA thread ended: " + from);
log.debug("Midnights: " + MidnightTime.log());
}
Profiler.log(log, "IobCobThread", start);
} }
} }

View file

@ -10,27 +10,35 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date;
import java.util.List; 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.data.IobTotal; import info.nightscout.androidaps.data.IobTotal;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.db.BgReading; import info.nightscout.androidaps.db.BgReading;
import info.nightscout.androidaps.db.TemporaryBasal;
import info.nightscout.androidaps.interfaces.Constraint; import info.nightscout.androidaps.interfaces.Constraint;
import info.nightscout.androidaps.interfaces.PumpDescription;
import info.nightscout.androidaps.interfaces.PumpInterface; import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.logging.L;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.ConfigBuilder.ProfileFunctions;
import info.nightscout.androidaps.plugins.Treatments.TreatmentsPlugin;
import info.nightscout.utils.DecimalFormatter; import info.nightscout.utils.DecimalFormatter;
import info.nightscout.utils.SP;
/** /**
* Created by mike on 09.06.2016. * Created by mike on 09.06.2016.
*/ */
public class APSResult { public class APSResult {
private static Logger log = LoggerFactory.getLogger(APSResult.class); private static Logger log = LoggerFactory.getLogger(L.APS);
public Date date; public long date = 0;
public String reason; public String reason;
public double rate; public double rate;
public int percent;
public boolean usePercent = false;
public int duration; public int duration;
public boolean tempBasalRequested = false; public boolean tempBasalRequested = false;
public boolean bolusRequested = false; public boolean bolusRequested = false;
@ -43,11 +51,42 @@ public class APSResult {
public Constraint<Double> inputConstraints; public Constraint<Double> inputConstraints;
public Constraint<Double> rateConstraint; public Constraint<Double> rateConstraint;
public Constraint<Integer> percentConstraint;
public Constraint<Double> smbConstraint; public Constraint<Double> smbConstraint;
public APSResult rate(double rate) {
this.rate = rate;
return this;
}
public APSResult duration(int duration) {
this.duration = duration;
return this;
}
public APSResult percent(int percent) {
this.percent = percent;
return this;
}
public APSResult tempBasalRequested(boolean tempBasalRequested) {
this.tempBasalRequested = tempBasalRequested;
return this;
}
public APSResult usePercent(boolean usePercent) {
this.usePercent = usePercent;
return this;
}
public APSResult json(JSONObject json) {
this.json = json;
return this;
}
@Override @Override
public String toString() { public String toString() {
final PumpInterface pump = ConfigBuilderPlugin.getActivePump(); final PumpInterface pump = ConfigBuilderPlugin.getPlugin().getActivePump();
if (isChangeRequested()) { if (isChangeRequested()) {
String ret; String ret;
// rate // rate
@ -55,6 +94,10 @@ public class APSResult {
ret = MainApp.gs(R.string.canceltemp) + "\n"; ret = MainApp.gs(R.string.canceltemp) + "\n";
else if (rate == -1) else if (rate == -1)
ret = MainApp.gs(R.string.let_temp_basal_run) + "\n"; ret = MainApp.gs(R.string.let_temp_basal_run) + "\n";
else if (usePercent)
ret = MainApp.gs(R.string.rate) + ": " + DecimalFormatter.to2Decimal(percent) + "% " +
"(" + DecimalFormatter.to2Decimal(percent * pump.getBaseBasalRate() / 100d) + " U/h)\n" +
MainApp.gs(R.string.duration) + ": " + DecimalFormatter.to2Decimal(duration) + " min\n";
else else
ret = MainApp.gs(R.string.rate) + ": " + DecimalFormatter.to2Decimal(rate) + " U/h " + ret = MainApp.gs(R.string.rate) + ": " + DecimalFormatter.to2Decimal(rate) + " U/h " +
"(" + DecimalFormatter.to2Decimal(rate / pump.getBaseBasalRate() * 100) + "%) \n" + "(" + DecimalFormatter.to2Decimal(rate / pump.getBaseBasalRate() * 100) + "%) \n" +
@ -72,7 +115,7 @@ public class APSResult {
} }
public Spanned toSpanned() { public Spanned toSpanned() {
final PumpInterface pump = ConfigBuilderPlugin.getActivePump(); final PumpInterface pump = ConfigBuilderPlugin.getPlugin().getActivePump();
if (isChangeRequested()) { if (isChangeRequested()) {
String ret; String ret;
// rate // rate
@ -80,9 +123,13 @@ public class APSResult {
ret = MainApp.gs(R.string.canceltemp) + "<br>"; ret = MainApp.gs(R.string.canceltemp) + "<br>";
else if (rate == -1) else if (rate == -1)
ret = MainApp.gs(R.string.let_temp_basal_run) + "<br>"; ret = MainApp.gs(R.string.let_temp_basal_run) + "<br>";
else if (usePercent)
ret = "<b>" + MainApp.gs(R.string.rate) + "</b>: " + DecimalFormatter.to2Decimal(percent) + "% " +
"(" + DecimalFormatter.to2Decimal(percent * pump.getBaseBasalRate() / 100d) + " U/h)<br>" +
"<b>" + MainApp.gs(R.string.duration) + "</b>: " + DecimalFormatter.to2Decimal(duration) + " min<br>";
else else
ret = "<b>" + MainApp.gs(R.string.rate) + "</b>: " + DecimalFormatter.to2Decimal(rate) + " U/h " + ret = "<b>" + MainApp.gs(R.string.rate) + "</b>: " + DecimalFormatter.to2Decimal(rate) + " U/h " +
"(" + DecimalFormatter.to2Decimal(rate / pump.getBaseBasalRate() * 100) + "%) <br>" + "(" + DecimalFormatter.to2Decimal(rate / pump.getBaseBasalRate() * 100d) + "%) <br>" +
"<b>" + MainApp.gs(R.string.duration) + "</b>: " + DecimalFormatter.to2Decimal(duration) + " min<br>"; "<b>" + MainApp.gs(R.string.duration) + "</b>: " + DecimalFormatter.to2Decimal(duration) + " min<br>";
// smb // smb
@ -101,21 +148,33 @@ public class APSResult {
public APSResult clone() { public APSResult clone() {
APSResult newResult = new APSResult(); APSResult newResult = new APSResult();
newResult.reason = reason; doClone(newResult);
return newResult;
}
protected void doClone(APSResult newResult) {
newResult.date = date;
newResult.reason = reason != null ? new String(reason) : null;
newResult.rate = rate; newResult.rate = rate;
newResult.duration = duration; newResult.duration = duration;
newResult.tempBasalRequested = tempBasalRequested; newResult.tempBasalRequested = tempBasalRequested;
newResult.bolusRequested = bolusRequested; newResult.bolusRequested = bolusRequested;
newResult.iob = iob; newResult.iob = iob;
newResult.json = json; try {
newResult.json = new JSONObject(json.toString());
} catch (JSONException e) {
log.error("Unhandled exception", e);
}
newResult.hasPredictions = hasPredictions; newResult.hasPredictions = hasPredictions;
newResult.smb = smb; newResult.smb = smb;
newResult.deliverAt = deliverAt; newResult.deliverAt = deliverAt;
newResult.rateConstraint = rateConstraint; newResult.rateConstraint = rateConstraint;
newResult.smbConstraint = smbConstraint; newResult.smbConstraint = smbConstraint;
return newResult; newResult.percent = percent;
newResult.usePercent = usePercent;
} }
public JSONObject json() { public JSONObject json() {
JSONObject json = new JSONObject(); JSONObject json = new JSONObject();
try { try {
@ -133,8 +192,8 @@ public class APSResult {
public List<BgReading> getPredictions() { public List<BgReading> getPredictions() {
List<BgReading> array = new ArrayList<>(); List<BgReading> array = new ArrayList<>();
try { try {
long startTime = date.getTime(); long startTime = date;
if (json.has("predBGs")) { if (json != null && json.has("predBGs")) {
JSONObject predBGs = json.getJSONObject("predBGs"); JSONObject predBGs = json.getJSONObject("predBGs");
if (predBGs.has("IOB")) { if (predBGs.has("IOB")) {
JSONArray iob = predBGs.getJSONArray("IOB"); JSONArray iob = predBGs.getJSONArray("IOB");
@ -196,8 +255,8 @@ public class APSResult {
public long getLatestPredictionsTime() { public long getLatestPredictionsTime() {
long latest = 0; long latest = 0;
try { try {
long startTime = date != null ? date.getTime() : 0; long startTime = date;
if (json.has("predBGs")) { if (json != null && json.has("predBGs")) {
JSONObject predBGs = json.getJSONObject("predBGs"); JSONObject predBGs = json.getJSONObject("predBGs");
if (predBGs.has("IOB")) { if (predBGs.has("IOB")) {
JSONArray iob = predBGs.getJSONArray("IOB"); JSONArray iob = predBGs.getJSONArray("IOB");
@ -228,6 +287,119 @@ public class APSResult {
} }
public boolean isChangeRequested() { public boolean isChangeRequested() {
Constraint<Boolean> closedLoopEnabled = MainApp.getConstraintChecker().isClosedLoopAllowed();
// closed loop mode: handle change at driver level
if (closedLoopEnabled.value()) {
if (L.isEnabled(L.APS))
log.debug("DEFAULT: Closed mode");
return tempBasalRequested || bolusRequested; return tempBasalRequested || bolusRequested;
} }
// open loop mode: try to limit request
if (!tempBasalRequested && !bolusRequested) {
if (L.isEnabled(L.APS))
log.debug("FALSE: No request");
return false;
}
long now = System.currentTimeMillis();
TemporaryBasal activeTemp = TreatmentsPlugin.getPlugin().getTempBasalFromHistory(now);
PumpInterface pump = ConfigBuilderPlugin.getPlugin().getActivePump();
Profile profile = ProfileFunctions.getInstance().getProfile();
if (profile == null) {
log.error("FALSE: No Profile");
return false;
}
if (usePercent) {
if (activeTemp == null && percent == 100) {
if (L.isEnabled(L.APS))
log.debug("FALSE: No temp running, asking cancel temp");
return false;
}
if (activeTemp != null && Math.abs(percent - activeTemp.tempBasalConvertedToPercent(now, profile)) < pump.getPumpDescription().basalStep) {
if (L.isEnabled(L.APS))
log.debug("FALSE: Temp equal");
return false;
}
// always report zerotemp
if (percent == 0) {
if (L.isEnabled(L.APS))
log.debug("TRUE: Zero temp");
return true;
}
// always report hightemp
if (pump != null && pump.getPumpDescription().tempBasalStyle == PumpDescription.PERCENT) {
double pumpLimit = pump.getPumpDescription().pumpType.getTbrSettings().getMaxDose();
if (percent == pumpLimit) {
if (L.isEnabled(L.APS))
log.debug("TRUE: Pump limit");
return true;
}
}
// report change bigger than 30%
double percentMinChangeChange = SP.getDouble(R.string.key_loop_openmode_min_change, 30d);
percentMinChangeChange /= 100d;
double lowThreshold = 1 - percentMinChangeChange;
double highThreshold = 1 + percentMinChangeChange;
double change = percent / 100d;
if (activeTemp != null)
change = percent / (double) activeTemp.tempBasalConvertedToPercent(now, profile);
if (change < lowThreshold || change > highThreshold) {
if (L.isEnabled(L.APS))
log.debug("TRUE: Outside allowed range " + (change * 100d) + "%");
return true;
} else {
if (L.isEnabled(L.APS))
log.debug("TRUE: Inside allowed range " + (change * 100d) + "%");
return false;
}
} else {
if (activeTemp == null && rate == pump.getBaseBasalRate()) {
if (L.isEnabled(L.APS))
log.debug("FALSE: No temp running, asking cancel temp");
return false;
}
if (activeTemp != null && Math.abs(rate - activeTemp.tempBasalConvertedToAbsolute(now, profile)) < pump.getPumpDescription().basalStep) {
if (L.isEnabled(L.APS))
log.debug("FALSE: Temp equal");
return false;
}
// always report zerotemp
if (rate == 0) {
if (L.isEnabled(L.APS))
log.debug("TRUE: Zero temp");
return true;
}
// always report hightemp
if (pump != null && pump.getPumpDescription().tempBasalStyle == PumpDescription.ABSOLUTE) {
double pumpLimit = pump.getPumpDescription().pumpType.getTbrSettings().getMaxDose();
if (rate == pumpLimit) {
if (L.isEnabled(L.APS))
log.debug("TRUE: Pump limit");
return true;
}
}
// report change bigger than 30%
double percentMinChangeChange = SP.getDouble(R.string.key_loop_openmode_min_change, 30d);
percentMinChangeChange /= 100d;
double lowThreshold = 1 - percentMinChangeChange;
double highThreshold = 1 + percentMinChangeChange;
double change = rate / profile.getBasal();
if (activeTemp != null)
change = rate / activeTemp.tempBasalConvertedToAbsolute(now, profile);
if (change < lowThreshold || change > highThreshold) {
if (L.isEnabled(L.APS))
log.debug("TRUE: Outside allowed range " + (change * 100d) + "%");
return true;
} else {
if (L.isEnabled(L.APS))
log.debug("TRUE: Inside allowed range " + (change * 100d) + "%");
return false;
}
}
}
} }

View file

@ -1,17 +1,11 @@
package info.nightscout.androidaps.plugins.Loop; package info.nightscout.androidaps.plugins.Loop;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.logging.L;
import info.nightscout.androidaps.Services.Intents;
import info.nightscout.androidaps.plugins.NSClientInternal.data.DbLogger;
/* /*
{ {
@ -371,7 +365,7 @@ import info.nightscout.androidaps.plugins.NSClientInternal.data.DbLogger;
*/ */
public class DeviceStatus { public class DeviceStatus {
private static Logger log = LoggerFactory.getLogger(DeviceStatus.class); private static Logger log = LoggerFactory.getLogger(L.APS);
public String device = null; public String device = null;
public JSONObject pump = null; public JSONObject pump = null;

View file

@ -28,8 +28,6 @@ import info.nightscout.androidaps.plugins.Loop.events.EventLoopUpdateGui;
import info.nightscout.utils.FabricPrivacy; import info.nightscout.utils.FabricPrivacy;
public class LoopFragment extends SubscriberFragment { public class LoopFragment extends SubscriberFragment {
private static Logger log = LoggerFactory.getLogger(LoopFragment.class);
@BindView(R.id.loop_run) @BindView(R.id.loop_run)
Button runNowButton; Button runNowButton;
@BindView(R.id.loop_lastrun) @BindView(R.id.loop_lastrun)
@ -80,7 +78,7 @@ public class LoopFragment extends SubscriberFragment {
clearGUI(); clearGUI();
final Activity activity = getActivity(); final Activity activity = getActivity();
if (activity != null) if (activity != null)
activity.runOnUiThread(() -> lastRunView.setText(ev.text)); activity.runOnUiThread(() -> { synchronized (LoopFragment.this) { if (lastRunView != null) lastRunView.setText(ev.text); } });
} }
@ -89,6 +87,8 @@ public class LoopFragment extends SubscriberFragment {
Activity activity = getActivity(); Activity activity = getActivity();
if (activity != null) if (activity != null)
activity.runOnUiThread(() -> { activity.runOnUiThread(() -> {
synchronized (LoopFragment.this) {
if (!isBound()) return;
LoopPlugin.LastRun lastRun = LoopPlugin.lastRun; LoopPlugin.LastRun lastRun = LoopPlugin.lastRun;
if (lastRun != null) { if (lastRun != null) {
requestView.setText(lastRun.request != null ? lastRun.request.toSpanned() : ""); requestView.setText(lastRun.request != null ? lastRun.request.toSpanned() : "");
@ -110,6 +110,7 @@ public class LoopFragment extends SubscriberFragment {
} }
constraintsView.setText(constraints); constraintsView.setText(constraints);
} }
}
}); });
} }
@ -117,6 +118,8 @@ public class LoopFragment extends SubscriberFragment {
Activity activity = getActivity(); Activity activity = getActivity();
if (activity != null) if (activity != null)
activity.runOnUiThread(() -> { activity.runOnUiThread(() -> {
synchronized (LoopFragment.this) {
if (isBound()) {
requestView.setText(""); requestView.setText("");
constraintsProcessedView.setText(""); constraintsProcessedView.setText("");
sourceView.setText(""); sourceView.setText("");
@ -124,6 +127,20 @@ public class LoopFragment extends SubscriberFragment {
lastEnactView.setText(""); lastEnactView.setText("");
tbrSetByPumpView.setText(""); tbrSetByPumpView.setText("");
smbSetByPumpView.setText(""); smbSetByPumpView.setText("");
}
}
}); });
} }
boolean isBound() {
return requestView != null
&& constraintsProcessedView != null
&& sourceView != null
&& lastRunView != null
&& lastEnactView != null
&& tbrSetByPumpView != null
&& smbSetByPumpView != null
&& constraintsView != null
&& runNowButton != null;
}
} }

View file

@ -21,46 +21,58 @@ import org.slf4j.LoggerFactory;
import java.util.Date; import java.util.Date;
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.Constants; import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainActivity; import info.nightscout.androidaps.MainActivity;
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.Profile; import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.data.PumpEnactResult; import info.nightscout.androidaps.data.PumpEnactResult;
import info.nightscout.androidaps.db.BgReading; import info.nightscout.androidaps.db.BgReading;
import info.nightscout.androidaps.db.CareportalEvent;
import info.nightscout.androidaps.db.DatabaseHelper; import info.nightscout.androidaps.db.DatabaseHelper;
import info.nightscout.androidaps.events.Event; import info.nightscout.androidaps.db.Source;
import info.nightscout.androidaps.db.TemporaryBasal;
import info.nightscout.androidaps.events.EventNewBG; import info.nightscout.androidaps.events.EventNewBG;
import info.nightscout.androidaps.events.EventTreatmentChange;
import info.nightscout.androidaps.interfaces.APSInterface; import info.nightscout.androidaps.interfaces.APSInterface;
import info.nightscout.androidaps.interfaces.Constraint; import info.nightscout.androidaps.interfaces.Constraint;
import info.nightscout.androidaps.interfaces.PluginBase; import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.PluginDescription; import info.nightscout.androidaps.interfaces.PluginDescription;
import info.nightscout.androidaps.interfaces.PluginType; import info.nightscout.androidaps.interfaces.PluginType;
import info.nightscout.androidaps.interfaces.PumpDescription;
import info.nightscout.androidaps.interfaces.PumpInterface; import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.interfaces.TreatmentsInterface;
import info.nightscout.androidaps.logging.L;
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.ConfigBuilder.ProfileFunctions;
import info.nightscout.androidaps.plugins.IobCobCalculator.events.EventAutosensCalculationFinished; import info.nightscout.androidaps.plugins.IobCobCalculator.events.EventAutosensCalculationFinished;
import info.nightscout.androidaps.plugins.Loop.events.EventLoopSetLastRunGui; import info.nightscout.androidaps.plugins.Loop.events.EventLoopSetLastRunGui;
import info.nightscout.androidaps.plugins.Loop.events.EventLoopUpdateGui; import info.nightscout.androidaps.plugins.Loop.events.EventLoopUpdateGui;
import info.nightscout.androidaps.plugins.Loop.events.EventNewOpenLoopNotification; import info.nightscout.androidaps.plugins.Loop.events.EventNewOpenLoopNotification;
import info.nightscout.androidaps.plugins.NSClientInternal.NSUpload;
import info.nightscout.androidaps.plugins.PumpVirtual.VirtualPumpPlugin;
import info.nightscout.androidaps.plugins.Treatments.TreatmentsPlugin; import info.nightscout.androidaps.plugins.Treatments.TreatmentsPlugin;
import info.nightscout.androidaps.plugins.Wear.ActionStringHandler;
import info.nightscout.androidaps.events.EventAcceptOpenLoopChange;
import info.nightscout.androidaps.queue.Callback; import info.nightscout.androidaps.queue.Callback;
import info.nightscout.androidaps.queue.commands.Command;
import info.nightscout.utils.FabricPrivacy; import info.nightscout.utils.FabricPrivacy;
import info.nightscout.utils.NSUpload;
import info.nightscout.utils.SP; import info.nightscout.utils.SP;
import info.nightscout.utils.T;
import info.nightscout.utils.ToastUtils;
/** /**
* Created by mike on 05.08.2016. * Created by mike on 05.08.2016.
*/ */
public class LoopPlugin extends PluginBase { public class LoopPlugin extends PluginBase {
private static Logger log = LoggerFactory.getLogger(LoopPlugin.class); private static Logger log = LoggerFactory.getLogger(L.APS);
public static final String CHANNEL_ID = "AndroidAPS-Openloop"; private static final String CHANNEL_ID = "AndroidAPS-Openloop";
long lastBgTriggeredRun = 0; private long lastBgTriggeredRun = 0;
protected static LoopPlugin loopPlugin; private static LoopPlugin loopPlugin;
@NonNull @NonNull
public static LoopPlugin getPlugin() { public static LoopPlugin getPlugin() {
@ -93,7 +105,8 @@ public class LoopPlugin extends PluginBase {
.fragmentClass(LoopFragment.class.getName()) .fragmentClass(LoopFragment.class.getName())
.pluginName(R.string.loop) .pluginName(R.string.loop)
.shortName(R.string.loop_shortname) .shortName(R.string.loop_shortname)
.preferencesId(R.xml.pref_closedmode) .preferencesId(R.xml.pref_loop)
.description(R.string.description_loop)
); );
loopSuspendedTill = SP.getLong("loopSuspendedTill", 0L); loopSuspendedTill = SP.getLong("loopSuspendedTill", 0L);
isSuperBolus = SP.getBoolean("isSuperBolus", false); isSuperBolus = SP.getBoolean("isSuperBolus", false);
@ -127,7 +140,7 @@ public class LoopPlugin extends PluginBase {
@Override @Override
public boolean specialEnableCondition() { public boolean specialEnableCondition() {
PumpInterface pump = ConfigBuilderPlugin.getActivePump(); PumpInterface pump = ConfigBuilderPlugin.getPlugin().getActivePump();
return pump == null || pump.getPumpDescription().isTempBasalCapable; return pump == null || pump.getPumpDescription().isTempBasalCapable;
} }
@ -136,9 +149,7 @@ public class LoopPlugin extends PluginBase {
* has current data to work with. However, autosens calculation can be triggered by multiple * has current data to work with. However, autosens calculation can be triggered by multiple
* sources and currently only a new BG should trigger a loop run. Hence we return early if * sources and currently only a new BG should trigger a loop run. Hence we return early if
* the event causing the calculation is not EventNewBg. * the event causing the calculation is not EventNewBg.
* * <p>
* Callers of {@link info.nightscout.androidaps.plugins.IobCobCalculator.IobCobCalculatorPlugin#runCalculation(String, long, boolean, Event)}
* are sources triggering a calculation which triggers this method upon completion.
*/ */
@Subscribe @Subscribe
public void onStatusEvent(final EventAutosensCalculationFinished ev) { public void onStatusEvent(final EventAutosensCalculationFinished ev) {
@ -253,25 +264,27 @@ public class LoopPlugin extends PluginBase {
public synchronized void invoke(String initiator, boolean allowNotification, boolean tempBasalFallback) { public synchronized void invoke(String initiator, boolean allowNotification, boolean tempBasalFallback) {
try { try {
if (Config.logFunctionCalls) if (L.isEnabled(L.APS))
log.debug("invoke from " + initiator); log.debug("invoke from " + initiator);
Constraint<Boolean> loopEnabled = MainApp.getConstraintChecker().isLoopInvokationAllowed(); Constraint<Boolean> loopEnabled = MainApp.getConstraintChecker().isLoopInvokationAllowed();
if (!loopEnabled.value()) { if (!loopEnabled.value()) {
String message = MainApp.gs(R.string.loopdisabled) + "\n" + loopEnabled.getReasons(); String message = MainApp.gs(R.string.loopdisabled) + "\n" + loopEnabled.getReasons();
if (L.isEnabled(L.APS))
log.debug(message); log.debug(message);
MainApp.bus().post(new EventLoopSetLastRunGui(message)); MainApp.bus().post(new EventLoopSetLastRunGui(message));
return; return;
} }
final PumpInterface pump = ConfigBuilderPlugin.getActivePump(); final PumpInterface pump = ConfigBuilderPlugin.getPlugin().getActivePump();
APSResult result = null; APSResult result = null;
if (!isEnabled(PluginType.LOOP)) if (!isEnabled(PluginType.LOOP))
return; return;
Profile profile = MainApp.getConfigBuilder().getProfile(); Profile profile = ProfileFunctions.getInstance().getProfile();
if (!MainApp.getConfigBuilder().isProfileValid("Loop")) { if (!ProfileFunctions.getInstance().isProfileValid("Loop")) {
if (L.isEnabled(L.APS))
log.debug(MainApp.gs(R.string.noprofileselected)); log.debug(MainApp.gs(R.string.noprofileselected));
MainApp.bus().post(new EventLoopSetLastRunGui(MainApp.gs(R.string.noprofileselected))); MainApp.bus().post(new EventLoopSetLastRunGui(MainApp.gs(R.string.noprofileselected)));
return; return;
@ -280,7 +293,7 @@ public class LoopPlugin extends PluginBase {
// Check if pump info is loaded // Check if pump info is loaded
if (pump.getBaseBasalRate() < 0.01d) return; if (pump.getBaseBasalRate() < 0.01d) return;
APSInterface usedAPS = ConfigBuilderPlugin.getActiveAPS(); APSInterface usedAPS = ConfigBuilderPlugin.getPlugin().getActiveAPS();
if (usedAPS != null && ((PluginBase) usedAPS).isEnabled(PluginType.APS)) { if (usedAPS != null && ((PluginBase) usedAPS).isEnabled(PluginType.APS)) {
usedAPS.invoke(initiator, tempBasalFallback); usedAPS.invoke(initiator, tempBasalFallback);
result = usedAPS.getLastAPSResult(); result = usedAPS.getLastAPSResult();
@ -292,16 +305,27 @@ public class LoopPlugin extends PluginBase {
return; return;
} }
// Prepare for pumps using % basals
if (pump.getPumpDescription().tempBasalStyle == PumpDescription.PERCENT) {
result.usePercent = true;
}
result.percent = (int) (result.rate / profile.getBasal() * 100);
// check rate for constrais // check rate for constrais
final APSResult resultAfterConstraints = result.clone(); final APSResult resultAfterConstraints = result.clone();
resultAfterConstraints.rateConstraint = new Constraint<>(resultAfterConstraints.rate); resultAfterConstraints.rateConstraint = new Constraint<>(resultAfterConstraints.rate);
resultAfterConstraints.rate = MainApp.getConstraintChecker().applyBasalConstraints(resultAfterConstraints.rateConstraint, profile).value(); resultAfterConstraints.rate = MainApp.getConstraintChecker().applyBasalConstraints(resultAfterConstraints.rateConstraint, profile).value();
resultAfterConstraints.percentConstraint = new Constraint<>(resultAfterConstraints.percent);
resultAfterConstraints.percent = MainApp.getConstraintChecker().applyBasalPercentConstraints(resultAfterConstraints.percentConstraint, profile).value();
resultAfterConstraints.smbConstraint = new Constraint<>(resultAfterConstraints.smb); resultAfterConstraints.smbConstraint = new Constraint<>(resultAfterConstraints.smb);
resultAfterConstraints.smb = MainApp.getConstraintChecker().applyBolusConstraints(resultAfterConstraints.smbConstraint).value(); resultAfterConstraints.smb = MainApp.getConstraintChecker().applyBolusConstraints(resultAfterConstraints.smbConstraint).value();
// safety check for multiple SMBs // safety check for multiple SMBs
long lastBolusTime = TreatmentsPlugin.getPlugin().getLastBolusTime(); long lastBolusTime = TreatmentsPlugin.getPlugin().getLastBolusTime();
if (lastBolusTime != 0 && lastBolusTime + 3 * 60 * 1000 > System.currentTimeMillis()) { if (lastBolusTime != 0 && lastBolusTime + T.mins(3).msecs() > System.currentTimeMillis()) {
if (L.isEnabled(L.APS))
log.debug("SMB requsted but still in 3 min interval"); log.debug("SMB requsted but still in 3 min interval");
resultAfterConstraints.smb = 0; resultAfterConstraints.smb = 0;
} }
@ -317,12 +341,14 @@ public class LoopPlugin extends PluginBase {
NSUpload.uploadDeviceStatus(); NSUpload.uploadDeviceStatus();
if (isSuspended()) { if (isSuspended()) {
if (L.isEnabled(L.APS))
log.debug(MainApp.gs(R.string.loopsuspended)); log.debug(MainApp.gs(R.string.loopsuspended));
MainApp.bus().post(new EventLoopSetLastRunGui(MainApp.gs(R.string.loopsuspended))); MainApp.bus().post(new EventLoopSetLastRunGui(MainApp.gs(R.string.loopsuspended)));
return; return;
} }
if (pump.isSuspended()) { if (pump.isSuspended()) {
if (L.isEnabled(L.APS))
log.debug(MainApp.gs(R.string.pumpsuspended)); log.debug(MainApp.gs(R.string.pumpsuspended));
MainApp.bus().post(new EventLoopSetLastRunGui(MainApp.gs(R.string.pumpsuspended))); MainApp.bus().post(new EventLoopSetLastRunGui(MainApp.gs(R.string.pumpsuspended)));
return; return;
@ -331,7 +357,9 @@ public class LoopPlugin extends PluginBase {
Constraint<Boolean> closedLoopEnabled = MainApp.getConstraintChecker().isClosedLoopAllowed(); Constraint<Boolean> closedLoopEnabled = MainApp.getConstraintChecker().isClosedLoopAllowed();
if (closedLoopEnabled.value()) { if (closedLoopEnabled.value()) {
if (result.isChangeRequested()) { if (resultAfterConstraints.isChangeRequested()
&& !ConfigBuilderPlugin.getPlugin().getCommandQueue().bolusInQueue()
&& !ConfigBuilderPlugin.getPlugin().getCommandQueue().isRunning(Command.CommandType.BOLUS)) {
final PumpEnactResult waiting = new PumpEnactResult(); final PumpEnactResult waiting = new PumpEnactResult();
waiting.queued = true; waiting.queued = true;
if (resultAfterConstraints.tempBasalRequested) if (resultAfterConstraints.tempBasalRequested)
@ -340,13 +368,13 @@ public class LoopPlugin extends PluginBase {
lastRun.smbSetByPump = waiting; lastRun.smbSetByPump = waiting;
MainApp.bus().post(new EventLoopUpdateGui()); MainApp.bus().post(new EventLoopUpdateGui());
FabricPrivacy.getInstance().logCustom(new CustomEvent("APSRequest")); FabricPrivacy.getInstance().logCustom(new CustomEvent("APSRequest"));
MainApp.getConfigBuilder().applyTBRRequest(resultAfterConstraints, profile, new Callback() { applyTBRRequest(resultAfterConstraints, profile, new Callback() {
@Override @Override
public void run() { public void run() {
if (result.enacted || result.success) { if (result.enacted || result.success) {
lastRun.tbrSetByPump = result; lastRun.tbrSetByPump = result;
lastRun.lastEnact = lastRun.lastAPSRun; lastRun.lastEnact = lastRun.lastAPSRun;
MainApp.getConfigBuilder().applySMBRequest(resultAfterConstraints, new Callback() { applySMBRequest(resultAfterConstraints, new Callback() {
@Override @Override
public void run() { public void run() {
//Callback is only called if a bolus was acutally requested //Callback is only called if a bolus was acutally requested
@ -372,7 +400,7 @@ public class LoopPlugin extends PluginBase {
lastRun.smbSetByPump = null; lastRun.smbSetByPump = null;
} }
} else { } else {
if (result.isChangeRequested() && allowNotification) { if (resultAfterConstraints.isChangeRequested() && allowNotification) {
NotificationCompat.Builder builder = NotificationCompat.Builder builder =
new NotificationCompat.Builder(MainApp.instance().getApplicationContext(), CHANNEL_ID); new NotificationCompat.Builder(MainApp.instance().getApplicationContext(), CHANNEL_ID);
builder.setSmallIcon(R.drawable.notif_icon) builder.setSmallIcon(R.drawable.notif_icon)
@ -381,7 +409,8 @@ public class LoopPlugin extends PluginBase {
.setAutoCancel(true) .setAutoCancel(true)
.setPriority(Notification.PRIORITY_HIGH) .setPriority(Notification.PRIORITY_HIGH)
.setCategory(Notification.CATEGORY_ALARM) .setCategory(Notification.CATEGORY_ALARM)
.setVisibility(Notification.VISIBILITY_PUBLIC); .setVisibility(Notification.VISIBILITY_PUBLIC)
.setLocalOnly(true);
// Creates an explicit intent for an Activity in your app // Creates an explicit intent for an Activity in your app
Intent resultIntent = new Intent(MainApp.instance().getApplicationContext(), MainActivity.class); Intent resultIntent = new Intent(MainApp.instance().getApplicationContext(), MainActivity.class);
@ -403,14 +432,243 @@ public class LoopPlugin extends PluginBase {
// mId allows you to update the notification later on. // mId allows you to update the notification later on.
mNotificationManager.notify(Constants.notificationID, builder.build()); mNotificationManager.notify(Constants.notificationID, builder.build());
MainApp.bus().post(new EventNewOpenLoopNotification()); MainApp.bus().post(new EventNewOpenLoopNotification());
// Send to Wear
ActionStringHandler.handleInitiate("changeRequest");
} else if (allowNotification) {
// dismiss notifications
NotificationManager notificationManager =
(NotificationManager) MainApp.instance().getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.cancel(Constants.notificationID);
ActionStringHandler.handleInitiate("cancelChangeRequest");
} }
} }
MainApp.bus().post(new EventLoopUpdateGui()); MainApp.bus().post(new EventLoopUpdateGui());
} finally { } finally {
if (Config.logFunctionCalls) if (L.isEnabled(L.APS))
log.debug("invoke end"); log.debug("invoke end");
} }
} }
public void acceptChangeRequest() {
Profile profile = ProfileFunctions.getInstance().getProfile();
applyTBRRequest(lastRun.constraintsProcessed, profile, new Callback() {
@Override
public void run() {
if (result.enacted) {
lastRun.tbrSetByPump = result;
lastRun.lastEnact = new Date();
lastRun.lastOpenModeAccept = new Date();
NSUpload.uploadDeviceStatus();
ObjectivesPlugin objectivesPlugin = MainApp.getSpecificPlugin(ObjectivesPlugin.class);
if (objectivesPlugin != null) {
ObjectivesPlugin.getPlugin().manualEnacts++;
ObjectivesPlugin.getPlugin().saveProgress();
}
}
MainApp.bus().post(new EventAcceptOpenLoopChange());
}
});
FabricPrivacy.getInstance().logCustom(new CustomEvent("AcceptTemp"));
}
/**
* expect absolute request and allow both absolute and percent response based on pump capabilities
* TODO: update pump drivers to support APS request in %
*/
public void applyTBRRequest(APSResult request, Profile profile, Callback callback) {
boolean allowPercentage = VirtualPumpPlugin.getPlugin().isEnabled(PluginType.PUMP);
if (!request.tempBasalRequested) {
if (callback != null) {
callback.result(new PumpEnactResult().enacted(false).success(true).comment(MainApp.gs(R.string.nochangerequested))).run();
}
return;
}
PumpInterface pump = ConfigBuilderPlugin.getPlugin().getActivePump();
TreatmentsInterface activeTreatments = TreatmentsPlugin.getPlugin();
if (!pump.isInitialized()) {
if (L.isEnabled(L.APS))
log.debug("applyAPSRequest: " + MainApp.gs(R.string.pumpNotInitialized));
if (callback != null) {
callback.result(new PumpEnactResult().comment(MainApp.gs(R.string.pumpNotInitialized)).enacted(false).success(false)).run();
}
return;
}
if (pump.isSuspended()) {
if (L.isEnabled(L.APS))
log.debug("applyAPSRequest: " + MainApp.gs(R.string.pumpsuspended));
if (callback != null) {
callback.result(new PumpEnactResult().comment(MainApp.gs(R.string.pumpsuspended)).enacted(false).success(false)).run();
}
return;
}
if (L.isEnabled(L.APS))
log.debug("applyAPSRequest: " + request.toString());
long now = System.currentTimeMillis();
TemporaryBasal activeTemp = activeTreatments.getTempBasalFromHistory(now);
if (request.usePercent && allowPercentage) {
if (request.percent == 100 && request.duration == 0) {
if (activeTemp != null) {
if (L.isEnabled(L.APS))
log.debug("applyAPSRequest: cancelTempBasal()");
ConfigBuilderPlugin.getPlugin().getCommandQueue().cancelTempBasal(false, callback);
} else {
if (L.isEnabled(L.APS))
log.debug("applyAPSRequest: Basal set correctly");
if (callback != null) {
callback.result(new PumpEnactResult().percent(request.percent).duration(0)
.enacted(false).success(true).comment(MainApp.gs(R.string.basal_set_correctly))).run();
}
}
} else if (activeTemp != null
&& activeTemp.getPlannedRemainingMinutes() > 5
&& request.duration - activeTemp.getPlannedRemainingMinutes() < 30
&& request.percent == activeTemp.percentRate) {
if (L.isEnabled(L.APS))
log.debug("applyAPSRequest: Temp basal set correctly");
if (callback != null) {
callback.result(new PumpEnactResult().percent(request.percent)
.enacted(false).success(true).duration(activeTemp.getPlannedRemainingMinutes())
.comment(MainApp.gs(R.string.let_temp_basal_run))).run();
}
} else {
if (L.isEnabled(L.APS))
log.debug("applyAPSRequest: tempBasalPercent()");
ConfigBuilderPlugin.getPlugin().getCommandQueue().tempBasalPercent(request.percent, request.duration, false, profile, callback);
}
} else {
if ((request.rate == 0 && request.duration == 0) || Math.abs(request.rate - pump.getBaseBasalRate()) < pump.getPumpDescription().basalStep) {
if (activeTemp != null) {
if (L.isEnabled(L.APS))
log.debug("applyAPSRequest: cancelTempBasal()");
ConfigBuilderPlugin.getPlugin().getCommandQueue().cancelTempBasal(false, callback);
} else {
if (L.isEnabled(L.APS))
log.debug("applyAPSRequest: Basal set correctly");
if (callback != null) {
callback.result(new PumpEnactResult().absolute(request.rate).duration(0)
.enacted(false).success(true).comment(MainApp.gs(R.string.basal_set_correctly))).run();
}
}
} else if (activeTemp != null
&& activeTemp.getPlannedRemainingMinutes() > 5
&& request.duration - activeTemp.getPlannedRemainingMinutes() < 30
&& Math.abs(request.rate - activeTemp.tempBasalConvertedToAbsolute(now, profile)) < pump.getPumpDescription().basalStep) {
if (L.isEnabled(L.APS))
log.debug("applyAPSRequest: Temp basal set correctly");
if (callback != null) {
callback.result(new PumpEnactResult().absolute(activeTemp.tempBasalConvertedToAbsolute(now, profile))
.enacted(false).success(true).duration(activeTemp.getPlannedRemainingMinutes())
.comment(MainApp.gs(R.string.let_temp_basal_run))).run();
}
} else {
if (L.isEnabled(L.APS))
log.debug("applyAPSRequest: setTempBasalAbsolute()");
ConfigBuilderPlugin.getPlugin().getCommandQueue().tempBasalAbsolute(request.rate, request.duration, false, profile, callback);
}
}
}
public void applySMBRequest(APSResult request, Callback callback) {
if (!request.bolusRequested) {
return;
}
PumpInterface pump = ConfigBuilderPlugin.getPlugin().getActivePump();
TreatmentsInterface activeTreatments = TreatmentsPlugin.getPlugin();
long lastBolusTime = activeTreatments.getLastBolusTime();
if (lastBolusTime != 0 && lastBolusTime + 3 * 60 * 1000 > System.currentTimeMillis()) {
if (L.isEnabled(L.APS))
log.debug("SMB requested but still in 3 min interval");
if (callback != null) {
callback.result(new PumpEnactResult()
.comment(MainApp.gs(R.string.smb_frequency_exceeded))
.enacted(false).success(false)).run();
}
return;
}
if (!pump.isInitialized()) {
if (L.isEnabled(L.APS))
log.debug("applySMBRequest: " + MainApp.gs(R.string.pumpNotInitialized));
if (callback != null) {
callback.result(new PumpEnactResult().comment(MainApp.gs(R.string.pumpNotInitialized)).enacted(false).success(false)).run();
}
return;
}
if (pump.isSuspended()) {
if (L.isEnabled(L.APS))
log.debug("applySMBRequest: " + MainApp.gs(R.string.pumpsuspended));
if (callback != null) {
callback.result(new PumpEnactResult().comment(MainApp.gs(R.string.pumpsuspended)).enacted(false).success(false)).run();
}
return;
}
if (L.isEnabled(L.APS))
log.debug("applySMBRequest: " + request.toString());
// deliver SMB
DetailedBolusInfo detailedBolusInfo = new DetailedBolusInfo();
detailedBolusInfo.lastKnownBolusTime = activeTreatments.getLastBolusTime();
detailedBolusInfo.eventType = CareportalEvent.CORRECTIONBOLUS;
detailedBolusInfo.insulin = request.smb;
detailedBolusInfo.isSMB = true;
detailedBolusInfo.source = Source.USER;
detailedBolusInfo.deliverAt = request.deliverAt;
if (L.isEnabled(L.APS))
log.debug("applyAPSRequest: bolus()");
ConfigBuilderPlugin.getPlugin().getCommandQueue().bolus(detailedBolusInfo, callback);
}
public void disconnectPump(int durationInMinutes, Profile profile) {
PumpInterface pump = ConfigBuilderPlugin.getPlugin().getActivePump();
TreatmentsInterface activeTreatments = TreatmentsPlugin.getPlugin();
LoopPlugin.getPlugin().disconnectTo(System.currentTimeMillis() + durationInMinutes * 60 * 1000L);
ConfigBuilderPlugin.getPlugin().getCommandQueue().tempBasalPercent(0, durationInMinutes, true, profile, new Callback() {
@Override
public void run() {
if (!result.success) {
ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), MainApp.gs(R.string.tempbasaldeliveryerror));
}
}
});
if (pump.getPumpDescription().isExtendedBolusCapable && activeTreatments.isInHistoryExtendedBoluslInProgress()) {
ConfigBuilderPlugin.getPlugin().getCommandQueue().cancelExtended(new Callback() {
@Override
public void run() {
if (!result.success) {
ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), MainApp.gs(R.string.extendedbolusdeliveryerror));
}
}
});
}
NSUpload.uploadOpenAPSOffline(durationInMinutes);
}
public void suspendLoop(int durationInMinutes) {
LoopPlugin.getPlugin().suspendTo(System.currentTimeMillis() + durationInMinutes * 60 * 1000);
ConfigBuilderPlugin.getPlugin().getCommandQueue().cancelTempBasal(true, new Callback() {
@Override
public void run() {
if (!result.success) {
ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), MainApp.gs(R.string.tempbasaldeliveryerror));
}
}
});
NSUpload.uploadOpenAPSOffline(durationInMinutes);
}
} }

View file

@ -0,0 +1,160 @@
package info.nightscout.androidaps.plugins.Maintenance;
import android.Manifest;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.os.Environment;
import android.preference.PreferenceManager;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.Fragment;
import android.support.v4.content.ContextCompat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Map;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.events.EventAppExit;
import info.nightscout.androidaps.logging.L;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.utils.OKDialog;
import info.nightscout.utils.ToastUtils;
/**
* Created by mike on 03.07.2016.
*/
public class ImportExportPrefs {
private static Logger log = LoggerFactory.getLogger(L.CORE);
static File path = new File(Environment.getExternalStorageDirectory().toString());
static public final File file = new File(path, MainApp.gs(R.string.app_name) + "Preferences");
private static final int REQUEST_EXTERNAL_STORAGE = 1;
private static String[] PERMISSIONS_STORAGE = {
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
};
public static void verifyStoragePermissions(Activity activity) {
// Check if we have write permission
int permission = ActivityCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE);
if (permission != PackageManager.PERMISSION_GRANTED) {
// We don't have permission so prompt the user
ActivityCompat.requestPermissions(
activity,
PERMISSIONS_STORAGE,
REQUEST_EXTERNAL_STORAGE
);
}
}
public static void verifyStoragePermissions(Fragment fragment) {
int permission = ContextCompat.checkSelfPermission(fragment.getContext(),
Manifest.permission.WRITE_EXTERNAL_STORAGE);
if (permission != PackageManager.PERMISSION_GRANTED) {
// We don't have permission so prompt the user
fragment.requestPermissions(PERMISSIONS_STORAGE, REQUEST_EXTERNAL_STORAGE);
}
}
public static void exportSharedPreferences(final Fragment f) {
exportSharedPreferences(f.getContext());
}
public static void exportSharedPreferences(final Context c) {
new AlertDialog.Builder(c)
.setMessage(MainApp.gs(R.string.export_to) + " " + file + " ?")
.setPositiveButton(android.R.string.yes, (dialog, which) -> {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(c);
try {
FileWriter fw = new FileWriter(file);
PrintWriter pw = new PrintWriter(fw);
Map<String, ?> prefsMap = prefs.getAll();
for (Map.Entry<String, ?> entry : prefsMap.entrySet()) {
pw.println(entry.getKey() + "::" + entry.getValue().toString());
}
pw.close();
fw.close();
ToastUtils.showToastInUiThread(c, MainApp.gs(R.string.exported));
} catch (FileNotFoundException e) {
ToastUtils.showToastInUiThread(c, MainApp.gs(R.string.filenotfound) + " " + file);
log.error("Unhandled exception", e);
} catch (IOException e) {
log.error("Unhandled exception", e);
}
})
.setNegativeButton(android.R.string.cancel, null)
.show();
}
public static void importSharedPreferences(final Fragment fragment) {
importSharedPreferences(fragment.getContext());
}
public static void importSharedPreferences(final Context context) {
new AlertDialog.Builder(context)
.setMessage(MainApp.gs(R.string.import_from) + " " + file + " ?")
.setPositiveButton(android.R.string.yes, (dialog, which) -> {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor editor = prefs.edit();
String line;
String[] lineParts;
try {
editor.clear();
editor.commit();
BufferedReader reader = new BufferedReader(new FileReader(file));
while ((line = reader.readLine()) != null) {
lineParts = line.split("::");
if (lineParts.length == 2) {
if (lineParts[1].equals("true") || lineParts[1].equals("false")) {
editor.putBoolean(lineParts[0], Boolean.parseBoolean(lineParts[1]));
} else {
editor.putString(lineParts[0], lineParts[1]);
}
}
}
reader.close();
editor.commit();
OKDialog.show(context, MainApp.gs(R.string.setting_imported), MainApp.gs(R.string.restartingapp), () -> {
log.debug("Exiting");
MainApp.instance().stopKeepAliveService();
MainApp.bus().post(new EventAppExit());
MainApp.closeDbHelper();
if (context instanceof Activity) {
((Activity)context).finish();
}
System.runFinalization();
System.exit(0);
});
} catch (FileNotFoundException e) {
ToastUtils.showToastInUiThread(context, MainApp.gs(R.string.filenotfound) + " " + file);
log.error("Unhandled exception", e);
} catch (IOException e) {
log.error("Unhandled exception", e);
}
})
.setNegativeButton(android.R.string.cancel, null)
.show();
}
}

View file

@ -0,0 +1,29 @@
package info.nightscout.androidaps.plugins.Maintenance;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ch.qos.logback.classic.LoggerContext;
import info.nightscout.androidaps.logging.L;
/**
* This class provides serveral methods for log-handling (eg. sending logs as emails).
*/
public class LoggerUtils {
private static final Logger LOGGER = LoggerFactory.getLogger(L.CORE);
public static String SUFFIX = ".log.zip";
/**
* Returns the directory, in which the logs are stored on the system. This is configured in the
* logback.xml file.
*
* @return
*/
public static String getLogDirectory() {
LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
return lc.getProperty("EXT_FILES_DIR");
}
}

View file

@ -0,0 +1,83 @@
package info.nightscout.androidaps.plugins.Maintenance;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v7.app.AlertDialog;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.plugins.Food.FoodPlugin;
import info.nightscout.androidaps.plugins.Maintenance.activities.LogSettingActivity;
import info.nightscout.androidaps.plugins.Treatments.TreatmentsPlugin;
/**
*
*/
public class MaintenanceFragment extends Fragment {
private Fragment f;
@Override
public void onResume() {
super.onResume();
this.f = this;
}
@Override
public void onPause() {
super.onPause();
this.f = null;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.maintenance_fragment, container, false);
final Fragment f = this;
view.findViewById(R.id.log_send).setOnClickListener(view1 -> MaintenancePlugin.getPlugin().sendLogs());
view.findViewById(R.id.log_delete).setOnClickListener(view1 -> MaintenancePlugin.getPlugin().deleteLogs());
view.findViewById(R.id.nav_resetdb).setOnClickListener(view1 -> new AlertDialog.Builder(f.getContext())
.setTitle(R.string.nav_resetdb)
.setMessage(R.string.reset_db_confirm)
.setNegativeButton(android.R.string.cancel, null)
.setPositiveButton(android.R.string.ok, (dialog, which) -> {
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()
.show());
view.findViewById(R.id.nav_export).setOnClickListener(view1 -> {
// start activity for checking permissions...
ImportExportPrefs.verifyStoragePermissions(f);
ImportExportPrefs.exportSharedPreferences(f);
});
view.findViewById(R.id.nav_import).setOnClickListener(view1 -> {
// start activity for checking permissions...
ImportExportPrefs.verifyStoragePermissions(f);
ImportExportPrefs.importSharedPreferences(f);
});
view.findViewById(R.id.nav_logsettings).setOnClickListener(view1 -> {
startActivity(new Intent(getActivity(), LogSettingActivity.class));
});
return view;
}
}

View file

@ -0,0 +1,265 @@
package info.nightscout.androidaps.plugins.Maintenance;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.support.v4.content.FileProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import info.nightscout.androidaps.BuildConfig;
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.PluginDescription;
import info.nightscout.androidaps.interfaces.PluginType;
import info.nightscout.androidaps.logging.L;
import info.nightscout.androidaps.plugins.NSClientInternal.data.NSSettingsStatus;
import info.nightscout.utils.SP;
public class MaintenancePlugin extends PluginBase {
private static final Logger LOG = LoggerFactory.getLogger(L.CORE);
private final Context ctx;
private static MaintenancePlugin maintenancePlugin;
public static MaintenancePlugin getPlugin() {
return maintenancePlugin;
}
public static MaintenancePlugin initPlugin(Context ctx) {
if (maintenancePlugin == null) {
maintenancePlugin = new MaintenancePlugin(ctx);
}
return maintenancePlugin;
}
public MaintenancePlugin() {
// required for testing
super(null);
this.ctx = null;
}
MaintenancePlugin(Context ctx) {
super(new PluginDescription()
.mainType(PluginType.GENERAL)
.fragmentClass(MaintenanceFragment.class.getName())
.alwayVisible(false)
.alwaysEnabled(true)
.pluginName(R.string.maintenance)
.shortName(R.string.maintenance_shortname)
.preferencesId(R.xml.pref_maintenance)
.description(R.string.description_maintenance)
);
this.ctx = ctx;
}
public void sendLogs() {
String recipient = SP.getString(R.string.key_maintenance_logs_email, "logs@androidaps.org");
int amount = SP.getInt(R.string.key_maintenance_logs_amount, 2);
String logDirectory = LoggerUtils.getLogDirectory();
List<File> logs = this.getLogfiles(logDirectory, amount);
File zipDir = this.ctx.getExternalFilesDir("exports");
File zipFile = new File(zipDir, this.constructName());
LOG.debug("zipFile: {}", zipFile.getAbsolutePath());
File zip = this.zipLogs(zipFile, logs);
Uri attachementUri = FileProvider.getUriForFile(this.ctx, BuildConfig.APPLICATION_ID + ".fileprovider", zip);
Intent emailIntent = this.sendMail(attachementUri, recipient, "Log Export");
LOG.debug("sending emailIntent");
ctx.startActivity(emailIntent);
}
//todo replace this with a call on startup of the application, specifically to remove
// unnecessary garbage from the log exports
public void deleteLogs() {
String logDirectory = LoggerUtils.getLogDirectory();
File logDir = new File(logDirectory);
File[] files = logDir.listFiles((file, name) -> name.startsWith("AndroidAPS")
&& name.endsWith(".zip"));
Arrays.sort(files, (f1, f2) -> f1.getName().compareTo(f2.getName()));
List<File> delFiles = Arrays.asList(files);
int amount = SP.getInt(R.string.key_logshipper_amount, 2);
int keepIndex = amount - 1;
if (keepIndex < delFiles.size()) {
delFiles = delFiles.subList(keepIndex, delFiles.size());
for (File file : delFiles) {
file.delete();
}
}
File exportDir = new File(logDirectory, "exports");
if (exportDir.exists()) {
File[] expFiles = exportDir.listFiles();
for (File file : expFiles) {
file.delete();
}
exportDir.delete();
}
}
/**
* returns a list of log files. The number of returned logs is given via the amount
* parameter.
*
* The log files are sorted by the name descending.
*
* @param directory
* @param amount
* @return
*/
public List<File> getLogfiles(String directory, int amount) {
LOG.debug("getting {} logs from directory {}", amount, directory);
File logDir = new File(directory);
File[] files = logDir.listFiles((file, name) -> name.startsWith("AndroidAPS")
&& (name.endsWith(".log")
|| (name.endsWith(".zip") && !name.endsWith(LoggerUtils.SUFFIX))));
Arrays.sort(files, (f1, f2) -> f2.getName().compareTo(f1.getName()));
List<File> result = Arrays.asList(files);
int toIndex = amount++;
if (toIndex > result.size()) {
toIndex = result.size();
}
LOG.debug("returning sublist 0 to {}", toIndex);
return result.subList(0, toIndex);
}
public File zipLogs(File zipFile, List<File> files) {
LOG.debug("creating zip {}", zipFile.getAbsolutePath());
try {
zip(zipFile, files);
} catch (IOException e) {
LOG.error("Cannot retrieve zip", e);
}
return zipFile;
}
/**
* construct the name of zip file which is used to export logs.
*
* The name is constructed using the following scheme:
* AndroidAPS_LOG_ + Long Time + .log.zip
*
* @return
*/
public String constructName() {
return "AndroidAPS_LOG_" + String.valueOf(new Date().getTime()) + LoggerUtils.SUFFIX;
}
public void zip(File zipFile, List<File> files) throws IOException {
final int BUFFER_SIZE = 2048;
ZipOutputStream out = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(zipFile)));
for (File file : files) {
byte data[] = new byte[BUFFER_SIZE];
try(FileInputStream fileInputStream = new FileInputStream( file )) {
try(BufferedInputStream origin = new BufferedInputStream(fileInputStream, BUFFER_SIZE)) {
ZipEntry entry = new ZipEntry(file.getName());
out.putNextEntry(entry);
int count;
while ((count = origin.read(data, 0, BUFFER_SIZE)) != -1) {
out.write(data, 0, count);
}
}
}
}
out.close();
}
public static Intent sendMail(Uri attachementUri, String recipient, String subject) {
StringBuilder builder =new StringBuilder();
builder.append("ADD TIME OF EVENT HERE: " + System.lineSeparator());
builder.append("ADD ISSUE DESCRIPTION OR GITHUB ISSUE REFERENCE NUMBER: " + System.lineSeparator());
builder.append("-------------------------------------------------------" + System.lineSeparator());
builder.append("(Please remember this will send only very recent logs." + System.lineSeparator());
builder.append("If you want to provide logs for event older than a few hours," + System.lineSeparator());
builder.append("you have to do it manually)" + System.lineSeparator());
builder.append("-------------------------------------------------------" + System.lineSeparator());
builder.append(MainApp.gs(R.string.app_name) + " " + BuildConfig.VERSION + System.lineSeparator());
if (Config.NSCLIENT)
builder.append("NSCLIENT" + System.lineSeparator());
builder.append("Build: " + BuildConfig.BUILDVERSION + System.lineSeparator());
builder.append("Flavor: " + BuildConfig.FLAVOR + BuildConfig.BUILD_TYPE + System.lineSeparator());
builder.append(MainApp.gs(R.string.configbuilder_nightscoutversion_label) + " " + NSSettingsStatus.getInstance().nightscoutVersionName + System.lineSeparator());
if (MainApp.engineeringMode)
builder.append(MainApp.gs(R.string.engineering_mode_enabled));
return sendMail(attachementUri, recipient, subject, builder.toString());
}
/**
* send a mail with the given file to the recipients with the given subject.
*
* the returned intent should be used to really send the mail using
*
* startActivity(Intent.createChooser(emailIntent , "Send email..."));
*
* @param attachementUri
* @param recipient
* @param subject
* @param body
*
* @return
*/
public static Intent sendMail(Uri attachementUri, String recipient, String subject, String body) {
LOG.debug("sending email to {} with subject {}", recipient, subject);
Intent emailIntent = new Intent(Intent.ACTION_SEND);
emailIntent.setType("text/plain");
emailIntent.putExtra(Intent.EXTRA_EMAIL , new String[]{recipient});
emailIntent.putExtra(Intent.EXTRA_SUBJECT, subject);
emailIntent.putExtra(Intent.EXTRA_TEXT, body);
LOG.debug("put path {}", attachementUri.toString());
emailIntent.putExtra(Intent.EXTRA_STREAM, attachementUri);
emailIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
return emailIntent;
}
}

View file

@ -0,0 +1,80 @@
package info.nightscout.androidaps.plugins.Maintenance.activities;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.CheckBox;
import android.widget.LinearLayout;
import android.widget.TextView;
import java.util.List;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import butterknife.Unbinder;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.logging.L;
public class LogSettingActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_logsetting);
ButterKnife.bind(this);
createViewsForSettings(L.getLogElements());
}
private void createViewsForSettings(List<L.LogElement> elements) {
if (elements.size() == 0) return;
LinearLayout container = (LinearLayout) findViewById(R.id.logsettings_placeholder);
container.removeAllViews();
for (L.LogElement element : elements) {
PluginViewHolder pluginViewHolder = new PluginViewHolder(element);
container.addView(pluginViewHolder.getBaseView());
}
}
@OnClick(R.id.logsettings_reset)
public void onResetClick() {
L.resetToDefaults();
createViewsForSettings(L.getLogElements());
}
public class PluginViewHolder {
private Unbinder unbinder;
private L.LogElement element;
LinearLayout baseView;
@BindView(R.id.logsettings_description)
TextView description;
@BindView(R.id.logsettings_visibility)
CheckBox enabled;
public PluginViewHolder(L.LogElement element) {
this.element = element;
baseView = (LinearLayout) getLayoutInflater().inflate(R.layout.logsettings_item, null);
unbinder = ButterKnife.bind(this, baseView);
description.setText(element.name);
enabled.setChecked(element.enabled);
}
public View getBaseView() {
return baseView;
}
@OnClick(R.id.logsettings_visibility)
void onEnagledChanged() {
element.setEnabled(enabled.isChecked());
}
public void unbind() {
unbinder.unbind();
}
}
}

View file

@ -34,8 +34,6 @@ import info.nightscout.utils.FabricPrivacy;
import info.nightscout.utils.SP; import info.nightscout.utils.SP;
public class NSClientFragment extends SubscriberFragment implements View.OnClickListener, CompoundButton.OnCheckedChangeListener { public class NSClientFragment extends SubscriberFragment implements View.OnClickListener, CompoundButton.OnCheckedChangeListener {
private static Logger log = LoggerFactory.getLogger(NSClientFragment.class);
private TextView logTextView; private TextView logTextView;
private TextView queueTextView; private TextView queueTextView;
private TextView urlTextView; private TextView urlTextView;
@ -133,9 +131,7 @@ public class NSClientFragment extends SubscriberFragment implements View.OnClick
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
switch (buttonView.getId()) { switch (buttonView.getId()) {
case R.id.nsclientinternal_paused: case R.id.nsclientinternal_paused:
SP.putBoolean(R.string.key_nsclientinternal_paused, isChecked); NSClientPlugin.getPlugin().pause(isChecked);
NSClientPlugin.getPlugin().paused = isChecked;
MainApp.bus().post(new EventPreferenceChange(R.string.key_nsclientinternal_paused));
updateGUI(); updateGUI();
FabricPrivacy.getInstance().logCustom(new CustomEvent("NSClientPause")); FabricPrivacy.getInstance().logCustom(new CustomEvent("NSClientPause"));
break; break;
@ -156,10 +152,9 @@ public class NSClientFragment extends SubscriberFragment implements View.OnClick
protected void updateGUI() { protected void updateGUI() {
Activity activity = getActivity(); Activity activity = getActivity();
if (activity != null) if (activity != null)
activity.runOnUiThread(new Runnable() { activity.runOnUiThread(() -> {
@Override
public void run() {
NSClientPlugin.getPlugin().updateLog(); NSClientPlugin.getPlugin().updateLog();
pausedCheckbox.setChecked(SP.getBoolean(R.string.key_nsclientinternal_paused, false));
logTextView.setText(NSClientPlugin.getPlugin().textLog); logTextView.setText(NSClientPlugin.getPlugin().textLog);
if (NSClientPlugin.getPlugin().autoscroll) { if (NSClientPlugin.getPlugin().autoscroll) {
logScrollview.fullScroll(ScrollView.FOCUS_DOWN); logScrollview.fullScroll(ScrollView.FOCUS_DOWN);
@ -168,7 +163,6 @@ public class NSClientFragment extends SubscriberFragment implements View.OnClick
Spanned queuetext = Html.fromHtml(MainApp.gs(R.string.queue) + " <b>" + UploadQueue.size() + "</b>"); Spanned queuetext = Html.fromHtml(MainApp.gs(R.string.queue) + " <b>" + UploadQueue.size() + "</b>");
queueTextView.setText(queuetext); queueTextView.setText(queuetext);
statusTextView.setText(NSClientPlugin.getPlugin().status); statusTextView.setText(NSClientPlugin.getPlugin().status);
}
}); });
} }

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