diff --git a/app/build.gradle b/app/build.gradle index 152572006c..31de31b970 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -44,7 +44,7 @@ android { minSdkVersion 21 targetSdkVersion 23 versionCode 1100 - version "1.3rc1" + version "1.33" buildConfigField "String", "VERSION", '"' + version + '"' buildConfigField "String", "BUILDVERSION", generateGitBuild() } @@ -140,10 +140,10 @@ dependencies { wearcontrolWearApp project(path: ':wear', configuration: 'fullRelease') compile fileTree(include: ['*.jar'], dir: 'libs') - compile('com.crashlytics.sdk.android:crashlytics:2.6.6@aar') { + compile('com.crashlytics.sdk.android:crashlytics:2.6.7@aar') { transitive = true; } - compile('com.crashlytics.sdk.android:answers:1.3.11@aar') { + compile('com.crashlytics.sdk.android:answers:1.3.12@aar') { transitive = true; } @@ -170,14 +170,18 @@ dependencies { testCompile 'org.json:json:20140107' testCompile 'org.mockito:mockito-core:2.+' androidTestCompile 'org.mockito:mockito-core:2.+' - androidTestCompile "com.google.dexmaker:dexmaker:1.2" - androidTestCompile "com.google.dexmaker:dexmaker-mockito:1.2" - compile(name:'android-edittext-validator-v1.3.4-mod', ext:'aar') - compile ('io.socket:socket.io-client:0.8.3') { + androidTestCompile 'com.google.dexmaker:dexmaker:1.2' + androidTestCompile 'com.google.dexmaker:dexmaker-mockito:1.2' + compile(name: 'android-edittext-validator-v1.3.4-mod', ext: 'aar') + compile('io.socket:socket.io-client:0.8.3') { // excluding org.json which is provided by Android exclude group: 'org.json', module: 'json' } compile 'com.google.code.gson:gson:2.4' compile 'com.google.guava:guava:18.0' + compile ('com.jakewharton:butterknife:8.5.1') { + exclude module: 'support-compat' + } + annotationProcessor 'com.jakewharton:butterknife-compiler:8.5.1' } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 2694197809..e01ed53f34 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -17,6 +17,7 @@ + @@ -74,6 +75,8 @@ + + diff --git a/app/src/main/java/info/nightscout/androidaps/MainActivity.java b/app/src/main/java/info/nightscout/androidaps/MainActivity.java index 715756259a..ccca5bcb22 100644 --- a/app/src/main/java/info/nightscout/androidaps/MainActivity.java +++ b/app/src/main/java/info/nightscout/androidaps/MainActivity.java @@ -1,13 +1,17 @@ package info.nightscout.androidaps; import android.Manifest; +import android.content.ActivityNotFoundException; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.pm.PackageManager; import android.graphics.Rect; +import android.net.Uri; import android.os.Build; import android.os.Bundle; +import android.os.PowerManager; +import android.provider.Settings; import android.support.v4.app.ActivityCompat; import android.support.v4.content.ContextCompat; import android.support.v4.view.ViewPager; @@ -37,8 +41,10 @@ import info.nightscout.androidaps.tabs.TabPageAdapter; import info.nightscout.utils.ImportExportPrefs; import info.nightscout.utils.LocaleHelper; import info.nightscout.utils.LogDialog; +import info.nightscout.utils.OKDialog; import info.nightscout.utils.PasswordProtection; import info.nightscout.utils.SP; +import info.nightscout.utils.ToastUtils; public class MainActivity extends AppCompatActivity { private static Logger log = LoggerFactory.getLogger(MainActivity.class); @@ -59,6 +65,7 @@ public class MainActivity extends AppCompatActivity { askForPermission(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE}, CASE_STORAGE); } + askForBatteryOptimizationPermission(); if (Config.logFunctionCalls) log.debug("onCreate"); @@ -228,6 +235,37 @@ public class MainActivity extends AppCompatActivity { askForSMSPermissions(); } + private void askForBatteryOptimizationPermission() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + final String packageName = getPackageName(); + + final PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); + if (!pm.isIgnoringBatteryOptimizations(packageName)) { + log.debug("Requesting ignore battery optimization"); + + OKDialog.show(this, getString(R.string.pleaseallowpermission), String.format(getString(R.string.needwhitelisting), getString(R.string.app_name)), new Runnable() { + + @Override + public void run() { + try { + final Intent intent = new Intent(); + + // ignoring battery optimizations required for constant connection + intent.setAction(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS); + intent.setData(Uri.parse("package:" + packageName)); + startActivity(intent); + + } catch (ActivityNotFoundException e) { + final String msg = getString(R.string.batteryoptimalizationerror); + ToastUtils.showToastInUiThread(getApplicationContext(), msg); + log.error(msg); + } + } + }); + } + } + } + private synchronized void askForSMSPermissions() { if (askForSMS) { //only when settings were changed an MainActivity resumes. askForSMS = false; diff --git a/app/src/main/java/info/nightscout/androidaps/MainApp.java b/app/src/main/java/info/nightscout/androidaps/MainApp.java index ec478584a2..6568e03a53 100644 --- a/app/src/main/java/info/nightscout/androidaps/MainApp.java +++ b/app/src/main/java/info/nightscout/androidaps/MainApp.java @@ -19,6 +19,7 @@ import java.util.ArrayList; import info.nightscout.androidaps.db.DatabaseHelper; import info.nightscout.androidaps.interfaces.PluginBase; +import info.nightscout.androidaps.interfaces.PumpInterface; import info.nightscout.androidaps.plugins.Actions.ActionsFragment; import info.nightscout.androidaps.plugins.Careportal.CareportalFragment; import info.nightscout.androidaps.plugins.CircadianPercentageProfile.CircadianPercentageProfileFragment; @@ -38,6 +39,7 @@ import info.nightscout.androidaps.plugins.Overview.OverviewFragment; import info.nightscout.androidaps.plugins.SafetyFragment.SafetyFragment; import info.nightscout.androidaps.plugins.SimpleProfile.SimpleProfileFragment; import info.nightscout.androidaps.plugins.SmsCommunicator.SmsCommunicatorFragment; +import info.nightscout.androidaps.plugins.SourceGlimp.SourceGlimpFragment; import info.nightscout.androidaps.plugins.SourceMM640g.SourceMM640gFragment; import info.nightscout.androidaps.plugins.SourceNSClient.SourceNSClientFragment; import info.nightscout.androidaps.plugins.SourceXdrip.SourceXdripFragment; @@ -104,6 +106,7 @@ public class MainApp extends Application { pluginsList.add(SourceXdripFragment.getPlugin()); pluginsList.add(SourceNSClientFragment.getPlugin()); pluginsList.add(SourceMM640gFragment.getPlugin()); + pluginsList.add(SourceGlimpFragment.getPlugin()); if (Config.SMSCOMMUNICATORENABLED) pluginsList.add(SmsCommunicatorFragment.getPlugin()); if (Config.WEAR) pluginsList.add(WearFragment.getPlugin(this)); @@ -117,6 +120,20 @@ public class MainApp extends Application { MainApp.getConfigBuilder().uploadAppStart(); startKeepAliveService(); + + Thread t = new Thread(new Runnable() { + @Override + public void run() { + try { + Thread.sleep(5000); + } catch (InterruptedException e) { + } + PumpInterface pump = MainApp.getConfigBuilder(); + if (pump != null) + pump.refreshDataFromPump("Initialization"); + } + }); + t.start(); } private void startKeepAliveService() { diff --git a/app/src/main/java/info/nightscout/androidaps/PreferencesActivity.java b/app/src/main/java/info/nightscout/androidaps/PreferencesActivity.java index 132ac5d059..29a4913bc3 100644 --- a/app/src/main/java/info/nightscout/androidaps/PreferencesActivity.java +++ b/app/src/main/java/info/nightscout/androidaps/PreferencesActivity.java @@ -11,7 +11,6 @@ import android.preference.PreferenceFragment; import android.preference.PreferenceGroup; import android.preference.PreferenceManager; - import info.nightscout.androidaps.events.EventPreferenceChange; import info.nightscout.androidaps.events.EventRefreshGui; import info.nightscout.androidaps.interfaces.PluginBase; @@ -50,14 +49,14 @@ public class PreferencesActivity extends PreferenceActivity implements SharedPre updatePrefSummary(myPreferenceFragment.getPreference(key)); } - private static void updatePrefSummary(Preference pref) { + private static void updatePrefSummary(Preference pref) { if (pref instanceof ListPreference || pref instanceof BluetoothDevicePreference) { ListPreference listPref = (ListPreference) pref; pref.setSummary(listPref.getEntry()); } if (pref instanceof EditTextPreference) { EditTextPreference editTextPref = (EditTextPreference) pref; - if (pref.getKey().contains("password")|| pref.getKey().contains("secret")) { + if (pref.getKey().contains("password") || pref.getKey().contains("secret")) { pref.setSummary("******"); } else if (editTextPref.getText() != null && !editTextPref.getText().equals("")) { ((EditTextPreference) pref).setDialogMessage(editTextPref.getDialogMessage()); @@ -119,11 +118,11 @@ public class PreferencesActivity extends PreferenceActivity implements SharedPre } VirtualPumpPlugin virtualPumpPlugin = (VirtualPumpPlugin) MainApp.getSpecificPlugin(VirtualPumpPlugin.class); if (virtualPumpPlugin != null && virtualPumpPlugin.isEnabled(PluginBase.PUMP)) { - addPreferencesFromResource(R.xml.pref_virtualpump); + addPreferencesFromResource(R.xml.pref_virtualpump); } NSClientInternalPlugin nsClientInternalPlugin = (NSClientInternalPlugin) MainApp.getSpecificPlugin(NSClientInternalPlugin.class); if (nsClientInternalPlugin != null && nsClientInternalPlugin.isEnabled(PluginBase.GENERAL)) { - addPreferencesFromResource(R.xml.pref_nsclientinternal); + addPreferencesFromResource(R.xml.pref_nsclientinternal); } if (Config.SMSCOMMUNICATORENABLED) addPreferencesFromResource(R.xml.pref_smscommunicator); @@ -131,7 +130,6 @@ public class PreferencesActivity extends PreferenceActivity implements SharedPre addPreferencesFromResource(R.xml.pref_others); addPreferencesFromResource(R.xml.pref_advanced); } - initSummary(getPreferenceScreen()); if (Config.WEAR) { WearPlugin wearPlugin = (WearPlugin) MainApp.getSpecificPlugin(WearPlugin.class); @@ -139,9 +137,11 @@ public class PreferencesActivity extends PreferenceActivity implements SharedPre addPreferencesFromResource(R.xml.pref_wear); } } + + initSummary(getPreferenceScreen()); } - public Preference getPreference (String key) { + public Preference getPreference(String key) { return findPreference(key); } } diff --git a/app/src/main/java/info/nightscout/androidaps/Services/DataService.java b/app/src/main/java/info/nightscout/androidaps/Services/DataService.java index b27a1a85b4..f45e59f4c1 100644 --- a/app/src/main/java/info/nightscout/androidaps/Services/DataService.java +++ b/app/src/main/java/info/nightscout/androidaps/Services/DataService.java @@ -44,6 +44,7 @@ import info.nightscout.androidaps.plugins.Overview.events.EventDismissNotificati import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification; import info.nightscout.androidaps.plugins.SmsCommunicator.SmsCommunicatorPlugin; import info.nightscout.androidaps.plugins.SmsCommunicator.events.EventNewSMS; +import info.nightscout.androidaps.plugins.SourceGlimp.SourceGlimpPlugin; import info.nightscout.androidaps.plugins.SourceMM640g.SourceMM640gPlugin; import info.nightscout.androidaps.plugins.SourceNSClient.SourceNSClientPlugin; import info.nightscout.androidaps.plugins.SourceXdrip.SourceXdripPlugin; @@ -59,6 +60,7 @@ public class DataService extends IntentService { boolean xDripEnabled = false; boolean nsClientEnabled = true; boolean mm640gEnabled = false; + boolean glimpEnabled = false; public DataService() { super("DataService"); @@ -74,14 +76,22 @@ public class DataService extends IntentService { xDripEnabled = true; nsClientEnabled = false; mm640gEnabled = false; + glimpEnabled = false; } else if (ConfigBuilderPlugin.getActiveBgSource().getClass().equals(SourceNSClientPlugin.class)) { xDripEnabled = false; nsClientEnabled = true; mm640gEnabled = false; + glimpEnabled = false; } else if (ConfigBuilderPlugin.getActiveBgSource().getClass().equals(SourceMM640gPlugin.class)) { xDripEnabled = false; nsClientEnabled = false; mm640gEnabled = true; + glimpEnabled = false; + } else if (ConfigBuilderPlugin.getActiveBgSource().getClass().equals(SourceGlimpPlugin.class)) { + xDripEnabled = false; + nsClientEnabled = false; + mm640gEnabled = false; + glimpEnabled = true; } boolean isNSProfile = ConfigBuilderPlugin.getActiveProfile().getClass().equals(NSProfilePlugin.class); @@ -99,6 +109,10 @@ public class DataService extends IntentService { if (mm640gEnabled) { handleNewDataFromMM640g(intent); } + } else if (Intents.GLIMP_BG.equals(action)) { + if (glimpEnabled) { + handleNewDataFromGlimp(intent); + } } else if (Intents.ACTION_NEW_SGV.equals(action)) { // always handle SGV if NS-Client is the source if (nsClientEnabled) { @@ -185,6 +199,30 @@ public class DataService extends IntentService { MainApp.bus().post(new EventNewBG()); } + 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.battery_level = bundle.getInt("myBatLvl"); + bgReading.timeIndex = bundle.getLong("myTimestamp"); + bgReading.raw = 0; + + if (Config.logIncommingBG) + log.debug(bundle.toString()); + log.debug("GLIMP BG " + bgReading.toString()); + + try { + MainApp.getDbHelper().getDaoBgReadings().createIfNotExists(bgReading); + } catch (SQLException e) { + e.printStackTrace(); + } + MainApp.bus().post(new EventNewBG()); + } + private void handleNewDataFromMM640g(Intent intent) { Bundle bundle = intent.getExtras(); if (bundle == null) return; diff --git a/app/src/main/java/info/nightscout/androidaps/Services/Intents.java b/app/src/main/java/info/nightscout/androidaps/Services/Intents.java index 4787838d4f..1b7b0875e5 100644 --- a/app/src/main/java/info/nightscout/androidaps/Services/Intents.java +++ b/app/src/main/java/info/nightscout/androidaps/Services/Intents.java @@ -35,4 +35,6 @@ public interface Intents { String NS_EMULATOR = "com.eveningoutpost.dexdrip.NS_EMULATOR"; String ACTION_REMOTE_CALIBRATION = "com.eveningoutpost.dexdrip.NewCalibration"; + + String GLIMP_BG = "it.ct.glicemia.ACTION_GLUCOSE_MEASURED"; } diff --git a/app/src/main/java/info/nightscout/androidaps/data/GlucoseStatus.java b/app/src/main/java/info/nightscout/androidaps/data/GlucoseStatus.java index 9fc8bd0ff4..ad9b0acecf 100644 --- a/app/src/main/java/info/nightscout/androidaps/data/GlucoseStatus.java +++ b/app/src/main/java/info/nightscout/androidaps/data/GlucoseStatus.java @@ -73,7 +73,7 @@ public class GlucoseStatus { List data = MainApp.getDbHelper().getBgreadingsDataFromTime(fromtime, false); int sizeRecords = data.size(); - if (sizeRecords < 4 || data.get(0).timeIndex < new Date().getTime() - 7 * 60 * 1000L) { + if (sizeRecords < 1 || data.get(0).timeIndex < new Date().getTime() - 7 * 60 * 1000L) { return null; } @@ -81,6 +81,16 @@ public class GlucoseStatus { long now_date = now.timeIndex; double change; + if (sizeRecords < 2) { + GlucoseStatus status = new GlucoseStatus(); + status.glucose = now.value; + status.short_avgdelta = 0d; + status.delta = 0d; + status.long_avgdelta = 0d; + status.avgdelta = 0d; // for OpenAPS MA + return status.round(); + } + ArrayList last_deltas = new ArrayList(); ArrayList short_deltas = new ArrayList(); ArrayList long_deltas = new ArrayList(); @@ -121,7 +131,7 @@ public class GlucoseStatus { status.short_avgdelta = average(short_deltas); - if(prefs.getBoolean("always_use_shortavg",false) || last_deltas.isEmpty()){ + if (prefs.getBoolean("always_use_shortavg", false) || last_deltas.isEmpty()) { status.delta = status.short_avgdelta; } else { status.delta = average(last_deltas); diff --git a/app/src/main/java/info/nightscout/androidaps/db/BgReading.java b/app/src/main/java/info/nightscout/androidaps/db/BgReading.java index 951d370bf3..8a0aaf96e1 100644 --- a/app/src/main/java/info/nightscout/androidaps/db/BgReading.java +++ b/app/src/main/java/info/nightscout/androidaps/db/BgReading.java @@ -47,7 +47,7 @@ public class BgReading implements DataPointInterface { public BgReading(NSSgv sgv) { timeIndex = sgv.getMills(); value = sgv.getMgdl(); - raw = sgv.getFiltered(); + raw = sgv.getFiltered() != null ? sgv.getFiltered() : value; direction = sgv.getDirection(); } diff --git a/app/src/main/java/info/nightscout/androidaps/db/TempBasal.java b/app/src/main/java/info/nightscout/androidaps/db/TempBasal.java index d15ab436da..149d188b7c 100644 --- a/app/src/main/java/info/nightscout/androidaps/db/TempBasal.java +++ b/app/src/main/java/info/nightscout/androidaps/db/TempBasal.java @@ -59,11 +59,15 @@ public class TempBasal { if (profile == null) return result; + Double basalRate = profile.getBasal(profile.secondsFromMidnight(time)); + + if (basalRate == null) + return result; + int realDuration = getRealDuration(); if (realDuration > 0) { Double netBasalRate = 0d; - Double basalRate = profile.getBasal(profile.secondsFromMidnight(time)); Double tempBolusSize = 0.05; if (isExtended) { diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Actions/dialogs/NewTempBasalDialog.java b/app/src/main/java/info/nightscout/androidaps/plugins/Actions/dialogs/NewTempBasalDialog.java index 75d9bcec11..2d5a4580c4 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/Actions/dialogs/NewTempBasalDialog.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/Actions/dialogs/NewTempBasalDialog.java @@ -54,7 +54,7 @@ public class NewTempBasalDialog extends DialogFragment implements View.OnClickLi public static HandlerThread mHandlerThread; public NewTempBasalDialog() { - mHandlerThread = new HandlerThread(NewExtendedBolusDialog.class.getSimpleName()); + mHandlerThread = new HandlerThread(NewTempBasalDialog.class.getSimpleName()); mHandlerThread.start(); this.mHandler = new Handler(mHandlerThread.getLooper()); } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/ConfigBuilder/ConfigBuilderPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/ConfigBuilder/ConfigBuilderPlugin.java index f780596e59..2c42ffaa41 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/ConfigBuilder/ConfigBuilderPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/ConfigBuilder/ConfigBuilderPlugin.java @@ -59,6 +59,7 @@ import info.nightscout.androidaps.plugins.NSClientInternal.data.DbLogger; import info.nightscout.androidaps.plugins.NSClientInternal.data.NSProfile; import info.nightscout.utils.BatteryLevel; import info.nightscout.utils.DateUtil; +import info.nightscout.utils.SP; /** * Created by mike on 05.08.2016. @@ -1025,7 +1026,7 @@ public class ConfigBuilderPlugin implements PluginBase, PumpInterface, Constrain deviceStatus.device = "openaps://" + deviceID(); JSONObject pumpstatus = getJSONStatus(); if (pumpstatus != null) { - deviceStatus.pump = getJSONStatus(); + deviceStatus.pump = pumpstatus; } } @@ -1128,24 +1129,26 @@ public class ConfigBuilderPlugin implements PluginBase, PumpInterface, Constrain } public void uploadAppStart() { - Context context = MainApp.instance().getApplicationContext(); - Bundle bundle = new Bundle(); - bundle.putString("action", "dbAdd"); - bundle.putString("collection", "treatments"); - JSONObject data = new JSONObject(); - try { - data.put("eventType", "Note"); - data.put("created_at", DateUtil.toISOString(new Date())); - data.put("notes", MainApp.sResources.getString(R.string.androidaps_start)); - } catch (JSONException e) { - e.printStackTrace(); + if (SP.getBoolean(R.string.key_ns_logappstartedevent, true)) { + Context context = MainApp.instance().getApplicationContext(); + Bundle bundle = new Bundle(); + bundle.putString("action", "dbAdd"); + bundle.putString("collection", "treatments"); + JSONObject data = new JSONObject(); + try { + data.put("eventType", "Note"); + data.put("created_at", DateUtil.toISOString(new Date())); + data.put("notes", MainApp.sResources.getString(R.string.androidaps_start)); + } catch (JSONException e) { + e.printStackTrace(); + } + bundle.putString("data", data.toString()); + Intent intent = new Intent(Intents.ACTION_DATABASE); + intent.putExtras(bundle); + intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES); + context.sendBroadcast(intent); + DbLogger.dbAdd(intent, data.toString(), ConfigBuilderPlugin.class); } - bundle.putString("data", data.toString()); - Intent intent = new Intent(Intents.ACTION_DATABASE); - intent.putExtras(bundle); - intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES); - context.sendBroadcast(intent); - DbLogger.dbAdd(intent, data.toString(), ConfigBuilderPlugin.class); } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/DanaRPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/DanaRPlugin.java index 556c6d9770..4a2d9d3a56 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/DanaRPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/DanaRPlugin.java @@ -276,6 +276,7 @@ public class DanaRPlugin implements PluginBase, PumpInterface, ConstraintsInterf for (int h = 0; h < basalValues; h++) { Double pumpValue = pump.pumpProfiles[pump.activeProfile][h]; Double profileValue = profile.getBasal(h * basalIncrement); + if (profileValue == null) return true; if (Math.abs(pumpValue - profileValue) > getPumpDescription().basalStep) { log.debug("Diff found. Hour: " + h + " Pump: " + pumpValue + " Profile: " + profileValue); return false; diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/DanaRKoreanPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/DanaRKoreanPlugin.java index 683e2d8f1b..11debc415a 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/DanaRKoreanPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/DanaRKoreanPlugin.java @@ -215,7 +215,7 @@ public class DanaRKoreanPlugin implements PluginBase, PumpInterface, Constraints @Override public boolean isSuspended() { - return false; + return getDanaRPump().pumpSuspended; } @Override diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/DanaRKoreanPump.java b/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/DanaRKoreanPump.java index b8a7016956..6786cc4c2e 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/DanaRKoreanPump.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/DanaRKoreanPump.java @@ -43,6 +43,8 @@ public class DanaRKoreanPump { public int protocol; public int productCode; + public boolean pumpSuspended; + public boolean isConfigUD; public boolean isExtendedBolusEnabled; public boolean isEasyModeEnabled; diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/comm/MsgInitConnStatusBasic.java b/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/comm/MsgInitConnStatusBasic.java index 39f45d7843..e21db06d4c 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/comm/MsgInitConnStatusBasic.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/comm/MsgInitConnStatusBasic.java @@ -26,13 +26,13 @@ public class MsgInitConnStatusBasic extends MessageBase { return; } DanaRKoreanPump pump = DanaRKoreanPlugin.getDanaRPump(); - int isStatusSuspendOn = intFromBuff(bytes, 0, 1); + pump.pumpSuspended = intFromBuff(bytes, 0, 1) == 1; int isUtilityEnable = intFromBuff(bytes, 1, 1); pump.isEasyModeEnabled = intFromBuff(bytes, 2, 1) == 1; int easyUIMode = intFromBuff(bytes, 3, 1); pump.password = intFromBuff(bytes, 4, 2) ^ 0x3463; if (Config.logDanaMessageDetail) { - log.debug("isStatusSuspendOn: " + isStatusSuspendOn); + log.debug("isStatusSuspendOn: " + pump.pumpSuspended); log.debug("isUtilityEnable: " + isUtilityEnable); log.debug("Is EasyUI Enabled: " + pump.isEasyModeEnabled); log.debug("easyUIMode: " + easyUIMode); diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Loop/LoopPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/Loop/LoopPlugin.java index c73b4a7f1f..6a3869589b 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/Loop/LoopPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/Loop/LoopPlugin.java @@ -32,6 +32,7 @@ import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.Loop.events.EventLoopSetLastRunGui; import info.nightscout.androidaps.plugins.Loop.events.EventLoopUpdateGui; import info.nightscout.androidaps.plugins.Loop.events.EventNewOpenLoopNotification; +import info.nightscout.utils.SP; /** * Created by mike on 05.08.2016. @@ -45,6 +46,9 @@ public class LoopPlugin implements PluginBase { private boolean fragmentEnabled = false; private boolean fragmentVisible = true; + private long loopSuspendedTill = 0L; // end of manual loop suspend + private boolean isSuperBolus = false; + public class LastRun { public APSResult request = null; public APSResult constraintsProcessed = null; @@ -64,6 +68,8 @@ public class LoopPlugin implements PluginBase { sHandler = new Handler(sHandlerThread.getLooper()); } MainApp.bus().register(this); + loopSuspendedTill = SP.getLong("loopSuspendedTill", 0L); + isSuperBolus = SP.getBoolean("isSuperBolus", false); } @Override @@ -127,12 +133,72 @@ public class LoopPlugin implements PluginBase { invoke("EventNewBG", true); } + public long suspendedTo() { + return loopSuspendedTill; + } + + public void suspendTo(long endTime) { + loopSuspendedTill = endTime; + isSuperBolus = false; + SP.putLong("loopSuspendedTill", loopSuspendedTill); + } + + public void superBolusTo(long endTime) { + loopSuspendedTill = endTime; + isSuperBolus = true; + SP.putLong("loopSuspendedTill", loopSuspendedTill); + } + + public int minutesToEndOfSuspend() { + if (loopSuspendedTill == 0) + return 0; + + long now = new Date().getTime(); + long msecDiff = loopSuspendedTill - now; + + if (loopSuspendedTill <= now) { // time exceeded + suspendTo(0L); + return 0; + } + + return (int) (msecDiff / 60d / 1000d); + } + + public boolean isSuspended() { + if (loopSuspendedTill == 0) + return false; + + long now = new Date().getTime(); + + if (loopSuspendedTill <= now) { // time exceeded + suspendTo(0L); + return false; + } + + return true; + } + + public boolean isSuperBolus() { + if (loopSuspendedTill == 0) + return false; + + long now = new Date().getTime(); + + if (loopSuspendedTill <= now) { // time exceeded + suspendTo(0L); + return false; + } + + return isSuperBolus; + } + public void invoke(String initiator, boolean allowNotification) { try { if (Config.logFunctionCalls) log.debug("invoke"); ConstraintsInterface constraintsInterface = MainApp.getConfigBuilder(); if (!constraintsInterface.isLoopEnabled()) { + log.debug(MainApp.sResources.getString(R.string.loopdisabled)); MainApp.bus().post(new EventLoopSetLastRunGui(MainApp.sResources.getString(R.string.loopdisabled))); return; } @@ -142,6 +208,18 @@ public class LoopPlugin implements PluginBase { if (configBuilder == null || !isEnabled(PluginBase.LOOP)) return; + if (isSuspended()) { + log.debug(MainApp.sResources.getString(R.string.loopsuspended)); + MainApp.bus().post(new EventLoopSetLastRunGui(MainApp.sResources.getString(R.string.loopsuspended))); + return; + } + + if (configBuilder.isSuspended()) { + log.debug(MainApp.sResources.getString(R.string.pumpsuspended)); + MainApp.bus().post(new EventLoopSetLastRunGui(MainApp.sResources.getString(R.string.pumpsuspended))); + return; + } + // Check if pump info is loaded if (configBuilder.getBaseBasalRate() < 0.01d) return; diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/NSClientInternal/NSClientInternalPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/NSClientInternal/NSClientInternalPlugin.java index 1849bf7149..46c19b2eaa 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/NSClientInternal/NSClientInternalPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/NSClientInternal/NSClientInternalPlugin.java @@ -23,6 +23,7 @@ import java.util.ArrayList; import java.util.Date; import java.util.List; +import info.nightscout.androidaps.BuildConfig; import info.nightscout.androidaps.Constants; import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.R; @@ -37,12 +38,13 @@ import info.nightscout.androidaps.plugins.NSClientInternal.events.EventNSClientS import info.nightscout.androidaps.plugins.NSClientInternal.events.EventNSClientUpdateGUI; import info.nightscout.androidaps.plugins.NSClientInternal.services.NSClientService; import info.nightscout.utils.SP; +import info.nightscout.utils.ToastUtils; public class NSClientInternalPlugin implements PluginBase { private static Logger log = LoggerFactory.getLogger(NSClientInternalPlugin.class); - boolean fragmentEnabled = false; - boolean fragmentVisible = false; + boolean fragmentEnabled = true; + boolean fragmentVisible = true; static public Handler handler; static private HandlerThread handlerThread; @@ -188,12 +190,16 @@ public class NSClientInternalPlugin implements PluginBase { } private void updateLog() { - Spanned newTextLog = Html.fromHtml(""); - for (EventNSClientNewLog log : listLog) { - newTextLog = (Spanned) TextUtils.concat(newTextLog, log.toHtml()); + try { + Spanned newTextLog = Html.fromHtml(""); + for (EventNSClientNewLog log : listLog) { + newTextLog = (Spanned) TextUtils.concat(newTextLog, log.toHtml()); + } + textLog = newTextLog; + MainApp.bus().post(new EventNSClientUpdateGUI()); + } catch (OutOfMemoryError e) { + ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), "Out of memory!\nStop using this phone !!!", R.raw.error); } - textLog = newTextLog; - MainApp.bus().post(new EventNSClientUpdateGUI()); } public void resend(String reason) { diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/NSClientInternal/UploadQueue.java b/app/src/main/java/info/nightscout/androidaps/plugins/NSClientInternal/UploadQueue.java index cae7d6b9b2..b318d8026f 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/NSClientInternal/UploadQueue.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/NSClientInternal/UploadQueue.java @@ -40,66 +40,78 @@ public class UploadQueue { if (NSClientService.handler == null) { Context context = MainApp.instance(); context.startService(new Intent(context, NSClientService.class)); + try { + Thread.sleep(2000); + } catch (InterruptedException e) { + } } } public static void add(final DbRequest dbr) { startService(); - NSClientService.handler.post(new Runnable() { - @Override - public void run() { - log.debug("QUEUE adding: " + dbr.data); - MainApp.getDbHelper().create(dbr); - NSClientInternalPlugin plugin = (NSClientInternalPlugin) MainApp.getSpecificPlugin(NSClientInternalPlugin.class); - if (plugin != null) { - plugin.resend("newdata"); + if (NSClientService.handler != null) { + NSClientService.handler.post(new Runnable() { + @Override + public void run() { + log.debug("QUEUE adding: " + dbr.data); + MainApp.getDbHelper().create(dbr); + NSClientInternalPlugin plugin = (NSClientInternalPlugin) MainApp.getSpecificPlugin(NSClientInternalPlugin.class); + if (plugin != null) { + plugin.resend("newdata"); + } } - } - }); + }); + } } public static void clearQueue() { startService(); - NSClientService.handler.post(new Runnable() { - @Override - public void run() { - log.debug("QUEUE ClearQueue"); - MainApp.getDbHelper().deleteAllDbRequests(); - log.debug(status()); - } - }); + if (NSClientService.handler != null) { + NSClientService.handler.post(new Runnable() { + @Override + public void run() { + log.debug("QUEUE ClearQueue"); + MainApp.getDbHelper().deleteAllDbRequests(); + log.debug(status()); + } + }); + } } public static void removeID(final JSONObject record) { startService(); - NSClientService.handler.post(new Runnable() { - @Override - public void run() { - try { - String id; - if (record.has("NSCLIENT_ID")) { - id = record.getString("NSCLIENT_ID"); - } else { - return; + if (NSClientService.handler != null) { + NSClientService.handler.post(new Runnable() { + @Override + public void run() { + try { + String id; + if (record.has("NSCLIENT_ID")) { + id = record.getString("NSCLIENT_ID"); + } else { + return; + } + if (MainApp.getDbHelper().deleteDbRequest(id) == 1) { + log.debug("Removed item from UploadQueue. " + UploadQueue.status()); + } + } catch (JSONException e) { + e.printStackTrace(); } - if (MainApp.getDbHelper().deleteDbRequest(id) == 1) { - log.debug("Removed item from UploadQueue. " + UploadQueue.status()); - } - } catch (JSONException e) { - e.printStackTrace(); } - } - }); + }); + } } public static void removeID(final String action, final String _id) { startService(); - NSClientService.handler.post(new Runnable() { - @Override - public void run() { - MainApp.getDbHelper().deleteDbRequestbyMongoId(action, _id); - } - }); + if (NSClientService.handler != null) { + NSClientService.handler.post(new Runnable() { + @Override + public void run() { + MainApp.getDbHelper().deleteDbRequestbyMongoId(action, _id); + } + }); + } } public String textList() { diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/NSClientInternal/data/NSProfile.java b/app/src/main/java/info/nightscout/androidaps/plugins/NSClientInternal/data/NSProfile.java index 4d3df3068c..5ff95ddf39 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/NSClientInternal/data/NSProfile.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/NSClientInternal/data/NSProfile.java @@ -1,5 +1,7 @@ package info.nightscout.androidaps.plugins.NSClientInternal.data; +import android.support.annotation.Nullable; + import com.crashlytics.android.Crashlytics; import org.json.JSONArray; @@ -178,6 +180,7 @@ public class NSProfile { return TimeZone.getDefault(); } + @Nullable public Double getValueToTime(JSONArray array, Integer timeAsSeconds) { Double lastValue = null; @@ -221,10 +224,12 @@ public class NSProfile { return retValue; } + @Nullable public Double getIsf(Integer timeAsSeconds) { return getIsf(getDefaultProfile(), timeAsSeconds); } + @Nullable public Double getIsf(JSONObject profile, Integer timeAsSeconds) { if (profile != null) { try { @@ -251,10 +256,12 @@ public class NSProfile { return ""; } + @Nullable public Double getIc(Integer timeAsSeconds) { return getIc(getDefaultProfile(), timeAsSeconds); } + @Nullable public Double getIc(JSONObject profile, Integer timeAsSeconds) { if (profile != null) { try { @@ -281,10 +288,12 @@ public class NSProfile { return ""; } + @Nullable public Double getBasal(Integer timeAsSeconds) { return getBasal(getDefaultProfile(), timeAsSeconds); } + @Nullable public Double getBasal(JSONObject profile, Integer timeAsSeconds) { if (profile != null) { try { @@ -339,10 +348,12 @@ public class NSProfile { return ""; } + @Nullable public Double getTargetLow(Integer timeAsSeconds) { return getTargetLow(getDefaultProfile(), timeAsSeconds); } + @Nullable public Double getTargetLow(JSONObject profile, Integer timeAsSeconds) { if (profile != null) { try { @@ -354,10 +365,12 @@ public class NSProfile { return 0D; } + @Nullable public Double getTargetHigh(Integer timeAsSeconds) { return getTargetHigh(getDefaultProfile(), timeAsSeconds); } + @Nullable public Double getTargetHigh(JSONObject profile, Integer timeAsSeconds) { if (profile != null) { try { diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Objectives/ObjectivesPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/Objectives/ObjectivesPlugin.java index 5d33fdae5e..86cea210b4 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/Objectives/ObjectivesPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/Objectives/ObjectivesPlugin.java @@ -153,7 +153,7 @@ public class ObjectivesPlugin implements PluginBase, ConstraintsInterface { MainApp.sResources.getString(R.string.objectives_0_objective), MainApp.sResources.getString(R.string.objectives_0_gate), new Date(0), - 1, // 1 day + 0, // 0 day new Date(0))); objectives.add(new Objective(1, MainApp.sResources.getString(R.string.objectives_1_objective), diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSAMA/Autosens.java b/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSAMA/Autosens.java index 44c3970ac5..b504dde984 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSAMA/Autosens.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSAMA/Autosens.java @@ -34,6 +34,7 @@ public class Autosens { for (int i = 1; i < glucose_data.size(); ++i) { long bgTime = glucose_data.get(i).getTimeIndex(); long lastbgTime = glucose_data.get(i - 1).getTimeIndex(); + //log.error("Processing " + i + ": " + new Date(bgTime).toString() + " " + glucose_data.get(i).value + " Previous: " + new Date(lastbgTime).toString() + " " + glucose_data.get(i - 1).value); if (glucose_data.get(i).value < 39 || glucose_data.get(i - 1).value < 39) { continue; } @@ -46,29 +47,38 @@ public class Autosens { //console.error(elapsed_minutes); long nextbgTime; while (elapsed_minutes > 5) { - nextbgTime = lastbgTime + 5 * 60 * 1000; + nextbgTime = lastbgTime - 5 * 60 * 1000; j++; BgReading newBgreading = new BgReading(); newBgreading.timeIndex = nextbgTime; double gapDelta = glucose_data.get(i).value - lastbg; //console.error(gapDelta, lastbg, elapsed_minutes); - double nextbg = lastbg + (5 / elapsed_minutes * gapDelta); + double nextbg = lastbg + (5d / elapsed_minutes * gapDelta); newBgreading.value = Math.round(nextbg); //console.error("Interpolated", bucketed_data[j]); bucketed_data.add(newBgreading); + //log.error("******************************************************************************************************* Adding:" + new Date(newBgreading.timeIndex).toString() + " " + newBgreading.value); elapsed_minutes = elapsed_minutes - 5; lastbg = nextbg; lastbgTime = nextbgTime; } + j++; + BgReading newBgreading = new BgReading(); + newBgreading.value = glucose_data.get(i).value; + newBgreading.timeIndex = bgTime; + bucketed_data.add(newBgreading); + //log.error("******************************************************************************************************* Copying:" + new Date(newBgreading.timeIndex).toString() + " " + newBgreading.value); } else if (Math.abs(elapsed_minutes) > 2) { j++; BgReading newBgreading = new BgReading(); newBgreading.value = glucose_data.get(i).value; newBgreading.timeIndex = bgTime; bucketed_data.add(newBgreading); + //log.error("******************************************************************************************************* Copying:" + new Date(newBgreading.timeIndex).toString() + " " + newBgreading.value); } else { bucketed_data.get(j).value = (bucketed_data.get(j).value + glucose_data.get(i).value) / 2; + //log.error("***** Average"); } } //console.error(bucketed_data); @@ -81,6 +91,12 @@ public class Autosens { long bgTime = bucketed_data.get(i).timeIndex; int secondsFromMidnight = NSProfile.secondsFromMidnight(new Date(bgTime)); + String hour = ""; + //log.debug(new Date(bgTime).toString()); + if (secondsFromMidnight % 3600 < 2.5 * 60 || secondsFromMidnight % 3600 > 57.5 * 60) { + hour += "(" + Math.round(secondsFromMidnight / 3600d) + ")"; + } + double sens = NSProfile.toMgdl(profile.getIsf(secondsFromMidnight), profile.getUnits()); //console.error(bgTime , bucketed_data[i].glucose); @@ -122,6 +138,7 @@ public class Autosens { pastSensitivity += ">"; //console.error(bgTime); } + pastSensitivity += hour; //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); // if bgTime is more recent than mealTime diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Overview/Dialogs/CalibrationDialog.java b/app/src/main/java/info/nightscout/androidaps/plugins/Overview/Dialogs/CalibrationDialog.java index 5c96cb58e5..6ff9dceb1f 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/Overview/Dialogs/CalibrationDialog.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/Overview/Dialogs/CalibrationDialog.java @@ -35,14 +35,16 @@ public class CalibrationDialog extends DialogFragment implements View.OnClickLis PlusMinusEditText bgText; TextView unitsView; - Context parentContext; + Context context; public CalibrationDialog() { // Required empty public constructor } - public void setContext(Context context) { - parentContext = context; + @Override + public void onAttach(Context context) { + super.onAttach(context); + this.context = context; } @Override @@ -58,13 +60,18 @@ public class CalibrationDialog extends DialogFragment implements View.OnClickLis NSProfile profile = MainApp.getConfigBuilder().getActiveProfile().getProfile(); Double bg = profile != null ? NSProfile.fromMgdlToUnits(GlucoseStatus.getGlucoseStatusData() != null ? GlucoseStatus.getGlucoseStatusData().glucose : 0d, profile.getUnits()) : 0d; - if (profile.getUnits().equals(Constants.MMOL)) + + String units = Constants.MGDL; + if (profile != null) + units = profile.getUnits(); + + if (units.equals(Constants.MMOL)) bgText = new PlusMinusEditText(view, R.id.overview_calibration_bg, R.id.overview_calibration_bg_plus, R.id.overview_calibration_bg_minus, bg, 0d, 30d, 0.1d, new DecimalFormat("0.0"), false); else bgText = new PlusMinusEditText(view, R.id.overview_calibration_bg, R.id.overview_calibration_bg_plus, R.id.overview_calibration_bg_minus, bg, 0d, 500d, 1d, new DecimalFormat("0"), false); unitsView = (TextView) view.findViewById(R.id.overview_calibration_units); - unitsView.setText(profile.getUnits()); + unitsView.setText(units); return view; } @@ -74,7 +81,7 @@ public class CalibrationDialog extends DialogFragment implements View.OnClickLis switch (view.getId()) { case R.id.overview_calibration_okbutton: final Double bg = bgText.getValue(); - XdripCalibrations.confirmAndSendCalibration(bg, parentContext); + XdripCalibrations.confirmAndSendCalibration(bg, context); dismiss(); Answers.getInstance().logCustom(new CustomEvent("Calibration")); break; diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Overview/Dialogs/WizardDialog.java b/app/src/main/java/info/nightscout/androidaps/plugins/Overview/Dialogs/WizardDialog.java index 7916291ccc..eaebeec73e 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/Overview/Dialogs/WizardDialog.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/Overview/Dialogs/WizardDialog.java @@ -1,5 +1,6 @@ package info.nightscout.androidaps.plugins.Overview.Dialogs; +import android.app.Activity; import android.content.Context; import android.content.DialogInterface; import android.os.Bundle; @@ -21,32 +22,49 @@ import android.widget.Button; import android.widget.CheckBox; import android.widget.CompoundButton; import android.widget.EditText; +import android.widget.LinearLayout; import android.widget.Spinner; import android.widget.TextView; import com.crashlytics.android.answers.Answers; import com.crashlytics.android.answers.CustomEvent; +import com.squareup.otto.Subscribe; import org.json.JSONException; import org.json.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.w3c.dom.Text; import java.text.DecimalFormat; import java.util.ArrayList; import java.util.Date; +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.OnCheckedChanged; +import butterknife.OnClick; +import butterknife.OnItemSelected; +import butterknife.OnTextChanged; +import butterknife.Unbinder; import info.nightscout.androidaps.Constants; import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.R; import info.nightscout.androidaps.data.GlucoseStatus; import info.nightscout.androidaps.data.PumpEnactResult; import info.nightscout.androidaps.db.BgReading; +import info.nightscout.androidaps.events.EventNewBG; +import info.nightscout.androidaps.events.EventRefreshGui; import info.nightscout.androidaps.interfaces.TempBasalsInterface; import info.nightscout.androidaps.interfaces.TreatmentsInterface; import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.data.IobTotal; +import info.nightscout.androidaps.plugins.Loop.APSResult; +import info.nightscout.androidaps.plugins.Loop.LoopPlugin; import info.nightscout.androidaps.plugins.NSClientInternal.data.NSProfile; +import info.nightscout.androidaps.plugins.OpenAPSAMA.DetermineBasalResultAMA; +import info.nightscout.androidaps.plugins.OpenAPSAMA.OpenAPSAMAPlugin; +import info.nightscout.androidaps.plugins.OpenAPSMA.events.EventOpenAPSUpdateGui; import info.nightscout.utils.BolusWizard; import info.nightscout.utils.DateUtil; import info.nightscout.utils.DecimalFormatter; @@ -54,48 +72,149 @@ import info.nightscout.utils.PlusMinusEditText; import info.nightscout.utils.SafeParse; import info.nightscout.utils.ToastUtils; -public class WizardDialog extends DialogFragment implements OnClickListener { +import static butterknife.OnItemSelected.Callback.NOTHING_SELECTED; + +public class WizardDialog extends DialogFragment { private static Logger log = LoggerFactory.getLogger(WizardDialog.class); + @BindView(R.id.treatments_wizard_deliverButton) Button wizardDialogDeliverButton; + @BindView(R.id.treatments_wizard_correctioninput) TextView correctionInput; + @BindView(R.id.treatments_wizard_carbsinput) TextView carbsInput; + @BindView(R.id.treatments_wizard_bginput) TextView bgInput; - TextView bg, bgInsulin, bgUnits; + @BindView(R.id.treatments_wizard_bg) + TextView bg; + @BindView(R.id.treatments_wizard_bginsulin) + TextView bgInsulin; + @BindView(R.id.treatments_wizard_bgunits) + TextView bgUnits; + @BindView(R.id.treatments_wizard_bgcheckbox) CheckBox bgCheckbox; - TextView carbs, carbsInsulin; + @BindView(R.id.treatments_wizard_carbs) + TextView carbs; + @BindView(R.id.treatments_wizard_carbsinsulin) + TextView carbsInsulin; + @BindView(R.id.treatments_wizard_bolusiobinsulin) TextView bolusIobInsulin; + @BindView(R.id.treatments_wizard_basaliobinsulin) TextView basalIobInsulin; + @BindView(R.id.treatments_wizard_bolusiobcheckbox) CheckBox bolusIobCheckbox; + @BindView(R.id.treatments_wizard_basaliobcheckbox) CheckBox basalIobCheckbox; + @BindView(R.id.treatments_wizard_correctioninsulin) TextView correctionInsulin; - TextView total, totalInsulin; + @BindView(R.id.treatments_wizard_total) + TextView total; + @BindView(R.id.treatments_wizard_totalinsulin) + TextView totalInsulin; + @BindView(R.id.treatments_wizard_carbtimeinput) EditText carbTimeEdit; + @BindView(R.id.treatments_wizard_profile) Spinner profileSpinner; + @BindView(R.id.treatments_wizard_sbcheckbox) + CheckBox superbolusCheckbox; + @BindView(R.id.treatments_wizard_sb) + TextView superbolus; + @BindView(R.id.treatments_wizard_sbinsulin) + TextView superbolusInsulin; + @BindView(R.id.treatments_wizard_bgtrendcheckbox) + CheckBox bgtrendCheckbox; + @BindView(R.id.treatments_wizard_bgtrend) + TextView bgTrend; + @BindView(R.id.treatments_wizard_bgtrendinsulin) + TextView bgTrendInsulin; + @BindView(R.id.treatments_wizard_cob_layout) + LinearLayout cobLayout; + @BindView(R.id.treatments_wizard_cobcheckbox) + CheckBox cobCheckbox; + @BindView(R.id.treatments_wizard_cob) + TextView cob; + @BindView(R.id.treatments_wizard_cobinsulin) + TextView cobInsulin; PlusMinusEditText editBg; PlusMinusEditText editCarbs; PlusMinusEditText editCorr; PlusMinusEditText editCarbTime; + private Unbinder unbinder; + Integer calculatedCarbs = 0; Double calculatedTotalInsulin = 0d; JSONObject boluscalcJSON; + boolean cobAvailable = false; Handler mHandler; public static HandlerThread mHandlerThread; - Context parentContext; + Context context; public WizardDialog() { + super(); mHandlerThread = new HandlerThread(WizardDialog.class.getSimpleName()); mHandlerThread.start(); mHandler = new Handler(mHandlerThread.getLooper()); } + @Override + public void onAttach(Context context) { + super.onAttach(context); + this.context = context; + } - public void setContext(Context context) { - parentContext = context; + @Override + public void onDestroyView() { + super.onDestroyView(); + unbinder.unbind(); + } + + @Override + public void onResume() { + super.onResume(); + if (getDialog() != null) + getDialog().getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); + MainApp.bus().register(this); + } + + @Override + public void onPause() { + super.onPause(); + MainApp.bus().unregister(this); + } + + @Subscribe + public void onStatusEvent(final EventOpenAPSUpdateGui e) { + Activity activity = getActivity(); + if (activity != null) + activity.runOnUiThread(new Runnable() { + @Override + public void run() { + if (ConfigBuilderPlugin.getActiveAPS() instanceof OpenAPSAMAPlugin && ConfigBuilderPlugin.getActiveAPS().getLastAPSResult() != null && ConfigBuilderPlugin.getActiveAPS().getLastAPSRun().after(new Date(new Date().getTime() - 11 * 60 * 1000L))) { + cobLayout.setVisibility(View.VISIBLE); + cobAvailable = true; + } else { + cobLayout.setVisibility(View.GONE); + cobAvailable = false; + } + calculateInsulin(); + } + }); + } + + @Subscribe + public void onStatusEvent(final EventNewBG e) { + Activity activity = getActivity(); + if (activity != null) + activity.runOnUiThread(new Runnable() { + @Override + public void run() { + calculateInsulin(); + } + }); } final private TextWatcher textWatcher = new TextWatcher() { @@ -113,67 +232,20 @@ public class WizardDialog extends DialogFragment implements OnClickListener { } }; - final CompoundButton.OnCheckedChangeListener onCheckedChangeListener = new CompoundButton.OnCheckedChangeListener() { - @Override - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - calculateInsulin(); - } - }; - - final AdapterView.OnItemSelectedListener onItemSelectedListener = new AdapterView.OnItemSelectedListener() { - @Override - public void onItemSelected(AdapterView parent, View view, int position, long id) { - calculateInsulin(); - wizardDialogDeliverButton.setVisibility(View.VISIBLE); - } - - @Override - public void onNothingSelected(AdapterView parent) { - ToastUtils.showToastInUiThread(parentContext, MainApp.sResources.getString(R.string.noprofileselected)); - wizardDialogDeliverButton.setVisibility(View.GONE); - } - }; - @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.overview_wizard_dialog, null, false); - wizardDialogDeliverButton = (Button) view.findViewById(R.id.treatments_wizard_deliverButton); - wizardDialogDeliverButton.setOnClickListener(this); - getDialog().getWindow().requestFeature(Window.FEATURE_NO_TITLE); getDialog().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN); - correctionInput = (TextView) view.findViewById(R.id.treatments_wizard_correctioninput); - carbsInput = (TextView) view.findViewById(R.id.treatments_wizard_carbsinput); - bgInput = (TextView) view.findViewById(R.id.treatments_wizard_bginput); + unbinder = ButterKnife.bind(this, view); correctionInput.addTextChangedListener(textWatcher); carbsInput.addTextChangedListener(textWatcher); bgInput.addTextChangedListener(textWatcher); - bg = (TextView) view.findViewById(R.id.treatments_wizard_bg); - bgInsulin = (TextView) view.findViewById(R.id.treatments_wizard_bginsulin); - bgUnits = (TextView) view.findViewById(R.id.treatments_wizard_bgunits); - bgCheckbox = (CheckBox) view.findViewById(R.id.treatments_wizard_bgcheckbox); - carbs = (TextView) view.findViewById(R.id.treatments_wizard_carbs); - carbsInsulin = (TextView) view.findViewById(R.id.treatments_wizard_carbsinsulin); - bolusIobInsulin = (TextView) view.findViewById(R.id.treatments_wizard_bolusiobinsulin); - basalIobInsulin = (TextView) view.findViewById(R.id.treatments_wizard_basaliobinsulin); - bolusIobCheckbox = (CheckBox) view.findViewById(R.id.treatments_wizard_bolusiobcheckbox); - basalIobCheckbox = (CheckBox) view.findViewById(R.id.treatments_wizard_basaliobcheckbox); - correctionInsulin = (TextView) view.findViewById(R.id.treatments_wizard_correctioninsulin); - total = (TextView) view.findViewById(R.id.treatments_wizard_total); - totalInsulin = (TextView) view.findViewById(R.id.treatments_wizard_totalinsulin); - carbTimeEdit = (EditText) view.findViewById(R.id.treatments_wizard_carbtimeinput); - profileSpinner = (Spinner) view.findViewById(R.id.treatments_wizard_profile); - - bgCheckbox.setOnCheckedChangeListener(onCheckedChangeListener); - basalIobCheckbox.setOnCheckedChangeListener(onCheckedChangeListener); - bolusIobCheckbox.setOnCheckedChangeListener(onCheckedChangeListener); - profileSpinner.setOnItemSelectedListener(onItemSelectedListener); - Integer maxCarbs = MainApp.getConfigBuilder().applyCarbsConstraints(Constants.carbsOnlyForCheckLimit); Double maxCorrection = MainApp.getConfigBuilder().applyBolusConstraints(Constants.bolusOnlyForCheckLimit); @@ -186,75 +258,102 @@ public class WizardDialog extends DialogFragment implements OnClickListener { return view; } - @Override + @OnCheckedChanged({R.id.treatments_wizard_bgcheckbox, R.id.treatments_wizard_bolusiobcheckbox, R.id.treatments_wizard_basaliobcheckbox, R.id.treatments_wizard_sbcheckbox, R.id.treatments_wizard_cobcheckbox, R.id.treatments_wizard_bgtrendcheckbox}) + public void checkboxToggled(boolean isChecked) { + calculateInsulin(); + } + + @OnItemSelected(R.id.treatments_wizard_profile) + public void profileSelected(int position) { + calculateInsulin(); + wizardDialogDeliverButton.setVisibility(View.VISIBLE); + } + + @OnItemSelected(value = R.id.treatments_wizard_profile, + callback = NOTHING_SELECTED) + public void profileNotSelected() { + ToastUtils.showToastInUiThread(context, MainApp.sResources.getString(R.string.noprofileselected)); + wizardDialogDeliverButton.setVisibility(View.GONE); + } + + @OnClick(R.id.treatments_wizard_deliverButton) public void onClick(View view) { - switch (view.getId()) { - case R.id.treatments_wizard_deliverButton: - if (calculatedTotalInsulin > 0d || calculatedCarbs > 0d) { - DecimalFormat formatNumber2decimalplaces = new DecimalFormat("0.00"); - String confirmMessage = getString(R.string.entertreatmentquestion); + if (calculatedTotalInsulin > 0d || calculatedCarbs > 0d) { + DecimalFormat formatNumber2decimalplaces = new DecimalFormat("0.00"); + String confirmMessage = getString(R.string.entertreatmentquestion); - Double insulinAfterConstraints = MainApp.getConfigBuilder().applyBolusConstraints(calculatedTotalInsulin); - Integer carbsAfterConstraints = MainApp.getConfigBuilder().applyCarbsConstraints(calculatedCarbs); + Double insulinAfterConstraints = MainApp.getConfigBuilder().applyBolusConstraints(calculatedTotalInsulin); + Integer carbsAfterConstraints = MainApp.getConfigBuilder().applyCarbsConstraints(calculatedCarbs); - confirmMessage += "\n" + getString(R.string.bolus) + ": " + formatNumber2decimalplaces.format(insulinAfterConstraints) + "U"; - confirmMessage += "\n" + getString(R.string.carbs) + ": " + carbsAfterConstraints + "g"; + confirmMessage += "\n" + getString(R.string.bolus) + ": " + formatNumber2decimalplaces.format(insulinAfterConstraints) + "U"; + confirmMessage += "\n" + getString(R.string.carbs) + ": " + carbsAfterConstraints + "g"; - if (insulinAfterConstraints - calculatedTotalInsulin != 0 || !carbsAfterConstraints.equals(calculatedCarbs)) { - AlertDialog.Builder builder = new AlertDialog.Builder(parentContext); - builder.setTitle(MainApp.sResources.getString(R.string.treatmentdeliveryerror)); - builder.setMessage(getString(R.string.constraints_violation) + "\n" + getString(R.string.changeyourinput)); - builder.setPositiveButton(MainApp.sResources.getString(R.string.ok), null); - builder.show(); - return; - } + if (insulinAfterConstraints - calculatedTotalInsulin != 0 || !carbsAfterConstraints.equals(calculatedCarbs)) { + AlertDialog.Builder builder = new AlertDialog.Builder(context); + builder.setTitle(MainApp.sResources.getString(R.string.treatmentdeliveryerror)); + builder.setMessage(getString(R.string.constraints_violation) + "\n" + getString(R.string.changeyourinput)); + builder.setPositiveButton(MainApp.sResources.getString(R.string.ok), null); + builder.show(); + return; + } - final Double finalInsulinAfterConstraints = insulinAfterConstraints; - final Integer finalCarbsAfterConstraints = carbsAfterConstraints; + final Double finalInsulinAfterConstraints = insulinAfterConstraints; + final Integer finalCarbsAfterConstraints = carbsAfterConstraints; + final Double bg = SafeParse.stringToDouble(bgInput.getText().toString()); + final int carbTime = SafeParse.stringToInt(carbTimeEdit.getText().toString()); + final boolean useSuperBolus = superbolusCheckbox.isChecked(); - if (parentContext != null) { - AlertDialog.Builder builder = new AlertDialog.Builder(parentContext); - builder.setTitle(MainApp.sResources.getString(R.string.confirmation)); - builder.setMessage(confirmMessage); - builder.setPositiveButton(getString(R.string.ok), new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - if (finalInsulinAfterConstraints > 0 || finalCarbsAfterConstraints > 0) { - final ConfigBuilderPlugin pump = MainApp.getConfigBuilder(); - mHandler.post(new Runnable() { - @Override - public void run() { - PumpEnactResult result = pump.deliverTreatmentFromBolusWizard( - parentContext, - finalInsulinAfterConstraints, - finalCarbsAfterConstraints, - SafeParse.stringToDouble(bgInput.getText().toString()), - "Manual", - SafeParse.stringToInt(carbTimeEdit.getText().toString()), - boluscalcJSON - ); - if (!result.success) { - AlertDialog.Builder builder = new AlertDialog.Builder(parentContext); - builder.setTitle(MainApp.sResources.getString(R.string.treatmentdeliveryerror)); - builder.setMessage(result.comment); - builder.setPositiveButton(MainApp.sResources.getString(R.string.ok), null); - builder.show(); - } - } - }); - Answers.getInstance().logCustom(new CustomEvent("Wizard")); + AlertDialog.Builder builder = new AlertDialog.Builder(context); + builder.setTitle(MainApp.sResources.getString(R.string.confirmation)); + builder.setMessage(confirmMessage); + builder.setPositiveButton(getString(R.string.ok), new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + if (finalInsulinAfterConstraints > 0 || finalCarbsAfterConstraints > 0) { + final ConfigBuilderPlugin pump = MainApp.getConfigBuilder(); + mHandler.post(new Runnable() { + @Override + public void run() { + PumpEnactResult result = pump.deliverTreatmentFromBolusWizard( + context, + finalInsulinAfterConstraints, + finalCarbsAfterConstraints, + bg, + "Manual", + carbTime, + boluscalcJSON + ); + if (!result.success) { + AlertDialog.Builder builder = new AlertDialog.Builder(context); + builder.setTitle(MainApp.sResources.getString(R.string.treatmentdeliveryerror)); + builder.setMessage(result.comment); + builder.setPositiveButton(MainApp.sResources.getString(R.string.ok), null); + builder.show(); + } + if (useSuperBolus) { + final LoopPlugin activeloop = MainApp.getConfigBuilder().getActiveLoop(); + result = pump.setTempBasalAbsolute(0d, 120); + if (!result.success) { + AlertDialog.Builder builder = new AlertDialog.Builder(context); + builder.setTitle(MainApp.sResources.getString(R.string.tempbasaldeliveryerror)); + builder.setMessage(result.comment); + builder.setPositiveButton(MainApp.sResources.getString(R.string.ok), null); + builder.show(); + } + if (activeloop != null) { + activeloop.superBolusTo(new Date().getTime() + 2 * 60L * 60 * 1000); + MainApp.bus().post(new EventRefreshGui(false)); + } } } }); - builder.setNegativeButton(getString(R.string.cancel), null); - builder.show(); - dismiss(); - } else { - log.error("parentContext == null"); + Answers.getInstance().logCustom(new CustomEvent("Wizard")); } } - break; + }); + builder.setNegativeButton(getString(R.string.cancel), null); + builder.show(); + dismiss(); } - } private void initDialog() { @@ -329,13 +428,14 @@ public class WizardDialog extends DialogFragment implements OnClickListener { totalInsulin.setText(""); wizardDialogDeliverButton.setVisibility(Button.INVISIBLE); - } - - @Override - public void onResume() { - super.onResume(); - if (getDialog() != null) - getDialog().getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); + // COB only if AMA is selected + if (ConfigBuilderPlugin.getActiveAPS() instanceof OpenAPSAMAPlugin && ConfigBuilderPlugin.getActiveAPS().getLastAPSResult() != null && ConfigBuilderPlugin.getActiveAPS().getLastAPSRun().after(new Date(new Date().getTime() - 11 * 60 * 1000L))) { + cobLayout.setVisibility(View.VISIBLE); + cobAvailable = true; + } else { + cobLayout.setVisibility(View.GONE); + cobAvailable = false; + } } private void calculateInsulin() { @@ -370,8 +470,19 @@ public class WizardDialog extends DialogFragment implements OnClickListener { c_bg = bgCheckbox.isChecked() ? c_bg : 0d; + // COB + Double c_cob = 0d; + if (cobAvailable && cobCheckbox.isChecked()) { + if (ConfigBuilderPlugin.getActiveAPS().getLastAPSResult() != null && ConfigBuilderPlugin.getActiveAPS().getLastAPSRun().after(new Date(new Date().getTime() - 11 * 60 * 1000L))) { + try { + c_cob = SafeParse.stringToDouble(ConfigBuilderPlugin.getActiveAPS().getLastAPSResult().json().getString("COB")); + } catch (JSONException e) { + } + } + } + BolusWizard wizard = new BolusWizard(); - wizard.doCalc(specificProfile, carbsAfterConstraint, c_bg, corrAfterConstraint, bolusIobCheckbox.isChecked(), basalIobCheckbox.isChecked()); + wizard.doCalc(specificProfile, carbsAfterConstraint, c_cob, c_bg, corrAfterConstraint, bolusIobCheckbox.isChecked(), basalIobCheckbox.isChecked(), superbolusCheckbox.isChecked(), bgtrendCheckbox.isChecked()); bg.setText(c_bg + " ISF: " + DecimalFormatter.to1Decimal(wizard.sens)); bgInsulin.setText(DecimalFormatter.to2Decimal(wizard.insulinFromBG) + "U"); @@ -395,6 +506,35 @@ public class WizardDialog extends DialogFragment implements OnClickListener { calculatedCarbs = carbsAfterConstraint; + // Superbolus + if (superbolusCheckbox.isChecked()) { + superbolus.setText("2h"); + } else { + superbolus.setText(""); + } + superbolusInsulin.setText(DecimalFormatter.to2Decimal(wizard.insulinFromSuperBolus) + "U"); + + // Trend + if (bgtrendCheckbox.isChecked()) { + if (wizard.glucoseStatus != null) { + bgTrend.setText((wizard.glucoseStatus.avgdelta > 0 ? "+" : "") + NSProfile.toUnitsString(wizard.glucoseStatus.avgdelta * 3, wizard.glucoseStatus.avgdelta * 3 / 18, profile.getUnits()) + " " + profile.getUnits()); + } else { + bgTrend.setText(""); + } + } else { + bgTrend.setText(""); + } + bgTrendInsulin.setText(DecimalFormatter.to2Decimal(wizard.insulinFromTrend) + "U"); + + // COB + if (cobAvailable && cobCheckbox.isChecked()) { + cob.setText(DecimalFormatter.to2Decimal(c_cob) + "g IC: " + DecimalFormatter.to1Decimal(wizard.ic)); + cobInsulin.setText(DecimalFormatter.to2Decimal(wizard.insulinFromCOB) + "U"); + } else { + cob.setText(""); + cobInsulin.setText(""); + } + if (calculatedTotalInsulin > 0d || calculatedCarbs > 0d) { String insulinText = calculatedTotalInsulin > 0d ? (DecimalFormatter.to2Decimal(calculatedTotalInsulin) + "U") : ""; String carbsText = calculatedCarbs > 0d ? (DecimalFormatter.to0Decimal(calculatedCarbs) + "g") : ""; @@ -421,7 +561,11 @@ public class WizardDialog extends DialogFragment implements OnClickListener { boluscalcJSON.put("bgdiff", wizard.bgDiff); boluscalcJSON.put("insulincarbs", wizard.insulinFromCarbs); boluscalcJSON.put("carbs", c_carbs); + boluscalcJSON.put("cob", c_cob); + boluscalcJSON.put("insulincob", wizard.insulinFromCOB); boluscalcJSON.put("othercorrection", corrAfterConstraint); + boluscalcJSON.put("insulinsuperbolus", wizard.insulinFromSuperBolus); + boluscalcJSON.put("insulintrend", wizard.insulinFromTrend); boluscalcJSON.put("insulin", calculatedTotalInsulin); } catch (JSONException e) { e.printStackTrace(); diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Overview/OverviewFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/Overview/OverviewFragment.java index b925080c17..22d5e48b57 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/Overview/OverviewFragment.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/Overview/OverviewFragment.java @@ -18,8 +18,10 @@ import android.support.v7.app.AlertDialog; import android.support.v7.widget.CardView; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; +import android.view.ContextMenu; import android.view.HapticFeedbackConstants; import android.view.LayoutInflater; +import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.Button; @@ -95,6 +97,7 @@ import info.nightscout.utils.DateUtil; import info.nightscout.utils.DecimalFormatter; import info.nightscout.utils.Round; import info.nightscout.utils.SP; +import info.nightscout.utils.ToastUtils; public class OverviewFragment extends Fragment { @@ -216,7 +219,6 @@ public class OverviewFragment extends Fragment { public void onClick(View view) { FragmentManager manager = getFragmentManager(); WizardDialog wizardDialog = new WizardDialog(); - wizardDialog.setContext(getContext()); wizardDialog.show(manager, "WizardDialog"); } }); @@ -250,7 +252,6 @@ public class OverviewFragment extends Fragment { public void onClick(View view) { FragmentManager manager = getFragmentManager(); CalibrationDialog calibrationDialog = new CalibrationDialog(); - calibrationDialog.setContext(getContext()); calibrationDialog.show(manager, "CalibrationDialog"); } }); @@ -258,40 +259,42 @@ public class OverviewFragment extends Fragment { acceptTempButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { - ConfigBuilderPlugin.getActiveLoop().invoke("Accept temp button", false); - final LoopPlugin.LastRun finalLastRun = LoopPlugin.lastRun; - if (finalLastRun != null && finalLastRun.lastAPSRun != null && finalLastRun.constraintsProcessed.changeRequested) { - AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); - builder.setTitle(getContext().getString(R.string.confirmation)); - builder.setMessage(getContext().getString(R.string.setbasalquestion) + "\n" + finalLastRun.constraintsProcessed); - builder.setPositiveButton(getContext().getString(R.string.ok), new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - sHandler.post(new Runnable() { - @Override - public void run() { - hideTempRecommendation(); - PumpEnactResult applyResult = MainApp.getConfigBuilder().applyAPSRequest(finalLastRun.constraintsProcessed); - if (applyResult.enacted) { - finalLastRun.setByPump = applyResult; - finalLastRun.lastEnact = new Date(); - finalLastRun.lastOpenModeAccept = new Date(); - MainApp.getConfigBuilder().uploadDeviceStatus(); - ObjectivesPlugin objectivesPlugin = (ObjectivesPlugin) MainApp.getSpecificPlugin(ObjectivesPlugin.class); - if (objectivesPlugin != null) { - objectivesPlugin.manualEnacts++; - objectivesPlugin.saveProgress(); + if (ConfigBuilderPlugin.getActiveLoop() != null) { + ConfigBuilderPlugin.getActiveLoop().invoke("Accept temp button", false); + final LoopPlugin.LastRun finalLastRun = LoopPlugin.lastRun; + if (finalLastRun != null && finalLastRun.lastAPSRun != null && finalLastRun.constraintsProcessed.changeRequested) { + AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); + builder.setTitle(getContext().getString(R.string.confirmation)); + builder.setMessage(getContext().getString(R.string.setbasalquestion) + "\n" + finalLastRun.constraintsProcessed); + builder.setPositiveButton(getContext().getString(R.string.ok), new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + sHandler.post(new Runnable() { + @Override + public void run() { + hideTempRecommendation(); + PumpEnactResult applyResult = MainApp.getConfigBuilder().applyAPSRequest(finalLastRun.constraintsProcessed); + if (applyResult.enacted) { + finalLastRun.setByPump = applyResult; + finalLastRun.lastEnact = new Date(); + finalLastRun.lastOpenModeAccept = new Date(); + MainApp.getConfigBuilder().uploadDeviceStatus(); + ObjectivesPlugin objectivesPlugin = (ObjectivesPlugin) MainApp.getSpecificPlugin(ObjectivesPlugin.class); + if (objectivesPlugin != null) { + objectivesPlugin.manualEnacts++; + objectivesPlugin.saveProgress(); + } } + updateGUIIfVisible(); } - updateGUIIfVisible(); - } - }); - Answers.getInstance().logCustom(new CustomEvent("AcceptTemp")); - } - }); - builder.setNegativeButton(getContext().getString(R.string.cancel), null); - builder.show(); + }); + Answers.getInstance().logCustom(new CustomEvent("AcceptTemp")); + } + }); + builder.setNegativeButton(getContext().getString(R.string.cancel), null); + builder.show(); + } + updateGUI(); } - updateGUI(); } }); @@ -312,6 +315,133 @@ public class OverviewFragment extends Fragment { return view; } + @Override + public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) { + super.onCreateContextMenu(menu, v, menuInfo); + final LoopPlugin activeloop = MainApp.getConfigBuilder().getActiveLoop(); + if (activeloop == null) + return; + menu.setHeaderTitle(MainApp.sResources.getString(R.string.loop)); + if (activeloop.isEnabled(PluginBase.LOOP)) { + menu.add(MainApp.sResources.getString(R.string.disableloop)); + if (!activeloop.isSuspended()) { + menu.add(MainApp.sResources.getString(R.string.suspendloopfor1h)); + menu.add(MainApp.sResources.getString(R.string.suspendloopfor2h)); + menu.add(MainApp.sResources.getString(R.string.suspendloopfor3h)); + menu.add(MainApp.sResources.getString(R.string.suspendloopfor10h)); + menu.add(MainApp.sResources.getString(R.string.disconnectpumpfor30m)); + menu.add(MainApp.sResources.getString(R.string.disconnectpumpfor1h)); + menu.add(MainApp.sResources.getString(R.string.disconnectpumpfor2h)); + menu.add(MainApp.sResources.getString(R.string.disconnectpumpfor3h)); + } else { + menu.add(MainApp.sResources.getString(R.string.resume)); + } + } + if (!activeloop.isEnabled(PluginBase.LOOP)) + menu.add(MainApp.sResources.getString(R.string.enableloop)); + } + + @Override + public boolean onContextItemSelected(MenuItem item) { + final LoopPlugin activeloop = MainApp.getConfigBuilder().getActiveLoop(); + if (item.getTitle().equals(MainApp.sResources.getString(R.string.disableloop))) { + activeloop.setFragmentEnabled(PluginBase.LOOP, false); + activeloop.setFragmentVisible(PluginBase.LOOP, false); + MainApp.getConfigBuilder().storeSettings(); + MainApp.bus().post(new EventRefreshGui(false)); + return true; + } else if (item.getTitle().equals(MainApp.sResources.getString(R.string.enableloop))) { + activeloop.setFragmentEnabled(PluginBase.LOOP, true); + activeloop.setFragmentVisible(PluginBase.LOOP, true); + MainApp.getConfigBuilder().storeSettings(); + MainApp.bus().post(new EventRefreshGui(false)); + return true; + } else if (item.getTitle().equals(MainApp.sResources.getString(R.string.resume))) { + activeloop.suspendTo(0L); + sHandler.post(new Runnable() { + @Override + public void run() { + MainApp.bus().post(new EventRefreshGui(false)); + PumpEnactResult result = MainApp.getConfigBuilder().cancelTempBasal(); + if (!result.success) { + ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), MainApp.sResources.getString(R.string.tempbasaldeliveryerror)); + } + } + }); + return true; + } else if (item.getTitle().equals(MainApp.sResources.getString(R.string.suspendloopfor1h))) { + activeloop.suspendTo(new Date().getTime() + 60L * 60 * 1000); + MainApp.bus().post(new EventRefreshGui(false)); + return true; + } else if (item.getTitle().equals(MainApp.sResources.getString(R.string.suspendloopfor2h))) { + activeloop.suspendTo(new Date().getTime() + 2 * 60L * 60 * 1000); + MainApp.bus().post(new EventRefreshGui(false)); + return true; + } else if (item.getTitle().equals(MainApp.sResources.getString(R.string.suspendloopfor3h))) { + activeloop.suspendTo(new Date().getTime() + 3 * 60L * 60 * 1000); + MainApp.bus().post(new EventRefreshGui(false)); + return true; + } else if (item.getTitle().equals(MainApp.sResources.getString(R.string.suspendloopfor10h))) { + activeloop.suspendTo(new Date().getTime() + 10 * 60L * 60 * 1000); + MainApp.bus().post(new EventRefreshGui(false)); + return true; + } else if (item.getTitle().equals(MainApp.sResources.getString(R.string.disconnectpumpfor30m))) { + activeloop.suspendTo(new Date().getTime() + 30L * 60 * 1000); + sHandler.post(new Runnable() { + @Override + public void run() { + PumpEnactResult result = MainApp.getConfigBuilder().setTempBasalAbsolute(0d, 30); + if (!result.success) { + ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), MainApp.sResources.getString(R.string.tempbasaldeliveryerror)); + } + MainApp.bus().post(new EventRefreshGui(false)); + } + }); + return true; + } else if (item.getTitle().equals(MainApp.sResources.getString(R.string.disconnectpumpfor1h))) { + activeloop.suspendTo(new Date().getTime() + 1 * 60L * 60 * 1000); + sHandler.post(new Runnable() { + @Override + public void run() { + MainApp.bus().post(new EventRefreshGui(false)); + PumpEnactResult result = MainApp.getConfigBuilder().setTempBasalAbsolute(0d, 60); + if (!result.success) { + ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), MainApp.sResources.getString(R.string.tempbasaldeliveryerror)); + } + } + }); + return true; + } else if (item.getTitle().equals(MainApp.sResources.getString(R.string.disconnectpumpfor2h))) { + activeloop.suspendTo(new Date().getTime() + 2 * 60L * 60 * 1000); + sHandler.post(new Runnable() { + @Override + public void run() { + MainApp.bus().post(new EventRefreshGui(false)); + PumpEnactResult result = MainApp.getConfigBuilder().setTempBasalAbsolute(0d, 2 * 60); + if (!result.success) { + ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), MainApp.sResources.getString(R.string.tempbasaldeliveryerror)); + } + } + }); + return true; + } else if (item.getTitle().equals(MainApp.sResources.getString(R.string.disconnectpumpfor3h))) { + activeloop.suspendTo(new Date().getTime() + 3 * 60L * 60 * 1000); + sHandler.post(new Runnable() { + @Override + public void run() { + MainApp.bus().post(new EventRefreshGui(false)); + PumpEnactResult result = MainApp.getConfigBuilder().setTempBasalAbsolute(0d, 3 * 60); + if (!result.success) { + ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), MainApp.sResources.getString(R.string.tempbasaldeliveryerror)); + } + } + }); + return true; + } + + return super.onContextItemSelected(item); + } + void processQuickWizard() { final BgReading actualBg = GlucoseStatus.actualBg(); if (MainApp.getConfigBuilder() == null || ConfigBuilderPlugin.getActiveProfile() == null) // app not initialized yet @@ -323,7 +453,7 @@ public class OverviewFragment extends Fragment { quickWizardButton.setVisibility(View.VISIBLE); String text = MainApp.sResources.getString(R.string.bolus) + ": " + quickWizardEntry.buttonText(); BolusWizard wizard = new BolusWizard(); - wizard.doCalc(profile.getDefaultProfile(), quickWizardEntry.carbs(), actualBg.valueToUnits(profile.getUnits()), 0d, true, true); + wizard.doCalc(profile.getDefaultProfile(), quickWizardEntry.carbs(), 0d, actualBg.valueToUnits(profile.getUnits()), 0d, true, true, false, true); final JSONObject boluscalcJSON = new JSONObject(); try { @@ -342,6 +472,7 @@ public class OverviewFragment extends Fragment { boluscalcJSON.put("insulincarbs", wizard.insulinFromCarbs); boluscalcJSON.put("carbs", quickWizardEntry.carbs()); boluscalcJSON.put("othercorrection", 0d); + boluscalcJSON.put("insulintrend", wizard.insulinFromTrend); boluscalcJSON.put("insulin", wizard.calculatedTotalInsulin); } catch (JSONException e) { e.printStackTrace(); @@ -412,6 +543,7 @@ public class OverviewFragment extends Fragment { super.onPause(); MainApp.bus().unregister(this); sLoopHandler.removeCallbacksAndMessages(null); + unregisterForContextMenu(apsModeView); } @Override @@ -426,6 +558,7 @@ public class OverviewFragment extends Fragment { } }; sLoopHandler.postDelayed(sRefreshLoop, 60 * 1000L); + registerForContextMenu(apsModeView); updateGUIIfVisible(); } @@ -548,6 +681,8 @@ public class OverviewFragment extends Fragment { loopStatusLayout.setVisibility(View.VISIBLE); } + PumpInterface pump = MainApp.getConfigBuilder(); + // Skip if not initialized yet if (bgGraph == null) return; @@ -562,7 +697,19 @@ public class OverviewFragment extends Fragment { apsModeView.setBackgroundResource(R.drawable.loopmodeborder); apsModeView.setTextColor(Color.BLACK); final LoopPlugin activeloop = MainApp.getConfigBuilder().getActiveLoop(); - if (activeloop != null && activeloop.isEnabled(activeloop.getType())) { + if (activeloop != null && activeloop.isEnabled(activeloop.getType()) && activeloop.isSuperBolus()) { + apsModeView.setBackgroundResource(R.drawable.loopmodesuspendedborder); + apsModeView.setText(String.format(MainApp.sResources.getString(R.string.loopsuperbolusfor), activeloop.minutesToEndOfSuspend())); + apsModeView.setTextColor(Color.WHITE); + } else if (activeloop != null && activeloop.isEnabled(activeloop.getType()) && activeloop.isSuspended()) { + apsModeView.setBackgroundResource(R.drawable.loopmodesuspendedborder); + apsModeView.setText(String.format(MainApp.sResources.getString(R.string.loopsuspendedfor), activeloop.minutesToEndOfSuspend())); + apsModeView.setTextColor(Color.WHITE); + } else if (pump.isSuspended()) { + apsModeView.setBackgroundResource(R.drawable.loopmodesuspendedborder); + apsModeView.setText(MainApp.sResources.getString(R.string.pumpsuspended)); + apsModeView.setTextColor(Color.WHITE); + } else if (activeloop != null && activeloop.isEnabled(activeloop.getType())) { if (MainApp.getConfigBuilder().isClosedModeEnabled()) { apsModeView.setText(MainApp.sResources.getString(R.string.closedloop)); } else { @@ -572,31 +719,7 @@ public class OverviewFragment extends Fragment { apsModeView.setBackgroundResource(R.drawable.loopmodedisabledborder); apsModeView.setText(MainApp.sResources.getString(R.string.disabledloop)); apsModeView.setTextColor(Color.WHITE); - } - - - apsModeView.setOnLongClickListener(new View.OnLongClickListener() { - @Override - public boolean onLongClick(View view) { - view.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); - if (activeloop == null) { - log.error("no active loop?"); - return true; - } else if (activeloop.isEnabled(PluginBase.LOOP)) { - activeloop.setFragmentEnabled(PluginBase.LOOP, false); - activeloop.setFragmentVisible(PluginBase.LOOP, false); - } else { - activeloop.setFragmentEnabled(PluginBase.LOOP, true); - activeloop.setFragmentVisible(PluginBase.LOOP, true); - } - MainApp.getConfigBuilder().storeSettings(); - MainApp.bus().post(new EventRefreshGui(false)); - return true; - } - }); - apsModeView.setLongClickable(true); - } else { apsModeView.setVisibility(View.GONE); } @@ -629,8 +752,6 @@ public class OverviewFragment extends Fragment { } // **** Temp button **** - PumpInterface pump = MainApp.getConfigBuilder(); - boolean showAcceptButton = !MainApp.getConfigBuilder().isClosedModeEnabled(); // Open mode needed showAcceptButton = showAcceptButton && finalLastRun != null && finalLastRun.lastAPSRun != null; // aps result must exist showAcceptButton = showAcceptButton && (finalLastRun.lastOpenModeAccept == null || finalLastRun.lastOpenModeAccept.getTime() < finalLastRun.lastAPSRun.getTime()); // never accepted or before last result @@ -706,7 +827,7 @@ public class OverviewFragment extends Fragment { quickWizardButton.setVisibility(View.VISIBLE); String text = MainApp.sResources.getString(R.string.bolus) + ": " + quickWizardEntry.buttonText() + " " + DecimalFormatter.to0Decimal(quickWizardEntry.carbs()) + "g"; BolusWizard wizard = new BolusWizard(); - wizard.doCalc(profile.getDefaultProfile(), quickWizardEntry.carbs(), lastBG.valueToUnits(profile.getUnits()), 0d, true, true); + wizard.doCalc(profile.getDefaultProfile(), quickWizardEntry.carbs(), 0d, lastBG.valueToUnits(profile.getUnits()), 0d, true, true, false, true); text += " " + DecimalFormatter.to2Decimal(wizard.calculatedTotalInsulin) + "U"; quickWizardButton.setText(text); if (wizard.calculatedTotalInsulin <= 0) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/SmsCommunicator/SmsCommunicatorPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/SmsCommunicator/SmsCommunicatorPlugin.java index 4258907547..fcaf379af2 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/SmsCommunicator/SmsCommunicatorPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/SmsCommunicator/SmsCommunicatorPlugin.java @@ -7,6 +7,8 @@ import android.preference.PreferenceManager; import android.telephony.SmsManager; import android.telephony.SmsMessage; +import com.crashlytics.android.answers.Answers; +import com.crashlytics.android.answers.CustomEvent; import com.squareup.otto.Subscribe; import org.slf4j.Logger; @@ -26,6 +28,7 @@ import info.nightscout.androidaps.data.IobTotal; import info.nightscout.androidaps.data.PumpEnactResult; import info.nightscout.androidaps.db.BgReading; import info.nightscout.androidaps.events.EventPreferenceChange; +import info.nightscout.androidaps.events.EventRefreshGui; import info.nightscout.androidaps.interfaces.PluginBase; import info.nightscout.androidaps.interfaces.PumpInterface; import info.nightscout.androidaps.plugins.DanaR.DanaRPlugin; @@ -66,6 +69,7 @@ public class SmsCommunicatorPlugin implements PluginBase { double bolusRequested = 0d; double tempBasal = 0d; double calibrationRequested = 0d; + int duration = 0; public Sms(SmsMessage message) { phoneNumber = message.getOriginatingAddress(); @@ -98,6 +102,7 @@ public class SmsCommunicatorPlugin implements PluginBase { Sms tempBasalWaitingForConfirmation = null; Sms bolusWaitingForConfirmation = null; Sms calibrationWaitingForConfirmation = null; + Sms suspendWaitingForConfirmation = null; Date lastRemoteBolusTime = new Date(0); ArrayList messages = new ArrayList<>(); @@ -210,7 +215,9 @@ public class SmsCommunicatorPlugin implements PluginBase { String[] splited = receivedSms.text.split("\\s+"); Double amount = 0d; Double tempBasal = 0d; + int duration = 0; String passCode = ""; + boolean remoteCommandsAllowed = SP.getBoolean(R.string.key_smscommunicator_remotecommandsallowed, false); if (splited.length > 0) { switch (splited[0].toUpperCase()) { @@ -244,9 +251,11 @@ public class SmsCommunicatorPlugin implements PluginBase { sendSMS(new Sms(receivedSms.phoneNumber, reply, new Date())); receivedSms.processed = true; + Answers.getInstance().logCustom(new CustomEvent("SMS_Bg")); break; case "LOOP": switch (splited[1].toUpperCase()) { + case "DISABLE": case "STOP": LoopPlugin loopPlugin = (LoopPlugin) MainApp.getSpecificPlugin(LoopPlugin.class); if (loopPlugin != null && loopPlugin.isEnabled(PluginBase.LOOP)) { @@ -255,7 +264,9 @@ public class SmsCommunicatorPlugin implements PluginBase { sendSMS(new Sms(receivedSms.phoneNumber, reply, new Date())); } receivedSms.processed = true; + Answers.getInstance().logCustom(new CustomEvent("SMS_Loop_Stop")); break; + case "ENABLE": case "START": loopPlugin = (LoopPlugin) MainApp.getSpecificPlugin(LoopPlugin.class); if (loopPlugin != null && !loopPlugin.isEnabled(PluginBase.LOOP)) { @@ -264,18 +275,52 @@ public class SmsCommunicatorPlugin implements PluginBase { sendSMS(new Sms(receivedSms.phoneNumber, reply, new Date())); } receivedSms.processed = true; + Answers.getInstance().logCustom(new CustomEvent("SMS_Loop_Start")); break; case "STATUS": loopPlugin = (LoopPlugin) MainApp.getSpecificPlugin(LoopPlugin.class); if (loopPlugin != null) { if (loopPlugin.isEnabled(PluginBase.LOOP)) { - reply = MainApp.sResources.getString(R.string.smscommunicator_loopisenabled); + if (loopPlugin.isSuspended()) + reply = String.format(MainApp.sResources.getString(R.string.loopsuspendedfor), loopPlugin.minutesToEndOfSuspend()); + else + reply = MainApp.sResources.getString(R.string.smscommunicator_loopisenabled); } else { reply = MainApp.sResources.getString(R.string.smscommunicator_loopisdisabled); } sendSMS(new Sms(receivedSms.phoneNumber, reply, new Date())); } receivedSms.processed = true; + Answers.getInstance().logCustom(new CustomEvent("SMS_Loop_Status")); + break; + case "RESUME": + final LoopPlugin activeloop = MainApp.getConfigBuilder().getActiveLoop(); + activeloop.suspendTo(0); + MainApp.bus().post(new EventRefreshGui(false)); + reply = String.format(MainApp.sResources.getString(R.string.smscommunicator_loopresumed)); + sendSMSToAllNumbers(new Sms(receivedSms.phoneNumber, reply, new Date())); + Answers.getInstance().logCustom(new CustomEvent("SMS_Loop_Resume")); + break; + case "SUSPEND": + if (splited.length >= 3) + duration = SafeParse.stringToInt(splited[2]); + duration = Math.max(0, duration); + duration = Math.min(180, duration); + if (duration == 0) { + reply = MainApp.sResources.getString(R.string.smscommunicator_wrongduration); + sendSMS(new Sms(receivedSms.phoneNumber, reply, new Date())); + } else if (remoteCommandsAllowed) { + passCode = generatePasscode(); + reply = String.format(MainApp.sResources.getString(R.string.smscommunicator_suspendreplywithcode), duration, passCode); + receivedSms.processed = true; + resetWaitingMessages(); + sendSMS(suspendWaitingForConfirmation = new Sms(receivedSms.phoneNumber, reply, new Date(), passCode)); + suspendWaitingForConfirmation.duration = duration; + Answers.getInstance().logCustom(new CustomEvent("SMS_Loop_Suspend")); + } else { + reply = MainApp.sResources.getString(R.string.smscommunicator_remotecommandnotallowed); + sendSMS(new Sms(receivedSms.phoneNumber, reply, new Date())); + } break; } break; @@ -289,6 +334,7 @@ public class SmsCommunicatorPlugin implements PluginBase { reply = "TERATMENTS REFRESH " + q.size() + " receivers"; sendSMS(new Sms(receivedSms.phoneNumber, reply, new Date())); receivedSms.processed = true; + Answers.getInstance().logCustom(new CustomEvent("SMS_Treatments_Refresh")); break; } break; @@ -301,6 +347,7 @@ public class SmsCommunicatorPlugin implements PluginBase { reply = "NSCLIENT RESTART " + q.size() + " receivers"; sendSMS(new Sms(receivedSms.phoneNumber, reply, new Date())); receivedSms.processed = true; + Answers.getInstance().logCustom(new CustomEvent("SMS_Nsclient_Restart")); break; } break; @@ -316,10 +363,10 @@ public class SmsCommunicatorPlugin implements PluginBase { sendSMS(new Sms(receivedSms.phoneNumber, reply, new Date())); } receivedSms.processed = true; + Answers.getInstance().logCustom(new CustomEvent("SMS_Danar")); break; case "BASAL": if (splited.length > 1) { - boolean remoteCommandsAllowed = SP.getBoolean(R.string.key_smscommunicator_remotecommandsallowed, false); if (splited[1].toUpperCase().equals("CANCEL") || splited[1].toUpperCase().equals("STOP")) { if (remoteCommandsAllowed) { passCode = generatePasscode(); @@ -327,6 +374,7 @@ public class SmsCommunicatorPlugin implements PluginBase { receivedSms.processed = true; resetWaitingMessages(); sendSMS(cancelTempBasalWaitingForConfirmation = new Sms(receivedSms.phoneNumber, reply, new Date(), passCode)); + Answers.getInstance().logCustom(new CustomEvent("SMS_Basal")); } else { reply = MainApp.sResources.getString(R.string.smscommunicator_remotebasalnotallowed); sendSMS(new Sms(receivedSms.phoneNumber, reply, new Date())); @@ -341,6 +389,7 @@ public class SmsCommunicatorPlugin implements PluginBase { resetWaitingMessages(); sendSMS(tempBasalWaitingForConfirmation = new Sms(receivedSms.phoneNumber, reply, new Date(), passCode)); tempBasalWaitingForConfirmation.tempBasal = tempBasal; + Answers.getInstance().logCustom(new CustomEvent("SMS_Basal")); } else { reply = MainApp.sResources.getString(R.string.smscommunicator_remotebasalnotallowed); sendSMS(new Sms(receivedSms.phoneNumber, reply, new Date())); @@ -355,7 +404,6 @@ public class SmsCommunicatorPlugin implements PluginBase { } else if (splited.length > 1) { amount = SafeParse.stringToDouble(splited[1]); amount = MainApp.getConfigBuilder().applyBolusConstraints(amount); - boolean remoteCommandsAllowed = SP.getBoolean(R.string.key_smscommunicator_remotecommandsallowed, false); if (amount > 0d && remoteCommandsAllowed) { passCode = generatePasscode(); reply = String.format(MainApp.sResources.getString(R.string.smscommunicator_bolusreplywithcode), amount, passCode); @@ -363,6 +411,7 @@ public class SmsCommunicatorPlugin implements PluginBase { resetWaitingMessages(); sendSMS(bolusWaitingForConfirmation = new Sms(receivedSms.phoneNumber, reply, new Date(), passCode)); bolusWaitingForConfirmation.bolusRequested = amount; + Answers.getInstance().logCustom(new CustomEvent("SMS_Bolus")); } else { reply = MainApp.sResources.getString(R.string.smscommunicator_remotebolusnotallowed); sendSMS(new Sms(receivedSms.phoneNumber, reply, new Date())); @@ -372,7 +421,6 @@ public class SmsCommunicatorPlugin implements PluginBase { case "CAL": if (splited.length > 1) { amount = SafeParse.stringToDouble(splited[1]); - boolean remoteCommandsAllowed = SP.getBoolean(R.string.key_smscommunicator_remotecommandsallowed, false); if (amount > 0d && remoteCommandsAllowed) { passCode = generatePasscode(); reply = String.format(MainApp.sResources.getString(R.string.smscommunicator_calibrationreplywithcode), amount, passCode); @@ -380,6 +428,7 @@ public class SmsCommunicatorPlugin implements PluginBase { resetWaitingMessages(); sendSMS(calibrationWaitingForConfirmation = new Sms(receivedSms.phoneNumber, reply, new Date(), passCode)); calibrationWaitingForConfirmation.calibrationRequested = amount; + Answers.getInstance().logCustom(new CustomEvent("SMS_Cal")); } else { reply = MainApp.sResources.getString(R.string.smscommunicator_remotecalibrationnotallowed); sendSMS(new Sms(receivedSms.phoneNumber, reply, new Date())); @@ -396,12 +445,14 @@ public class SmsCommunicatorPlugin implements PluginBase { PumpEnactResult result = pumpInterface.deliverTreatment(bolusWaitingForConfirmation.bolusRequested, 0, null); if (result.success) { reply = String.format(MainApp.sResources.getString(R.string.smscommunicator_bolusdelivered), result.bolusDelivered); - if (danaRPlugin != null) reply += "\n" + danaRPlugin.shortStatus(true); + if (danaRPlugin != null) + reply += "\n" + danaRPlugin.shortStatus(true); lastRemoteBolusTime = new Date(); sendSMSToAllNumbers(new Sms(receivedSms.phoneNumber, reply, new Date())); } else { reply = MainApp.sResources.getString(R.string.smscommunicator_bolusfailed); - if (danaRPlugin != null) reply += "\n" + danaRPlugin.shortStatus(true); + if (danaRPlugin != null) + reply += "\n" + danaRPlugin.shortStatus(true); sendSMS(new Sms(receivedSms.phoneNumber, reply, new Date())); } } @@ -414,11 +465,13 @@ public class SmsCommunicatorPlugin implements PluginBase { PumpEnactResult result = pumpInterface.setTempBasalAbsolute(tempBasalWaitingForConfirmation.tempBasal, 30); if (result.success) { reply = String.format(MainApp.sResources.getString(R.string.smscommunicator_tempbasalset), result.absolute, result.duration); - if (danaRPlugin != null) reply += "\n" + danaRPlugin.shortStatus(true); + if (danaRPlugin != null) + reply += "\n" + danaRPlugin.shortStatus(true); sendSMSToAllNumbers(new Sms(receivedSms.phoneNumber, reply, new Date())); } else { reply = MainApp.sResources.getString(R.string.smscommunicator_tempbasalfailed); - if (danaRPlugin != null) reply += "\n" + danaRPlugin.shortStatus(true); + if (danaRPlugin != null) + reply += "\n" + danaRPlugin.shortStatus(true); sendSMS(new Sms(receivedSms.phoneNumber, reply, new Date())); } } @@ -431,11 +484,13 @@ public class SmsCommunicatorPlugin implements PluginBase { PumpEnactResult result = pumpInterface.cancelTempBasal(); if (result.success) { reply = String.format(MainApp.sResources.getString(R.string.smscommunicator_tempbasalcanceled)); - if (danaRPlugin != null) reply += "\n" + danaRPlugin.shortStatus(true); + if (danaRPlugin != null) + reply += "\n" + danaRPlugin.shortStatus(true); sendSMSToAllNumbers(new Sms(receivedSms.phoneNumber, reply, new Date())); } else { reply = MainApp.sResources.getString(R.string.smscommunicator_tempbasalcancelfailed); - if (danaRPlugin != null) reply += "\n" + danaRPlugin.shortStatus(true); + if (danaRPlugin != null) + reply += "\n" + danaRPlugin.shortStatus(true); sendSMS(new Sms(receivedSms.phoneNumber, reply, new Date())); } } @@ -450,6 +505,14 @@ public class SmsCommunicatorPlugin implements PluginBase { reply = MainApp.sResources.getString(R.string.smscommunicator_calibrationfailed); sendSMS(new Sms(receivedSms.phoneNumber, reply, new Date())); } + } else if (suspendWaitingForConfirmation != null && !suspendWaitingForConfirmation.processed && + suspendWaitingForConfirmation.confirmCode.equals(splited[0]) && new Date().getTime() - suspendWaitingForConfirmation.date.getTime() < CONFIRM_TIMEOUT) { + suspendWaitingForConfirmation.processed = true; + final LoopPlugin activeloop = MainApp.getConfigBuilder().getActiveLoop(); + activeloop.suspendTo(new Date().getTime() + suspendWaitingForConfirmation.duration * 60L * 1000); + MainApp.bus().post(new EventRefreshGui(false)); + reply = String.format(MainApp.sResources.getString(R.string.smscommunicator_loopsuspended)); + sendSMSToAllNumbers(new Sms(receivedSms.phoneNumber, reply, new Date())); } else { sendSMS(new Sms(receivedSms.phoneNumber, MainApp.sResources.getString(R.string.smscommunicator_unknowncommand), new Date())); } @@ -469,7 +532,7 @@ public class SmsCommunicatorPlugin implements PluginBase { } public void sendSMSToAllNumbers(Sms sms) { - for (String number: allowedNumbers) { + for (String number : allowedNumbers) { sms.phoneNumber = number; sendSMS(sms); } @@ -504,6 +567,7 @@ public class SmsCommunicatorPlugin implements PluginBase { cancelTempBasalWaitingForConfirmation = null; bolusWaitingForConfirmation = null; calibrationWaitingForConfirmation = null; + suspendWaitingForConfirmation = null; } public static String stripAccents(String s) { diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/SourceGlimp/SourceGlimpFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/SourceGlimp/SourceGlimpFragment.java new file mode 100644 index 0000000000..85a4ee9646 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/SourceGlimp/SourceGlimpFragment.java @@ -0,0 +1,16 @@ +package info.nightscout.androidaps.plugins.SourceGlimp; + + +import android.support.v4.app.Fragment; + +import info.nightscout.androidaps.interfaces.FragmentBase; + +public class SourceGlimpFragment extends Fragment implements FragmentBase { + + private static SourceGlimpPlugin sourceGlimpPlugin = new SourceGlimpPlugin(); + + public static SourceGlimpPlugin getPlugin() { + return sourceGlimpPlugin; + } + +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/SourceGlimp/SourceGlimpPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/SourceGlimp/SourceGlimpPlugin.java new file mode 100644 index 0000000000..7a5965e3df --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/SourceGlimp/SourceGlimpPlugin.java @@ -0,0 +1,62 @@ +package info.nightscout.androidaps.plugins.SourceGlimp; + +import info.nightscout.androidaps.MainApp; +import info.nightscout.androidaps.R; +import info.nightscout.androidaps.interfaces.BgSourceInterface; +import info.nightscout.androidaps.interfaces.PluginBase; +import info.nightscout.androidaps.plugins.SourceMM640g.SourceMM640gFragment; + +/** + * Created by mike on 05.08.2016. + */ +public class SourceGlimpPlugin implements PluginBase, BgSourceInterface { + boolean fragmentEnabled = false; + + @Override + public String getFragmentClass() { + return SourceGlimpFragment.class.getName(); + } + + @Override + public int getType() { + return PluginBase.BGSOURCE; + } + + @Override + public String getName() { + return MainApp.instance().getString(R.string.Glimp); + } + + @Override + public String getNameShort() { + // use long name as fallback (no tabs) + return getName(); + } + + @Override + public boolean isEnabled(int type) { + return type == BGSOURCE && fragmentEnabled; + } + + @Override + public boolean isVisibleInTabs(int type) { + return false; + } + + @Override + public boolean canBeHidden(int type) { + return true; + } + + @Override + public void setFragmentEnabled(int type, boolean fragmentEnabled) { + if (type == BGSOURCE) this.fragmentEnabled = fragmentEnabled; + } + + @Override + public void setFragmentVisible(int type, boolean fragmentVisible) { + + } + + +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/VirtualPump/VirtualPumpPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/VirtualPump/VirtualPumpPlugin.java index f84adf737e..2e3a802a7a 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/VirtualPump/VirtualPumpPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/VirtualPump/VirtualPumpPlugin.java @@ -38,6 +38,8 @@ public class VirtualPumpPlugin implements PluginBase, PumpInterface { public static Integer batteryPercent = 50; public static Integer reservoirInUnits = 50; + Date lastDataTime = new Date(0); + boolean fragmentEnabled = true; boolean fragmentVisible = true; @@ -150,6 +152,7 @@ public class VirtualPumpPlugin implements PluginBase, PumpInterface { @Override public int setNewBasalProfile(NSProfile profile) { // Do nothing here. we are using MainApp.getConfigBuilder().getActiveProfile().getProfile(); + lastDataTime = new Date(); return SUCCESS; } @@ -160,12 +163,13 @@ public class VirtualPumpPlugin implements PluginBase, PumpInterface { @Override public Date lastDataTime() { - return new Date(); + return lastDataTime; } @Override public void refreshDataFromPump(String reason) { - // do nothing + MainApp.getConfigBuilder().uploadDeviceStatus(); + lastDataTime = new Date(); } @Override @@ -251,6 +255,7 @@ public class VirtualPumpPlugin implements PluginBase, PumpInterface { if (Config.logPumpComm) log.debug("Delivering treatment insulin: " + insulin + "U carbs: " + carbs + "g " + result); MainApp.bus().post(new EventVirtualPumpUpdateGui()); + lastDataTime = new Date(); return result; } @@ -285,6 +290,7 @@ public class VirtualPumpPlugin implements PluginBase, PumpInterface { if (Config.logPumpComm) log.debug("Setting temp basal absolute: " + result); MainApp.bus().post(new EventVirtualPumpUpdateGui()); + lastDataTime = new Date(); return result; } @@ -318,6 +324,7 @@ public class VirtualPumpPlugin implements PluginBase, PumpInterface { if (Config.logPumpComm) log.debug("Settings temp basal percent: " + result); MainApp.bus().post(new EventVirtualPumpUpdateGui()); + lastDataTime = new Date(); return result; } @@ -349,6 +356,7 @@ public class VirtualPumpPlugin implements PluginBase, PumpInterface { if (Config.logPumpComm) log.debug("Setting extended bolus: " + result); MainApp.bus().post(new EventVirtualPumpUpdateGui()); + lastDataTime = new Date(); return result; } @@ -375,6 +383,7 @@ public class VirtualPumpPlugin implements PluginBase, PumpInterface { result.comment = MainApp.instance().getString(R.string.virtualpump_sqlerror); } } + lastDataTime = new Date(); return result; } @@ -399,6 +408,7 @@ public class VirtualPumpPlugin implements PluginBase, PumpInterface { if (Config.logPumpComm) log.debug("Canceling extended basal: " + result); MainApp.bus().post(new EventVirtualPumpUpdateGui()); + lastDataTime = new Date(); return result; } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Wear/ActionStringHandler.java b/app/src/main/java/info/nightscout/androidaps/plugins/Wear/ActionStringHandler.java index 6afb51c5c6..ba93968e78 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/Wear/ActionStringHandler.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/Wear/ActionStringHandler.java @@ -192,7 +192,7 @@ public class ActionStringHandler { } DecimalFormat format = new DecimalFormat("0.00"); BolusWizard bolusWizard = new BolusWizard(); - bolusWizard.doCalc(profile.getDefaultProfile(), carbsAfterConstraints, useBG?bgReading.valueToUnits(profile.getUnits()):0d, 0d, useBolusIOB, useBasalIOB); + bolusWizard.doCalc(profile.getDefaultProfile(), carbsAfterConstraints, 0d, useBG?bgReading.valueToUnits(profile.getUnits()):0d, 0d, useBolusIOB, useBasalIOB, false, false); Double insulinAfterConstraints = MainApp.getConfigBuilder().applyBolusConstraints(bolusWizard.calculatedTotalInsulin); if(insulinAfterConstraints - bolusWizard.calculatedTotalInsulin !=0){ diff --git a/app/src/main/java/info/nightscout/androidaps/receivers/KeepAliveReceiver.java b/app/src/main/java/info/nightscout/androidaps/receivers/KeepAliveReceiver.java index 434d488086..5c889b661f 100644 --- a/app/src/main/java/info/nightscout/androidaps/receivers/KeepAliveReceiver.java +++ b/app/src/main/java/info/nightscout/androidaps/receivers/KeepAliveReceiver.java @@ -35,7 +35,7 @@ public class KeepAliveReceiver extends BroadcastReceiver { final PumpInterface pump = MainApp.getConfigBuilder(); final NSProfile profile = MainApp.getConfigBuilder().getActiveProfile().getProfile(); - if (pump != null && profile != null) { + if (pump != null && profile != null && profile.getBasal(NSProfile.secondsFromMidnight()) != null) { boolean isBasalOutdated = false; boolean isStatusOutdated = false; diff --git a/app/src/main/java/info/nightscout/utils/BolusWizard.java b/app/src/main/java/info/nightscout/utils/BolusWizard.java index 308da980e8..848263ebc5 100644 --- a/app/src/main/java/info/nightscout/utils/BolusWizard.java +++ b/app/src/main/java/info/nightscout/utils/BolusWizard.java @@ -5,6 +5,7 @@ import org.json.JSONObject; import java.util.Date; import info.nightscout.androidaps.MainApp; +import info.nightscout.androidaps.data.GlucoseStatus; import info.nightscout.androidaps.interfaces.TempBasalsInterface; import info.nightscout.androidaps.interfaces.TreatmentsInterface; import info.nightscout.androidaps.data.IobTotal; @@ -23,11 +24,15 @@ public class BolusWizard { Double correction; Boolean includeBolusIOB = true; Boolean includeBasalIOB = true; + Boolean superBolus = false; + Boolean trend = false; // Intermediate public Double sens = 0d; public Double ic = 0d; + public GlucoseStatus glucoseStatus; + public Double targetBGLow = 0d; public Double targetBGHigh = 0d; public Double bgDiff = 0d; @@ -40,16 +45,21 @@ public class BolusWizard { public Double insulingFromBolusIOB = 0d; public Double insulingFromBasalsIOB = 0d; public Double insulinFromCorrection = 0d; + public Double insulinFromSuperBolus = 0d; + public Double insulinFromCOB = 0d; + public Double insulinFromTrend = 0d; // Result public Double calculatedTotalInsulin = 0d; public Double carbsEquivalent = 0d; - public Double doCalc(JSONObject specificProfile, Integer carbs, Double bg, Double correction, Boolean includeBolusIOB, Boolean includeBasalIOB) { + public Double doCalc(JSONObject specificProfile, Integer carbs, Double cob, Double bg, Double correction, Boolean includeBolusIOB, Boolean includeBasalIOB, Boolean superBolus, Boolean trend) { this.specificProfile = specificProfile; this.carbs = carbs; this.bg = bg; this.correction = correction; + this.superBolus = superBolus; + this.trend = trend; NSProfile profile = ConfigBuilderPlugin.getActiveProfile().getProfile(); @@ -64,9 +74,16 @@ public class BolusWizard { } insulinFromBG = bg != 0d ? bgDiff / sens : 0d; + // Insulin from 15 min trend + glucoseStatus = GlucoseStatus.getGlucoseStatusData(); + if (glucoseStatus != null) { + insulinFromTrend = (NSProfile.fromMgdlToUnits(glucoseStatus.short_avgdelta, profile.getUnits()) * 3) / sens; + } + // Insuling from carbs ic = profile.getIc(specificProfile, NSProfile.secondsFromMidnight()); insulinFromCarbs = carbs / ic; + insulinFromCOB = -cob / ic; // Insulin from IOB // IOB calculation @@ -86,8 +103,16 @@ public class BolusWizard { // Insulin from correction insulinFromCorrection = correction; + // Insulin from superbolus for 2h. Get basal rate now and after 1h + if (superBolus) { + insulinFromSuperBolus = profile.getBasal(NSProfile.secondsFromMidnight()); + long timeAfter1h = new Date().getTime(); + timeAfter1h += 60L * 60 * 1000; + insulinFromSuperBolus += profile.getBasal(NSProfile.secondsFromMidnight(new Date(timeAfter1h))); + } + // Total - calculatedTotalInsulin = insulinFromBG + insulinFromCarbs + insulingFromBolusIOB + insulingFromBasalsIOB + insulinFromCorrection; + calculatedTotalInsulin = insulinFromBG + insulinFromTrend + insulinFromCarbs + insulingFromBolusIOB + insulingFromBasalsIOB + insulinFromCorrection + insulinFromSuperBolus + insulinFromCOB; if (calculatedTotalInsulin < 0) { carbsEquivalent = -calculatedTotalInsulin * ic; diff --git a/app/src/main/java/info/nightscout/utils/OKDialog.java b/app/src/main/java/info/nightscout/utils/OKDialog.java new file mode 100644 index 0000000000..19fbe7c62a --- /dev/null +++ b/app/src/main/java/info/nightscout/utils/OKDialog.java @@ -0,0 +1,44 @@ +package info.nightscout.utils; + +import android.app.Activity; +import android.content.DialogInterface; +import android.support.v7.app.AlertDialog; +import android.support.v7.view.ContextThemeWrapper; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import info.nightscout.androidaps.MainApp; +import info.nightscout.androidaps.R; + +/** + * Created by mike on 31.03.2017. + */ + +public class OKDialog { + private static Logger log = LoggerFactory.getLogger(OKDialog.class); + + public static void show(final Activity activity, String title, String message, final Runnable runnable) { + try { + AlertDialog.Builder builder = new AlertDialog.Builder(new ContextThemeWrapper(activity, R.style.AppTheme)); + builder.setTitle(title); + builder.setMessage(message); + builder.setPositiveButton(MainApp.sResources.getString(R.string.ok), new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + dialog.dismiss(); + if (runnable != null) { + try { + Thread.sleep(100); + } catch (InterruptedException e) { + } + activity.runOnUiThread(runnable); + } + } + }); + + builder.create().show(); + } catch (Exception e) { + log.debug("show_dialog exception: " + e); + } + } +} diff --git a/app/src/main/java/info/nightscout/utils/SP.java b/app/src/main/java/info/nightscout/utils/SP.java index cce1df9474..9bed316195 100644 --- a/app/src/main/java/info/nightscout/utils/SP.java +++ b/app/src/main/java/info/nightscout/utils/SP.java @@ -61,7 +61,11 @@ public class SP { } static public long getLong(String key, Long defaultValue) { - return SafeParse.stringToLong(sharedPreferences.getString(key, defaultValue.toString())); + try { + return sharedPreferences.getLong(key, defaultValue); + } catch (Exception e) { + return SafeParse.stringToLong(sharedPreferences.getString(key, defaultValue.toString())); + } } static public void putBoolean(String key, boolean value) { @@ -82,9 +86,9 @@ public class SP { editor.apply(); } - static public void putString(String key, String value) { + static public void putLong(String key, long value) { SharedPreferences.Editor editor = sharedPreferences.edit(); - editor.putString(key, value); + editor.putLong(key, value); editor.apply(); } diff --git a/app/src/main/java/info/nightscout/utils/SafeParse.java b/app/src/main/java/info/nightscout/utils/SafeParse.java index 470e649005..8697daeebd 100644 --- a/app/src/main/java/info/nightscout/utils/SafeParse.java +++ b/app/src/main/java/info/nightscout/utils/SafeParse.java @@ -1,15 +1,20 @@ package info.nightscout.utils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * Created by mike on 23.06.2016. */ public class SafeParse { + private static Logger log = LoggerFactory.getLogger(SafeParse.class); public static Double stringToDouble(String input) { Double result = 0d; input = input.replace(",", "."); try { result = Double.parseDouble(input); } catch (Exception e) { + log.error("Error parsing " + input + " to double"); } return result; } @@ -20,6 +25,7 @@ public class SafeParse { try { result = Integer.parseInt(input); } catch (Exception e) { + log.error("Error parsing " + input + " to int"); } return result; } @@ -30,6 +36,7 @@ public class SafeParse { try { result = Long.parseLong(input); } catch (Exception e) { + log.error("Error parsing " + input + " to long"); } return result; } diff --git a/app/src/main/res/drawable/loopmodeborder.xml b/app/src/main/res/drawable/loopmodeborder.xml index 86d49ae55d..95f3c114e6 100644 --- a/app/src/main/res/drawable/loopmodeborder.xml +++ b/app/src/main/res/drawable/loopmodeborder.xml @@ -1,5 +1,5 @@ - + diff --git a/app/src/main/res/drawable/loopmodedisabledborder.xml b/app/src/main/res/drawable/loopmodedisabledborder.xml index 1d312404e0..2326b5ca14 100644 --- a/app/src/main/res/drawable/loopmodedisabledborder.xml +++ b/app/src/main/res/drawable/loopmodedisabledborder.xml @@ -1,5 +1,5 @@ - + diff --git a/app/src/main/res/drawable/loopmodesuspendedborder.xml b/app/src/main/res/drawable/loopmodesuspendedborder.xml new file mode 100644 index 0000000000..9caa1789c1 --- /dev/null +++ b/app/src/main/res/drawable/loopmodesuspendedborder.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable-mdpi-v11/temptargetborder.xml b/app/src/main/res/drawable/temptargetborder.xml similarity index 100% rename from app/src/main/res/drawable-mdpi-v11/temptargetborder.xml rename to app/src/main/res/drawable/temptargetborder.xml diff --git a/app/src/main/res/drawable-mdpi-v11/temptargetborderdisabled.xml b/app/src/main/res/drawable/temptargetborderdisabled.xml similarity index 100% rename from app/src/main/res/drawable-mdpi-v11/temptargetborderdisabled.xml rename to app/src/main/res/drawable/temptargetborderdisabled.xml diff --git a/app/src/main/res/layout/overview_wizard_dialog.xml b/app/src/main/res/layout/overview_wizard_dialog.xml index 00b0df9e2a..caeee2b270 100644 --- a/app/src/main/res/layout/overview_wizard_dialog.xml +++ b/app/src/main/res/layout/overview_wizard_dialog.xml @@ -253,7 +253,7 @@ @@ -269,9 +269,42 @@ + android:layout_height="wrap_content" + android:layout_gravity="center_vertical" + android:layout_weight="0.5" /> + + + + + + +