Merge branch 'dev' into dev-wip

This commit is contained in:
Nico Schmitz 2018-07-01 22:44:11 +02:00 committed by GitHub
commit 2ce38702e2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
148 changed files with 3629 additions and 2205 deletions

View file

@ -166,6 +166,8 @@
android:name=".plugins.Overview.notifications.DismissNotificationService" android:name=".plugins.Overview.notifications.DismissNotificationService"
android:exported="false" /> android:exported="false" />
<service android:name=".plugins.Persistentnotification.DummyService" />
<meta-data <meta-data
android:name="io.fabric.ApiKey" android:name="io.fabric.ApiKey"
android:value="59d462666c664c57b29e1d79ea123e01f8057cfa" /> android:value="59d462666c664c57b29e1d79ea123e01f8057cfa" />

View file

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

View file

@ -176,13 +176,19 @@ public class HistoryBrowseActivity extends AppCompatActivity {
activity.runOnUiThread(new Runnable() { activity.runOnUiThread(new Runnable() {
@Override @Override
public void run() { public void run() {
synchronized (HistoryBrowseActivity.this) {
updateGUI("EventAutosensCalculationFinished"); updateGUI("EventAutosensCalculationFinished");
} }
}
}); });
} }
} }
void updateGUI(String from) { void updateGUI(String from) {
if (noProfile == null || buttonDate == null || buttonZoom == null || bgGraph == null || iobGraph == null || seekBar == null)
return;
final PumpInterface pump = ConfigBuilderPlugin.getActivePump(); final PumpInterface pump = ConfigBuilderPlugin.getActivePump();
final Profile profile = MainApp.getConfigBuilder().getProfile(); final Profile profile = MainApp.getConfigBuilder().getProfile();

View file

@ -20,7 +20,6 @@ import android.support.v7.widget.Toolbar;
import android.text.SpannableString; import android.text.SpannableString;
import android.text.method.LinkMovementMethod; import android.text.method.LinkMovementMethod;
import android.text.util.Linkify; import android.text.util.Linkify;
import android.util.Log;
import android.util.TypedValue; import android.util.TypedValue;
import android.view.Menu; import android.view.Menu;
import android.view.MenuItem; import android.view.MenuItem;
@ -42,11 +41,11 @@ import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.events.EventAppExit; import info.nightscout.androidaps.events.EventAppExit;
import info.nightscout.androidaps.events.EventFeatureRunning; import info.nightscout.androidaps.events.EventFeatureRunning;
import info.nightscout.androidaps.events.EventPreferenceChange;
import info.nightscout.androidaps.events.EventRefreshGui; import info.nightscout.androidaps.events.EventRefreshGui;
import info.nightscout.androidaps.interfaces.PluginBase; import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.Food.FoodPlugin; import info.nightscout.androidaps.plugins.Food.FoodPlugin;
import info.nightscout.androidaps.plugins.Overview.events.EventSetWakeLock;
import info.nightscout.androidaps.plugins.Treatments.TreatmentsPlugin; import info.nightscout.androidaps.plugins.Treatments.TreatmentsPlugin;
import info.nightscout.androidaps.setupwizard.SetupWizardActivity; import info.nightscout.androidaps.setupwizard.SetupWizardActivity;
import info.nightscout.androidaps.tabs.TabPageAdapter; import info.nightscout.androidaps.tabs.TabPageAdapter;
@ -88,7 +87,8 @@ public class MainActivity extends AppCompatActivity {
drawerLayout.addDrawerListener(actionBarDrawerToggle); drawerLayout.addDrawerListener(actionBarDrawerToggle);
actionBarDrawerToggle.syncState(); actionBarDrawerToggle.syncState();
onStatusEvent(new EventSetWakeLock(SP.getBoolean("lockscreen", false))); // initialize screen wake lock
onEventPreferenceChange(new EventPreferenceChange(R.string.key_keep_screen_on));
doMigrations(); doMigrations();
@ -156,9 +156,11 @@ public class MainActivity extends AppCompatActivity {
} }
@Subscribe @Subscribe
public void onStatusEvent(final EventSetWakeLock ev) { public void onEventPreferenceChange(final EventPreferenceChange ev) {
if (ev.isChanged(R.string.key_keep_screen_on)) {
boolean keepScreenOn = SP.getBoolean(R.string.key_keep_screen_on, false);
final PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); final PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
if (ev.lock) { if (keepScreenOn) {
mWakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "AAPS"); mWakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "AAPS");
if (!mWakeLock.isHeld()) if (!mWakeLock.isHeld())
mWakeLock.acquire(); mWakeLock.acquire();
@ -167,6 +169,7 @@ public class MainActivity extends AppCompatActivity {
mWakeLock.release(); mWakeLock.release();
} }
} }
}
@Subscribe @Subscribe
public void onStatusEvent(final EventRefreshGui ev) { public void onStatusEvent(final EventRefreshGui ev) {
@ -184,8 +187,8 @@ public class MainActivity extends AppCompatActivity {
} }
} }
boolean lockScreen = BuildConfig.NSCLIENTOLNY && SP.getBoolean("lockscreen", false); boolean keepScreenOn = BuildConfig.NSCLIENTOLNY && SP.getBoolean(R.string.key_keep_screen_on, false);
if (lockScreen) if (keepScreenOn)
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
else else
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

View file

@ -5,6 +5,7 @@ import android.content.IntentFilter;
import android.content.res.Resources; import android.content.res.Resources;
import android.os.SystemClock; import android.os.SystemClock;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.support.annotation.PluralsRes;
import android.support.v4.content.LocalBroadcastManager; import android.support.v4.content.LocalBroadcastManager;
import com.crashlytics.android.Crashlytics; import com.crashlytics.android.Crashlytics;
@ -47,8 +48,6 @@ import info.nightscout.androidaps.plugins.OpenAPSAMA.OpenAPSAMAPlugin;
import info.nightscout.androidaps.plugins.OpenAPSMA.OpenAPSMAPlugin; import info.nightscout.androidaps.plugins.OpenAPSMA.OpenAPSMAPlugin;
import info.nightscout.androidaps.plugins.OpenAPSSMB.OpenAPSSMBPlugin; import info.nightscout.androidaps.plugins.OpenAPSSMB.OpenAPSSMBPlugin;
import info.nightscout.androidaps.plugins.Overview.OverviewPlugin; import info.nightscout.androidaps.plugins.Overview.OverviewPlugin;
import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification;
import info.nightscout.androidaps.plugins.Overview.notifications.Notification;
import info.nightscout.androidaps.plugins.Persistentnotification.PersistentNotificationPlugin; import info.nightscout.androidaps.plugins.Persistentnotification.PersistentNotificationPlugin;
import info.nightscout.androidaps.plugins.ProfileLocal.LocalProfilePlugin; import info.nightscout.androidaps.plugins.ProfileLocal.LocalProfilePlugin;
import info.nightscout.androidaps.plugins.ProfileNS.NSProfilePlugin; import info.nightscout.androidaps.plugins.ProfileNS.NSProfilePlugin;
@ -61,9 +60,10 @@ import info.nightscout.androidaps.plugins.PumpDanaRv2.DanaRv2Plugin;
import info.nightscout.androidaps.plugins.PumpInsight.InsightPlugin; import info.nightscout.androidaps.plugins.PumpInsight.InsightPlugin;
import info.nightscout.androidaps.plugins.PumpMDI.MDIPlugin; import info.nightscout.androidaps.plugins.PumpMDI.MDIPlugin;
import info.nightscout.androidaps.plugins.PumpVirtual.VirtualPumpPlugin; import info.nightscout.androidaps.plugins.PumpVirtual.VirtualPumpPlugin;
import info.nightscout.androidaps.plugins.SensitivityAAPS.SensitivityAAPSPlugin; import info.nightscout.androidaps.plugins.Sensitivity.SensitivityAAPSPlugin;
import info.nightscout.androidaps.plugins.SensitivityOref0.SensitivityOref0Plugin; import info.nightscout.androidaps.plugins.Sensitivity.SensitivityOref0Plugin;
import info.nightscout.androidaps.plugins.SensitivityWeightedAverage.SensitivityWeightedAveragePlugin; import info.nightscout.androidaps.plugins.Sensitivity.SensitivityOref1Plugin;
import info.nightscout.androidaps.plugins.Sensitivity.SensitivityWeightedAveragePlugin;
import info.nightscout.androidaps.plugins.SmsCommunicator.SmsCommunicatorPlugin; import info.nightscout.androidaps.plugins.SmsCommunicator.SmsCommunicatorPlugin;
import info.nightscout.androidaps.plugins.Source.SourceDexcomG5Plugin; import info.nightscout.androidaps.plugins.Source.SourceDexcomG5Plugin;
import info.nightscout.androidaps.plugins.Source.SourceGlimpPlugin; import info.nightscout.androidaps.plugins.Source.SourceGlimpPlugin;
@ -149,6 +149,7 @@ public class MainApp extends Application {
pluginsList.add(SensitivityOref0Plugin.getPlugin()); pluginsList.add(SensitivityOref0Plugin.getPlugin());
pluginsList.add(SensitivityAAPSPlugin.getPlugin()); pluginsList.add(SensitivityAAPSPlugin.getPlugin());
pluginsList.add(SensitivityWeightedAveragePlugin.getPlugin()); pluginsList.add(SensitivityWeightedAveragePlugin.getPlugin());
pluginsList.add(SensitivityOref1Plugin.getPlugin());
if (Config.HWPUMPS) pluginsList.add(DanaRPlugin.getPlugin()); if (Config.HWPUMPS) pluginsList.add(DanaRPlugin.getPlugin());
if (Config.HWPUMPS) pluginsList.add(DanaRKoreanPlugin.getPlugin()); if (Config.HWPUMPS) pluginsList.add(DanaRKoreanPlugin.getPlugin());
if (Config.HWPUMPS) pluginsList.add(DanaRv2Plugin.getPlugin()); if (Config.HWPUMPS) pluginsList.add(DanaRv2Plugin.getPlugin());
@ -186,7 +187,7 @@ public class MainApp extends Application {
pluginsList.add(WearPlugin.initPlugin(this)); pluginsList.add(WearPlugin.initPlugin(this));
pluginsList.add(StatuslinePlugin.initPlugin(this)); pluginsList.add(StatuslinePlugin.initPlugin(this));
pluginsList.add(new PersistentNotificationPlugin(this)); pluginsList.add(PersistentNotificationPlugin.getPlugin());
pluginsList.add(NSClientPlugin.getPlugin()); pluginsList.add(NSClientPlugin.getPlugin());
pluginsList.add(sConfigBuilder = ConfigBuilderPlugin.getPlugin()); pluginsList.add(sConfigBuilder = ConfigBuilderPlugin.getPlugin());
@ -281,6 +282,10 @@ public class MainApp extends Application {
return sResources.getString(id, args); return sResources.getString(id, args);
} }
public static String gq(@PluralsRes int id, int quantity, Object... args) {
return sResources.getQuantityString(id, quantity, args);
}
public static int gc(int id) { public static int gc(int id) {
return sResources.getColor(id); return sResources.getColor(id);
} }

View file

@ -31,9 +31,10 @@ import info.nightscout.androidaps.plugins.PumpDanaRS.DanaRSPlugin;
import info.nightscout.androidaps.plugins.PumpDanaRv2.DanaRv2Plugin; import info.nightscout.androidaps.plugins.PumpDanaRv2.DanaRv2Plugin;
import info.nightscout.androidaps.plugins.PumpInsight.InsightPlugin; import info.nightscout.androidaps.plugins.PumpInsight.InsightPlugin;
import info.nightscout.androidaps.plugins.PumpVirtual.VirtualPumpPlugin; import info.nightscout.androidaps.plugins.PumpVirtual.VirtualPumpPlugin;
import info.nightscout.androidaps.plugins.SensitivityAAPS.SensitivityAAPSPlugin; import info.nightscout.androidaps.plugins.Sensitivity.SensitivityAAPSPlugin;
import info.nightscout.androidaps.plugins.SensitivityOref0.SensitivityOref0Plugin; import info.nightscout.androidaps.plugins.Sensitivity.SensitivityOref0Plugin;
import info.nightscout.androidaps.plugins.SensitivityWeightedAverage.SensitivityWeightedAveragePlugin; import info.nightscout.androidaps.plugins.Sensitivity.SensitivityOref1Plugin;
import info.nightscout.androidaps.plugins.Sensitivity.SensitivityWeightedAveragePlugin;
import info.nightscout.androidaps.plugins.SmsCommunicator.SmsCommunicatorPlugin; import info.nightscout.androidaps.plugins.SmsCommunicator.SmsCommunicatorPlugin;
import info.nightscout.androidaps.plugins.Source.SourceDexcomG5Plugin; import info.nightscout.androidaps.plugins.Source.SourceDexcomG5Plugin;
import info.nightscout.androidaps.plugins.Wear.WearPlugin; import info.nightscout.androidaps.plugins.Wear.WearPlugin;
@ -153,6 +154,7 @@ public class PreferencesActivity extends PreferenceActivity implements SharedPre
addPreferencesFromResourceIfEnabled(SensitivityAAPSPlugin.getPlugin(), PluginType.SENSITIVITY); addPreferencesFromResourceIfEnabled(SensitivityAAPSPlugin.getPlugin(), PluginType.SENSITIVITY);
addPreferencesFromResourceIfEnabled(SensitivityWeightedAveragePlugin.getPlugin(), PluginType.SENSITIVITY); addPreferencesFromResourceIfEnabled(SensitivityWeightedAveragePlugin.getPlugin(), PluginType.SENSITIVITY);
addPreferencesFromResourceIfEnabled(SensitivityOref0Plugin.getPlugin(), PluginType.SENSITIVITY); addPreferencesFromResourceIfEnabled(SensitivityOref0Plugin.getPlugin(), PluginType.SENSITIVITY);
addPreferencesFromResourceIfEnabled(SensitivityOref1Plugin.getPlugin(), PluginType.SENSITIVITY);
if (Config.HWPUMPS) { if (Config.HWPUMPS) {
addPreferencesFromResourceIfEnabled(DanaRPlugin.getPlugin(), PluginType.PUMP); addPreferencesFromResourceIfEnabled(DanaRPlugin.getPlugin(), PluginType.PUMP);

View file

@ -604,6 +604,7 @@ public class DataService extends IntentService {
NSSgv nsSgv = new NSSgv(sgvJson); NSSgv nsSgv = new NSSgv(sgvJson);
BgReading bgReading = new BgReading(nsSgv); BgReading bgReading = new BgReading(nsSgv);
MainApp.getDbHelper().createIfNotExists(bgReading, "NS"); MainApp.getDbHelper().createIfNotExists(bgReading, "NS");
SourceNSClientPlugin.getPlugin().detectSource(JsonHelper.safeGetString(sgvJson, "device"), JsonHelper.safeGetLong(sgvJson, "mills"));
} }
private void handleNewSMS(Intent intent) { private void handleNewSMS(Intent intent) {

View file

@ -4,12 +4,10 @@ import java.util.ArrayList;
import info.nightscout.androidaps.Constants; import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.interfaces.BgSourceInterface;
import info.nightscout.androidaps.interfaces.Constraint; import info.nightscout.androidaps.interfaces.Constraint;
import info.nightscout.androidaps.interfaces.ConstraintsInterface; import info.nightscout.androidaps.interfaces.ConstraintsInterface;
import info.nightscout.androidaps.interfaces.PluginBase; import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.PluginType; import info.nightscout.androidaps.interfaces.PluginType;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
/** /**
* Created by mike on 19.03.2018. * Created by mike on 19.03.2018.
@ -25,7 +23,7 @@ public class ConstraintChecker implements ConstraintsInterface {
public Constraint<Boolean> isLoopInvokationAllowed() { public Constraint<Boolean> isLoopInvokationAllowed() {
return isLoopInvokationAllowed(new Constraint<>(true)); return isLoopInvocationAllowed(new Constraint<>(true));
} }
public Constraint<Boolean> isClosedLoopAllowed() { public Constraint<Boolean> isClosedLoopAllowed() {
@ -69,13 +67,13 @@ public class ConstraintChecker implements ConstraintsInterface {
} }
@Override @Override
public Constraint<Boolean> isLoopInvokationAllowed(Constraint<Boolean> value) { public Constraint<Boolean> isLoopInvocationAllowed(Constraint<Boolean> value) {
ArrayList<PluginBase> constraintsPlugins = mainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class); ArrayList<PluginBase> constraintsPlugins = mainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class);
for (PluginBase p : constraintsPlugins) { for (PluginBase p : constraintsPlugins) {
ConstraintsInterface constraint = (ConstraintsInterface) p; ConstraintsInterface constraint = (ConstraintsInterface) p;
if (!p.isEnabled(PluginType.CONSTRAINTS)) continue; if (!p.isEnabled(PluginType.CONSTRAINTS)) continue;
constraint.isLoopInvokationAllowed(value); constraint.isLoopInvocationAllowed(value);
} }
return value; return value;
} }

View file

@ -10,6 +10,7 @@ import java.util.Date;
import info.nightscout.androidaps.db.CareportalEvent; import info.nightscout.androidaps.db.CareportalEvent;
import info.nightscout.androidaps.db.Source; import info.nightscout.androidaps.db.Source;
import info.nightscout.androidaps.plugins.Treatments.TreatmentsPlugin;
/** /**
* Created by mike on 29.05.2017. * Created by mike on 29.05.2017.
@ -17,6 +18,7 @@ import info.nightscout.androidaps.db.Source;
public class DetailedBolusInfo { public class DetailedBolusInfo {
public long date = System.currentTimeMillis(); public long date = System.currentTimeMillis();
public long lastKnownBolusTime;
public String eventType = CareportalEvent.MEALBOLUS; public String eventType = CareportalEvent.MEALBOLUS;
public double insulin = 0; public double insulin = 0;
public double carbs = 0; public double carbs = 0;

View file

@ -202,6 +202,12 @@ public class Profile {
if (targetHigh_v == null) if (targetHigh_v == null)
targetHigh_v = convertToSparseArray(targetHigh); targetHigh_v = convertToSparseArray(targetHigh);
validate(targetHigh_v); validate(targetHigh_v);
if (targetHigh_v.size() != targetLow_v.size()) isValid = false;
else for (int i = 0; i < targetHigh_v.size(); i++)
if (targetHigh_v.valueAt(i) < targetLow_v.valueAt(i))
isValid = false;
isValidated = true; isValidated = true;
} }
@ -452,12 +458,12 @@ public class Profile {
return ret; return ret;
} }
public double getTarget(){ public double getTarget() {
return getTarget(secondsFromMidnight(System.currentTimeMillis())); return getTarget(secondsFromMidnight(System.currentTimeMillis()));
} }
protected double getTarget(int timeAsSeconds) { protected double getTarget(int timeAsSeconds) {
return (getTargetLowTimeFromMidnight(timeAsSeconds) + getTargetHighTimeFromMidnight(timeAsSeconds))/2; return (getTargetLowTimeFromMidnight(timeAsSeconds) + getTargetHighTimeFromMidnight(timeAsSeconds)) / 2;
} }
public double getTargetLow() { public double getTargetLow() {
@ -552,6 +558,12 @@ public class Profile {
else return DecimalFormatter.to1Decimal(valueInMmol); else return DecimalFormatter.to1Decimal(valueInMmol);
} }
public static String toSignedUnitsString(Double valueInMgdl, Double valueInMmol, String units) {
if (units.equals(Constants.MGDL))
return (valueInMgdl > 0 ? "+" : "") + DecimalFormatter.to0Decimal(valueInMgdl);
else return (valueInMmol > 0 ? "+" : "") + DecimalFormatter.to1Decimal(valueInMmol);
}
// targets are stored in mg/dl but profile vary // targets are stored in mg/dl but profile vary
public static String toTargetRangeString(double low, double high, String sourceUnits, String units) { public static String toTargetRangeString(double low, double high, String sourceUnits, String units) {
double lowMgdl = toMgdl(low, sourceUnits); double lowMgdl = toMgdl(low, sourceUnits);

View file

@ -24,15 +24,17 @@ import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.interfaces.Interval;
import info.nightscout.androidaps.plugins.NSClientInternal.data.NSMbg; import info.nightscout.androidaps.plugins.NSClientInternal.data.NSMbg;
import info.nightscout.androidaps.plugins.Overview.OverviewFragment; import info.nightscout.androidaps.plugins.Overview.OverviewFragment;
import info.nightscout.androidaps.plugins.Overview.graphExtensions.DataPointWithLabelInterface; import info.nightscout.androidaps.plugins.Overview.graphExtensions.DataPointWithLabelInterface;
import info.nightscout.androidaps.plugins.Overview.graphExtensions.PointsWithLabelGraphSeries; import info.nightscout.androidaps.plugins.Overview.graphExtensions.PointsWithLabelGraphSeries;
import info.nightscout.utils.DateUtil; import info.nightscout.utils.DateUtil;
import info.nightscout.utils.T;
import info.nightscout.utils.Translator; import info.nightscout.utils.Translator;
@DatabaseTable(tableName = DatabaseHelper.DATABASE_CAREPORTALEVENTS) @DatabaseTable(tableName = DatabaseHelper.DATABASE_CAREPORTALEVENTS)
public class CareportalEvent implements DataPointWithLabelInterface { public class CareportalEvent implements DataPointWithLabelInterface, Interval {
private static Logger log = LoggerFactory.getLogger(CareportalEvent.class); private static Logger log = LoggerFactory.getLogger(CareportalEvent.class);
@DatabaseField(id = true) @DatabaseField(id = true)
@ -127,6 +129,19 @@ public class CareportalEvent implements DataPointWithLabelInterface {
return result; return result;
} }
public static boolean isEvent5minBack(List<CareportalEvent> list, long time) {
for (int i = 0; i < list.size(); i++) {
CareportalEvent event = list.get(i);
if (event.date <= time && event.date > (time - T.mins(5).msecs())) {
//log.debug("Found event for time: " + DateUtil.dateAndTimeString(time) + " " + event.toString());
return true;
}
}
//log.debug("WWWWWW No found event for time: " + DateUtil.dateAndTimeString(time));
return false;
}
// -------- DataPointWithLabelInterface ------- // -------- DataPointWithLabelInterface -------
@Override @Override
@ -207,14 +222,7 @@ public class CareportalEvent implements DataPointWithLabelInterface {
@Override @Override
public long getDuration() { public long getDuration() {
try { return end() - start();
JSONObject object = new JSONObject(json);
if (object.has("duration"))
return object.getInt("duration") * 60 * 1000L;
} catch (JSONException e) {
log.error("Unhandled exception", e);
}
return 0;
} }
@Override @Override
@ -253,8 +261,79 @@ public class CareportalEvent implements DataPointWithLabelInterface {
if (eventType.equals(EXERCISE)) if (eventType.equals(EXERCISE))
return Color.BLUE; return Color.BLUE;
if (eventType.equals(OPENAPSOFFLINE)) if (eventType.equals(OPENAPSOFFLINE))
return Color.GRAY; return Color.GRAY & 0x80FFFFFF;
return Color.GRAY; return Color.GRAY;
} }
// Interval interface
Long cuttedEnd = null;
@Override
public long durationInMsec() {
try {
JSONObject object = new JSONObject(json);
if (object.has("duration"))
return object.getInt("duration") * 60 * 1000L;
} catch (JSONException e) {
log.error("Unhandled exception", e);
}
return 0;
}
@Override
public long start() {
return date;
}
@Override
public long originalEnd() {
return date + durationInMsec();
}
@Override
public long end() {
if (cuttedEnd != null)
return cuttedEnd;
return originalEnd();
}
@Override
public void cutEndTo(long end) {
cuttedEnd = end;
}
@Override
public boolean match(long time) {
if (start() <= time && end() >= time)
return true;
return false;
}
public boolean before(long time) {
if (end() < time)
return true;
return false;
}
public boolean after(long time) {
if (start() > time)
return true;
return false;
}
@Override
public boolean isInProgress() {
return match(System.currentTimeMillis());
}
@Override
public boolean isEndingEvent() {
return durationInMsec() == 0;
}
@Override
public boolean isValid() {
return eventType.equals(OPENAPSOFFLINE);
}
} }

View file

@ -30,6 +30,7 @@ import java.util.concurrent.TimeUnit;
import info.nightscout.androidaps.Config; import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.Constants; import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.data.OverlappingIntervals;
import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.data.ProfileStore; import info.nightscout.androidaps.data.ProfileStore;
import info.nightscout.androidaps.events.EventCareportalEventChange; import info.nightscout.androidaps.events.EventCareportalEventChange;
@ -1242,6 +1243,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
where.ge("date", mills); where.ge("date", mills);
PreparedQuery<CareportalEvent> preparedQuery = queryBuilder.prepare(); PreparedQuery<CareportalEvent> preparedQuery = queryBuilder.prepare();
careportalEvents = getDaoCareportalEvents().query(preparedQuery); careportalEvents = getDaoCareportalEvents().query(preparedQuery);
preprocessOpenAPSOfflineEvents(careportalEvents);
return careportalEvents; return careportalEvents;
} catch (SQLException e) { } catch (SQLException e) {
log.error("Unhandled exception", e); log.error("Unhandled exception", e);
@ -1249,13 +1251,41 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
return new ArrayList<>(); return new ArrayList<>();
} }
public List<CareportalEvent> getCareportalEventsFromTime(boolean ascending) { public void preprocessOpenAPSOfflineEvents(List<CareportalEvent> list) {
OverlappingIntervals offlineEvents = new OverlappingIntervals();
for (int i = 0; i < list.size(); i++) {
CareportalEvent event = list.get(i);
if (!event.eventType.equals(CareportalEvent.OPENAPSOFFLINE)) continue;
offlineEvents.add(event);
}
}
public List<CareportalEvent> getCareportalEventsFromTime(long mills, String type, boolean ascending) {
try {
List<CareportalEvent> careportalEvents;
QueryBuilder<CareportalEvent, Long> queryBuilder = getDaoCareportalEvents().queryBuilder();
queryBuilder.orderBy("date", ascending);
Where where = queryBuilder.where();
where.ge("date", mills).and().eq("eventType", type);
PreparedQuery<CareportalEvent> preparedQuery = queryBuilder.prepare();
careportalEvents = getDaoCareportalEvents().query(preparedQuery);
preprocessOpenAPSOfflineEvents(careportalEvents);
return careportalEvents;
} catch (SQLException e) {
log.error("Unhandled exception", e);
}
return new ArrayList<>();
}
public List<CareportalEvent> getCareportalEvents(boolean ascending) {
try { try {
List<CareportalEvent> careportalEvents; List<CareportalEvent> careportalEvents;
QueryBuilder<CareportalEvent, Long> queryBuilder = getDaoCareportalEvents().queryBuilder(); QueryBuilder<CareportalEvent, Long> queryBuilder = getDaoCareportalEvents().queryBuilder();
queryBuilder.orderBy("date", ascending); queryBuilder.orderBy("date", ascending);
PreparedQuery<CareportalEvent> preparedQuery = queryBuilder.prepare(); PreparedQuery<CareportalEvent> preparedQuery = queryBuilder.prepare();
careportalEvents = getDaoCareportalEvents().query(preparedQuery); careportalEvents = getDaoCareportalEvents().query(preparedQuery);
preprocessOpenAPSOfflineEvents(careportalEvents);
return careportalEvents; return careportalEvents;
} catch (SQLException e) { } catch (SQLException e) {
log.error("Unhandled exception", e); log.error("Unhandled exception", e);
@ -1470,6 +1500,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
profileSwitch.profileJson = trJson.getString("profileJson"); profileSwitch.profileJson = trJson.getString("profileJson");
else { else {
ProfileStore store = MainApp.getConfigBuilder().getActiveProfileInterface().getProfile(); ProfileStore store = MainApp.getConfigBuilder().getActiveProfileInterface().getProfile();
if (store != null) {
Profile profile = store.getSpecificProfile(profileSwitch.profileName); Profile profile = store.getSpecificProfile(profileSwitch.profileName);
if (profile != null) { if (profile != null) {
profileSwitch.profileJson = profile.getData().toString(); profileSwitch.profileJson = profile.getData().toString();
@ -1480,6 +1511,10 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
log.debug("JSON for profile switch doesn't exist. Ignoring: " + trJson.toString()); log.debug("JSON for profile switch doesn't exist. Ignoring: " + trJson.toString());
return; return;
} }
} else {
log.debug("Store for profile switch doesn't exist. Ignoring: " + trJson.toString());
return;
}
} }
if (trJson.has("profilePlugin")) if (trJson.has("profilePlugin"))
profileSwitch.profilePlugin = trJson.getString("profilePlugin"); profileSwitch.profilePlugin = trJson.getString("profilePlugin");

View file

@ -103,15 +103,12 @@ public class ProfileSwitch implements Interval, DataPointWithLabelInterface {
if(LocalProfilePlugin.LOCAL_PROFILE.equals(name)){ if(LocalProfilePlugin.LOCAL_PROFILE.equals(name)){
name = DecimalFormatter.to2Decimal(getProfileObject().percentageBasalSum()) + "U "; name = DecimalFormatter.to2Decimal(getProfileObject().percentageBasalSum()) + "U ";
} }
//Test if name is already containing percentage or timeshift
if (!name.endsWith("h)") || !name.endsWith("%)")) {
if (isCPP) { if (isCPP) {
name += "(" + percentage + "%"; name += "(" + percentage + "%";
if (timeshift != 0) if (timeshift != 0)
name += "," + timeshift + "h"; name += "," + timeshift + "h";
name += ")"; name += ")";
} }
}
return name; return name;
} }

View file

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

View file

@ -7,7 +7,7 @@ import info.nightscout.androidaps.data.Profile;
*/ */
public interface ConstraintsInterface { public interface ConstraintsInterface {
default Constraint<Boolean> isLoopInvokationAllowed(Constraint<Boolean> value) { default Constraint<Boolean> isLoopInvocationAllowed(Constraint<Boolean> value) {
return value; return value;
} }

View file

@ -1,11 +1,13 @@
package info.nightscout.androidaps.interfaces; package info.nightscout.androidaps.interfaces;
import android.os.SystemClock; import android.os.SystemClock;
import android.support.v4.app.FragmentActivity;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderFragment;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
/** /**
@ -32,6 +34,12 @@ public abstract class PluginBase {
this.pluginDescription = pluginDescription; this.pluginDescription = pluginDescription;
} }
// Default always calls invoke
// Plugins that have special constraints if they get switched to may override this method
public void switchAllowed(ConfigBuilderFragment.PluginViewHolder.PluginSwitcher pluginSwitcher, FragmentActivity activity) {
pluginSwitcher.invoke();
}
// public PluginType getType() { // public PluginType getType() {
// return mainType; // return mainType;
// } // }

View file

@ -1,11 +1,28 @@
package info.nightscout.androidaps.interfaces; package info.nightscout.androidaps.interfaces;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.plugins.IobCobCalculator.AutosensResult; import info.nightscout.androidaps.plugins.IobCobCalculator.AutosensResult;
import info.nightscout.utils.Round;
import info.nightscout.utils.SP;
import info.nightscout.utils.SafeParse;
/** /**
* Created by mike on 24.06.2017. * Created by mike on 24.06.2017.
*/ */
public interface SensitivityInterface { public interface SensitivityInterface {
double MIN_HOURS = 1;
double MIN_HOURS_FULL_AUTOSENS = 4;
AutosensResult detectSensitivity(long fromTime, long toTime); AutosensResult detectSensitivity(long fromTime, long toTime);
} }

View file

@ -4,6 +4,7 @@ package info.nightscout.androidaps.plugins.ConfigBuilder;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.StringRes;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
@ -22,9 +23,7 @@ import java.util.List;
import butterknife.BindView; import butterknife.BindView;
import butterknife.ButterKnife; import butterknife.ButterKnife;
import butterknife.OnCheckedChanged;
import butterknife.OnClick; import butterknife.OnClick;
import butterknife.Optional;
import butterknife.Unbinder; import butterknife.Unbinder;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.PreferencesActivity; import info.nightscout.androidaps.PreferencesActivity;
@ -44,35 +43,17 @@ import info.nightscout.androidaps.plugins.Common.SubscriberFragment;
import info.nightscout.androidaps.plugins.Insulin.InsulinOrefRapidActingPlugin; import info.nightscout.androidaps.plugins.Insulin.InsulinOrefRapidActingPlugin;
import info.nightscout.androidaps.plugins.ProfileNS.NSProfilePlugin; import info.nightscout.androidaps.plugins.ProfileNS.NSProfilePlugin;
import info.nightscout.androidaps.plugins.PumpVirtual.VirtualPumpPlugin; import info.nightscout.androidaps.plugins.PumpVirtual.VirtualPumpPlugin;
import info.nightscout.androidaps.plugins.SensitivityOref0.SensitivityOref0Plugin; import info.nightscout.androidaps.plugins.Sensitivity.SensitivityOref0Plugin;
import info.nightscout.utils.FabricPrivacy; import info.nightscout.utils.FabricPrivacy;
import info.nightscout.utils.PasswordProtection; import info.nightscout.utils.PasswordProtection;
public class ConfigBuilderFragment extends SubscriberFragment { public class ConfigBuilderFragment extends SubscriberFragment {
private List<PluginView> pluginViews = new ArrayList<>(); private List<PluginViewHolder> pluginViewHolders = new ArrayList<>();
@BindView(R.id.profile_plugins) @BindView(R.id.categories)
LinearLayout profilePlugins; LinearLayout categories;
@BindView(R.id.insulin_plugins)
LinearLayout insulinPlugins;
@BindView(R.id.bgsource_plugins)
LinearLayout bgSourcePlugins;
@BindView(R.id.pump_plugins)
LinearLayout pumpPlugins;
@BindView(R.id.sensitivity_plugins)
LinearLayout sensitivityPlugins;
@BindView(R.id.aps_plugins)
LinearLayout apsPlugins;
@BindView(R.id.loop_plugins)
LinearLayout loopPlugins;
@BindView(R.id.constraints_plugins)
LinearLayout constraintsPlugins;
@BindView(R.id.treatments_plugins)
LinearLayout treatmentsPlugins;
@BindView(R.id.general_plugins)
LinearLayout generalPlugins;
@BindView(R.id.main_layout) @BindView(R.id.main_layout)
ScrollView mainLayout; ScrollView mainLayout;
@ -111,34 +92,40 @@ public class ConfigBuilderFragment extends SubscriberFragment {
@Override @Override
public void onDestroyView() { public void onDestroyView() {
super.onDestroyView(); super.onDestroyView();
for (PluginView pluginView : pluginViews) pluginView.unbind(); for (PluginViewHolder pluginViewHolder : pluginViewHolders) pluginViewHolder.unbind();
pluginViews.clear(); pluginViewHolders.clear();
} }
@Override @Override
protected void updateGUI() { protected void updateGUI() {
for (PluginView pluginView : pluginViews) pluginView.update(); for (PluginViewHolder pluginViewHolder : pluginViewHolders) pluginViewHolder.update();
} }
private void createViews() { private void createViews() {
createViewsForPlugins(profilePlugins, MainApp.getSpecificPluginsVisibleInListByInterface(ProfileInterface.class, PluginType.PROFILE)); createViewsForPlugins(R.string.configbuilder_profile, R.string.configbuilder_profile_description, PluginType.PROFILE, MainApp.getSpecificPluginsVisibleInListByInterface(ProfileInterface.class, PluginType.PROFILE));
createViewsForPlugins(insulinPlugins, MainApp.getSpecificPluginsVisibleInListByInterface(InsulinInterface.class, PluginType.INSULIN)); createViewsForPlugins(R.string.configbuilder_insulin, R.string.configbuilder_insulin_description, PluginType.INSULIN, MainApp.getSpecificPluginsVisibleInListByInterface(InsulinInterface.class, PluginType.INSULIN));
createViewsForPlugins(bgSourcePlugins, MainApp.getSpecificPluginsVisibleInListByInterface(BgSourceInterface.class, PluginType.BGSOURCE)); createViewsForPlugins(R.string.configbuilder_bgsource, R.string.configbuilder_bgsource_description, PluginType.BGSOURCE, MainApp.getSpecificPluginsVisibleInListByInterface(BgSourceInterface.class, PluginType.BGSOURCE));
createViewsForPlugins(pumpPlugins, MainApp.getSpecificPluginsVisibleInList(PluginType.PUMP)); createViewsForPlugins(R.string.configbuilder_pump, R.string.configbuilder_pump_description, PluginType.PUMP, MainApp.getSpecificPluginsVisibleInList(PluginType.PUMP));
createViewsForPlugins(sensitivityPlugins, MainApp.getSpecificPluginsVisibleInListByInterface(SensitivityInterface.class, PluginType.SENSITIVITY)); createViewsForPlugins(R.string.configbuilder_sensitivity, R.string.configbuilder_sensitivity_description, PluginType.SENSITIVITY, MainApp.getSpecificPluginsVisibleInListByInterface(SensitivityInterface.class, PluginType.SENSITIVITY));
createViewsForPlugins(apsPlugins, MainApp.getSpecificPluginsVisibleInList(PluginType.APS)); createViewsForPlugins(R.string.configbuilder_aps, R.string.configbuilder_aps_description, PluginType.APS, MainApp.getSpecificPluginsVisibleInList(PluginType.APS));
createViewsForPlugins(loopPlugins, MainApp.getSpecificPluginsVisibleInList(PluginType.LOOP)); createViewsForPlugins(R.string.configbuilder_loop, R.string.configbuilder_loop_description, PluginType.LOOP, MainApp.getSpecificPluginsVisibleInList(PluginType.LOOP));
createViewsForPlugins(constraintsPlugins, MainApp.getSpecificPluginsVisibleInListByInterface(ConstraintsInterface.class, PluginType.CONSTRAINTS)); createViewsForPlugins(R.string.constraints, R.string.configbuilder_constraints_description, PluginType.CONSTRAINTS, MainApp.getSpecificPluginsVisibleInListByInterface(ConstraintsInterface.class, PluginType.CONSTRAINTS));
createViewsForPlugins(treatmentsPlugins, MainApp.getSpecificPluginsVisibleInList(PluginType.TREATMENT)); createViewsForPlugins(R.string.configbuilder_treatments, R.string.configbuilder_treatments_description, PluginType.TREATMENT, MainApp.getSpecificPluginsVisibleInList(PluginType.TREATMENT));
createViewsForPlugins(generalPlugins, MainApp.getSpecificPluginsVisibleInList(PluginType.GENERAL)); createViewsForPlugins(R.string.configbuilder_general, R.string.configbuilder_general_description, PluginType.GENERAL, MainApp.getSpecificPluginsVisibleInList(PluginType.GENERAL));
} }
private void createViewsForPlugins(LinearLayout parent, List<PluginBase> plugins) { private void createViewsForPlugins(@StringRes int title, @StringRes int description, PluginType pluginType, List<PluginBase> plugins) {
if (plugins.size() == 0) return;
LinearLayout parent = (LinearLayout) getLayoutInflater().inflate(R.layout.configbuilder_single_category, null);
((TextView) parent.findViewById(R.id.category_title)).setText(MainApp.gs(title));
((TextView) parent.findViewById(R.id.category_description)).setText(MainApp.gs(description));
LinearLayout pluginContainer = parent.findViewById(R.id.category_plugins);
for (PluginBase plugin: plugins) { for (PluginBase plugin: plugins) {
PluginView pluginView = new PluginView(plugin); PluginViewHolder pluginViewHolder = new PluginViewHolder(pluginType, plugin);
parent.addView(pluginView.getBaseView()); pluginContainer.addView(pluginViewHolder.getBaseView());
pluginViews.add(pluginView); pluginViewHolders.add(pluginViewHolder);
} }
categories.addView(parent);
} }
private boolean areMultipleSelectionsAllowed(PluginType type) { private boolean areMultipleSelectionsAllowed(PluginType type) {
@ -200,9 +187,10 @@ public class ConfigBuilderFragment extends SubscriberFragment {
} }
} }
class PluginView { public class PluginViewHolder {
private Unbinder unbinder; private Unbinder unbinder;
private PluginType pluginType;
private PluginBase plugin; private PluginBase plugin;
LinearLayout baseView; LinearLayout baseView;
@ -219,7 +207,8 @@ public class ConfigBuilderFragment extends SubscriberFragment {
@BindView(R.id.plugin_visibility) @BindView(R.id.plugin_visibility)
CheckBox pluginVisibility; CheckBox pluginVisibility;
public PluginView(PluginBase plugin) { public PluginViewHolder(PluginType pluginType, PluginBase plugin) {
this.pluginType = pluginType;
this.plugin = plugin; this.plugin = plugin;
baseView = (LinearLayout) getLayoutInflater().inflate(R.layout.configbuilder_single_plugin, null); baseView = (LinearLayout) getLayoutInflater().inflate(R.layout.configbuilder_single_plugin, null);
unbinder = ButterKnife.bind(this, baseView); unbinder = ButterKnife.bind(this, baseView);
@ -231,10 +220,10 @@ public class ConfigBuilderFragment extends SubscriberFragment {
} }
public void update() { public void update() {
enabledExclusive.setVisibility(areMultipleSelectionsAllowed(plugin.getType()) ? View.GONE : View.VISIBLE); enabledExclusive.setVisibility(areMultipleSelectionsAllowed(pluginType) ? View.GONE : View.VISIBLE);
enabledInclusive.setVisibility(areMultipleSelectionsAllowed(plugin.getType()) ? View.VISIBLE : View.GONE); enabledInclusive.setVisibility(areMultipleSelectionsAllowed(pluginType) ? View.VISIBLE : View.GONE);
enabledExclusive.setChecked(plugin.isEnabled(plugin.getType())); enabledExclusive.setChecked(plugin.isEnabled(pluginType));
enabledInclusive.setChecked(plugin.isEnabled(plugin.getType())); enabledInclusive.setChecked(plugin.isEnabled(pluginType));
enabledInclusive.setEnabled(!plugin.pluginDescription.alwaysEnabled); enabledInclusive.setEnabled(!plugin.pluginDescription.alwaysEnabled);
enabledExclusive.setEnabled(!plugin.pluginDescription.alwaysEnabled); enabledExclusive.setEnabled(!plugin.pluginDescription.alwaysEnabled);
pluginName.setText(plugin.getName()); pluginName.setText(plugin.getName());
@ -243,15 +232,15 @@ public class ConfigBuilderFragment extends SubscriberFragment {
pluginDescription.setVisibility(View.VISIBLE); pluginDescription.setVisibility(View.VISIBLE);
pluginDescription.setText(plugin.getDescription()); pluginDescription.setText(plugin.getDescription());
} }
pluginPreferences.setVisibility(plugin.getPreferencesId() == -1 || !plugin.isEnabled(plugin.getType()) ? View.INVISIBLE : View.VISIBLE); pluginPreferences.setVisibility(plugin.getPreferencesId() == -1 || !plugin.isEnabled(pluginType) ? View.INVISIBLE : View.VISIBLE);
pluginVisibility.setVisibility(plugin.hasFragment() ? View.VISIBLE : View.INVISIBLE); pluginVisibility.setVisibility(plugin.hasFragment() ? View.VISIBLE : View.INVISIBLE);
pluginVisibility.setEnabled(!(plugin.pluginDescription.neverVisible || plugin.pluginDescription.alwayVisible) && plugin.isEnabled(plugin.getType())); pluginVisibility.setEnabled(!(plugin.pluginDescription.neverVisible || plugin.pluginDescription.alwayVisible) && plugin.isEnabled(pluginType));
pluginVisibility.setChecked(plugin.isFragmentVisible()); pluginVisibility.setChecked(plugin.isFragmentVisible());
} }
@OnClick(R.id.plugin_visibility) @OnClick(R.id.plugin_visibility)
void onVisibilityChanged() { void onVisibilityChanged() {
plugin.setFragmentVisible(plugin.getType(), pluginVisibility.isChecked()); plugin.setFragmentVisible(pluginType, pluginVisibility.isChecked());
ConfigBuilderPlugin.getPlugin().storeSettings("CheckedCheckboxVisible"); ConfigBuilderPlugin.getPlugin().storeSettings("CheckedCheckboxVisible");
MainApp.bus().post(new EventRefreshGui()); MainApp.bus().post(new EventRefreshGui());
ConfigBuilderPlugin.getPlugin().logPluginStatus(); ConfigBuilderPlugin.getPlugin().logPluginStatus();
@ -259,16 +248,7 @@ public class ConfigBuilderFragment extends SubscriberFragment {
@OnClick({R.id.plugin_enabled_exclusive, R.id.plugin_enabled_inclusive}) @OnClick({R.id.plugin_enabled_exclusive, R.id.plugin_enabled_inclusive})
void onEnabledChanged() { void onEnabledChanged() {
boolean enabled = enabledExclusive.getVisibility() == View.VISIBLE ? enabledExclusive.isChecked() : enabledInclusive.isChecked(); plugin.switchAllowed(new PluginSwitcher(), getActivity());
plugin.setPluginEnabled(plugin.getType(), enabled);
plugin.setFragmentVisible(plugin.getType(), enabled);
processOnEnabledCategoryChanged(plugin, plugin.getType());
updateGUI();
ConfigBuilderPlugin.getPlugin().storeSettings("CheckedCheckboxEnabled");
MainApp.bus().post(new EventRefreshGui());
MainApp.bus().post(new EventConfigBuilderChange());
ConfigBuilderPlugin.getPlugin().logPluginStatus();
FabricPrivacy.getInstance().logCustom(new CustomEvent("ConfigurationChange"));
} }
@OnClick(R.id.plugin_preferences) @OnClick(R.id.plugin_preferences)
@ -284,6 +264,23 @@ public class ConfigBuilderFragment extends SubscriberFragment {
unbinder.unbind(); unbinder.unbind();
} }
public class PluginSwitcher {
public void invoke() {
boolean enabled = enabledExclusive.getVisibility() == View.VISIBLE ? enabledExclusive.isChecked() : enabledInclusive.isChecked();
plugin.setPluginEnabled(pluginType, enabled);
plugin.setFragmentVisible(pluginType, enabled);
processOnEnabledCategoryChanged(plugin, pluginType);
updateGUI();
ConfigBuilderPlugin.getPlugin().storeSettings("CheckedCheckboxEnabled");
MainApp.bus().post(new EventRefreshGui());
MainApp.bus().post(new EventConfigBuilderChange());
ConfigBuilderPlugin.getPlugin().logPluginStatus();
FabricPrivacy.getInstance().logCustom(new CustomEvent("ConfigurationChange"));
} }
public void cancel(){
updateGUI();
}
}
}
} }

View file

@ -43,7 +43,7 @@ import info.nightscout.androidaps.plugins.Loop.APSResult;
import info.nightscout.androidaps.plugins.Loop.LoopPlugin; import info.nightscout.androidaps.plugins.Loop.LoopPlugin;
import info.nightscout.androidaps.plugins.Overview.Dialogs.ErrorHelperActivity; import info.nightscout.androidaps.plugins.Overview.Dialogs.ErrorHelperActivity;
import info.nightscout.androidaps.plugins.PumpVirtual.VirtualPumpPlugin; import info.nightscout.androidaps.plugins.PumpVirtual.VirtualPumpPlugin;
import info.nightscout.androidaps.plugins.SensitivityOref0.SensitivityOref0Plugin; import info.nightscout.androidaps.plugins.Sensitivity.SensitivityOref0Plugin;
import info.nightscout.androidaps.queue.Callback; import info.nightscout.androidaps.queue.Callback;
import info.nightscout.androidaps.queue.CommandQueue; import info.nightscout.androidaps.queue.CommandQueue;
import info.nightscout.utils.FabricPrivacy; import info.nightscout.utils.FabricPrivacy;
@ -113,9 +113,17 @@ public class ConfigBuilderPlugin extends PluginBase {
pluginList = MainApp.getPluginsList(); pluginList = MainApp.getPluginsList();
upgradeSettings(); upgradeSettings();
loadSettings(); loadSettings();
setAlwaysEnabledPluginsEnabled();
MainApp.bus().post(new EventAppInitialized()); MainApp.bus().post(new EventAppInitialized());
} }
private void setAlwaysEnabledPluginsEnabled() {
for (PluginBase plugin : pluginList) {
if (plugin.pluginDescription.alwaysEnabled) plugin.setPluginEnabled(plugin.getType(), true);
}
storeSettings("setAlwaysEnabledPluginsEnabled");
}
public void storeSettings(String from) { public void storeSettings(String from) {
if (pluginList != null) { if (pluginList != null) {
if (Config.logPrefsChange) if (Config.logPrefsChange)
@ -520,6 +528,7 @@ public class ConfigBuilderPlugin extends PluginBase {
// deliver SMB // deliver SMB
DetailedBolusInfo detailedBolusInfo = new DetailedBolusInfo(); DetailedBolusInfo detailedBolusInfo = new DetailedBolusInfo();
detailedBolusInfo.lastKnownBolusTime = activeTreatments.getLastBolusTime();
detailedBolusInfo.eventType = CareportalEvent.CORRECTIONBOLUS; detailedBolusInfo.eventType = CareportalEvent.CORRECTIONBOLUS;
detailedBolusInfo.insulin = request.smb; detailedBolusInfo.insulin = request.smb;
detailedBolusInfo.isSMB = true; detailedBolusInfo.isSMB = true;

View file

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

View file

@ -1,20 +1,14 @@
package info.nightscout.androidaps.plugins.ConstraintsObjectives; package info.nightscout.androidaps.plugins.ConstraintsObjectives;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date;
import java.util.List; import java.util.List;
import info.nightscout.androidaps.Config; import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
import info.nightscout.androidaps.db.DatabaseHelper;
import info.nightscout.androidaps.interfaces.APSInterface;
import info.nightscout.androidaps.interfaces.Constraint; import info.nightscout.androidaps.interfaces.Constraint;
import info.nightscout.androidaps.interfaces.ConstraintsInterface; import info.nightscout.androidaps.interfaces.ConstraintsInterface;
import info.nightscout.androidaps.interfaces.PluginBase; import info.nightscout.androidaps.interfaces.PluginBase;
@ -23,12 +17,15 @@ import info.nightscout.androidaps.interfaces.PluginType;
import info.nightscout.androidaps.interfaces.PumpInterface; import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.ConstraintsObjectives.events.EventObjectivesSaved; import info.nightscout.androidaps.plugins.ConstraintsObjectives.events.EventObjectivesSaved;
import info.nightscout.androidaps.plugins.ConstraintsSafety.SafetyPlugin; import info.nightscout.androidaps.plugins.ConstraintsObjectives.objectives.Objective;
import info.nightscout.androidaps.plugins.Loop.LoopPlugin; import info.nightscout.androidaps.plugins.ConstraintsObjectives.objectives.Objective1;
import info.nightscout.androidaps.plugins.NSClientInternal.NSClientPlugin; import info.nightscout.androidaps.plugins.ConstraintsObjectives.objectives.Objective2;
import info.nightscout.androidaps.plugins.PumpVirtual.VirtualPumpPlugin; import info.nightscout.androidaps.plugins.ConstraintsObjectives.objectives.Objective3;
import info.nightscout.androidaps.plugins.Treatments.TreatmentsPlugin; import info.nightscout.androidaps.plugins.ConstraintsObjectives.objectives.Objective4;
import info.nightscout.utils.DateUtil; import info.nightscout.androidaps.plugins.ConstraintsObjectives.objectives.Objective5;
import info.nightscout.androidaps.plugins.ConstraintsObjectives.objectives.Objective6;
import info.nightscout.androidaps.plugins.ConstraintsObjectives.objectives.Objective7;
import info.nightscout.androidaps.plugins.ConstraintsObjectives.objectives.Objective8;
import info.nightscout.utils.SP; import info.nightscout.utils.SP;
/** /**
@ -39,6 +36,11 @@ public class ObjectivesPlugin extends PluginBase implements ConstraintsInterface
private static ObjectivesPlugin objectivesPlugin; private static ObjectivesPlugin objectivesPlugin;
public static List<Objective> objectives = new ArrayList<>();
public static boolean bgIsAvailableInNS = false;
public static boolean pumpStatusIsAvailableInNS = false;
public static Integer manualEnacts = 0;
public static ObjectivesPlugin getPlugin() { public static ObjectivesPlugin getPlugin() {
if (objectivesPlugin == null) { if (objectivesPlugin == null) {
objectivesPlugin = new ObjectivesPlugin(); objectivesPlugin = new ObjectivesPlugin();
@ -46,8 +48,6 @@ public class ObjectivesPlugin extends PluginBase implements ConstraintsInterface
return objectivesPlugin; return objectivesPlugin;
} }
public static List<Objective> objectives;
private ObjectivesPlugin() { private ObjectivesPlugin() {
super(new PluginDescription() super(new PluginDescription()
.mainType(PluginType.CONSTRAINTS) .mainType(PluginType.CONSTRAINTS)
@ -58,7 +58,7 @@ public class ObjectivesPlugin extends PluginBase implements ConstraintsInterface
.shortName(R.string.objectives_shortname) .shortName(R.string.objectives_shortname)
.description(R.string.description_objectives) .description(R.string.description_objectives)
); );
initializeData(); setupObjectives();
loadProgress(); loadProgress();
} }
@ -68,187 +68,38 @@ public class ObjectivesPlugin extends PluginBase implements ConstraintsInterface
return pump == null || pump.getPumpDescription().isTempBasalCapable; return pump == null || pump.getPumpDescription().isTempBasalCapable;
} }
public class Objective { private void setupObjectives() {
Integer num; objectives.add(new Objective1());
String objective; objectives.add(new Objective2());
String gate; objectives.add(new Objective3());
Date started; objectives.add(new Objective4());
Integer durationInDays; objectives.add(new Objective5());
Date accomplished; objectives.add(new Objective6());
objectives.add(new Objective7());
Objective(Integer num, String objective, String gate, Date started, Integer durationInDays, Date accomplished) { objectives.add(new Objective8());
this.num = num;
this.objective = objective;
this.gate = gate;
this.started = started;
this.durationInDays = durationInDays;
this.accomplished = accomplished;
} }
public void setStarted(Date started) { public void reset() {
this.started = started; for (Objective objective : objectives) {
objective.setStartedOn(null);
objective.setAccomplishedOn(null);
} }
public boolean isStarted() {
return started.getTime() > 0;
}
boolean isFinished() {
return accomplished.getTime() != 0;
}
}
// Objective 0
public static boolean bgIsAvailableInNS = false;
public static boolean pumpStatusIsAvailableInNS = false;
// Objective 1
public static Integer manualEnacts = 0;
private static final Integer manualEnactsNeeded = 20;
class RequirementResult {
boolean done = false;
String comment = "";
RequirementResult(boolean done, String comment) {
this.done = done;
this.comment = comment;
}
}
private String yesOrNo(boolean yes) {
if (yes) return "";
else return "---";
}
RequirementResult requirementsMet(Integer objNum) {
switch (objNum) {
case 0:
boolean isVirtualPump = VirtualPumpPlugin.getPlugin().isEnabled(PluginType.PUMP);
boolean vpUploadEnabled = SP.getBoolean("virtualpump_uploadstatus", false);
boolean vpUploadNeeded = !isVirtualPump || vpUploadEnabled;
boolean hasBGData = DatabaseHelper.lastBg() != null;
boolean apsEnabled = false;
APSInterface usedAPS = ConfigBuilderPlugin.getActiveAPS();
if (usedAPS != null && ((PluginBase) usedAPS).isEnabled(PluginType.APS))
apsEnabled = true;
boolean profileSwitchExists = TreatmentsPlugin.getPlugin().getProfileSwitchFromHistory(DateUtil.now()) != null;
return new RequirementResult(hasBGData && bgIsAvailableInNS && pumpStatusIsAvailableInNS && NSClientPlugin.getPlugin().hasWritePermission() && LoopPlugin.getPlugin().isEnabled(PluginType.LOOP) && apsEnabled && vpUploadNeeded && profileSwitchExists,
MainApp.gs(R.string.objectives_bgavailableinns) + ": " + yesOrNo(bgIsAvailableInNS)
+ "\n" + MainApp.gs(R.string.nsclienthaswritepermission) + ": " + yesOrNo(NSClientPlugin.getPlugin().hasWritePermission())
+ (isVirtualPump ? "\n" + MainApp.gs(R.string.virtualpump_uploadstatus_title) + ": " + yesOrNo(vpUploadEnabled) : "")
+ "\n" + MainApp.gs(R.string.objectives_pumpstatusavailableinns) + ": " + yesOrNo(pumpStatusIsAvailableInNS)
+ "\n" + MainApp.gs(R.string.hasbgdata) + ": " + yesOrNo(hasBGData)
+ "\n" + MainApp.gs(R.string.loopenabled) + ": " + yesOrNo(LoopPlugin.getPlugin().isEnabled(PluginType.LOOP))
+ "\n" + MainApp.gs(R.string.apsselected) + ": " + yesOrNo(apsEnabled)
+ "\n" + MainApp.gs(R.string.activate_profile) + ": " + yesOrNo(profileSwitchExists)
);
case 1:
return new RequirementResult(manualEnacts >= manualEnactsNeeded,
MainApp.gs(R.string.objectives_manualenacts) + ": " + manualEnacts + "/" + manualEnactsNeeded);
case 2:
return new RequirementResult(true, "");
case 3:
Constraint<Boolean> closedLoopEnabled = new Constraint<>(true);
SafetyPlugin.getPlugin().isClosedLoopAllowed(closedLoopEnabled);
return new RequirementResult(closedLoopEnabled.value(), MainApp.gs(R.string.closedmodeenabled) + ": " + yesOrNo(closedLoopEnabled.value()));
case 4:
double maxIOB = MainApp.getConstraintChecker().getMaxIOBAllowed().value();
boolean maxIobSet = maxIOB > 0;
return new RequirementResult(maxIobSet, MainApp.gs(R.string.maxiobset) + ": " + yesOrNo(maxIobSet));
default:
return new RequirementResult(true, "");
}
}
void initializeData() {
bgIsAvailableInNS = false; bgIsAvailableInNS = false;
pumpStatusIsAvailableInNS = false; pumpStatusIsAvailableInNS = false;
manualEnacts = 0; manualEnacts = 0;
saveProgress();
objectives = new ArrayList<>();
objectives.add(new Objective(0,
MainApp.gs(R.string.objectives_0_objective),
MainApp.gs(R.string.objectives_0_gate),
new Date(0),
0, // 0 day
new Date(0)));
objectives.add(new Objective(1,
MainApp.gs(R.string.objectives_1_objective),
MainApp.gs(R.string.objectives_1_gate),
new Date(0),
7, // 7 days
new Date(0)));
objectives.add(new Objective(2,
MainApp.gs(R.string.objectives_2_objective),
MainApp.gs(R.string.objectives_2_gate),
new Date(0),
0, // 0 days
new Date(0)));
objectives.add(new Objective(3,
MainApp.gs(R.string.objectives_3_objective),
MainApp.gs(R.string.objectives_3_gate),
new Date(0),
5, // 5 days
new Date(0)));
objectives.add(new Objective(4,
MainApp.gs(R.string.objectives_4_objective),
MainApp.gs(R.string.objectives_4_gate),
new Date(0),
1,
new Date(0)));
objectives.add(new Objective(5,
MainApp.gs(R.string.objectives_5_objective),
MainApp.gs(R.string.objectives_5_gate),
new Date(0),
7,
new Date(0)));
objectives.add(new Objective(6,
MainApp.gs(R.string.objectives_6_objective),
"",
new Date(0),
28,
new Date(0)));
objectives.add(new Objective(7,
MainApp.gs(R.string.objectives_7_objective),
"",
new Date(0),
28,
new Date(0)));
} }
public static void saveProgress() { public static void saveProgress() {
if (objectives != null) { SP.putBoolean("Objectives" + "bgIsAvailableInNS", bgIsAvailableInNS);
SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(MainApp.instance().getApplicationContext()); SP.putBoolean("Objectives" + "pumpStatusIsAvailableInNS", pumpStatusIsAvailableInNS);
SharedPreferences.Editor editor = settings.edit(); SP.putString("Objectives" + "manualEnacts", Integer.toString(manualEnacts));
for (int num = 0; num < objectives.size(); num++) {
Objective o = objectives.get(num);
editor.putString("Objectives" + num + "started", Long.toString(o.started.getTime()));
editor.putString("Objectives" + num + "accomplished", Long.toString(o.accomplished.getTime()));
}
editor.putBoolean("Objectives" + "bgIsAvailableInNS", bgIsAvailableInNS);
editor.putBoolean("Objectives" + "pumpStatusIsAvailableInNS", pumpStatusIsAvailableInNS);
editor.putString("Objectives" + "manualEnacts", Integer.toString(manualEnacts));
editor.apply();
if (Config.logPrefsChange) if (Config.logPrefsChange)
log.debug("Objectives stored"); log.debug("Objectives stored");
MainApp.bus().post(new EventObjectivesSaved()); MainApp.bus().post(new EventObjectivesSaved());
} }
}
private void loadProgress() { private void loadProgress() {
for (int num = 0; num < objectives.size(); num++) {
Objective o = objectives.get(num);
try {
o.started = new Date(SP.getLong("Objectives" + num + "started", 0L));
o.accomplished = new Date(SP.getLong("Objectives" + num + "accomplished", 0L));
} catch (Exception e) {
log.error("Unhandled exception", e);
}
}
bgIsAvailableInNS = SP.getBoolean("Objectives" + "bgIsAvailableInNS", false); bgIsAvailableInNS = SP.getBoolean("Objectives" + "bgIsAvailableInNS", false);
pumpStatusIsAvailableInNS = SP.getBoolean("Objectives" + "pumpStatusIsAvailableInNS", false); pumpStatusIsAvailableInNS = SP.getBoolean("Objectives" + "pumpStatusIsAvailableInNS", false);
try { try {
@ -260,11 +111,15 @@ public class ObjectivesPlugin extends PluginBase implements ConstraintsInterface
log.debug("Objectives loaded"); log.debug("Objectives loaded");
} }
public static List<Objective> getObjectives() {
return objectives;
}
/** /**
* Constraints interface * Constraints interface
**/ **/
@Override @Override
public Constraint<Boolean> isLoopInvokationAllowed(Constraint<Boolean> value) { public Constraint<Boolean> isLoopInvocationAllowed(Constraint<Boolean> value) {
if (!objectives.get(0).isStarted()) if (!objectives.get(0).isStarted())
value.set(false, String.format(MainApp.gs(R.string.objectivenotstarted), 1), this); value.set(false, String.format(MainApp.gs(R.string.objectivenotstarted), 1), this);
return value; return value;
@ -300,7 +155,7 @@ public class ObjectivesPlugin extends PluginBase implements ConstraintsInterface
@Override @Override
public Constraint<Double> applyMaxIOBConstraints(Constraint<Double> maxIob) { public Constraint<Double> applyMaxIOBConstraints(Constraint<Double> maxIob) {
if (objectives.get(3).isStarted() && !objectives.get(3).isFinished()) if (objectives.get(3).isStarted() && !objectives.get(3).isAccomplished())
maxIob.set(0d, String.format(MainApp.gs(R.string.objectivenotfinished), 4), this); maxIob.set(0d, String.format(MainApp.gs(R.string.objectivenotfinished), 4), this);
return maxIob; return maxIob;
} }

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -0,0 +1,17 @@
package info.nightscout.androidaps.plugins.ConstraintsObjectives.objectives;
import java.util.List;
import info.nightscout.androidaps.R;
public class Objective8 extends Objective {
public Objective8() {
super(7, R.string.objectives_7_objective, 0);
}
@Override
protected void setupTasks(List<Task> tasks) {
tasks.add(new MinimumDurationTask(28L * 24L * 60L * 60L * 1000L));
}
}

View file

@ -49,7 +49,7 @@ public class SafetyPlugin extends PluginBase implements ConstraintsInterface {
* Constraints interface * Constraints interface
**/ **/
@Override @Override
public Constraint<Boolean> isLoopInvokationAllowed(Constraint<Boolean> value) { public Constraint<Boolean> isLoopInvocationAllowed(Constraint<Boolean> value) {
if (!ConfigBuilderPlugin.getActivePump().getPumpDescription().isTempBasalCapable) if (!ConfigBuilderPlugin.getActivePump().getPumpDescription().isTempBasalCapable)
value.set(false, MainApp.gs(R.string.pumpisnottempbasalcapable), this); value.set(false, MainApp.gs(R.string.pumpisnottempbasalcapable), this);
return value; return value;

View file

@ -16,8 +16,8 @@ import info.nightscout.androidaps.plugins.OpenAPSSMB.SMBDefaults;
import info.nightscout.androidaps.plugins.Overview.graphExtensions.DataPointWithLabelInterface; import info.nightscout.androidaps.plugins.Overview.graphExtensions.DataPointWithLabelInterface;
import info.nightscout.androidaps.plugins.Overview.graphExtensions.PointsWithLabelGraphSeries; import info.nightscout.androidaps.plugins.Overview.graphExtensions.PointsWithLabelGraphSeries;
import info.nightscout.androidaps.plugins.Overview.graphExtensions.Scale; import info.nightscout.androidaps.plugins.Overview.graphExtensions.Scale;
import info.nightscout.androidaps.plugins.SensitivityAAPS.SensitivityAAPSPlugin; import info.nightscout.androidaps.plugins.Sensitivity.SensitivityAAPSPlugin;
import info.nightscout.androidaps.plugins.SensitivityWeightedAverage.SensitivityWeightedAveragePlugin; import info.nightscout.androidaps.plugins.Sensitivity.SensitivityWeightedAveragePlugin;
import info.nightscout.androidaps.plugins.Treatments.Treatment; import info.nightscout.androidaps.plugins.Treatments.Treatment;
import info.nightscout.utils.SP; import info.nightscout.utils.SP;
@ -56,11 +56,11 @@ public class AutosensData implements DataPointWithLabelInterface {
} }
public long time = 0L; public long time = 0L;
long chartTime; public double bg = 0; // mgdl
private long chartTime;
public String pastSensitivity = ""; public String pastSensitivity = "";
public double deviation = 0d; public double deviation = 0d;
boolean nonCarbsDeviation = false; public boolean validDeviation = false;
public boolean nonEqualDeviation = false;
List<CarbsInPast> activeCarbsList = new ArrayList<>(); List<CarbsInPast> activeCarbsList = new ArrayList<>();
double absorbed = 0d; double absorbed = 0d;
public double carbsFromBolus = 0d; public double carbsFromBolus = 0d;
@ -76,6 +76,14 @@ public class AutosensData implements DataPointWithLabelInterface {
public double usedMinCarbsImpact = 0d; public double usedMinCarbsImpact = 0d;
public boolean failoverToMinAbsorbtionRate = false; public boolean failoverToMinAbsorbtionRate = false;
// Oref1
public boolean absorbing = false;
public double mealCarbs = 0;
public int mealStartCounter = 999;
public String type = "";
public boolean uam = false;
public List<Double> extraDeviation = new ArrayList<>();
@Override @Override
public String toString() { public String toString() {
return "AutosensData: " + new Date(time).toLocaleString() + " " + pastSensitivity + " Delta=" + delta + " avgDelta=" + avgDelta + " Bgi=" + bgi + " Deviation=" + deviation + " avgDeviation=" + avgDeviation + " Absorbed=" + absorbed + " CarbsFromBolus=" + carbsFromBolus + " COB=" + cob + " autosensRatio=" + autosensRatio + " slopeFromMaxDeviation=" + slopeFromMaxDeviation + " slopeFromMinDeviation =" + slopeFromMinDeviation; return "AutosensData: " + new Date(time).toLocaleString() + " " + pastSensitivity + " Delta=" + delta + " avgDelta=" + avgDelta + " Bgi=" + bgi + " Deviation=" + deviation + " avgDeviation=" + avgDeviation + " Absorbed=" + absorbed + " CarbsFromBolus=" + carbsFromBolus + " COB=" + cob + " autosensRatio=" + autosensRatio + " slopeFromMaxDeviation=" + slopeFromMaxDeviation + " slopeFromMinDeviation =" + slopeFromMinDeviation;

View file

@ -32,4 +32,8 @@ public class AutosensResult {
return ret; return ret;
} }
@Override
public String toString() {
return json().toString();
}
} }

View file

@ -35,6 +35,7 @@ import info.nightscout.androidaps.interfaces.PluginType;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.IobCobCalculator.events.EventNewHistoryData; import info.nightscout.androidaps.plugins.IobCobCalculator.events.EventNewHistoryData;
import info.nightscout.androidaps.plugins.OpenAPSSMB.OpenAPSSMBPlugin; import info.nightscout.androidaps.plugins.OpenAPSSMB.OpenAPSSMBPlugin;
import info.nightscout.androidaps.plugins.Sensitivity.SensitivityOref1Plugin;
import info.nightscout.androidaps.plugins.Treatments.Treatment; import info.nightscout.androidaps.plugins.Treatments.Treatment;
import info.nightscout.androidaps.plugins.Treatments.TreatmentsPlugin; import info.nightscout.androidaps.plugins.Treatments.TreatmentsPlugin;
import info.nightscout.utils.DateUtil; import info.nightscout.utils.DateUtil;
@ -68,7 +69,7 @@ public class IobCobCalculatorPlugin extends PluginBase {
final Object dataLock = new Object(); final Object dataLock = new Object();
boolean stopCalculationTrigger = false; boolean stopCalculationTrigger = false;
private IobCobThread thread = null; private Thread thread = null;
public IobCobCalculatorPlugin() { public IobCobCalculatorPlugin() {
super(new PluginDescription() super(new PluginDescription()
@ -387,10 +388,6 @@ public class IobCobCalculatorPlugin extends PluginBase {
//log.debug(">>> getAutosensData Cache hit " + data.log(time)); //log.debug(">>> getAutosensData Cache hit " + data.log(time));
return data; return data;
} else { } else {
if (time > now) {
// data may not be calculated yet, use last data
return getLastAutosensData("getAutosensData");
}
//log.debug(">>> getAutosensData Cache miss " + new Date(time).toLocaleString()); //log.debug(">>> getAutosensData Cache miss " + new Date(time).toLocaleString());
return null; return null;
} }
@ -541,6 +538,9 @@ public class IobCobCalculatorPlugin extends PluginBase {
public void runCalculation(String from, long start, boolean bgDataReload, Event cause) { public void runCalculation(String from, long start, boolean bgDataReload, Event cause) {
log.debug("Starting calculation thread: " + from); log.debug("Starting calculation thread: " + from);
if (thread == null || thread.getState() == Thread.State.TERMINATED) { if (thread == null || thread.getState() == Thread.State.TERMINATED) {
if (SensitivityOref1Plugin.getPlugin().isEnabled(PluginType.SENSITIVITY))
thread = new IobCobOref1Thread(this, from, start, bgDataReload, cause);
else
thread = new IobCobThread(this, from, start, bgDataReload, cause); thread = new IobCobThread(this, from, start, bgDataReload, cause);
thread.start(); thread.start();
} }
@ -580,7 +580,9 @@ public class IobCobCalculatorPlugin extends PluginBase {
ev.isChanged(R.string.key_age) || ev.isChanged(R.string.key_age) ||
ev.isChanged(R.string.key_absorption_maxtime) || ev.isChanged(R.string.key_absorption_maxtime) ||
ev.isChanged(R.string.key_openapsama_min_5m_carbimpact) || ev.isChanged(R.string.key_openapsama_min_5m_carbimpact) ||
ev.isChanged(R.string.key_absorption_cutoff) ev.isChanged(R.string.key_absorption_cutoff) ||
ev.isChanged(R.string.key_openapsama_autosens_max) ||
ev.isChanged(R.string.key_openapsama_autosens_min)
) { ) {
stopCalculation("onEventPreferenceChange"); stopCalculation("onEventPreferenceChange");
synchronized (dataLock) { synchronized (dataLock) {

View file

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

View file

@ -26,8 +26,8 @@ import info.nightscout.androidaps.interfaces.PluginType;
import info.nightscout.androidaps.plugins.IobCobCalculator.events.EventAutosensCalculationFinished; import info.nightscout.androidaps.plugins.IobCobCalculator.events.EventAutosensCalculationFinished;
import info.nightscout.androidaps.plugins.IobCobCalculator.events.EventIobCalculationProgress; import info.nightscout.androidaps.plugins.IobCobCalculator.events.EventIobCalculationProgress;
import info.nightscout.androidaps.plugins.OpenAPSSMB.SMBDefaults; import info.nightscout.androidaps.plugins.OpenAPSSMB.SMBDefaults;
import info.nightscout.androidaps.plugins.SensitivityAAPS.SensitivityAAPSPlugin; import info.nightscout.androidaps.plugins.Sensitivity.SensitivityAAPSPlugin;
import info.nightscout.androidaps.plugins.SensitivityWeightedAverage.SensitivityWeightedAveragePlugin; import info.nightscout.androidaps.plugins.Sensitivity.SensitivityWeightedAveragePlugin;
import info.nightscout.androidaps.plugins.Treatments.Treatment; import info.nightscout.androidaps.plugins.Treatments.Treatment;
import info.nightscout.androidaps.plugins.Treatments.TreatmentsPlugin; import info.nightscout.androidaps.plugins.Treatments.TreatmentsPlugin;
import info.nightscout.utils.DateUtil; import info.nightscout.utils.DateUtil;
@ -145,6 +145,7 @@ public class IobCobThread extends Thread {
log.error("! value < 39"); log.error("! value < 39");
continue; continue;
} }
autosensData.bg = bg;
delta = (bg - bucketed_data.get(i + 1).value); delta = (bg - bucketed_data.get(i + 1).value);
avgDelta = (bg - bucketed_data.get(i + 3).value) / 3; avgDelta = (bg - bucketed_data.get(i + 3).value) / 3;
@ -245,26 +246,29 @@ public class IobCobThread extends Thread {
// calculate autosens only without COB // calculate autosens only without COB
if (autosensData.cob <= 0) { if (autosensData.cob <= 0) {
if (Math.abs(deviation) < Constants.DEVIATION_TO_BE_EQUAL) { if (Math.abs(deviation) < Constants.DEVIATION_TO_BE_EQUAL) {
autosensData.pastSensitivity += "="; autosensData.pastSensitivity = "=";
autosensData.nonEqualDeviation = true; autosensData.validDeviation = true;
} else if (deviation > 0) { } else if (deviation > 0) {
autosensData.pastSensitivity += "+"; autosensData.pastSensitivity = "+";
autosensData.nonEqualDeviation = true; autosensData.validDeviation = true;
} else { } else {
autosensData.pastSensitivity += "-"; autosensData.pastSensitivity = "-";
autosensData.nonEqualDeviation = true; autosensData.validDeviation = true;
} }
autosensData.nonCarbsDeviation = true;
} else { } else {
autosensData.pastSensitivity += "C"; autosensData.pastSensitivity = "C";
} }
//log.debug("TIME: " + new Date(bgTime).toString() + " BG: " + bg + " SENS: " + sens + " DELTA: " + delta + " AVGDELTA: " + avgDelta + " IOB: " + iob.iob + " ACTIVITY: " + iob.activity + " BGI: " + bgi + " DEVIATION: " + deviation); //log.debug("TIME: " + new Date(bgTime).toString() + " BG: " + bg + " SENS: " + sens + " DELTA: " + delta + " AVGDELTA: " + avgDelta + " IOB: " + iob.iob + " ACTIVITY: " + iob.activity + " BGI: " + bgi + " DEVIATION: " + deviation);
previous = autosensData; previous = autosensData;
if (bgTime < now())
autosensDataTable.put(bgTime, autosensData); autosensDataTable.put(bgTime, autosensData);
if (Config.logAutosensData) if (Config.logAutosensData)
log.debug("Running detectSensitivity from: " + DateUtil.dateAndTimeString(oldestTimeWithData) + " to: " + DateUtil.dateAndTimeString(bgTime)); log.debug("Running detectSensitivity from: " + DateUtil.dateAndTimeString(oldestTimeWithData) + " to: " + DateUtil.dateAndTimeString(bgTime));
autosensData.autosensRatio = iobCobCalculatorPlugin.detectSensitivity(oldestTimeWithData, bgTime).ratio; AutosensResult sensitivity = iobCobCalculatorPlugin.detectSensitivity(oldestTimeWithData, bgTime);
if (Config.logAutosensData)
log.debug("Sensitivity result: " + sensitivity.toString());
autosensData.autosensRatio = sensitivity.ratio;
if (Config.logAutosensData) if (Config.logAutosensData)
log.debug(autosensData.toString()); log.debug(autosensData.toString());
} }

View file

@ -10,7 +10,6 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date;
import java.util.List; import java.util.List;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
@ -28,7 +27,7 @@ import info.nightscout.utils.DecimalFormatter;
public class APSResult { public class APSResult {
private static Logger log = LoggerFactory.getLogger(APSResult.class); private static Logger log = LoggerFactory.getLogger(APSResult.class);
public Date date; public long date = 0;
public String reason; public String reason;
public double rate; public double rate;
public int duration; public int duration;
@ -133,8 +132,8 @@ public class APSResult {
public List<BgReading> getPredictions() { public List<BgReading> getPredictions() {
List<BgReading> array = new ArrayList<>(); List<BgReading> array = new ArrayList<>();
try { try {
long startTime = date.getTime(); long startTime = date;
if (json.has("predBGs")) { if (json != null && json.has("predBGs")) {
JSONObject predBGs = json.getJSONObject("predBGs"); JSONObject predBGs = json.getJSONObject("predBGs");
if (predBGs.has("IOB")) { if (predBGs.has("IOB")) {
JSONArray iob = predBGs.getJSONArray("IOB"); JSONArray iob = predBGs.getJSONArray("IOB");
@ -196,8 +195,8 @@ public class APSResult {
public long getLatestPredictionsTime() { public long getLatestPredictionsTime() {
long latest = 0; long latest = 0;
try { try {
long startTime = date != null ? date.getTime() : 0; long startTime = date;
if (json.has("predBGs")) { if (json != null && json.has("predBGs")) {
JSONObject predBGs = json.getJSONObject("predBGs"); JSONObject predBGs = json.getJSONObject("predBGs");
if (predBGs.has("IOB")) { if (predBGs.has("IOB")) {
JSONArray iob = predBGs.getJSONArray("IOB"); JSONArray iob = predBGs.getJSONArray("IOB");

View file

@ -80,7 +80,7 @@ public class LoopFragment extends SubscriberFragment {
clearGUI(); clearGUI();
final Activity activity = getActivity(); final Activity activity = getActivity();
if (activity != null) if (activity != null)
activity.runOnUiThread(() -> lastRunView.setText(ev.text)); activity.runOnUiThread(() -> { synchronized (LoopFragment.this) { if (lastRunView != null) lastRunView.setText(ev.text); } });
} }
@ -89,6 +89,8 @@ public class LoopFragment extends SubscriberFragment {
Activity activity = getActivity(); Activity activity = getActivity();
if (activity != null) if (activity != null)
activity.runOnUiThread(() -> { activity.runOnUiThread(() -> {
synchronized (LoopFragment.this) {
if (!isBound()) return;
LoopPlugin.LastRun lastRun = LoopPlugin.lastRun; LoopPlugin.LastRun lastRun = LoopPlugin.lastRun;
if (lastRun != null) { if (lastRun != null) {
requestView.setText(lastRun.request != null ? lastRun.request.toSpanned() : ""); requestView.setText(lastRun.request != null ? lastRun.request.toSpanned() : "");
@ -110,6 +112,7 @@ public class LoopFragment extends SubscriberFragment {
} }
constraintsView.setText(constraints); constraintsView.setText(constraints);
} }
}
}); });
} }
@ -117,6 +120,8 @@ public class LoopFragment extends SubscriberFragment {
Activity activity = getActivity(); Activity activity = getActivity();
if (activity != null) if (activity != null)
activity.runOnUiThread(() -> { activity.runOnUiThread(() -> {
synchronized (LoopFragment.this) {
if (isBound()) {
requestView.setText(""); requestView.setText("");
constraintsProcessedView.setText(""); constraintsProcessedView.setText("");
sourceView.setText(""); sourceView.setText("");
@ -124,6 +129,20 @@ public class LoopFragment extends SubscriberFragment {
lastEnactView.setText(""); lastEnactView.setText("");
tbrSetByPumpView.setText(""); tbrSetByPumpView.setText("");
smbSetByPumpView.setText(""); smbSetByPumpView.setText("");
}
}
}); });
} }
boolean isBound() {
return requestView != null
&& constraintsProcessedView != null
&& sourceView != null
&& lastRunView != null
&& lastEnactView != null
&& tbrSetByPumpView != null
&& smbSetByPumpView != null
&& constraintsView != null
&& runNowButton != null;
}
} }

View file

@ -46,6 +46,7 @@ import info.nightscout.androidaps.plugins.Loop.events.EventLoopUpdateGui;
import info.nightscout.androidaps.plugins.Loop.events.EventNewOpenLoopNotification; import info.nightscout.androidaps.plugins.Loop.events.EventNewOpenLoopNotification;
import info.nightscout.androidaps.plugins.Treatments.TreatmentsPlugin; import info.nightscout.androidaps.plugins.Treatments.TreatmentsPlugin;
import info.nightscout.androidaps.queue.Callback; import info.nightscout.androidaps.queue.Callback;
import info.nightscout.androidaps.queue.commands.Command;
import info.nightscout.utils.FabricPrivacy; import info.nightscout.utils.FabricPrivacy;
import info.nightscout.utils.NSUpload; import info.nightscout.utils.NSUpload;
import info.nightscout.utils.SP; import info.nightscout.utils.SP;
@ -332,7 +333,9 @@ public class LoopPlugin extends PluginBase {
Constraint<Boolean> closedLoopEnabled = MainApp.getConstraintChecker().isClosedLoopAllowed(); Constraint<Boolean> closedLoopEnabled = MainApp.getConstraintChecker().isClosedLoopAllowed();
if (closedLoopEnabled.value()) { if (closedLoopEnabled.value()) {
if (result.isChangeRequested()) { if (result.isChangeRequested()
&& !ConfigBuilderPlugin.getCommandQueue().bolusInQueue()
&& !ConfigBuilderPlugin.getCommandQueue().isRunning(Command.CommandType.BOLUS)) {
final PumpEnactResult waiting = new PumpEnactResult(); final PumpEnactResult waiting = new PumpEnactResult();
waiting.queued = true; waiting.queued = true;
if (resultAfterConstraints.tempBasalRequested) if (resultAfterConstraints.tempBasalRequested)

View file

@ -122,7 +122,8 @@ class NsClientReceiverDelegate {
boolean newAllowedState = true; boolean newAllowedState = true;
if (ev.wifiConnected) { if (ev.wifiConnected) {
if (!allowedSSIDs.trim().isEmpty() && !allowedSSIDs.contains(ev.ssid)) { if (!allowedSSIDs.trim().isEmpty() &&
(!allowedSSIDs.contains(ev.getSsid()) && !allowedSSIDs.contains(ev.ssid))) {
newAllowedState = false; newAllowedState = false;
} }
} else { } else {

View file

@ -13,6 +13,7 @@ import java.util.Iterator;
import java.util.Map; import java.util.Map;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
import info.nightscout.androidaps.plugins.Loop.APSResult;
import info.nightscout.utils.DateUtil; import info.nightscout.utils.DateUtil;
import info.nightscout.utils.Round; import info.nightscout.utils.Round;
import info.nightscout.utils.SP; import info.nightscout.utils.SP;
@ -374,7 +375,7 @@ public class NSDeviceStatus {
public String getUploaderStatus() { public String getUploaderStatus() {
Iterator iter = uploaders.entrySet().iterator(); Iterator iter = uploaders.entrySet().iterator();
int minBattery = 100; int minBattery = 100;
while(iter.hasNext()) { while (iter.hasNext()) {
Map.Entry pair = (Map.Entry) iter.next(); Map.Entry pair = (Map.Entry) iter.next();
Uploader uploader = (Uploader) pair.getValue(); Uploader uploader = (Uploader) pair.getValue();
if (minBattery > uploader.battery) if (minBattery > uploader.battery)
@ -388,7 +389,7 @@ public class NSDeviceStatus {
StringBuilder string = new StringBuilder(); StringBuilder string = new StringBuilder();
Iterator iter = uploaders.entrySet().iterator(); Iterator iter = uploaders.entrySet().iterator();
while(iter.hasNext()) { while (iter.hasNext()) {
Map.Entry pair = (Map.Entry) iter.next(); Map.Entry pair = (Map.Entry) iter.next();
Uploader uploader = (Uploader) pair.getValue(); Uploader uploader = (Uploader) pair.getValue();
String device = (String) pair.getKey(); String device = (String) pair.getKey();
@ -398,4 +399,11 @@ public class NSDeviceStatus {
return Html.fromHtml(string.toString()); return Html.fromHtml(string.toString());
} }
public static APSResult getAPSResult() {
APSResult result = new APSResult();
result.json = deviceStatusOpenAPSData.suggested;
result.date = deviceStatusOpenAPSData.clockSuggested;
return result;
}
} }

View file

@ -6,19 +6,18 @@ import org.mozilla.javascript.NativeObject;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.util.Date;
import info.nightscout.androidaps.plugins.Loop.APSResult; import info.nightscout.androidaps.plugins.Loop.APSResult;
import info.nightscout.utils.DateUtil;
public class DetermineBasalResultAMA extends APSResult { public class DetermineBasalResultAMA extends APSResult {
private static Logger log = LoggerFactory.getLogger(DetermineBasalResultAMA.class); private static Logger log = LoggerFactory.getLogger(DetermineBasalResultAMA.class);
public double eventualBG; private double eventualBG;
public double snoozeBG; private double snoozeBG;
public DetermineBasalResultAMA(NativeObject result, JSONObject j) { DetermineBasalResultAMA(NativeObject result, JSONObject j) {
this(); this();
date = new Date(); date = DateUtil.now();
json = j; json = j;
if (result.containsKey("error")) { if (result.containsKey("error")) {
reason = result.get("error").toString(); reason = result.get("error").toString();

View file

@ -234,8 +234,8 @@ public class DetermineBasalAdapterSMBJS {
mProfile.put("max_daily_safety_multiplier", SP.getInt(R.string.key_openapsama_max_daily_safety_multiplier, 3)); mProfile.put("max_daily_safety_multiplier", SP.getInt(R.string.key_openapsama_max_daily_safety_multiplier, 3));
mProfile.put("current_basal_safety_multiplier", SP.getDouble(R.string.key_openapsama_current_basal_safety_multiplier, 4d)); mProfile.put("current_basal_safety_multiplier", SP.getDouble(R.string.key_openapsama_current_basal_safety_multiplier, 4d));
mProfile.put("high_temptarget_raises_sensitivity", SMBDefaults.high_temptarget_raises_sensitivity); mProfile.put("high_temptarget_raises_sensitivity", SP.getBoolean(R.string.key_high_temptarget_raises_sensitivity, SMBDefaults.high_temptarget_raises_sensitivity));
mProfile.put("low_temptarget_lowers_sensitivity", SMBDefaults.low_temptarget_lowers_sensitivity); mProfile.put("low_temptarget_lowers_sensitivity", SP.getBoolean(R.string.key_low_temptarget_lowers_sensitivity, SMBDefaults.low_temptarget_lowers_sensitivity));
mProfile.put("sensitivity_raises_target", SMBDefaults.sensitivity_raises_target); mProfile.put("sensitivity_raises_target", SMBDefaults.sensitivity_raises_target);
mProfile.put("resistance_lowers_target", SMBDefaults.resistance_lowers_target); mProfile.put("resistance_lowers_target", SMBDefaults.resistance_lowers_target);
mProfile.put("adv_target_adjustments", SMBDefaults.adv_target_adjustments); mProfile.put("adv_target_adjustments", SMBDefaults.adv_target_adjustments);

View file

@ -5,22 +5,20 @@ import org.json.JSONObject;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.util.Date;
import info.nightscout.androidaps.plugins.Loop.APSResult; import info.nightscout.androidaps.plugins.Loop.APSResult;
import info.nightscout.utils.DateUtil; import info.nightscout.utils.DateUtil;
public class DetermineBasalResultSMB extends APSResult { public class DetermineBasalResultSMB extends APSResult {
private static final Logger log = LoggerFactory.getLogger(DetermineBasalResultSMB.class); private static final Logger log = LoggerFactory.getLogger(DetermineBasalResultSMB.class);
public double eventualBG; private double eventualBG;
public double snoozeBG; private double snoozeBG;
public double insulinReq; //public double insulinReq;
public double carbsReq; //public double carbsReq;
public DetermineBasalResultSMB(JSONObject result) { DetermineBasalResultSMB(JSONObject result) {
this(); this();
date = new Date(); date = DateUtil.now();
json = result; json = result;
try { try {
if (result.has("error")) { if (result.has("error")) {
@ -31,8 +29,8 @@ public class DetermineBasalResultSMB extends APSResult {
reason = result.getString("reason"); reason = result.getString("reason");
if (result.has("eventualBG")) eventualBG = result.getDouble("eventualBG"); if (result.has("eventualBG")) eventualBG = result.getDouble("eventualBG");
if (result.has("snoozeBG")) snoozeBG = result.getDouble("snoozeBG"); if (result.has("snoozeBG")) snoozeBG = result.getDouble("snoozeBG");
if (result.has("insulinReq")) insulinReq = result.getDouble("insulinReq"); //if (result.has("insulinReq")) insulinReq = result.getDouble("insulinReq");
if (result.has("carbsReq")) carbsReq = result.getDouble("carbsReq"); //if (result.has("carbsReq")) carbsReq = result.getDouble("carbsReq");
if (result.has("rate") && result.has("duration")) { if (result.has("rate") && result.has("duration")) {
tempBasalRequested = true; tempBasalRequested = true;
@ -64,7 +62,7 @@ public class DetermineBasalResultSMB extends APSResult {
} }
} }
public DetermineBasalResultSMB() { private DetermineBasalResultSMB() {
hasPredictions = true; hasPredictions = true;
} }

View file

@ -87,6 +87,8 @@ public class OpenAPSSMBFragment extends SubscriberFragment {
activity.runOnUiThread(new Runnable() { activity.runOnUiThread(new Runnable() {
@Override @Override
public void run() { public void run() {
synchronized (OpenAPSSMBFragment.this) {
if (!isBound()) return;
OpenAPSSMBPlugin plugin = OpenAPSSMBPlugin.getPlugin(); OpenAPSSMBPlugin plugin = OpenAPSSMBPlugin.getPlugin();
DetermineBasalResultSMB lastAPSResult = plugin.lastAPSResult; DetermineBasalResultSMB lastAPSResult = plugin.lastAPSResult;
if (lastAPSResult != null) { if (lastAPSResult != null) {
@ -117,6 +119,7 @@ public class OpenAPSSMBFragment extends SubscriberFragment {
autosensDataView.setText(JSONFormatter.format(plugin.lastAutosensResult.json()).toString().trim()); autosensDataView.setText(JSONFormatter.format(plugin.lastAutosensResult.json()).toString().trim());
} }
} }
}
}); });
} }
@ -126,6 +129,8 @@ public class OpenAPSSMBFragment extends SubscriberFragment {
activity.runOnUiThread(new Runnable() { activity.runOnUiThread(new Runnable() {
@Override @Override
public void run() { public void run() {
synchronized (OpenAPSSMBFragment.this) {
if (isBound()) {
resultView.setText(text); resultView.setText(text);
glucoseStatusView.setText(""); glucoseStatusView.setText("");
currentTempView.setText(""); currentTempView.setText("");
@ -137,6 +142,23 @@ public class OpenAPSSMBFragment extends SubscriberFragment {
requestView.setText(""); requestView.setText("");
lastRunView.setText(""); lastRunView.setText("");
} }
}
}
}); });
} }
private boolean isBound() {
return run != null
&& lastRunView != null
&& constraintsView != null
&& glucoseStatusView != null
&& currentTempView != null
&& iobDataView != null
&& profileView != null
&& mealDataView != null
&& autosensDataView != null
&& resultView != null
&& scriptdebugView != null
&& requestView != null;
}
} }

View file

@ -25,14 +25,11 @@ import android.text.style.ForegroundColorSpan;
import android.util.DisplayMetrics; import android.util.DisplayMetrics;
import android.util.TypedValue; import android.util.TypedValue;
import android.view.ContextMenu; import android.view.ContextMenu;
import android.view.HapticFeedbackConstants;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.Menu; import android.view.Menu;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.ImageButton; import android.widget.ImageButton;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.TextView; import android.widget.TextView;
@ -89,10 +86,12 @@ import info.nightscout.androidaps.plugins.Careportal.Dialogs.NewNSTreatmentDialo
import info.nightscout.androidaps.plugins.Careportal.OptionsToShow; import info.nightscout.androidaps.plugins.Careportal.OptionsToShow;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.ConstraintsObjectives.ObjectivesPlugin; import info.nightscout.androidaps.plugins.ConstraintsObjectives.ObjectivesPlugin;
import info.nightscout.androidaps.plugins.IobCobCalculator.AutosensResult;
import info.nightscout.androidaps.plugins.IobCobCalculator.CobInfo; import info.nightscout.androidaps.plugins.IobCobCalculator.CobInfo;
import info.nightscout.androidaps.plugins.IobCobCalculator.IobCobCalculatorPlugin; import info.nightscout.androidaps.plugins.IobCobCalculator.IobCobCalculatorPlugin;
import info.nightscout.androidaps.plugins.IobCobCalculator.events.EventAutosensCalculationFinished; import info.nightscout.androidaps.plugins.IobCobCalculator.events.EventAutosensCalculationFinished;
import info.nightscout.androidaps.plugins.IobCobCalculator.events.EventIobCalculationProgress; import info.nightscout.androidaps.plugins.IobCobCalculator.events.EventIobCalculationProgress;
import info.nightscout.androidaps.plugins.Loop.APSResult;
import info.nightscout.androidaps.plugins.Loop.LoopPlugin; import info.nightscout.androidaps.plugins.Loop.LoopPlugin;
import info.nightscout.androidaps.plugins.Loop.events.EventNewOpenLoopNotification; import info.nightscout.androidaps.plugins.Loop.events.EventNewOpenLoopNotification;
import info.nightscout.androidaps.plugins.NSClientInternal.data.NSDeviceStatus; import info.nightscout.androidaps.plugins.NSClientInternal.data.NSDeviceStatus;
@ -104,7 +103,6 @@ import info.nightscout.androidaps.plugins.Overview.Dialogs.NewInsulinDialog;
import info.nightscout.androidaps.plugins.Overview.Dialogs.NewTreatmentDialog; import info.nightscout.androidaps.plugins.Overview.Dialogs.NewTreatmentDialog;
import info.nightscout.androidaps.plugins.Overview.Dialogs.WizardDialog; import info.nightscout.androidaps.plugins.Overview.Dialogs.WizardDialog;
import info.nightscout.androidaps.plugins.Overview.activities.QuickWizardListActivity; import info.nightscout.androidaps.plugins.Overview.activities.QuickWizardListActivity;
import info.nightscout.androidaps.plugins.Overview.events.EventSetWakeLock;
import info.nightscout.androidaps.plugins.Overview.graphData.GraphData; import info.nightscout.androidaps.plugins.Overview.graphData.GraphData;
import info.nightscout.androidaps.plugins.Overview.notifications.NotificationRecyclerViewAdapter; import info.nightscout.androidaps.plugins.Overview.notifications.NotificationRecyclerViewAdapter;
import info.nightscout.androidaps.plugins.Overview.notifications.NotificationStore; import info.nightscout.androidaps.plugins.Overview.notifications.NotificationStore;
@ -116,6 +114,7 @@ import info.nightscout.androidaps.queue.Callback;
import info.nightscout.utils.BolusWizard; import info.nightscout.utils.BolusWizard;
import info.nightscout.utils.DateUtil; import info.nightscout.utils.DateUtil;
import info.nightscout.utils.DecimalFormatter; import info.nightscout.utils.DecimalFormatter;
import info.nightscout.utils.DefaultValueHelper;
import info.nightscout.utils.FabricPrivacy; import info.nightscout.utils.FabricPrivacy;
import info.nightscout.utils.NSUpload; import info.nightscout.utils.NSUpload;
import info.nightscout.utils.OKDialog; import info.nightscout.utils.OKDialog;
@ -124,14 +123,19 @@ import info.nightscout.utils.SP;
import info.nightscout.utils.SingleClickButton; import info.nightscout.utils.SingleClickButton;
import info.nightscout.utils.ToastUtils; import info.nightscout.utils.ToastUtils;
import static info.nightscout.utils.DateUtil.now;
public class OverviewFragment extends Fragment implements View.OnClickListener, View.OnLongClickListener { public class OverviewFragment extends Fragment implements View.OnClickListener, View.OnLongClickListener {
private static Logger log = LoggerFactory.getLogger(OverviewFragment.class); private static Logger log = LoggerFactory.getLogger(OverviewFragment.class);
TextView timeView; TextView timeView;
TextView bgView; TextView bgView;
TextView arrowView; TextView arrowView;
TextView sensitivityView;
TextView timeAgoView; TextView timeAgoView;
TextView timeAgoShortView;
TextView deltaView; TextView deltaView;
TextView deltaShortView;
TextView avgdeltaView; TextView avgdeltaView;
TextView baseBasalView; TextView baseBasalView;
TextView extendedBolusView; TextView extendedBolusView;
@ -177,8 +181,6 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
SingleClickButton cgmButton; SingleClickButton cgmButton;
SingleClickButton quickWizardButton; SingleClickButton quickWizardButton;
CheckBox lockScreen;
boolean smallWidth; boolean smallWidth;
boolean smallHeight; boolean smallHeight;
@ -235,8 +237,11 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
if (smallWidth) { if (smallWidth) {
arrowView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 35); arrowView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 35);
} }
sensitivityView = (TextView) view.findViewById(R.id.overview_sensitivity);
timeAgoView = (TextView) view.findViewById(R.id.overview_timeago); timeAgoView = (TextView) view.findViewById(R.id.overview_timeago);
timeAgoShortView = (TextView) view.findViewById(R.id.overview_timeagoshort);
deltaView = (TextView) view.findViewById(R.id.overview_delta); deltaView = (TextView) view.findViewById(R.id.overview_delta);
deltaShortView = (TextView) view.findViewById(R.id.overview_deltashort);
avgdeltaView = (TextView) view.findViewById(R.id.overview_avgdelta); avgdeltaView = (TextView) view.findViewById(R.id.overview_avgdelta);
baseBasalView = (TextView) view.findViewById(R.id.overview_basebasal); baseBasalView = (TextView) view.findViewById(R.id.overview_basebasal);
extendedBolusView = (TextView) view.findViewById(R.id.overview_extendedbolus); extendedBolusView = (TextView) view.findViewById(R.id.overview_extendedbolus);
@ -323,7 +328,7 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
iobGraph.getGridLabelRenderer().setHorizontalLabelsVisible(false); iobGraph.getGridLabelRenderer().setHorizontalLabelsVisible(false);
bgGraph.getGridLabelRenderer().setLabelVerticalWidth(axisWidth); bgGraph.getGridLabelRenderer().setLabelVerticalWidth(axisWidth);
iobGraph.getGridLabelRenderer().setLabelVerticalWidth(axisWidth); iobGraph.getGridLabelRenderer().setLabelVerticalWidth(axisWidth);
iobGraph.getGridLabelRenderer().setNumVerticalLabels(5); iobGraph.getGridLabelRenderer().setNumVerticalLabels(3);
rangeToDisplay = SP.getInt(R.string.key_rangetodisplay, 6); rangeToDisplay = SP.getInt(R.string.key_rangetodisplay, 6);
@ -340,18 +345,6 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
setupChartMenu(view); setupChartMenu(view);
lockScreen = (CheckBox) view.findViewById(R.id.overview_lockscreen);
if (lockScreen != null) {
lockScreen.setChecked(SP.getBoolean("lockscreen", false));
lockScreen.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
SP.putBoolean("lockscreen", isChecked);
MainApp.bus().post(new EventSetWakeLock(isChecked));
}
});
}
return view; return view;
} catch (Exception e) { } catch (Exception e) {
FabricPrivacy.logException(e); FabricPrivacy.logException(e);
@ -367,7 +360,13 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
@Override @Override
public void onClick(View v) { public void onClick(View v) {
final LoopPlugin.LastRun finalLastRun = LoopPlugin.lastRun; final LoopPlugin.LastRun finalLastRun = LoopPlugin.lastRun;
final boolean predictionsAvailable = finalLastRun != null && finalLastRun.request.hasPredictions; boolean predictionsAvailable;
if (Config.APS)
predictionsAvailable = finalLastRun != null && finalLastRun.request.hasPredictions;
else if (Config.NSCLIENT)
predictionsAvailable = true;
else
predictionsAvailable = false;
MenuItem item; MenuItem item;
CharSequence title; CharSequence title;
@ -504,6 +503,15 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
if (MainApp.getConfigBuilder().getActiveProfileInterface().getProfile() != null) { if (MainApp.getConfigBuilder().getActiveProfileInterface().getProfile() != null) {
menu.add(MainApp.gs(R.string.careportal_profileswitch)); menu.add(MainApp.gs(R.string.careportal_profileswitch));
} }
} else if (v == tempTargetView) {
menu.setHeaderTitle(MainApp.gs(R.string.careportal_temporarytarget));
menu.add(MainApp.gs(R.string.custom));
menu.add(MainApp.gs(R.string.eatingsoon));
menu.add(MainApp.gs(R.string.activity));
menu.add(MainApp.gs(R.string.hypo));
if (TreatmentsPlugin.getPlugin().getTempTargetFromHistory() != null) {
menu.add(MainApp.gs(R.string.cancel));
}
} }
} }
@ -594,6 +602,53 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
ProfileViewerDialog pvd = ProfileViewerDialog.newInstance(System.currentTimeMillis()); ProfileViewerDialog pvd = ProfileViewerDialog.newInstance(System.currentTimeMillis());
FragmentManager manager = getFragmentManager(); FragmentManager manager = getFragmentManager();
pvd.show(manager, "ProfileViewDialog"); pvd.show(manager, "ProfileViewDialog");
} else if (item.getTitle().equals(MainApp.gs(R.string.eatingsoon))) {
DefaultValueHelper defHelper = new DefaultValueHelper();
double target = defHelper.determineEatingSoonTT(profile.getUnits());
TempTarget tempTarget = new TempTarget()
.date(System.currentTimeMillis())
.duration(defHelper.determineEatingSoonTTDuration())
.reason(MainApp.gs(R.string.eatingsoon))
.source(Source.USER)
.low(target)
.high(target);
TreatmentsPlugin.getPlugin().addToHistoryTempTarget(tempTarget);
} else if (item.getTitle().equals(MainApp.gs(R.string.activity))) {
DefaultValueHelper defHelper = new DefaultValueHelper();
double target = defHelper.determineActivityTT(profile.getUnits());
TempTarget tempTarget = new TempTarget()
.date(now())
.duration(defHelper.determineActivityTTDuration())
.reason(MainApp.gs(R.string.activity))
.source(Source.USER)
.low(target)
.high(target);
TreatmentsPlugin.getPlugin().addToHistoryTempTarget(tempTarget);
} else if (item.getTitle().equals(MainApp.gs(R.string.hypo))) {
DefaultValueHelper defHelper = new DefaultValueHelper();
double target = defHelper.determineHypoTT(profile.getUnits());
TempTarget tempTarget = new TempTarget()
.date(now())
.duration(defHelper.determineHypoTTDuration())
.reason(MainApp.gs(R.string.activity))
.source(Source.USER)
.low(target)
.high(target);
TreatmentsPlugin.getPlugin().addToHistoryTempTarget(tempTarget);
} else if (item.getTitle().equals(MainApp.gs(R.string.custom))) {
NewNSTreatmentDialog newTTDialog = new NewNSTreatmentDialog();
final OptionsToShow temptarget = CareportalFragment.TEMPTARGET;
temptarget.executeTempTarget = true;
newTTDialog.setOptions(temptarget, R.string.careportal_temporarytarget);
newTTDialog.show(getFragmentManager(), "NewNSTreatmentDialog");
} else if (item.getTitle().equals(MainApp.gs(R.string.cancel))) {
TempTarget tempTarget = new TempTarget()
.source(Source.USER)
.date(now())
.duration(0)
.low(0)
.high(0);
TreatmentsPlugin.getPlugin().addToHistoryTempTarget(tempTarget);
} }
return super.onContextItemSelected(item); return super.onContextItemSelected(item);
@ -859,6 +914,7 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
sLoopHandler.removeCallbacksAndMessages(null); sLoopHandler.removeCallbacksAndMessages(null);
unregisterForContextMenu(apsModeView); unregisterForContextMenu(apsModeView);
unregisterForContextMenu(activeProfileView); unregisterForContextMenu(activeProfileView);
unregisterForContextMenu(tempTargetView);
} }
@Override @Override
@ -872,6 +928,7 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
sLoopHandler.postDelayed(sRefreshLoop, 60 * 1000L); sLoopHandler.postDelayed(sRefreshLoop, 60 * 1000L);
registerForContextMenu(apsModeView); registerForContextMenu(apsModeView);
registerForContextMenu(activeProfileView); registerForContextMenu(activeProfileView);
registerForContextMenu(tempTargetView);
updateGUI("onResume"); updateGUI("onResume");
} }
@ -1043,12 +1100,18 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
arrowView.setTextColor(color); arrowView.setTextColor(color);
GlucoseStatus glucoseStatus = GlucoseStatus.getGlucoseStatusData(); GlucoseStatus glucoseStatus = GlucoseStatus.getGlucoseStatusData();
if (glucoseStatus != null) { if (glucoseStatus != null) {
if (deltaView != null)
deltaView.setText("Δ " + Profile.toUnitsString(glucoseStatus.delta, glucoseStatus.delta * Constants.MGDL_TO_MMOLL, units) + " " + units); deltaView.setText("Δ " + Profile.toUnitsString(glucoseStatus.delta, glucoseStatus.delta * Constants.MGDL_TO_MMOLL, units) + " " + units);
if (deltaShortView != null)
deltaShortView.setText(Profile.toSignedUnitsString(glucoseStatus.delta, glucoseStatus.delta * Constants.MGDL_TO_MMOLL, units));
if (avgdeltaView != null) if (avgdeltaView != null)
avgdeltaView.setText("øΔ15m: " + Profile.toUnitsString(glucoseStatus.short_avgdelta, glucoseStatus.short_avgdelta * Constants.MGDL_TO_MMOLL, units) + avgdeltaView.setText("øΔ15m: " + Profile.toUnitsString(glucoseStatus.short_avgdelta, glucoseStatus.short_avgdelta * Constants.MGDL_TO_MMOLL, units) +
" øΔ40m: " + Profile.toUnitsString(glucoseStatus.long_avgdelta, glucoseStatus.long_avgdelta * Constants.MGDL_TO_MMOLL, units)); " øΔ40m: " + Profile.toUnitsString(glucoseStatus.long_avgdelta, glucoseStatus.long_avgdelta * Constants.MGDL_TO_MMOLL, units));
} else { } else {
if (deltaView != null)
deltaView.setText("Δ " + MainApp.gs(R.string.notavailable)); deltaView.setText("Δ " + MainApp.gs(R.string.notavailable));
if (deltaShortView != null)
deltaShortView.setText("---");
if (avgdeltaView != null) if (avgdeltaView != null)
avgdeltaView.setText(""); avgdeltaView.setText("");
} }
@ -1204,7 +1267,7 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
extendedBolusView.setText(extendedBolusText); extendedBolusView.setText(extendedBolusText);
} }
if (extendedBolusText.equals("")) if (extendedBolusText.equals(""))
extendedBolusView.setVisibility(View.GONE); extendedBolusView.setVisibility(shorttextmode ? View.INVISIBLE : View.GONE);
else else
extendedBolusView.setVisibility(View.VISIBLE); extendedBolusView.setVisibility(View.VISIBLE);
} }
@ -1218,17 +1281,6 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
activeProfileView.setTextColor(MainApp.gc(R.color.ribbonTextDefault)); activeProfileView.setTextColor(MainApp.gc(R.color.ribbonTextDefault));
} }
tempTargetView.setOnLongClickListener(view -> {
view.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
NewNSTreatmentDialog newTTDialog = new NewNSTreatmentDialog();
final OptionsToShow temptarget = CareportalFragment.TEMPTARGET;
temptarget.executeTempTarget = true;
newTTDialog.setOptions(temptarget, R.string.careportal_temporarytarget);
newTTDialog.show(getFragmentManager(), "NewNSTreatmentDialog");
return true;
});
tempTargetView.setLongClickable(true);
// QuickWizard button // QuickWizard button
QuickWizardEntry quickWizardEntry = OverviewPlugin.getPlugin().quickWizard.getActive(); QuickWizardEntry quickWizardEntry = OverviewPlugin.getPlugin().quickWizard.getActive();
if (quickWizardEntry != null && lastBG != null && pump.isInitialized() && !pump.isSuspended()) { if (quickWizardEntry != null && lastBG != null && pump.isInitialized() && !pump.isSuspended()) {
@ -1288,7 +1340,10 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
flag &= ~Paint.STRIKE_THRU_TEXT_FLAG; flag &= ~Paint.STRIKE_THRU_TEXT_FLAG;
bgView.setPaintFlags(flag); bgView.setPaintFlags(flag);
if (timeAgoView != null)
timeAgoView.setText(DateUtil.minAgo(lastBG.date)); timeAgoView.setText(DateUtil.minAgo(lastBG.date));
if (timeAgoShortView != null)
timeAgoShortView.setText("(" + DateUtil.minAgoShort(lastBG.date) + ")");
// iob // iob
TreatmentsPlugin.getPlugin().updateTotalIOBTreatments(); TreatmentsPlugin.getPlugin().updateTotalIOBTreatments();
@ -1379,7 +1434,15 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
} }
} }
final boolean predictionsAvailable = finalLastRun != null && finalLastRun.request.hasPredictions; boolean predictionsAvailable;
if (Config.APS)
predictionsAvailable = finalLastRun != null && finalLastRun.request.hasPredictions;
else if (Config.NSCLIENT)
predictionsAvailable = true;
else
predictionsAvailable = false;
final boolean finalPredictionsAvailable = predictionsAvailable;
// pump status from ns // pump status from ns
if (pumpDeviceStatusView != null) { if (pumpDeviceStatusView != null) {
pumpDeviceStatusView.setText(NSDeviceStatus.getInstance().getPumpStatus()); pumpDeviceStatusView.setText(NSDeviceStatus.getInstance().getPumpStatus());
@ -1398,6 +1461,15 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
uploaderDeviceStatusView.setOnClickListener(v -> OKDialog.show(getActivity(), MainApp.gs(R.string.uploader), NSDeviceStatus.getInstance().getExtendedUploaderStatus(), null)); uploaderDeviceStatusView.setOnClickListener(v -> OKDialog.show(getActivity(), MainApp.gs(R.string.uploader), NSDeviceStatus.getInstance().getExtendedUploaderStatus(), null));
} }
// Sensitivity
if (sensitivityView != null) {
AutosensResult lastAutosensResult = IobCobCalculatorPlugin.getPlugin().detectSensitivityWithLock(IobCobCalculatorPlugin.getPlugin().oldestDataAvailable(), System.currentTimeMillis());
if (lastAutosensResult != null)
sensitivityView.setText(String.format("%.0f%%", lastAutosensResult.ratio * 100));
else
sensitivityView.setText("");
}
// ****** GRAPH ******* // ****** GRAPH *******
new Thread(() -> { new Thread(() -> {
@ -1413,8 +1485,15 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
final long toTime; final long toTime;
final long fromTime; final long fromTime;
final long endTime; final long endTime;
if (predictionsAvailable && SP.getBoolean("showprediction", false)) {
int predHours = (int) (Math.ceil(finalLastRun.constraintsProcessed.getLatestPredictionsTime() - System.currentTimeMillis()) / (60 * 60 * 1000)); APSResult apsResult = null;
if (finalPredictionsAvailable && SP.getBoolean("showprediction", false)) {
if (Config.APS)
apsResult = finalLastRun.constraintsProcessed;
else
apsResult = NSDeviceStatus.getAPSResult();
int predHours = (int) (Math.ceil(apsResult.getLatestPredictionsTime() - System.currentTimeMillis()) / (60 * 60 * 1000));
predHours = Math.min(2, predHours); predHours = Math.min(2, predHours);
predHours = Math.max(0, predHours); predHours = Math.max(0, predHours);
hoursToFetch = rangeToDisplay - predHours; hoursToFetch = rangeToDisplay - predHours;
@ -1440,9 +1519,9 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
graphData.addInRangeArea(fromTime, endTime, lowLine, highLine); graphData.addInRangeArea(fromTime, endTime, lowLine, highLine);
// **** BG **** // **** BG ****
if (predictionsAvailable && SP.getBoolean("showprediction", false)) if (finalPredictionsAvailable && SP.getBoolean("showprediction", false))
graphData.addBgReadings(fromTime, toTime, lowLine, highLine, graphData.addBgReadings(fromTime, toTime, lowLine, highLine,
finalLastRun.constraintsProcessed.getPredictions()); apsResult.getPredictions());
else else
graphData.addBgReadings(fromTime, toTime, lowLine, highLine, null); graphData.addBgReadings(fromTime, toTime, lowLine, highLine, null);
@ -1494,7 +1573,7 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
secondGraphData.addDeviations(fromTime, now, useDevForScale, 1d); secondGraphData.addDeviations(fromTime, now, useDevForScale, 1d);
if (SP.getBoolean("showratios", false)) if (SP.getBoolean("showratios", false))
secondGraphData.addRatio(fromTime, now, useRatioForScale, 1d); secondGraphData.addRatio(fromTime, now, useRatioForScale, 1d);
if (SP.getBoolean("showdevslope", false)) if (SP.getBoolean("showdevslope", false) && MainApp.devBranch)
secondGraphData.addDeviationSlope(fromTime, now, useDSForScale, 1d); secondGraphData.addDeviationSlope(fromTime, now, useDSForScale, 1d);
// **** NOW line **** // **** NOW line ****

View file

@ -1,15 +0,0 @@
package info.nightscout.androidaps.plugins.Overview.events;
import info.nightscout.androidaps.events.Event;
/**
* Created by mike on 02.07.2017.
*/
public class EventSetWakeLock extends Event {
public boolean lock = false;
public EventSetWakeLock(boolean val) {
lock = val;
}
}

View file

@ -49,7 +49,8 @@ import info.nightscout.utils.Round;
public class GraphData { public class GraphData {
private GraphView graph; private GraphView graph;
public double maxY = 0; public double maxY = Double.MIN_VALUE;
public double minY = Double.MAX_VALUE;
private List<BgReading> bgReadingsArray; private List<BgReading> bgReadingsArray;
private String units; private String units;
private List<Series> series = new ArrayList<>(); private List<Series> series = new ArrayList<>();
@ -63,7 +64,7 @@ public class GraphData {
} }
public void addBgReadings(long fromTime, long toTime, double lowLine, double highLine, List<BgReading> predictions) { public void addBgReadings(long fromTime, long toTime, double lowLine, double highLine, List<BgReading> predictions) {
double maxBgValue = 0d; double maxBgValue = Double.MIN_VALUE;
bgReadingsArray = MainApp.getDbHelper().getBgreadingsDataFromTime(fromTime, true); bgReadingsArray = MainApp.getDbHelper().getBgreadingsDataFromTime(fromTime, true);
List<DataPointWithLabelInterface> bgListArray = new ArrayList<>(); List<DataPointWithLabelInterface> bgListArray = new ArrayList<>();
@ -93,10 +94,8 @@ public class GraphData {
maxY = maxBgValue; maxY = maxBgValue;
minY = 0;
// set manual y bounds to have nice steps // set manual y bounds to have nice steps
graph.getViewport().setMaxY(maxY);
graph.getViewport().setMinY(0);
graph.getViewport().setYAxisBoundsManual(true);
graph.getGridLabelRenderer().setNumVerticalLabels(numOfVertLines); graph.getGridLabelRenderer().setNumVerticalLabels(numOfVertLines);
addSeries(new PointsWithLabelGraphSeries<>(bg)); addSeries(new PointsWithLabelGraphSeries<>(bg));
@ -335,7 +334,7 @@ public class GraphData {
public void addIob(long fromTime, long toTime, boolean useForScale, double scale) { public void addIob(long fromTime, long toTime, boolean useForScale, double scale) {
FixedLineGraphSeries<ScaledDataPoint> iobSeries; FixedLineGraphSeries<ScaledDataPoint> iobSeries;
List<ScaledDataPoint> iobArray = new ArrayList<>(); List<ScaledDataPoint> iobArray = new ArrayList<>();
Double maxIobValueFound = 0d; Double maxIobValueFound = Double.MIN_VALUE;
double lastIob = 0; double lastIob = 0;
Scale iobScale = new Scale(); Scale iobScale = new Scale();
@ -361,8 +360,10 @@ public class GraphData {
iobSeries.setColor(MainApp.gc(R.color.iob)); iobSeries.setColor(MainApp.gc(R.color.iob));
iobSeries.setThickness(3); iobSeries.setThickness(3);
if (useForScale) if (useForScale) {
maxY = maxIobValueFound; maxY = maxIobValueFound;
minY = -maxIobValueFound;
}
iobScale.setMultiplier(maxY * scale / maxIobValueFound); iobScale.setMultiplier(maxY * scale / maxIobValueFound);
@ -406,8 +407,10 @@ public class GraphData {
cobSeries.setColor(MainApp.gc(R.color.cob)); cobSeries.setColor(MainApp.gc(R.color.cob));
cobSeries.setThickness(3); cobSeries.setThickness(3);
if (useForScale) if (useForScale) {
maxY = maxCobValueFound; maxY = maxCobValueFound;
minY = 0;
}
cobScale.setMultiplier(maxY * scale / maxCobValueFound); cobScale.setMultiplier(maxY * scale / maxCobValueFound);
@ -438,9 +441,18 @@ public class GraphData {
AutosensData autosensData = IobCobCalculatorPlugin.getPlugin().getAutosensData(time); AutosensData autosensData = IobCobCalculatorPlugin.getPlugin().getAutosensData(time);
if (autosensData != null) { if (autosensData != null) {
int color = MainApp.gc(R.color.deviationblack); // "=" int color = MainApp.gc(R.color.deviationblack); // "="
if (autosensData.pastSensitivity.equals("C")) color = MainApp.gc(R.color.deviationgrey); if (autosensData.type.equals("") || autosensData.type.equals("non-meal")) {
if (autosensData.pastSensitivity.equals("+")) color = MainApp.gc(R.color.deviationgreen); if (autosensData.pastSensitivity.equals("C"))
if (autosensData.pastSensitivity.equals("-")) color = MainApp.gc(R.color.deviationred); color = MainApp.gc(R.color.deviationgrey);
if (autosensData.pastSensitivity.equals("+"))
color = MainApp.gc(R.color.deviationgreen);
if (autosensData.pastSensitivity.equals("-"))
color = MainApp.gc(R.color.deviationred);
} else if (autosensData.type.equals("uam")) {
color = MainApp.gc(R.color.uam);
} else if (autosensData.type.equals("csf")) {
color = MainApp.gc(R.color.deviationgrey);
}
devArray.add(new DeviationDataPoint(time, autosensData.deviation, color, devScale)); devArray.add(new DeviationDataPoint(time, autosensData.deviation, color, devScale));
maxDevValueFound = Math.max(maxDevValueFound, Math.abs(autosensData.deviation)); maxDevValueFound = Math.max(maxDevValueFound, Math.abs(autosensData.deviation));
} }
@ -457,8 +469,10 @@ public class GraphData {
} }
}); });
if (useForScale) if (useForScale) {
maxY = maxDevValueFound; maxY = maxDevValueFound;
minY = -maxY;
}
devScale.setMultiplier(maxY * scale / maxDevValueFound); devScale.setMultiplier(maxY * scale / maxDevValueFound);
@ -469,14 +483,16 @@ public class GraphData {
public void addRatio(long fromTime, long toTime, boolean useForScale, double scale) { public void addRatio(long fromTime, long toTime, boolean useForScale, double scale) {
LineGraphSeries<ScaledDataPoint> ratioSeries; LineGraphSeries<ScaledDataPoint> ratioSeries;
List<ScaledDataPoint> ratioArray = new ArrayList<>(); List<ScaledDataPoint> ratioArray = new ArrayList<>();
Double maxRatioValueFound = 0d; Double maxRatioValueFound = Double.MIN_VALUE;
Scale ratioScale = new Scale(-1d); Double minRatioValueFound = Double.MAX_VALUE;
Scale ratioScale = new Scale();
for (long time = fromTime; time <= toTime; time += 5 * 60 * 1000L) { for (long time = fromTime; time <= toTime; time += 5 * 60 * 1000L) {
AutosensData autosensData = IobCobCalculatorPlugin.getPlugin().getAutosensData(time); AutosensData autosensData = IobCobCalculatorPlugin.getPlugin().getAutosensData(time);
if (autosensData != null) { if (autosensData != null) {
ratioArray.add(new ScaledDataPoint(time, autosensData.autosensRatio, ratioScale)); ratioArray.add(new ScaledDataPoint(time, autosensData.autosensRatio - 1, ratioScale));
maxRatioValueFound = Math.max(maxRatioValueFound, Math.abs(autosensData.autosensRatio)); maxRatioValueFound = Math.max(maxRatioValueFound, autosensData.autosensRatio - 1);
minRatioValueFound = Math.min(minRatioValueFound, autosensData.autosensRatio - 1);
} }
} }
@ -487,8 +503,10 @@ public class GraphData {
ratioSeries.setColor(MainApp.gc(R.color.ratio)); ratioSeries.setColor(MainApp.gc(R.color.ratio));
ratioSeries.setThickness(3); ratioSeries.setThickness(3);
if (useForScale) if (useForScale) {
maxY = maxRatioValueFound; maxY = maxRatioValueFound;
minY = minRatioValueFound;
}
ratioScale.setMultiplier(maxY * scale / maxRatioValueFound); ratioScale.setMultiplier(maxY * scale / maxRatioValueFound);
@ -529,8 +547,10 @@ public class GraphData {
dsMinSeries.setColor(MainApp.gc(R.color.devslopeneg)); dsMinSeries.setColor(MainApp.gc(R.color.devslopeneg));
dsMinSeries.setThickness(3); dsMinSeries.setThickness(3);
if (useForScale) if (useForScale) {
maxY = Math.max(maxFromMaxValueFound, maxFromMinValueFound); maxY = Math.max(maxFromMaxValueFound, maxFromMinValueFound);
minY = -maxY;
}
dsMaxScale.setMultiplier(maxY * scale / maxFromMaxValueFound); dsMaxScale.setMultiplier(maxY * scale / maxFromMaxValueFound);
dsMinScale.setMultiplier(maxY * scale / maxFromMinValueFound); dsMinScale.setMultiplier(maxY * scale / maxFromMinValueFound);
@ -584,6 +604,10 @@ public class GraphData {
} }
} }
graph.getViewport().setMaxY(Round.ceilTo(maxY, 1d));
graph.getViewport().setMinY(Round.floorTo(minY, 1d));
graph.getViewport().setYAxisBoundsManual(true);
// draw it // draw it
graph.onDataChanged(false, false); graph.onDataChanged(false, false);
} }

View file

@ -312,20 +312,20 @@ public class PointsWithLabelGraphSeries<E extends DataPointWithLabelInterface> e
mPaint.setStrokeWidth(5); mPaint.setStrokeWidth(5);
canvas.drawRect(px - 3, bounds.top + py - 3, xpluslength + 3, bounds.bottom + py + 3, mPaint); canvas.drawRect(px - 3, bounds.top + py - 3, xpluslength + 3, bounds.bottom + py + 3, mPaint);
} }
} else if (value.getShape() == Shape.OPENAPSOFFLINE) { } else if (value.getShape() == Shape.OPENAPSOFFLINE && value.getDuration() != 0) {
mPaint.setStrokeWidth(0); mPaint.setStrokeWidth(0);
if (value.getLabel() != null) { if (value.getLabel() != null) {
mPaint.setStrokeWidth(0); //mPaint.setStrokeWidth(0);
mPaint.setTextSize(scaledTextSize); //mPaint.setTextSize(scaledTextSize);
mPaint.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.BOLD)); //mPaint.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.BOLD));
Rect bounds = new Rect(); Rect bounds = new Rect();
mPaint.getTextBounds(value.getLabel(), 0, value.getLabel().length(), bounds); //mPaint.getTextBounds(value.getLabel(), 0, value.getLabel().length(), bounds);
mPaint.setStyle(Paint.Style.STROKE); mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
float px = endX; float px = endX;
float py = graphTop + 50; float py = graphTop + 50;
canvas.drawText(value.getLabel(), px, py, mPaint); //canvas.drawText(value.getLabel(), px, py, mPaint);
mPaint.setStrokeWidth(5); mPaint.setStrokeWidth(5);
canvas.drawRect(px - 3, bounds.top + py - 3, xpluslength + 3, bounds.bottom + py + 3, mPaint); canvas.drawRect(px - 3, graphTop, xpluslength + 3, graphTop + graphHeight, mPaint);
} }
} else if (value.getShape() == Shape.GENERALWITHDURATION) { } else if (value.getShape() == Shape.GENERALWITHDURATION) {
mPaint.setStrokeWidth(0); mPaint.setStrokeWidth(0);

View file

@ -0,0 +1,31 @@
package info.nightscout.androidaps.plugins.Persistentnotification;
import android.app.Notification;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.support.annotation.Nullable;
/**
* Keeps AndroidAPS in foreground state, so it won't be terminated by Android nor get restricted by the background execution limits
*/
public class DummyService extends Service {
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Notification notification = PersistentNotificationPlugin.getPlugin().updateNotification();
if (notification != null)
startForeground(PersistentNotificationPlugin.ONGOING_NOTIFICATION_ID, notification);
return START_STICKY;
}
@Override
public void onDestroy() {
stopForeground(true);
}
}

View file

@ -1,6 +1,7 @@
package info.nightscout.androidaps.plugins.Persistentnotification; package info.nightscout.androidaps.plugins.Persistentnotification;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.app.Notification;
import android.app.NotificationChannel; import android.app.NotificationChannel;
import android.app.NotificationManager; import android.app.NotificationManager;
import android.app.PendingIntent; import android.app.PendingIntent;
@ -35,7 +36,6 @@ import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.PluginDescription; import info.nightscout.androidaps.interfaces.PluginDescription;
import info.nightscout.androidaps.interfaces.PluginType; import info.nightscout.androidaps.interfaces.PluginType;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.IobCobCalculator.CobInfo;
import info.nightscout.androidaps.plugins.IobCobCalculator.IobCobCalculatorPlugin; import info.nightscout.androidaps.plugins.IobCobCalculator.IobCobCalculatorPlugin;
import info.nightscout.androidaps.plugins.Treatments.TreatmentsPlugin; import info.nightscout.androidaps.plugins.Treatments.TreatmentsPlugin;
import info.nightscout.utils.DecimalFormatter; import info.nightscout.utils.DecimalFormatter;
@ -46,9 +46,16 @@ import info.nightscout.utils.DecimalFormatter;
public class PersistentNotificationPlugin extends PluginBase { public class PersistentNotificationPlugin extends PluginBase {
private static PersistentNotificationPlugin plugin;
public static PersistentNotificationPlugin getPlugin() {
if (plugin == null) plugin = new PersistentNotificationPlugin(MainApp.instance());
return plugin;
}
public static final String CHANNEL_ID = "AndroidAPS-Ongoing"; public static final String CHANNEL_ID = "AndroidAPS-Ongoing";
private static final int ONGOING_NOTIFICATION_ID = 4711; public static final int ONGOING_NOTIFICATION_ID = 4711;
private final Context ctx; private final Context ctx;
public PersistentNotificationPlugin(Context ctx) { public PersistentNotificationPlugin(Context ctx) {
@ -57,6 +64,7 @@ public class PersistentNotificationPlugin extends PluginBase {
.neverVisible(true) .neverVisible(true)
.pluginName(R.string.ongoingnotificaction) .pluginName(R.string.ongoingnotificaction)
.enableByDefault(true) .enableByDefault(true)
.alwaysEnabled(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
.description(R.string.description_persistent_notification) .description(R.string.description_persistent_notification)
); );
this.ctx = ctx; this.ctx = ctx;
@ -66,7 +74,7 @@ public class PersistentNotificationPlugin extends PluginBase {
protected void onStart() { protected void onStart() {
MainApp.bus().register(this); MainApp.bus().register(this);
createNotificationChannel(); createNotificationChannel();
updateNotification(); triggerNotificationUpdate();
super.onStart(); super.onStart();
} }
@ -85,20 +93,22 @@ public class PersistentNotificationPlugin extends PluginBase {
@Override @Override
protected void onStop() { protected void onStop() {
MainApp.bus().unregister(this); MainApp.bus().unregister(this);
NotificationManager mNotificationManager = MainApp.instance().stopService(new Intent(MainApp.instance(), DummyService.class));
(NotificationManager) ctx.getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.cancel(ONGOING_NOTIFICATION_ID);
} }
private void updateNotification() { private void triggerNotificationUpdate() {
MainApp.instance().startService(new Intent(MainApp.instance(), DummyService.class));
}
Notification updateNotification() {
if (!isEnabled(PluginType.GENERAL)) { if (!isEnabled(PluginType.GENERAL)) {
return; return null;
} }
String line1 = ""; String line1 = "";
if (MainApp.getConfigBuilder().getActiveProfileInterface() == null || !MainApp.getConfigBuilder().isProfileValid("Notificiation")) if (MainApp.getConfigBuilder().getActiveProfileInterface() == null || !MainApp.getConfigBuilder().isProfileValid("Notificiation"))
return; return null;
String units = MainApp.getConfigBuilder().getProfileUnits(); String units = MainApp.getConfigBuilder().getProfileUnits();
@ -166,7 +176,7 @@ public class PersistentNotificationPlugin extends PluginBase {
android.app.Notification notification = builder.build(); android.app.Notification notification = builder.build();
mNotificationManager.notify(ONGOING_NOTIFICATION_ID, notification); mNotificationManager.notify(ONGOING_NOTIFICATION_ID, notification);
return notification;
} }
private String deltastring(double deltaMGDL, double deltaMMOL, String units) { private String deltastring(double deltaMGDL, double deltaMMOL, String units) {
@ -188,42 +198,42 @@ public class PersistentNotificationPlugin extends PluginBase {
@Subscribe @Subscribe
public void onStatusEvent(final EventPreferenceChange ev) { public void onStatusEvent(final EventPreferenceChange ev) {
updateNotification(); triggerNotificationUpdate();
} }
@Subscribe @Subscribe
public void onStatusEvent(final EventTreatmentChange ev) { public void onStatusEvent(final EventTreatmentChange ev) {
updateNotification(); triggerNotificationUpdate();
} }
@Subscribe @Subscribe
public void onStatusEvent(final EventTempBasalChange ev) { public void onStatusEvent(final EventTempBasalChange ev) {
updateNotification(); triggerNotificationUpdate();
} }
@Subscribe @Subscribe
public void onStatusEvent(final EventExtendedBolusChange ev) { public void onStatusEvent(final EventExtendedBolusChange ev) {
updateNotification(); triggerNotificationUpdate();
} }
@Subscribe @Subscribe
public void onStatusEvent(final EventNewBG ev) { public void onStatusEvent(final EventNewBG ev) {
updateNotification(); triggerNotificationUpdate();
} }
@Subscribe @Subscribe
public void onStatusEvent(final EventNewBasalProfile ev) { public void onStatusEvent(final EventNewBasalProfile ev) {
updateNotification(); triggerNotificationUpdate();
} }
@Subscribe @Subscribe
public void onStatusEvent(final EventInitializationChanged ev) { public void onStatusEvent(final EventInitializationChanged ev) {
updateNotification(); triggerNotificationUpdate();
} }
@Subscribe @Subscribe
public void onStatusEvent(final EventRefreshOverview ev) { public void onStatusEvent(final EventRefreshOverview ev) {
updateNotification(); triggerNotificationUpdate();
} }
} }

View file

@ -132,7 +132,7 @@ public class LocalProfileFragment extends SubscriberFragment {
LocalProfilePlugin.getPlugin().loadSettings(); LocalProfilePlugin.getPlugin().loadSettings();
mgdlView.setChecked(LocalProfilePlugin.getPlugin().mgdl); mgdlView.setChecked(LocalProfilePlugin.getPlugin().mgdl);
mmolView.setChecked(LocalProfilePlugin.getPlugin().mmol); mmolView.setChecked(LocalProfilePlugin.getPlugin().mmol);
diaView.setParams(LocalProfilePlugin.getPlugin().dia, 2d, 48d, 0.1d, new DecimalFormat("0.0"), false, textWatch); diaView.setParams(LocalProfilePlugin.getPlugin().dia, 5d, 12d, 0.1d, new DecimalFormat("0.0"), false, textWatch);
icView = new TimeListEdit(getContext(), layout, R.id.localprofile_ic, MainApp.gs(R.string.nsprofileview_ic_label) + ":", LocalProfilePlugin.getPlugin().ic, null, 0.5, 50d, 0.1d, new DecimalFormat("0.0"), save); icView = new TimeListEdit(getContext(), layout, R.id.localprofile_ic, MainApp.gs(R.string.nsprofileview_ic_label) + ":", LocalProfilePlugin.getPlugin().ic, null, 0.5, 50d, 0.1d, new DecimalFormat("0.0"), save);
isfView = new TimeListEdit(getContext(), layout, R.id.localprofile_isf, MainApp.gs(R.string.nsprofileview_isf_label) + ":", LocalProfilePlugin.getPlugin().isf, null, 0.5, 500d, 0.1d, new DecimalFormat("0.0"), save); isfView = new TimeListEdit(getContext(), layout, R.id.localprofile_isf, MainApp.gs(R.string.nsprofileview_isf_label) + ":", LocalProfilePlugin.getPlugin().isf, null, 0.5, 500d, 0.1d, new DecimalFormat("0.0"), save);
basalView = new TimeListEdit(getContext(), layout, R.id.localprofile_basal, MainApp.gs(R.string.nsprofileview_basal_label) + ": " + getSumLabel(), LocalProfilePlugin.getPlugin().basal, null, pumpDescription.basalMinimumRate, 10, 0.01d, new DecimalFormat("0.00"), save); basalView = new TimeListEdit(getContext(), layout, R.id.localprofile_basal, MainApp.gs(R.string.nsprofileview_basal_label) + ": " + getSumLabel(), LocalProfilePlugin.getPlugin().basal, null, pumpDescription.basalMinimumRate, 10, 0.01d, new DecimalFormat("0.00"), save);

View file

@ -79,11 +79,14 @@ public class NSProfileFragment extends SubscriberFragment {
public void onStatusEvent(final EventNSProfileUpdateGUI ev) { public void onStatusEvent(final EventNSProfileUpdateGUI ev) {
Activity activity = getActivity(); Activity activity = getActivity();
if (activity != null) if (activity != null)
activity.runOnUiThread(() -> updateGUI()); activity.runOnUiThread(() -> { synchronized (NSProfileFragment.this) { updateGUI(); } });
} }
@Override @Override
protected void updateGUI() { protected void updateGUI() {
if (noProfile == null || profileSpinner == null)
return;
ProfileStore profileStore = NSProfilePlugin.getPlugin().getProfile(); ProfileStore profileStore = NSProfilePlugin.getPlugin().getProfile();
if (profileStore != null) { if (profileStore != null) {
ArrayList<CharSequence> profileList = profileStore.getProfileList(); ArrayList<CharSequence> profileList = profileStore.getProfileList();

View file

@ -1,8 +1,11 @@
package info.nightscout.androidaps.plugins.PumpCombo; package info.nightscout.androidaps.plugins.PumpCombo;
import android.content.DialogInterface;
import android.os.SystemClock; import android.os.SystemClock;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.support.v4.app.FragmentActivity;
import android.support.v7.app.AlertDialog;
import com.crashlytics.android.answers.CustomEvent; import com.crashlytics.android.answers.CustomEvent;
@ -28,6 +31,7 @@ import info.nightscout.androidaps.db.CareportalEvent;
import info.nightscout.androidaps.db.Source; import info.nightscout.androidaps.db.Source;
import info.nightscout.androidaps.db.TDD; import info.nightscout.androidaps.db.TDD;
import info.nightscout.androidaps.db.TemporaryBasal; import info.nightscout.androidaps.db.TemporaryBasal;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderFragment;
import info.nightscout.androidaps.plugins.Treatments.Treatment; import info.nightscout.androidaps.plugins.Treatments.Treatment;
import info.nightscout.androidaps.events.EventInitializationChanged; import info.nightscout.androidaps.events.EventInitializationChanged;
import info.nightscout.androidaps.events.EventRefreshOverview; import info.nightscout.androidaps.events.EventRefreshOverview;
@ -194,6 +198,32 @@ public class ComboPlugin extends PluginBase implements PumpInterface, Constraint
return MainApp.gs(R.string.combo_pump_state_running); return MainApp.gs(R.string.combo_pump_state_running);
} }
@Override
public void switchAllowed(ConfigBuilderFragment.PluginViewHolder.PluginSwitcher pluginSwitcher, FragmentActivity context) {
boolean allowHardwarePump = SP.getBoolean("allow_hardware_pump", false);
if (allowHardwarePump || context == null){
pluginSwitcher.invoke();
} else {
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setMessage(R.string.allow_hardware_pump_text)
.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
pluginSwitcher.invoke();
SP.putBoolean("allow_hardware_pump", true);
log.debug("First time HW pump allowed!");
}
})
.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
pluginSwitcher.cancel();
log.debug("User does not allow switching to HW pump!");
}
});
builder.create().show();
}
}
@Override @Override
public boolean isInitialized() { public boolean isInitialized() {
return pump.initialized; return pump.initialized;
@ -354,6 +384,11 @@ public class ComboPlugin extends PluginBase implements PumpInterface, Constraint
// trigger a connect, which will update state and check history // trigger a connect, which will update state and check history
CommandResult stateResult = runCommand(null, 1, ruffyScripter::readPumpState); CommandResult stateResult = runCommand(null, 1, ruffyScripter::readPumpState);
if (stateResult.invalidSetup) {
MainApp.bus().post(new EventNewNotification(
new Notification(Notification.COMBO_PUMP_ALARM, MainApp.gs(R.string.combo_invalid_setup), Notification.URGENT)));
return;
}
if (!stateResult.success) { if (!stateResult.success) {
return; return;
} }
@ -1374,7 +1409,7 @@ public class ComboPlugin extends PluginBase implements PumpInterface, Constraint
private boolean validBasalRateProfileSelectedOnPump = true; private boolean validBasalRateProfileSelectedOnPump = true;
@Override @Override
public Constraint<Boolean> isLoopInvokationAllowed(Constraint<Boolean> value) { public Constraint<Boolean> isLoopInvocationAllowed(Constraint<Boolean> value) {
if (!validBasalRateProfileSelectedOnPump) if (!validBasalRateProfileSelectedOnPump)
value.set(false, MainApp.gs(R.string.novalidbasalrate), this); value.set(false, MainApp.gs(R.string.novalidbasalrate), this);
return value; return value;

View file

@ -5,10 +5,11 @@ import android.support.annotation.Nullable;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import info.nightscout.androidaps.plugins.PumpCombo.ruffyscripter.history.Bolus;
import info.nightscout.androidaps.plugins.PumpCombo.ruffyscripter.history.PumpHistory; import info.nightscout.androidaps.plugins.PumpCombo.ruffyscripter.history.PumpHistory;
public class CommandResult { public class CommandResult {
/** True if a condition indicating a broken pump setup/configuration is detected */
public boolean invalidSetup;
/** Whether the command was executed successfully. */ /** Whether the command was executed successfully. */
public boolean success; public boolean success;
/** State of the pump *after* command execution. */ /** State of the pump *after* command execution. */

View file

@ -281,10 +281,10 @@ public class RuffyScripter implements RuffyCommands {
log.debug("Executing " + cmd + " took " + (cmdEndTime - cmdStartTime) + "ms"); log.debug("Executing " + cmd + " took " + (cmdEndTime - cmdStartTime) + "ms");
} catch (CommandException e) { } catch (CommandException e) {
log.error("CommandException running command", e); log.error("CommandException running command", e);
activeCmd.getResult().success = false; cmd.getResult().success = false;
} catch (Exception e) { } catch (Exception e) {
log.error("Unexpected exception running cmd", e); log.error("Unexpected exception running cmd", e);
activeCmd.getResult().success = false; cmd.getResult().success = false;
} }
}, cmd.getClass().getSimpleName()); }, cmd.getClass().getSimpleName());
long executionStart = System.currentTimeMillis(); long executionStart = System.currentTimeMillis();
@ -328,6 +328,7 @@ public class RuffyScripter implements RuffyCommands {
if (unparsableMenuEncountered) { if (unparsableMenuEncountered) {
log.error("UnparsableMenuEncountered flagged, aborting command"); log.error("UnparsableMenuEncountered flagged, aborting command");
cmdThread.interrupt(); cmdThread.interrupt();
activeCmd.getResult().invalidSetup = true;
activeCmd.getResult().success = false; activeCmd.getResult().success = false;
} }

View file

@ -39,6 +39,7 @@ public class ReadQuickInfoCommand extends BaseCommand {
// read bolus records // read bolus records
int totalRecords = (int) scripter.getCurrentMenu().getAttribute(MenuAttribute.TOTAL_RECORD); int totalRecords = (int) scripter.getCurrentMenu().getAttribute(MenuAttribute.TOTAL_RECORD);
int record = (int) scripter.getCurrentMenu().getAttribute(MenuAttribute.CURRENT_RECORD); int record = (int) scripter.getCurrentMenu().getAttribute(MenuAttribute.CURRENT_RECORD);
if (record > 0) {
while (true) { while (true) {
bolusHistory.add(readBolusRecord()); bolusHistory.add(readBolusRecord());
if (bolusHistory.size() == numberOfBolusRecordsToRetrieve || record == totalRecords) { if (bolusHistory.size() == numberOfBolusRecordsToRetrieve || record == totalRecords) {
@ -51,6 +52,7 @@ public class ReadQuickInfoCommand extends BaseCommand {
} }
record = (int) scripter.getCurrentMenu().getAttribute(MenuAttribute.CURRENT_RECORD); record = (int) scripter.getCurrentMenu().getAttribute(MenuAttribute.CURRENT_RECORD);
} }
}
if (log.isDebugEnabled()) { if (log.isDebugEnabled()) {
if (!result.history.bolusHistory.isEmpty()) { if (!result.history.bolusHistory.isEmpty()) {
log.debug("Read bolus history (" + result.history.bolusHistory.size() + "):"); log.debug("Read bolus history (" + result.history.bolusHistory.size() + "):");

View file

@ -216,6 +216,9 @@ public class DanaRFragment extends SubscriberFragment {
@SuppressLint("SetTextI18n") @SuppressLint("SetTextI18n")
@Override @Override
public void run() { public void run() {
synchronized(DanaRFragment.this) {
if (!isBound()) return;
DanaRPump pump = DanaRPump.getInstance(); DanaRPump pump = DanaRPump.getInstance();
if (pump.lastConnection != 0) { if (pump.lastConnection != 0) {
Long agoMsec = System.currentTimeMillis() - pump.lastConnection; Long agoMsec = System.currentTimeMillis() - pump.lastConnection;
@ -279,11 +282,30 @@ public class DanaRFragment extends SubscriberFragment {
} }
//hide user options button if not an RS pump //hide user options button if not an RS pump
boolean isKorean = MainApp.getSpecificPlugin(DanaRKoreanPlugin.class) != null && MainApp.getSpecificPlugin(DanaRKoreanPlugin.class).isEnabled(PluginType.PUMP); boolean isKorean = MainApp.getSpecificPlugin(DanaRKoreanPlugin.class) != null && MainApp.getSpecificPlugin(DanaRKoreanPlugin.class).isEnabled(PluginType.PUMP);
if (isKorean ) { if (isKorean) {
danar_user_options.setVisibility(View.GONE); danar_user_options.setVisibility(View.GONE);
} }
} }
}
}); });
} }
private boolean isBound() {
return lastConnectionView != null
&& lastBolusView != null
&& dailyUnitsView != null
&& basaBasalRateView != null
&& tempBasalView != null
&& extendedBolusView != null
&& reservoirView != null
&& batteryView != null
&& iobView != null
&& firmwareView != null
&& basalStepView != null
&& bolusStepView != null
&& serialNumberView != null
&& danar_user_options != null
&& queueView != null;
}
} }

View file

@ -2,9 +2,12 @@ package info.nightscout.androidaps.plugins.PumpDanaR;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.content.ServiceConnection; import android.content.ServiceConnection;
import android.os.IBinder; import android.os.IBinder;
import android.support.v4.app.FragmentActivity;
import android.support.v7.app.AlertDialog;
import com.squareup.otto.Subscribe; import com.squareup.otto.Subscribe;
@ -18,6 +21,7 @@ import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.data.PumpEnactResult; import info.nightscout.androidaps.data.PumpEnactResult;
import info.nightscout.androidaps.db.ExtendedBolus; import info.nightscout.androidaps.db.ExtendedBolus;
import info.nightscout.androidaps.db.TemporaryBasal; import info.nightscout.androidaps.db.TemporaryBasal;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderFragment;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgBolusStartWithSpeed; import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgBolusStartWithSpeed;
import info.nightscout.androidaps.plugins.Treatments.Treatment; import info.nightscout.androidaps.plugins.Treatments.Treatment;
import info.nightscout.androidaps.events.EventAppExit; import info.nightscout.androidaps.events.EventAppExit;
@ -78,6 +82,31 @@ public class DanaRPlugin extends AbstractDanaRPlugin {
pumpDescription.needsManualTDDLoad = true; pumpDescription.needsManualTDDLoad = true;
} }
@Override
public void switchAllowed(ConfigBuilderFragment.PluginViewHolder.PluginSwitcher pluginSwitcher, FragmentActivity context) {
boolean allowHardwarePump = SP.getBoolean("allow_hardware_pump", false);
if (allowHardwarePump || context == null){
pluginSwitcher.invoke();
} else {
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setMessage(R.string.allow_hardware_pump_text)
.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
pluginSwitcher.invoke();
SP.putBoolean("allow_hardware_pump", true);
log.debug("First time HW pump allowed!");
}
})
.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
pluginSwitcher.cancel();
log.debug("User does not allow switching to HW pump!");
}
});
builder.create().show();
}
}
@Override @Override
protected void onStart() { protected void onStart() {
Context context = MainApp.instance().getApplicationContext(); Context context = MainApp.instance().getApplicationContext();

View file

@ -2,9 +2,12 @@ package info.nightscout.androidaps.plugins.PumpDanaRKorean;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.content.ServiceConnection; import android.content.ServiceConnection;
import android.os.IBinder; import android.os.IBinder;
import android.support.v4.app.FragmentActivity;
import android.support.v7.app.AlertDialog;
import com.squareup.otto.Subscribe; import com.squareup.otto.Subscribe;
@ -23,6 +26,7 @@ import info.nightscout.androidaps.events.EventPreferenceChange;
import info.nightscout.androidaps.interfaces.Constraint; import info.nightscout.androidaps.interfaces.Constraint;
import info.nightscout.androidaps.interfaces.PluginType; import info.nightscout.androidaps.interfaces.PluginType;
import info.nightscout.androidaps.interfaces.PumpDescription; import info.nightscout.androidaps.interfaces.PumpDescription;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderFragment;
import info.nightscout.androidaps.plugins.PumpDanaR.AbstractDanaRPlugin; import info.nightscout.androidaps.plugins.PumpDanaR.AbstractDanaRPlugin;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgBolusStart; import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgBolusStart;
import info.nightscout.androidaps.plugins.PumpDanaRKorean.services.DanaRKoreanExecutionService; import info.nightscout.androidaps.plugins.PumpDanaRKorean.services.DanaRKoreanExecutionService;
@ -45,7 +49,8 @@ public class DanaRKoreanPlugin extends AbstractDanaRPlugin {
} }
public DanaRKoreanPlugin() { public DanaRKoreanPlugin() {
super(); pluginDescription.description(R.string.description_pump_dana_r_korean);
log = LoggerFactory.getLogger(DanaRKoreanPlugin.class); log = LoggerFactory.getLogger(DanaRKoreanPlugin.class);
useExtendedBoluses = SP.getBoolean("danar_useextended", false); useExtendedBoluses = SP.getBoolean("danar_useextended", false);
@ -79,6 +84,32 @@ public class DanaRKoreanPlugin extends AbstractDanaRPlugin {
pumpDescription.needsManualTDDLoad = true; pumpDescription.needsManualTDDLoad = true;
} }
@Override
public void switchAllowed(ConfigBuilderFragment.PluginViewHolder.PluginSwitcher pluginSwitcher, FragmentActivity context) {
boolean allowHardwarePump = SP.getBoolean("allow_hardware_pump", false);
if (allowHardwarePump || context == null){
pluginSwitcher.invoke();
} else {
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setMessage(R.string.allow_hardware_pump_text)
.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
pluginSwitcher.invoke();
SP.putBoolean("allow_hardware_pump", true);
log.debug("First time HW pump allowed!");
}
})
.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
pluginSwitcher.cancel();
log.debug("User does not allow switching to HW pump!");
}
});
builder.create().show();
}
}
@Override @Override
protected void onStart() { protected void onStart() {
Context context = MainApp.instance().getApplicationContext(); Context context = MainApp.instance().getApplicationContext();

View file

@ -2,10 +2,13 @@ package info.nightscout.androidaps.plugins.PumpDanaRS;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.content.ServiceConnection; import android.content.ServiceConnection;
import android.os.IBinder; import android.os.IBinder;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.support.v4.app.FragmentActivity;
import android.support.v7.app.AlertDialog;
import com.squareup.otto.Subscribe; import com.squareup.otto.Subscribe;
@ -36,6 +39,7 @@ import info.nightscout.androidaps.interfaces.PluginType;
import info.nightscout.androidaps.interfaces.ProfileInterface; import info.nightscout.androidaps.interfaces.ProfileInterface;
import info.nightscout.androidaps.interfaces.PumpDescription; import info.nightscout.androidaps.interfaces.PumpDescription;
import info.nightscout.androidaps.interfaces.PumpInterface; import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderFragment;
import info.nightscout.androidaps.plugins.ConfigBuilder.DetailedBolusInfoStorage; import info.nightscout.androidaps.plugins.ConfigBuilder.DetailedBolusInfoStorage;
import info.nightscout.androidaps.plugins.Overview.events.EventDismissNotification; import info.nightscout.androidaps.plugins.Overview.events.EventDismissNotification;
import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification; import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification;
@ -147,6 +151,31 @@ public class DanaRSPlugin extends PluginBase implements PumpInterface, DanaRInte
MainApp.bus().unregister(this); MainApp.bus().unregister(this);
} }
@Override
public void switchAllowed(ConfigBuilderFragment.PluginViewHolder.PluginSwitcher pluginSwitcher, FragmentActivity context) {
boolean allowHardwarePump = SP.getBoolean("allow_hardware_pump", false);
if (allowHardwarePump || context == null){
pluginSwitcher.invoke();
} else {
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setMessage(R.string.allow_hardware_pump_text)
.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
pluginSwitcher.invoke();
SP.putBoolean("allow_hardware_pump", true);
log.debug("First time HW pump allowed!");
}
})
.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
pluginSwitcher.cancel();
log.debug("User does not allow switching to HW pump!");
}
});
builder.create().show();
}
}
private ServiceConnection mConnection = new ServiceConnection() { private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceDisconnected(ComponentName name) { public void onServiceDisconnected(ComponentName name) {
@ -494,8 +523,12 @@ public class DanaRSPlugin extends PluginBase implements PumpInterface, DanaRInte
// Convert duration from minutes to hours // Convert duration from minutes to hours
if (Config.logPumpActions) if (Config.logPumpActions)
log.debug("setTempBasalAbsolute: Setting temp basal " + percentRate + "% for " + durationInMinutes + " mins (doLowTemp || doHighTemp)"); log.debug("setTempBasalAbsolute: Setting temp basal " + percentRate + "% for " + durationInMinutes + " mins (doLowTemp || doHighTemp)");
if (percentRate == 0 && durationInMinutes > 30) {
result = setTempBasalPercent(percentRate, durationInMinutes, profile, false);
} else {
// use special APS temp basal call ... 100+/15min .... 100-/30min // use special APS temp basal call ... 100+/15min .... 100-/30min
result = setHighTempBasalPercent(percentRate); result = setHighTempBasalPercent(percentRate);
}
if (!result.success) { if (!result.success) {
log.error("setTempBasalAbsolute: Failed to set hightemp basal"); log.error("setTempBasalAbsolute: Failed to set hightemp basal");
return result; return result;

View file

@ -20,8 +20,6 @@ import org.slf4j.LoggerFactory;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture; import java.util.concurrent.ScheduledFuture;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
@ -45,11 +43,11 @@ public class BLEComm {
private static final long WRITE_DELAY_MILLIS = 50; private static final long WRITE_DELAY_MILLIS = 50;
public static String UART_READ_UUID = "0000fff1-0000-1000-8000-00805f9b34fb"; private static String UART_READ_UUID = "0000fff1-0000-1000-8000-00805f9b34fb";
public static String UART_WRITE_UUID = "0000fff2-0000-1000-8000-00805f9b34fb"; private static String UART_WRITE_UUID = "0000fff2-0000-1000-8000-00805f9b34fb";
private byte PACKET_START_BYTE = (byte) 0xA5; private final byte PACKET_START_BYTE = (byte) 0xA5;
private byte PACKET_END_BYTE = (byte) 0x5A; private final byte PACKET_END_BYTE = (byte) 0x5A;
private static BLEComm instance = null; private static BLEComm instance = null;
public static BLEComm getInstance(DanaRSService service) { public static BLEComm getInstance(DanaRSService service) {
@ -58,16 +56,13 @@ public class BLEComm {
return instance; return instance;
} }
private final ScheduledExecutorService worker = Executors.newSingleThreadScheduledExecutor();
private ScheduledFuture<?> scheduledDisconnection = null; private ScheduledFuture<?> scheduledDisconnection = null;
private DanaRS_Packet processsedMessage = null; private DanaRS_Packet processsedMessage = null;
private ArrayList<byte[]> mSendQueue = new ArrayList<>(); private final ArrayList<byte[]> mSendQueue = new ArrayList<>();
private BluetoothManager mBluetoothManager = null; private BluetoothManager mBluetoothManager = null;
private BluetoothAdapter mBluetoothAdapter = null; private BluetoothAdapter mBluetoothAdapter = null;
private BluetoothDevice mBluetoothDevice = null;
private String mBluetoothDeviceAddress = null;
private String mBluetoothDeviceName = null; private String mBluetoothDeviceName = null;
private BluetoothGatt mBluetoothGatt = null; private BluetoothGatt mBluetoothGatt = null;
@ -79,7 +74,7 @@ public class BLEComm {
private DanaRSService service; private DanaRSService service;
BLEComm(DanaRSService service) { private BLEComm(DanaRSService service) {
this.service = service; this.service = service;
initialize(); initialize();
} }
@ -138,15 +133,13 @@ public class BLEComm {
BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address); BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
if (device == null) { if (device == null) {
log.debug("Device not found. Unable to connect."); log.debug("Device not found. Unable to connect from: " + from);
return false; return false;
} }
log.debug("Trying to create a new connection."); log.debug("Trying to create a new connection from: " + from);
mBluetoothGatt = device.connectGatt(service.getApplicationContext(), false, mGattCallback); mBluetoothGatt = device.connectGatt(service.getApplicationContext(), false, mGattCallback);
setCharacteristicNotification(getUARTReadBTGattChar(), true); setCharacteristicNotification(getUARTReadBTGattChar(), true);
mBluetoothDevice = device;
mBluetoothDeviceAddress = address;
mBluetoothDeviceName = device.getName(); mBluetoothDeviceName = device.getName();
return true; return true;
} }
@ -174,7 +167,7 @@ public class BLEComm {
SystemClock.sleep(2000); SystemClock.sleep(2000);
} }
public void close() { public synchronized void close() {
log.debug("BluetoothAdapter close"); log.debug("BluetoothAdapter close");
if (mBluetoothGatt == null) { if (mBluetoothGatt == null) {
return; return;
@ -184,15 +177,8 @@ public class BLEComm {
mBluetoothGatt = null; mBluetoothGatt = null;
} }
public BluetoothDevice getConnectDevice() {
return mBluetoothDevice;
}
public String getConnectDeviceAddress() { private String getConnectDeviceName() {
return mBluetoothDeviceAddress;
}
public String getConnectDeviceName() {
return mBluetoothDeviceName; return mBluetoothDeviceName;
} }
@ -229,19 +215,12 @@ public class BLEComm {
public void onCharacteristicChanged(BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic) { public void onCharacteristicChanged(BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic) {
log.debug("onCharacteristicChanged" + (characteristic != null ? ":" + DanaRS_Packet.toHexString(characteristic.getValue()) : "")); log.debug("onCharacteristicChanged" + (characteristic != null ? ":" + DanaRS_Packet.toHexString(characteristic.getValue()) : ""));
addToReadBuffer(characteristic.getValue()); addToReadBuffer(characteristic.getValue());
new Thread(new Runnable() { new Thread(() -> readDataParsing()).start();
@Override
public void run() {
readDataParsing();
}
}).start();
} }
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
log.debug("onCharacteristicWrite" + (characteristic != null ? ":" + DanaRS_Packet.toHexString(characteristic.getValue()) : "")); log.debug("onCharacteristicWrite" + (characteristic != null ? ":" + DanaRS_Packet.toHexString(characteristic.getValue()) : ""));
new Thread(new Runnable() { new Thread(() -> {
@Override
public void run() {
synchronized (mSendQueue) { synchronized (mSendQueue) {
// after message sent, check if there is the rest of the message waiting and send it // after message sent, check if there is the rest of the message waiting and send it
if (mSendQueue.size() > 0) { if (mSendQueue.size() > 0) {
@ -250,12 +229,11 @@ public class BLEComm {
writeCharacteristic_NO_RESPONSE(getUARTWriteBTGattChar(), bytes); writeCharacteristic_NO_RESPONSE(getUARTWriteBTGattChar(), bytes);
} }
} }
}
}).start(); }).start();
} }
}; };
public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic, boolean enabled) { private synchronized void setCharacteristicNotification(BluetoothGattCharacteristic characteristic, boolean enabled) {
log.debug("setCharacteristicNotification"); log.debug("setCharacteristicNotification");
if ((mBluetoothAdapter == null) || (mBluetoothGatt == null)) { if ((mBluetoothAdapter == null) || (mBluetoothGatt == null)) {
log.debug("BluetoothAdapter not initialized_ERROR"); log.debug("BluetoothAdapter not initialized_ERROR");
@ -266,7 +244,7 @@ public class BLEComm {
mBluetoothGatt.setCharacteristicNotification(characteristic, enabled); mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
} }
public void readCharacteristic(BluetoothGattCharacteristic characteristic) { public synchronized void readCharacteristic(BluetoothGattCharacteristic characteristic) {
log.debug("readCharacteristic"); log.debug("readCharacteristic");
if ((mBluetoothAdapter == null) || (mBluetoothGatt == null)) { if ((mBluetoothAdapter == null) || (mBluetoothGatt == null)) {
log.debug("BluetoothAdapter not initialized_ERROR"); log.debug("BluetoothAdapter not initialized_ERROR");
@ -277,9 +255,8 @@ public class BLEComm {
mBluetoothGatt.readCharacteristic(characteristic); mBluetoothGatt.readCharacteristic(characteristic);
} }
public void writeCharacteristic_NO_RESPONSE(final BluetoothGattCharacteristic characteristic, final byte[] data) { private synchronized void writeCharacteristic_NO_RESPONSE(final BluetoothGattCharacteristic characteristic, final byte[] data) {
new Thread(new Runnable() { new Thread(() -> {
public void run() {
SystemClock.sleep(WRITE_DELAY_MILLIS); SystemClock.sleep(WRITE_DELAY_MILLIS);
if ((mBluetoothAdapter == null) || (mBluetoothGatt == null)) { if ((mBluetoothAdapter == null) || (mBluetoothGatt == null)) {
@ -293,25 +270,24 @@ public class BLEComm {
characteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE); characteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE);
log.debug("writeCharacteristic:" + DanaRS_Packet.toHexString(data)); log.debug("writeCharacteristic:" + DanaRS_Packet.toHexString(data));
mBluetoothGatt.writeCharacteristic(characteristic); mBluetoothGatt.writeCharacteristic(characteristic);
}
}).start(); }).start();
} }
public BluetoothGattCharacteristic getUARTReadBTGattChar() { private BluetoothGattCharacteristic getUARTReadBTGattChar() {
if (UART_Read == null) { if (UART_Read == null) {
UART_Read = new BluetoothGattCharacteristic(UUID.fromString(UART_READ_UUID), BluetoothGattCharacteristic.PROPERTY_READ | BluetoothGattCharacteristic.PROPERTY_NOTIFY, 0); UART_Read = new BluetoothGattCharacteristic(UUID.fromString(UART_READ_UUID), BluetoothGattCharacteristic.PROPERTY_READ | BluetoothGattCharacteristic.PROPERTY_NOTIFY, 0);
} }
return UART_Read; return UART_Read;
} }
public BluetoothGattCharacteristic getUARTWriteBTGattChar() { private BluetoothGattCharacteristic getUARTWriteBTGattChar() {
if (UART_Write == null) { if (UART_Write == null) {
UART_Write = new BluetoothGattCharacteristic(UUID.fromString(UART_WRITE_UUID), BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE, 0); UART_Write = new BluetoothGattCharacteristic(UUID.fromString(UART_WRITE_UUID), BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE, 0);
} }
return UART_Write; return UART_Write;
} }
public List<BluetoothGattService> getSupportedGattServices() { private List<BluetoothGattService> getSupportedGattServices() {
log.debug("getSupportedGattServices"); log.debug("getSupportedGattServices");
if ((mBluetoothAdapter == null) || (mBluetoothGatt == null)) { if ((mBluetoothAdapter == null) || (mBluetoothGatt == null)) {
log.debug("BluetoothAdapter not initialized_ERROR"); log.debug("BluetoothAdapter not initialized_ERROR");
@ -329,7 +305,7 @@ public class BLEComm {
if (gattServices == null) { if (gattServices == null) {
return; return;
} }
String uuid = null; String uuid;
for (BluetoothGattService gattService : gattServices) { for (BluetoothGattService gattService : gattServices) {
List<BluetoothGattCharacteristic> gattCharacteristics = gattService.getCharacteristics(); List<BluetoothGattCharacteristic> gattCharacteristics = gattService.getCharacteristics();
@ -346,7 +322,7 @@ public class BLEComm {
} }
} }
private byte[] readBuffer = new byte[1024]; private final byte[] readBuffer = new byte[1024];
private int bufferLength = 0; private int bufferLength = 0;
private void addToReadBuffer(byte[] buffer) { private void addToReadBuffer(byte[] buffer) {
@ -634,7 +610,7 @@ public class BLEComm {
writeCharacteristic_NO_RESPONSE(getUARTWriteBTGattChar(), bytes); writeCharacteristic_NO_RESPONSE(getUARTWriteBTGattChar(), bytes);
} }
protected void SendPumpCheck() { private void SendPumpCheck() {
// 1st message sent to pump after connect // 1st message sent to pump after connect
byte[] bytes = BleCommandUtil.getInstance().getEncryptedPacket(BleCommandUtil.DANAR_PACKET__OPCODE_ENCRYPTION__PUMP_CHECK, null, getConnectDeviceName()); byte[] bytes = BleCommandUtil.getInstance().getEncryptedPacket(BleCommandUtil.DANAR_PACKET__OPCODE_ENCRYPTION__PUMP_CHECK, null, getConnectDeviceName());
log.debug(">>>>> " + "ENCRYPTION__PUMP_CHECK (0x00)" + " " + DanaRS_Packet.toHexString(bytes)); log.debug(">>>>> " + "ENCRYPTION__PUMP_CHECK (0x00)" + " " + DanaRS_Packet.toHexString(bytes));

View file

@ -19,6 +19,7 @@ import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.data.PumpEnactResult; import info.nightscout.androidaps.data.PumpEnactResult;
import info.nightscout.androidaps.plugins.Overview.Dialogs.ErrorHelperActivity;
import info.nightscout.androidaps.plugins.PumpDanaRS.comm.DanaRS_Packet_Option_Get_User_Option; import info.nightscout.androidaps.plugins.PumpDanaRS.comm.DanaRS_Packet_Option_Get_User_Option;
import info.nightscout.androidaps.plugins.Treatments.Treatment; import info.nightscout.androidaps.plugins.Treatments.Treatment;
import info.nightscout.androidaps.events.EventAppExit; import info.nightscout.androidaps.events.EventAppExit;
@ -135,6 +136,37 @@ public class DanaRSService extends Service {
bleComm.sendMessage(new DanaRS_Packet_Bolus_Get_Step_Bolus_Information()); // last bolus, bolusStep, maxBolus bleComm.sendMessage(new DanaRS_Packet_Bolus_Get_Step_Bolus_Information()); // last bolus, bolusStep, maxBolus
MainApp.bus().post(new EventPumpStatusChanged(MainApp.gs(R.string.gettingtempbasalstatus))); MainApp.bus().post(new EventPumpStatusChanged(MainApp.gs(R.string.gettingtempbasalstatus)));
bleComm.sendMessage(new DanaRS_Packet_Basal_Get_Temporary_Basal_State()); bleComm.sendMessage(new DanaRS_Packet_Basal_Get_Temporary_Basal_State());
MainApp.bus().post(new EventPumpStatusChanged(MainApp.gs(R.string.gettingpumptime)));
bleComm.sendMessage(new DanaRS_Packet_Option_Get_Pump_Time());
long timeDiff = (danaRPump.pumpTime.getTime() - System.currentTimeMillis()) / 1000L;
log.debug("Pump time difference: " + timeDiff + " seconds");
if (Math.abs(timeDiff) > 3) {
if (Math.abs(timeDiff) > 60*60*1.5) {
log.debug("Pump time difference: " + timeDiff + " seconds - large difference");
//If time-diff is very large, warn user until we can synchronize history readings properly
Intent i = new Intent(MainApp.instance(), ErrorHelperActivity.class);
i.putExtra("soundid", R.raw.error);
i.putExtra("status", MainApp.gs(R.string.largetimediff));
i.putExtra("title", MainApp.gs(R.string.largetimedifftitle));
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
MainApp.instance().startActivity(i);
//deinitialize pump
danaRPump.lastConnection = 0;
MainApp.bus().post(new EventDanaRNewStatus());
MainApp.bus().post(new EventInitializationChanged());
return;
} else {
waitForWholeMinute(); // Dana can set only whole minute
// add 10sec to be sure we are over minute (will be cutted off anyway)
bleComm.sendMessage(new DanaRS_Packet_Option_Set_Pump_Time(new Date(DateUtil.now() + T.secs(10).msecs())));
bleComm.sendMessage(new DanaRS_Packet_Option_Get_Pump_Time());
timeDiff = (danaRPump.pumpTime.getTime() - System.currentTimeMillis()) / 1000L;
log.debug("Pump time difference: " + timeDiff + " seconds");
}
}
danaRPump.lastConnection = System.currentTimeMillis();
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
if (danaRPump.lastSettingsRead + 60 * 60 * 1000L < now || !MainApp.getSpecificPlugin(DanaRSPlugin.class).isInitialized()) { if (danaRPump.lastSettingsRead + 60 * 60 * 1000L < now || !MainApp.getSpecificPlugin(DanaRSPlugin.class).isInitialized()) {
@ -146,19 +178,7 @@ public class DanaRSService extends Service {
bleComm.sendMessage(new DanaRS_Packet_Basal_Get_Basal_Rate()); // basal profile, basalStep, maxBasal bleComm.sendMessage(new DanaRS_Packet_Basal_Get_Basal_Rate()); // basal profile, basalStep, maxBasal
bleComm.sendMessage(new DanaRS_Packet_Bolus_Get_Calculation_Information()); // target bleComm.sendMessage(new DanaRS_Packet_Bolus_Get_Calculation_Information()); // target
bleComm.sendMessage(new DanaRS_Packet_Bolus_Get_CIR_CF_Array()); bleComm.sendMessage(new DanaRS_Packet_Bolus_Get_CIR_CF_Array());
MainApp.bus().post(new EventPumpStatusChanged(MainApp.gs(R.string.gettingpumptime)));
bleComm.sendMessage(new DanaRS_Packet_Option_Get_Pump_Time());
bleComm.sendMessage(new DanaRS_Packet_Option_Get_User_Option()); // Getting user options bleComm.sendMessage(new DanaRS_Packet_Option_Get_User_Option()); // Getting user options
long timeDiff = (danaRPump.pumpTime.getTime() - System.currentTimeMillis()) / 1000L;
log.debug("Pump time difference: " + timeDiff + " seconds");
if (Math.abs(timeDiff) > 3) {
waitForWholeMinute(); // Dana can set only whole minute
// add 10sec to be sure we are over minute (will be cutted off anyway)
bleComm.sendMessage(new DanaRS_Packet_Option_Set_Pump_Time(new Date(DateUtil.now() + T.secs(10).msecs())));
bleComm.sendMessage(new DanaRS_Packet_Option_Get_Pump_Time());
timeDiff = (danaRPump.pumpTime.getTime() - System.currentTimeMillis()) / 1000L;
log.debug("Pump time difference: " + timeDiff + " seconds");
}
danaRPump.lastSettingsRead = now; danaRPump.lastSettingsRead = now;
} }
@ -183,6 +203,13 @@ public class DanaRSService extends Service {
} }
public PumpEnactResult loadEvents() { public PumpEnactResult loadEvents() {
if(!MainApp.getSpecificPlugin(DanaRSPlugin.class).isInitialized()){
PumpEnactResult result = new PumpEnactResult().success(false);
result.comment = "pump not initialized";
return result;
}
DanaRS_Packet_APS_History_Events msg; DanaRS_Packet_APS_History_Events msg;
if (lastHistoryFetched == 0) { if (lastHistoryFetched == 0) {
msg = new DanaRS_Packet_APS_History_Events(0); msg = new DanaRS_Packet_APS_History_Events(0);

View file

@ -2,9 +2,12 @@ package info.nightscout.androidaps.plugins.PumpDanaRv2;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.content.ServiceConnection; import android.content.ServiceConnection;
import android.os.IBinder; import android.os.IBinder;
import android.support.v4.app.FragmentActivity;
import android.support.v7.app.AlertDialog;
import com.squareup.otto.Subscribe; import com.squareup.otto.Subscribe;
@ -20,6 +23,7 @@ import info.nightscout.androidaps.db.TemporaryBasal;
import info.nightscout.androidaps.events.EventAppExit; import info.nightscout.androidaps.events.EventAppExit;
import info.nightscout.androidaps.interfaces.Constraint; import info.nightscout.androidaps.interfaces.Constraint;
import info.nightscout.androidaps.interfaces.PumpDescription; import info.nightscout.androidaps.interfaces.PumpDescription;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderFragment;
import info.nightscout.androidaps.plugins.ConfigBuilder.DetailedBolusInfoStorage; import info.nightscout.androidaps.plugins.ConfigBuilder.DetailedBolusInfoStorage;
import info.nightscout.androidaps.plugins.PumpDanaR.AbstractDanaRPlugin; import info.nightscout.androidaps.plugins.PumpDanaR.AbstractDanaRPlugin;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgBolusStartWithSpeed; import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgBolusStartWithSpeed;
@ -44,6 +48,8 @@ public class DanaRv2Plugin extends AbstractDanaRPlugin {
} }
private DanaRv2Plugin() { private DanaRv2Plugin() {
pluginDescription.description(R.string.description_pump_dana_r_v2);
log = LoggerFactory.getLogger(DanaRv2Plugin.class); log = LoggerFactory.getLogger(DanaRv2Plugin.class);
useExtendedBoluses = false; useExtendedBoluses = false;
@ -138,6 +144,31 @@ public class DanaRv2Plugin extends AbstractDanaRPlugin {
return pump.lastConnection > 0 && pump.maxBasal > 0; return pump.lastConnection > 0 && pump.maxBasal > 0;
} }
@Override
public void switchAllowed(ConfigBuilderFragment.PluginViewHolder.PluginSwitcher pluginSwitcher, FragmentActivity context) {
boolean allowHardwarePump = SP.getBoolean("allow_hardware_pump", false);
if (allowHardwarePump || context == null){
pluginSwitcher.invoke();
} else {
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setMessage(R.string.allow_hardware_pump_text)
.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
pluginSwitcher.invoke();
SP.putBoolean("allow_hardware_pump", true);
log.debug("First time HW pump allowed!");
}
})
.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
pluginSwitcher.cancel();
log.debug("User does not allow switching to HW pump!");
}
});
builder.create().show();
}
}
// Pump interface // Pump interface
@Override @Override
public PumpEnactResult deliverTreatment(DetailedBolusInfo detailedBolusInfo) { public PumpEnactResult deliverTreatment(DetailedBolusInfo detailedBolusInfo) {
@ -266,8 +297,12 @@ public class DanaRv2Plugin extends AbstractDanaRPlugin {
// Convert duration from minutes to hours // Convert duration from minutes to hours
if (Config.logPumpActions) if (Config.logPumpActions)
log.debug("setTempBasalAbsolute: Setting temp basal " + percentRate + "% for " + durationInMinutes + " mins (doLowTemp || doHighTemp)"); log.debug("setTempBasalAbsolute: Setting temp basal " + percentRate + "% for " + durationInMinutes + " mins (doLowTemp || doHighTemp)");
if (percentRate == 0 && durationInMinutes > 30) {
result = setTempBasalPercent(percentRate, durationInMinutes, profile, false);
} else {
// use special APS temp basal call ... 100+/15min .... 100-/30min // use special APS temp basal call ... 100+/15min .... 100-/30min
result = setHighTempBasalPercent(percentRate); result = setHighTempBasalPercent(percentRate);
}
if (!result.success) { if (!result.success) {
log.error("setTempBasalAbsolute: Failed to set hightemp basal"); log.error("setTempBasalAbsolute: Failed to set hightemp basal");
return result; return result;

View file

@ -1,6 +1,7 @@
package info.nightscout.androidaps.plugins.PumpDanaRv2.services; package info.nightscout.androidaps.plugins.PumpDanaRv2.services;
import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothDevice;
import android.content.Intent;
import android.content.IntentFilter; import android.content.IntentFilter;
import android.os.Binder; import android.os.Binder;
import android.os.SystemClock; import android.os.SystemClock;
@ -18,6 +19,7 @@ import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.data.PumpEnactResult; import info.nightscout.androidaps.data.PumpEnactResult;
import info.nightscout.androidaps.plugins.Overview.Dialogs.ErrorHelperActivity;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgSettingUserOptions; import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgSettingUserOptions;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgSetUserOptions; import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgSetUserOptions;
import info.nightscout.androidaps.plugins.Treatments.Treatment; import info.nightscout.androidaps.plugins.Treatments.Treatment;
@ -187,6 +189,36 @@ public class DanaRv2ExecutionService extends AbstractDanaRExecutionService {
mSerialIOThread.sendMessage(tempStatusMsg); mSerialIOThread.sendMessage(tempStatusMsg);
MainApp.bus().post(new EventPumpStatusChanged(MainApp.gs(R.string.gettingextendedbolusstatus))); MainApp.bus().post(new EventPumpStatusChanged(MainApp.gs(R.string.gettingextendedbolusstatus)));
mSerialIOThread.sendMessage(exStatusMsg); mSerialIOThread.sendMessage(exStatusMsg);
MainApp.bus().post(new EventPumpStatusChanged(MainApp.gs(R.string.gettingpumptime)));
mSerialIOThread.sendMessage(new MsgSettingPumpTime());
long timeDiff = (mDanaRPump.pumpTime.getTime() - System.currentTimeMillis()) / 1000L;
log.debug("Pump time difference: " + timeDiff + " seconds");
if (Math.abs(timeDiff) > 3) {
if (Math.abs(timeDiff) > 60*60*1.5) {
log.debug("Pump time difference: " + timeDiff + " seconds - large difference");
//If time-diff is very large, warn user until we can synchronize history readings properly
Intent i = new Intent(MainApp.instance(), ErrorHelperActivity.class);
i.putExtra("soundid", R.raw.error);
i.putExtra("status", MainApp.gs(R.string.largetimediff));
i.putExtra("title", MainApp.gs(R.string.largetimedifftitle));
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
MainApp.instance().startActivity(i);
//deinitialize pump
mDanaRPump.lastConnection = 0;
MainApp.bus().post(new EventDanaRNewStatus());
MainApp.bus().post(new EventInitializationChanged());
return;
} else {
waitForWholeMinute(); // Dana can set only whole minute
// add 10sec to be sure we are over minute (will be cutted off anyway)
mSerialIOThread.sendMessage(new MsgSetTime(new Date(DateUtil.now() + T.secs(10).msecs())));
mSerialIOThread.sendMessage(new MsgSettingPumpTime());
timeDiff = (mDanaRPump.pumpTime.getTime() - System.currentTimeMillis()) / 1000L;
log.debug("Pump time difference: " + timeDiff + " seconds");
}
}
mDanaRPump.lastConnection = System.currentTimeMillis();
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
if (mDanaRPump.lastSettingsRead + 60 * 60 * 1000L < now || !MainApp.getSpecificPlugin(DanaRv2Plugin.class).isInitialized()) { if (mDanaRPump.lastSettingsRead + 60 * 60 * 1000L < now || !MainApp.getSpecificPlugin(DanaRv2Plugin.class).isInitialized()) {
@ -202,18 +234,6 @@ public class DanaRv2ExecutionService extends AbstractDanaRExecutionService {
mSerialIOThread.sendMessage(new MsgSettingProfileRatios()); mSerialIOThread.sendMessage(new MsgSettingProfileRatios());
mSerialIOThread.sendMessage(new MsgSettingUserOptions()); mSerialIOThread.sendMessage(new MsgSettingUserOptions());
mSerialIOThread.sendMessage(new MsgSettingProfileRatiosAll()); mSerialIOThread.sendMessage(new MsgSettingProfileRatiosAll());
MainApp.bus().post(new EventPumpStatusChanged(MainApp.gs(R.string.gettingpumptime)));
mSerialIOThread.sendMessage(new MsgSettingPumpTime());
long timeDiff = (mDanaRPump.pumpTime.getTime() - System.currentTimeMillis()) / 1000L;
log.debug("Pump time difference: " + timeDiff + " seconds");
if (Math.abs(timeDiff) > 3) {
waitForWholeMinute(); // Dana can set only whole minute
// add 10sec to be sure we are over minute (will be cutted off anyway)
mSerialIOThread.sendMessage(new MsgSetTime(new Date(DateUtil.now() + T.secs(10).msecs())));
mSerialIOThread.sendMessage(new MsgSettingPumpTime());
timeDiff = (mDanaRPump.pumpTime.getTime() - System.currentTimeMillis()) / 1000L;
log.debug("Pump time difference: " + timeDiff + " seconds");
}
mDanaRPump.lastSettingsRead = now; mDanaRPump.lastSettingsRead = now;
} }
@ -425,6 +445,14 @@ public class DanaRv2ExecutionService extends AbstractDanaRExecutionService {
} }
public PumpEnactResult loadEvents() { public PumpEnactResult loadEvents() {
if(!MainApp.getSpecificPlugin(DanaRv2Plugin.class).isInitialized()){
PumpEnactResult result = new PumpEnactResult().success(false);
result.comment = "pump not initialized";
return result;
}
if (!isConnected()) if (!isConnected())
return new PumpEnactResult().success(false); return new PumpEnactResult().success(false);
SystemClock.sleep(300); SystemClock.sleep(300);

View file

@ -1,5 +1,9 @@
package info.nightscout.androidaps.plugins.PumpInsight; package info.nightscout.androidaps.plugins.PumpInsight;
import android.content.DialogInterface;
import android.support.v4.app.FragmentActivity;
import android.support.v7.app.AlertDialog;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -27,6 +31,7 @@ import info.nightscout.androidaps.interfaces.PluginDescription;
import info.nightscout.androidaps.interfaces.PluginType; import info.nightscout.androidaps.interfaces.PluginType;
import info.nightscout.androidaps.interfaces.PumpDescription; import info.nightscout.androidaps.interfaces.PumpDescription;
import info.nightscout.androidaps.interfaces.PumpInterface; import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderFragment;
import info.nightscout.androidaps.plugins.Overview.events.EventDismissNotification; import info.nightscout.androidaps.plugins.Overview.events.EventDismissNotification;
import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification; import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification;
import info.nightscout.androidaps.plugins.Overview.events.EventOverviewBolusProgress; import info.nightscout.androidaps.plugins.Overview.events.EventOverviewBolusProgress;
@ -203,6 +208,31 @@ public class InsightPlugin extends PluginBase implements PumpInterface, Constrai
return result; return result;
} }
@Override
public void switchAllowed(ConfigBuilderFragment.PluginViewHolder.PluginSwitcher pluginSwitcher, FragmentActivity context) {
boolean allowHardwarePump = SP.getBoolean("allow_hardware_pump", false);
if (allowHardwarePump || context == null){
pluginSwitcher.invoke();
} else {
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setMessage(R.string.allow_hardware_pump_text)
.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
pluginSwitcher.invoke();
SP.putBoolean("allow_hardware_pump", true);
log.debug("First time HW pump allowed!");
}
})
.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
pluginSwitcher.cancel();
log.debug("User does not allow switching to HW pump!");
}
});
builder.create().show();
}
}
@Override @Override
public boolean isInitialized() { public boolean isInitialized() {
return initialized; return initialized;

View file

@ -0,0 +1,68 @@
package info.nightscout.androidaps.plugins.Sensitivity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.PluginDescription;
import info.nightscout.androidaps.interfaces.SensitivityInterface;
import info.nightscout.androidaps.plugins.IobCobCalculator.AutosensResult;
import info.nightscout.utils.Round;
import info.nightscout.utils.SP;
import info.nightscout.utils.SafeParse;
public abstract class AbstractSensitivityPlugin extends PluginBase implements SensitivityInterface {
private static final Logger log = LoggerFactory.getLogger(SensitivityInterface.class);
public AbstractSensitivityPlugin(PluginDescription pluginDescription) {
super(pluginDescription);
}
@Override
public abstract AutosensResult detectSensitivity(long fromTime, long toTime);
public AutosensResult fillResult(double ratio, double carbsAbsorbed, String pastSensitivity,
String ratioLimit, String sensResult, int deviationsArraySize) {
return this.fillResult(ratio, carbsAbsorbed, pastSensitivity, ratioLimit, sensResult,
deviationsArraySize,
SafeParse.stringToDouble(SP.getString(R.string.key_openapsama_autosens_min, "0.7")),
SafeParse.stringToDouble(SP.getString(R.string.key_openapsama_autosens_max, "1.2")));
}
public AutosensResult fillResult(double ratio, double carbsAbsorbed, String pastSensitivity,
String ratioLimit, String sensResult, int deviationsArraySize,
double ratioMin, double ratioMax) {
double rawRatio = ratio;
ratio = Math.max(ratio, ratioMin);
ratio = Math.min(ratio, ratioMax);
//If not-excluded data <= MIN_HOURS -> don't do Autosens
//If not-excluded data >= MIN_HOURS_FULL_AUTOSENS -> full Autosens
//Between MIN_HOURS and MIN_HOURS_FULL_AUTOSENS: gradually increase autosens
double autosensContrib = (Math.min(Math.max(MIN_HOURS, deviationsArraySize / 12d),
MIN_HOURS_FULL_AUTOSENS) - MIN_HOURS) / (MIN_HOURS_FULL_AUTOSENS - MIN_HOURS);
ratio = autosensContrib * (ratio - 1) + 1;
if (autosensContrib != 1d) {
ratioLimit += "(" + deviationsArraySize + " of " + MIN_HOURS_FULL_AUTOSENS * 12 + " values) ";
}
if (ratio != rawRatio) {
ratioLimit += "Ratio limited from " + rawRatio + " to " + ratio;
log.debug(ratioLimit);
}
AutosensResult output = new AutosensResult();
output.ratio = Round.roundTo(ratio, 0.01);
output.carbsAbsorbed = Round.roundTo(carbsAbsorbed, 0.01);
output.pastSensitivity = pastSensitivity;
output.ratioLimit = ratioLimit;
output.sensResult = sensResult;
return output;
}
}

View file

@ -1,11 +1,10 @@
package info.nightscout.androidaps.plugins.SensitivityAAPS; package info.nightscout.androidaps.plugins.Sensitivity;
import android.support.v4.util.LongSparseArray; import android.support.v4.util.LongSparseArray;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.lang.reflect.Array;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Date; import java.util.Date;
@ -15,6 +14,7 @@ import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.db.CareportalEvent;
import info.nightscout.androidaps.interfaces.PluginBase; import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.PluginDescription; import info.nightscout.androidaps.interfaces.PluginDescription;
import info.nightscout.androidaps.interfaces.PluginType; import info.nightscout.androidaps.interfaces.PluginType;
@ -30,7 +30,7 @@ import info.nightscout.utils.SafeParse;
* Created by mike on 24.06.2017. * Created by mike on 24.06.2017.
*/ */
public class SensitivityAAPSPlugin extends PluginBase implements SensitivityInterface { public class SensitivityAAPSPlugin extends AbstractSensitivityPlugin {
private static Logger log = LoggerFactory.getLogger(SensitivityAAPSPlugin.class); private static Logger log = LoggerFactory.getLogger(SensitivityAAPSPlugin.class);
static SensitivityAAPSPlugin plugin = null; static SensitivityAAPSPlugin plugin = null;
@ -81,6 +81,8 @@ public class SensitivityAAPSPlugin extends PluginBase implements SensitivityInte
} }
List<CareportalEvent> siteChanges = MainApp.getDbHelper().getCareportalEventsFromTime(fromTime, CareportalEvent.SITECHANGE, true);
List<Double> deviationsArray = new ArrayList<>(); List<Double> deviationsArray = new ArrayList<>();
String pastSensitivity = ""; String pastSensitivity = "";
int index = 0; int index = 0;
@ -97,8 +99,21 @@ public class SensitivityAAPSPlugin extends PluginBase implements SensitivityInte
continue; continue;
} }
// reset deviations after site change
if (CareportalEvent.isEvent5minBack(siteChanges, autosensData.time)) {
deviationsArray.clear();
pastSensitivity += "(SITECHANGE)";
}
double deviation = autosensData.deviation;
//set positive deviations to zero if bg < 80
if (autosensData.bg < 80 && deviation > 0)
deviation = 0;
if (autosensData.validDeviation)
if (autosensData.time > toTime - hoursForDetection * 60 * 60 * 1000L) if (autosensData.time > toTime - hoursForDetection * 60 * 60 * 1000L)
deviationsArray.add(autosensData.nonEqualDeviation ? autosensData.deviation : 0d); deviationsArray.add(deviation);
if (deviationsArray.size() > hoursForDetection * 60 / 5) if (deviationsArray.size() > hoursForDetection * 60 / 5)
deviationsArray.remove(0); deviationsArray.remove(0);
@ -139,26 +154,16 @@ public class SensitivityAAPSPlugin extends PluginBase implements SensitivityInte
if (Config.logAutosensData) if (Config.logAutosensData)
log.debug(sensResult); log.debug(sensResult);
double rawRatio = ratio; AutosensResult output = fillResult(ratio, current.cob, pastSensitivity, ratioLimit,
ratio = Math.max(ratio, SafeParse.stringToDouble(SP.getString(R.string.key_openapsama_autosens_min, "0.7"))); sensResult, deviationsArray.size());
ratio = Math.min(ratio, SafeParse.stringToDouble(SP.getString(R.string.key_openapsama_autosens_max, "1.2")));
if (ratio != rawRatio) {
ratioLimit = "Ratio limited from " + rawRatio + " to " + ratio;
log.debug(ratioLimit);
}
if (Config.logAutosensData) { if (Config.logAutosensData) {
log.debug("Sensitivity to: " + new Date(toTime).toLocaleString() + " percentile: " + percentile + " ratio: " + ratio + " mealCOB: " + current.cob); log.debug("Sensitivity to: {}, percentile: {} ratio: {} mealCOB: ",
new Date(toTime).toLocaleString(),
percentile, output.ratio, ratio, current.cob);
log.debug("Sensitivity to: deviations " + Arrays.toString(deviations)); log.debug("Sensitivity to: deviations " + Arrays.toString(deviations));
} }
AutosensResult output = new AutosensResult();
output.ratio = Round.roundTo(ratio, 0.01);
output.carbsAbsorbed = Round.roundTo(current.cob, 0.01);
output.pastSensitivity = pastSensitivity;
output.ratioLimit = ratioLimit;
output.sensResult = sensResult;
return output; return output;
} }
} }

View file

@ -1,4 +1,4 @@
package info.nightscout.androidaps.plugins.SensitivityOref0; package info.nightscout.androidaps.plugins.Sensitivity;
import android.support.v4.util.LongSparseArray; import android.support.v4.util.LongSparseArray;
@ -14,6 +14,7 @@ import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.db.CareportalEvent;
import info.nightscout.androidaps.interfaces.PluginBase; import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.PluginDescription; import info.nightscout.androidaps.interfaces.PluginDescription;
import info.nightscout.androidaps.interfaces.PluginType; import info.nightscout.androidaps.interfaces.PluginType;
@ -29,7 +30,7 @@ import info.nightscout.utils.SafeParse;
* Created by mike on 24.06.2017. * Created by mike on 24.06.2017.
*/ */
public class SensitivityOref0Plugin extends PluginBase implements SensitivityInterface { public class SensitivityOref0Plugin extends AbstractSensitivityPlugin {
private static Logger log = LoggerFactory.getLogger(IobCobCalculatorPlugin.class); private static Logger log = LoggerFactory.getLogger(IobCobCalculatorPlugin.class);
static SensitivityOref0Plugin plugin = null; static SensitivityOref0Plugin plugin = null;
@ -54,12 +55,7 @@ public class SensitivityOref0Plugin extends PluginBase implements SensitivityInt
public AutosensResult detectSensitivity(long fromTime, long toTime) { public AutosensResult detectSensitivity(long fromTime, long toTime) {
LongSparseArray<AutosensData> autosensDataTable = IobCobCalculatorPlugin.getPlugin().getAutosensDataTable(); LongSparseArray<AutosensData> autosensDataTable = IobCobCalculatorPlugin.getPlugin().getAutosensDataTable();
String age = SP.getString(R.string.key_age, ""); int hoursForDetection = 24;
int defaultHours = 24;
if (age.equals(MainApp.gs(R.string.key_adult))) defaultHours = 24;
if (age.equals(MainApp.gs(R.string.key_teenage))) defaultHours = 24;
if (age.equals(MainApp.gs(R.string.key_child))) defaultHours = 24;
int hoursForDetection = SP.getInt(R.string.key_openapsama_autosens_period, defaultHours);
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
Profile profile = MainApp.getConfigBuilder().getProfile(); Profile profile = MainApp.getConfigBuilder().getProfile();
@ -81,6 +77,8 @@ public class SensitivityOref0Plugin extends PluginBase implements SensitivityInt
} }
List<CareportalEvent> siteChanges = MainApp.getDbHelper().getCareportalEventsFromTime(fromTime, CareportalEvent.SITECHANGE, true);
List<Double> deviationsArray = new ArrayList<>(); List<Double> deviationsArray = new ArrayList<>();
String pastSensitivity = ""; String pastSensitivity = "";
int index = 0; int index = 0;
@ -97,8 +95,21 @@ public class SensitivityOref0Plugin extends PluginBase implements SensitivityInt
continue; continue;
} }
// reset deviations after site change
if (CareportalEvent.isEvent5minBack(siteChanges, autosensData.time)) {
deviationsArray.clear();
pastSensitivity += "(SITECHANGE)";
}
double deviation = autosensData.deviation;
//set positive deviations to zero if bg < 80
if (autosensData.bg < 80 && deviation > 0)
deviation = 0;
if (autosensData.validDeviation)
if (autosensData.time > toTime - hoursForDetection * 60 * 60 * 1000L) if (autosensData.time > toTime - hoursForDetection * 60 * 60 * 1000L)
deviationsArray.add(autosensData.nonEqualDeviation ? autosensData.deviation : 0d); deviationsArray.add(deviation);
if (deviationsArray.size() > hoursForDetection * 60 / 5) if (deviationsArray.size() > hoursForDetection * 60 / 5)
deviationsArray.remove(0); deviationsArray.remove(0);
@ -150,24 +161,13 @@ public class SensitivityOref0Plugin extends PluginBase implements SensitivityInt
ratio = 1 + (basalOff / profile.getMaxDailyBasal()); ratio = 1 + (basalOff / profile.getMaxDailyBasal());
double rawRatio = ratio; AutosensResult output = fillResult(ratio, current.cob, pastSensitivity, ratioLimit,
ratio = Math.max(ratio, SafeParse.stringToDouble(SP.getString(R.string.key_openapsama_autosens_min, "0.7"))); sensResult, deviationsArray.size());
ratio = Math.min(ratio, SafeParse.stringToDouble(SP.getString(R.string.key_openapsama_autosens_max, "1.2")));
if (ratio != rawRatio) {
ratioLimit = "Ratio limited from " + rawRatio + " to " + ratio;
log.debug(ratioLimit);
}
if (Config.logAutosensData) if (Config.logAutosensData)
log.debug("Sensitivity to: " + new Date(toTime).toLocaleString() + " ratio: " + ratio + " mealCOB: " + current.cob); log.debug("Sensitivity to: {} ratio: {} mealCOB: {}",
new Date(toTime).toLocaleString(), output.ratio, current.cob);
AutosensResult output = new AutosensResult();
output.ratio = Round.roundTo(ratio, 0.01);
output.carbsAbsorbed = Round.roundTo(current.cob, 0.01);
output.pastSensitivity = pastSensitivity;
output.ratioLimit = ratioLimit;
output.sensResult = sensResult;
return output; return output;
} }
} }

View file

@ -0,0 +1,187 @@
package info.nightscout.androidaps.plugins.Sensitivity;
import android.support.v4.util.LongSparseArray;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.db.CareportalEvent;
import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.PluginDescription;
import info.nightscout.androidaps.interfaces.PluginType;
import info.nightscout.androidaps.interfaces.SensitivityInterface;
import info.nightscout.androidaps.plugins.IobCobCalculator.AutosensData;
import info.nightscout.androidaps.plugins.IobCobCalculator.AutosensResult;
import info.nightscout.androidaps.plugins.IobCobCalculator.IobCobCalculatorPlugin;
import info.nightscout.utils.Round;
import info.nightscout.utils.SP;
import info.nightscout.utils.SafeParse;
/**
* Created by mike on 19.06.2018.
*/
public class SensitivityOref1Plugin extends AbstractSensitivityPlugin {
private static Logger log = LoggerFactory.getLogger(IobCobCalculatorPlugin.class);
static SensitivityOref1Plugin plugin = null;
public static SensitivityOref1Plugin getPlugin() {
if (plugin == null)
plugin = new SensitivityOref1Plugin();
return plugin;
}
public SensitivityOref1Plugin() {
super(new PluginDescription()
.mainType(PluginType.SENSITIVITY)
.pluginName(R.string.sensitivityoref1)
.shortName(R.string.sensitivity_shortname)
.preferencesId(R.xml.pref_absorption_oref1)
.description(R.string.description_sensitivity_oref1)
);
}
@Override
public AutosensResult detectSensitivity(long fromTime, long toTime) {
LongSparseArray<AutosensData> autosensDataTable = IobCobCalculatorPlugin.getPlugin().getAutosensDataTable();
Profile profile = MainApp.getConfigBuilder().getProfile();
if (profile == null) {
log.debug("No profile");
return new AutosensResult();
}
if (autosensDataTable == null || autosensDataTable.size() < 4) {
log.debug("No autosens data available");
return new AutosensResult();
}
AutosensData current = IobCobCalculatorPlugin.getPlugin().getAutosensData(toTime); // this is running inside lock already
if (current == null) {
log.debug("No current autosens data available");
return new AutosensResult();
}
List<CareportalEvent> siteChanges = MainApp.getDbHelper().getCareportalEventsFromTime(fromTime, CareportalEvent.SITECHANGE, true);
List<Double> deviationsArray = new ArrayList<>();
String pastSensitivity = "";
int index = 0;
while (index < autosensDataTable.size()) {
AutosensData autosensData = autosensDataTable.valueAt(index);
if (autosensData.time < fromTime) {
index++;
continue;
}
if (autosensData.time > toTime) {
index++;
continue;
}
// reset deviations after site change
if (CareportalEvent.isEvent5minBack(siteChanges, autosensData.time)) {
deviationsArray.clear();
pastSensitivity += "(SITECHANGE)";
}
double deviation = autosensData.deviation;
//set positive deviations to zero if bg < 80
if (autosensData.bg < 80 && deviation > 0)
deviation = 0;
if (autosensData.validDeviation)
deviationsArray.add(deviation);
for (int i = 0; i < autosensData.extraDeviation.size(); i++)
deviationsArray.add(autosensData.extraDeviation.get(i));
if (deviationsArray.size() > 96)
deviationsArray.remove(0);
pastSensitivity += autosensData.pastSensitivity;
int secondsFromMidnight = Profile.secondsFromMidnight(autosensData.time);
if (secondsFromMidnight % 3600 < 2.5 * 60 || secondsFromMidnight % 3600 > 57.5 * 60) {
pastSensitivity += "(" + Math.round(secondsFromMidnight / 3600d) + ")";
}
index++;
}
// when we have less than 8h worth of deviation data, add up to 90m of zero deviations
// this dampens any large sensitivity changes detected based on too little data, without ignoring them completely
log.debug("Using most recent " + deviationsArray.size() + " deviations");
if (deviationsArray.size() < 96) {
int pad = Math.round((1 - deviationsArray.size() / 96) * 18);
log.debug("Adding " + pad + " more zero deviations");
for (int d = 0; d < pad; d++) {
//process.stderr.write(".");
deviationsArray.add(0d);
}
}
Double[] deviations = new Double[deviationsArray.size()];
deviations = deviationsArray.toArray(deviations);
double sens = profile.getIsf();
double ratio = 1;
String ratioLimit = "";
String sensResult = "";
if (Config.logAutosensData)
log.debug("Records: " + index + " " + pastSensitivity);
Arrays.sort(deviations);
for (double i = 0.9; i > 0.1; i = i - 0.01) {
if (IobCobCalculatorPlugin.percentile(deviations, (i + 0.01)) >= 0 && IobCobCalculatorPlugin.percentile(deviations, i) < 0) {
if (Config.logAutosensData)
log.debug(Math.round(100 * i) + "% of non-meal deviations negative (>50% = sensitivity)");
}
if (IobCobCalculatorPlugin.percentile(deviations, (i + 0.01)) > 0 && IobCobCalculatorPlugin.percentile(deviations, i) <= 0) {
if (Config.logAutosensData)
log.debug(Math.round(100 * i) + "% of non-meal deviations negative (>50% = resistance)");
}
}
double pSensitive = IobCobCalculatorPlugin.percentile(deviations, 0.50);
double pResistant = IobCobCalculatorPlugin.percentile(deviations, 0.50);
double basalOff = 0;
if (pSensitive < 0) { // sensitive
basalOff = pSensitive * (60 / 5) / Profile.toMgdl(sens, profile.getUnits());
sensResult = "Excess insulin sensitivity detected";
} else if (pResistant > 0) { // resistant
basalOff = pResistant * (60 / 5) / Profile.toMgdl(sens, profile.getUnits());
sensResult = "Excess insulin resistance detected";
} else {
sensResult = "Sensitivity normal";
}
if (Config.logAutosensData)
log.debug(sensResult);
ratio = 1 + (basalOff / profile.getMaxDailyBasal());
AutosensResult output = fillResult(ratio, current.cob, pastSensitivity, ratioLimit,
sensResult, deviationsArray.size());
if (Config.logAutosensData)
log.debug("Sensitivity to: {} ratio: {} mealCOB: {}",
new Date(toTime).toLocaleString(), output.ratio, current.cob);
return output;
}
}

View file

@ -1,4 +1,4 @@
package info.nightscout.androidaps.plugins.SensitivityWeightedAverage; package info.nightscout.androidaps.plugins.Sensitivity;
import android.support.v4.util.LongSparseArray; import android.support.v4.util.LongSparseArray;
@ -6,11 +6,13 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.util.Date; import java.util.Date;
import java.util.List;
import info.nightscout.androidaps.Config; import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.db.CareportalEvent;
import info.nightscout.androidaps.interfaces.PluginBase; import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.PluginDescription; import info.nightscout.androidaps.interfaces.PluginDescription;
import info.nightscout.androidaps.interfaces.PluginType; import info.nightscout.androidaps.interfaces.PluginType;
@ -26,7 +28,7 @@ import info.nightscout.utils.SafeParse;
* Created by mike on 24.06.2017. * Created by mike on 24.06.2017.
*/ */
public class SensitivityWeightedAveragePlugin extends PluginBase implements SensitivityInterface { public class SensitivityWeightedAveragePlugin extends AbstractSensitivityPlugin {
private static Logger log = LoggerFactory.getLogger(SensitivityWeightedAveragePlugin.class); private static Logger log = LoggerFactory.getLogger(SensitivityWeightedAveragePlugin.class);
private static SensitivityWeightedAveragePlugin plugin = null; private static SensitivityWeightedAveragePlugin plugin = null;
@ -79,6 +81,8 @@ public class SensitivityWeightedAveragePlugin extends PluginBase implements Sens
return new AutosensResult(); return new AutosensResult();
} }
List<CareportalEvent> siteChanges = MainApp.getDbHelper().getCareportalEventsFromTime(fromTime, CareportalEvent.SITECHANGE, true);
String pastSensitivity = ""; String pastSensitivity = "";
int index = 0; int index = 0;
LongSparseArray<Double> data = new LongSparseArray<>(); LongSparseArray<Double> data = new LongSparseArray<>();
@ -101,11 +105,24 @@ public class SensitivityWeightedAveragePlugin extends PluginBase implements Sens
continue; continue;
} }
// reset deviations after site change
if (CareportalEvent.isEvent5minBack(siteChanges, autosensData.time)) {
data.clear();
pastSensitivity += "(SITECHANGE)";
}
double deviation = autosensData.deviation;
//set positive deviations to zero if bg < 80
if (autosensData.bg < 80 && deviation > 0)
deviation = 0;
//data.append(autosensData.time); //data.append(autosensData.time);
long reverseWeight = (toTime - autosensData.time) / (5 * 60 * 1000L); long reverseWeight = (toTime - autosensData.time) / (5 * 60 * 1000L);
data.append(reverseWeight, autosensData.nonEqualDeviation ? autosensData.deviation : 0d); if (autosensData.validDeviation)
data.append(reverseWeight, deviation);
//weights += reverseWeight; //weights += reverseWeight;
//weightedsum += reverseWeight * (autosensData.nonEqualDeviation ? autosensData.deviation : 0d); //weightedsum += reverseWeight * (autosensData.validDeviation ? autosensData.deviation : 0d);
pastSensitivity += autosensData.pastSensitivity; pastSensitivity += autosensData.pastSensitivity;
@ -159,25 +176,13 @@ public class SensitivityWeightedAveragePlugin extends PluginBase implements Sens
if (Config.logAutosensData) if (Config.logAutosensData)
log.debug(sensResult); log.debug(sensResult);
double rawRatio = ratio; AutosensResult output = fillResult(ratio, current.cob, pastSensitivity, ratioLimit,
ratio = Math.max(ratio, SafeParse.stringToDouble(SP.getString(R.string.key_openapsama_autosens_min, "0.7"))); sensResult, data.size());
ratio = Math.min(ratio, SafeParse.stringToDouble(SP.getString(R.string.key_openapsama_autosens_max, "1.2")));
if (ratio != rawRatio) {
ratioLimit = "Ratio limited from " + rawRatio + " to " + ratio;
if (Config.logAutosensData)
log.debug(ratioLimit);
}
if (Config.logAutosensData) if (Config.logAutosensData)
log.debug("Sensitivity to: " + new Date(toTime).toLocaleString() + " weightedaverage: " + average + " ratio: " + ratio + " mealCOB: " + current.cob); log.debug("Sensitivity to: {} weightedaverage: {} ratio: {} mealCOB: {}", new Date(toTime).toLocaleString(),
average, output.ratio, current.cob);
AutosensResult output = new AutosensResult();
output.ratio = Round.roundTo(ratio, 0.01);
output.carbsAbsorbed = Round.roundTo(current.cob, 0.01);
output.pastSensitivity = pastSensitivity;
output.ratioLimit = ratioLimit;
output.sensResult = sensResult;
return output; return output;
} }
} }

View file

@ -2,6 +2,7 @@ package info.nightscout.androidaps.plugins.SmsCommunicator;
import android.content.Intent; import android.content.Intent;
import android.content.pm.ResolveInfo; import android.content.pm.ResolveInfo;
import android.os.SystemClock;
import android.telephony.SmsManager; import android.telephony.SmsManager;
import android.telephony.SmsMessage; import android.telephony.SmsMessage;
@ -47,6 +48,7 @@ import info.nightscout.utils.FabricPrivacy;
import info.nightscout.utils.NSUpload; import info.nightscout.utils.NSUpload;
import info.nightscout.utils.SP; import info.nightscout.utils.SP;
import info.nightscout.utils.SafeParse; import info.nightscout.utils.SafeParse;
import info.nightscout.utils.T;
import info.nightscout.utils.XdripCalibrations; import info.nightscout.utils.XdripCalibrations;
/** /**
@ -450,12 +452,14 @@ public class SmsCommunicatorPlugin extends PluginBase {
public void run() { public void run() {
PumpInterface pump = MainApp.getConfigBuilder().getActivePump(); PumpInterface pump = MainApp.getConfigBuilder().getActivePump();
if (result.success) { if (result.success) {
SystemClock.sleep(T.secs(15).msecs()); // wait some time to get history
String reply = String.format(MainApp.gs(R.string.smscommunicator_bolusdelivered), result.bolusDelivered); String reply = String.format(MainApp.gs(R.string.smscommunicator_bolusdelivered), result.bolusDelivered);
if (pump != null) if (pump != null)
reply += "\n" + pump.shortStatus(true); reply += "\n" + pump.shortStatus(true);
lastRemoteBolusTime = new Date(); lastRemoteBolusTime = new Date();
sendSMSToAllNumbers(new Sms(receivedSms.phoneNumber, reply, new Date())); sendSMSToAllNumbers(new Sms(receivedSms.phoneNumber, reply, new Date()));
} else { } else {
SystemClock.sleep(T.secs(60).msecs()); // wait some time to get history
String reply = MainApp.gs(R.string.smscommunicator_bolusfailed); String reply = MainApp.gs(R.string.smscommunicator_bolusfailed);
if (pump != null) if (pump != null)
reply += "\n" + pump.shortStatus(true); reply += "\n" + pump.shortStatus(true);

View file

@ -20,6 +20,9 @@ public class SourceNSClientPlugin extends PluginBase implements BgSourceInterfac
return plugin; return plugin;
} }
private long lastBGTimeStamp = 0;
private boolean isAdvancedFilteringEnabled = false;
private SourceNSClientPlugin() { private SourceNSClientPlugin() {
super(new PluginDescription() super(new PluginDescription()
.mainType(PluginType.BGSOURCE) .mainType(PluginType.BGSOURCE)
@ -33,6 +36,16 @@ public class SourceNSClientPlugin extends PluginBase implements BgSourceInterfac
@Override @Override
public boolean advancedFilteringSupported() { public boolean advancedFilteringSupported() {
return false; return isAdvancedFilteringEnabled;
}
public void detectSource(String source, long timeStamp) {
if (timeStamp > lastBGTimeStamp) {
if (source.contains("G5 Native") || source.contains("AndroidAPS-DexcomG5"))
isAdvancedFilteringEnabled = true;
else
isAdvancedFilteringEnabled = false;
lastBGTimeStamp = timeStamp;
}
} }
} }

View file

@ -40,8 +40,8 @@ import info.nightscout.androidaps.plugins.IobCobCalculator.AutosensData;
import info.nightscout.androidaps.plugins.IobCobCalculator.IobCobCalculatorPlugin; import info.nightscout.androidaps.plugins.IobCobCalculator.IobCobCalculatorPlugin;
import info.nightscout.androidaps.plugins.Overview.events.EventDismissNotification; import info.nightscout.androidaps.plugins.Overview.events.EventDismissNotification;
import info.nightscout.androidaps.plugins.Overview.notifications.Notification; import info.nightscout.androidaps.plugins.Overview.notifications.Notification;
import info.nightscout.androidaps.plugins.SensitivityAAPS.SensitivityAAPSPlugin; import info.nightscout.androidaps.plugins.Sensitivity.SensitivityAAPSPlugin;
import info.nightscout.androidaps.plugins.SensitivityWeightedAverage.SensitivityWeightedAveragePlugin; import info.nightscout.androidaps.plugins.Sensitivity.SensitivityWeightedAveragePlugin;
import info.nightscout.utils.DateUtil; import info.nightscout.utils.DateUtil;
import info.nightscout.utils.NSUpload; import info.nightscout.utils.NSUpload;
import info.nightscout.utils.SP; import info.nightscout.utils.SP;
@ -78,7 +78,6 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface
.fragmentClass(TreatmentsFragment.class.getName()) .fragmentClass(TreatmentsFragment.class.getName())
.pluginName(R.string.treatments) .pluginName(R.string.treatments)
.shortName(R.string.treatments_shortname) .shortName(R.string.treatments_shortname)
.preferencesId(R.xml.pref_absorption_oref0)
.alwaysEnabled(true) .alwaysEnabled(true)
.description(R.string.description_treatments) .description(R.string.description_treatments)
); );

View file

@ -43,6 +43,8 @@ import info.nightscout.utils.DecimalFormatter;
import info.nightscout.utils.NSUpload; import info.nightscout.utils.NSUpload;
import info.nightscout.utils.SP; import info.nightscout.utils.SP;
import static info.nightscout.utils.DateUtil.now;
public class TreatmentsBolusFragment extends SubscriberFragment implements View.OnClickListener { public class TreatmentsBolusFragment extends SubscriberFragment implements View.OnClickListener {
private static Logger log = LoggerFactory.getLogger(TreatmentsBolusFragment.class); private static Logger log = LoggerFactory.getLogger(TreatmentsBolusFragment.class);
@ -52,6 +54,7 @@ public class TreatmentsBolusFragment extends SubscriberFragment implements View.
TextView iobTotal; TextView iobTotal;
TextView activityTotal; TextView activityTotal;
Button refreshFromNS; Button refreshFromNS;
Button deleteFutureTreatments;
Context context; Context context;
@ -89,7 +92,7 @@ public class TreatmentsBolusFragment extends SubscriberFragment implements View.
holder.iob.setTextColor(ContextCompat.getColor(MainApp.instance(), R.color.colorActive)); holder.iob.setTextColor(ContextCompat.getColor(MainApp.instance(), R.color.colorActive));
else else
holder.iob.setTextColor(holder.carbs.getCurrentTextColor()); holder.iob.setTextColor(holder.carbs.getCurrentTextColor());
if (t.date > DateUtil.now()) if (t.date > now())
holder.date.setTextColor(ContextCompat.getColor(MainApp.instance(), R.color.colorScheduled)); holder.date.setTextColor(ContextCompat.getColor(MainApp.instance(), R.color.colorScheduled));
else else
holder.date.setTextColor(holder.carbs.getCurrentTextColor()); holder.date.setTextColor(holder.carbs.getCurrentTextColor());
@ -189,6 +192,9 @@ public class TreatmentsBolusFragment extends SubscriberFragment implements View.
refreshFromNS = (Button) view.findViewById(R.id.treatments_reshreshfromnightscout); refreshFromNS = (Button) view.findViewById(R.id.treatments_reshreshfromnightscout);
refreshFromNS.setOnClickListener(this); refreshFromNS.setOnClickListener(this);
deleteFutureTreatments = (Button) view.findViewById(R.id.treatments_delete_future_treatments);
deleteFutureTreatments.setOnClickListener(this);
boolean nsUploadOnly = SP.getBoolean(R.string.key_ns_upload_only, false); boolean nsUploadOnly = SP.getBoolean(R.string.key_ns_upload_only, false);
if (nsUploadOnly) if (nsUploadOnly)
refreshFromNS.setVisibility(View.GONE); refreshFromNS.setVisibility(View.GONE);
@ -201,17 +207,37 @@ public class TreatmentsBolusFragment extends SubscriberFragment implements View.
@Override @Override
public void onClick(View view) { public void onClick(View view) {
AlertDialog.Builder builder;
switch (view.getId()) { switch (view.getId()) {
case R.id.treatments_reshreshfromnightscout: case R.id.treatments_reshreshfromnightscout:
AlertDialog.Builder builder = new AlertDialog.Builder(this.getContext()); builder = new AlertDialog.Builder(this.getContext());
builder.setTitle(MainApp.gs(R.string.confirmation)); builder.setTitle(MainApp.gs(R.string.confirmation));
builder.setMessage(MainApp.gs(R.string.refresheventsfromnightscout) + "?"); builder.setMessage(MainApp.gs(R.string.refresheventsfromnightscout) + "?");
builder.setPositiveButton(MainApp.gs(R.string.ok), new DialogInterface.OnClickListener() { builder.setPositiveButton(MainApp.gs(R.string.ok), (dialog, id) -> {
public void onClick(DialogInterface dialog, int id) {
TreatmentsPlugin.getPlugin().getService().resetTreatments(); TreatmentsPlugin.getPlugin().getService().resetTreatments();
Intent restartNSClient = new Intent(Intents.ACTION_RESTART); Intent restartNSClient = new Intent(Intents.ACTION_RESTART);
MainApp.instance().getApplicationContext().sendBroadcast(restartNSClient); MainApp.instance().getApplicationContext().sendBroadcast(restartNSClient);
});
builder.setNegativeButton(MainApp.gs(R.string.cancel), null);
builder.show();
break;
case R.id.treatments_delete_future_treatments:
builder = new AlertDialog.Builder(this.getContext());
builder.setTitle(MainApp.gs(R.string.confirmation));
builder.setMessage(MainApp.gs(R.string.deletefuturetreatments) + "?");
builder.setPositiveButton(MainApp.gs(R.string.ok), (dialog, id) -> {
final List<Treatment> futureTreatments = TreatmentsPlugin.getPlugin().getService()
.getTreatmentDataFromTime(now() + 1000, true);
for (Treatment treatment : futureTreatments) {
final String _id = treatment._id;
if (NSUpload.isIdValid(_id)) {
NSUpload.removeCareportalEntryFromNS(_id);
} else {
UploadQueue.removeID("dbAdd", _id);
} }
TreatmentsPlugin.getPlugin().getService().delete(treatment);
}
updateGUI();
}); });
builder.setNegativeButton(MainApp.gs(R.string.cancel), null); builder.setNegativeButton(MainApp.gs(R.string.cancel), null);
builder.show(); builder.show();
@ -233,14 +259,16 @@ public class TreatmentsBolusFragment extends SubscriberFragment implements View.
protected void updateGUI() { protected void updateGUI() {
Activity activity = getActivity(); Activity activity = getActivity();
if (activity != null) if (activity != null)
activity.runOnUiThread(new Runnable() { activity.runOnUiThread(() -> {
@Override
public void run() {
recyclerView.swapAdapter(new RecyclerViewAdapter(TreatmentsPlugin.getPlugin().getTreatmentsFromHistory()), false); recyclerView.swapAdapter(new RecyclerViewAdapter(TreatmentsPlugin.getPlugin().getTreatmentsFromHistory()), false);
if (TreatmentsPlugin.getPlugin().getLastCalculationTreatments() != null) { if (TreatmentsPlugin.getPlugin().getLastCalculationTreatments() != null) {
iobTotal.setText(DecimalFormatter.to2Decimal(TreatmentsPlugin.getPlugin().getLastCalculationTreatments().iob) + " U"); iobTotal.setText(DecimalFormatter.to2Decimal(TreatmentsPlugin.getPlugin().getLastCalculationTreatments().iob) + " " + MainApp.gs(R.string.insulin_unit_shortname));
activityTotal.setText(DecimalFormatter.to3Decimal(TreatmentsPlugin.getPlugin().getLastCalculationTreatments().activity) + " U"); activityTotal.setText(DecimalFormatter.to3Decimal(TreatmentsPlugin.getPlugin().getLastCalculationTreatments().activity) + " " + MainApp.gs(R.string.insulin_unit_shortname));
} }
if (!TreatmentsPlugin.getPlugin().getService().getTreatmentDataFromTime(now() + 1000, true).isEmpty()) {
deleteFutureTreatments.setVisibility(View.VISIBLE);
} else {
deleteFutureTreatments.setVisibility(View.GONE);
} }
}); });
} }

View file

@ -107,8 +107,7 @@ public class TreatmentsCareportalFragment extends SubscriberFragment implements
AlertDialog.Builder builder = new AlertDialog.Builder(context); AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle(MainApp.gs(R.string.confirmation)); builder.setTitle(MainApp.gs(R.string.confirmation));
builder.setMessage(MainApp.gs(R.string.removerecord) + "\n" + DateUtil.dateAndTimeString(careportalEvent.date)); builder.setMessage(MainApp.gs(R.string.removerecord) + "\n" + DateUtil.dateAndTimeString(careportalEvent.date));
builder.setPositiveButton(MainApp.gs(R.string.ok), new DialogInterface.OnClickListener() { builder.setPositiveButton(MainApp.gs(R.string.ok), (dialog, id) -> {
public void onClick(DialogInterface dialog, int id) {
final String _id = careportalEvent._id; final String _id = careportalEvent._id;
if (NSUpload.isIdValid(_id)) { if (NSUpload.isIdValid(_id)) {
NSUpload.removeCareportalEntryFromNS(_id); NSUpload.removeCareportalEntryFromNS(_id);
@ -116,7 +115,6 @@ public class TreatmentsCareportalFragment extends SubscriberFragment implements
UploadQueue.removeID("dbAdd", _id); UploadQueue.removeID("dbAdd", _id);
} }
MainApp.getDbHelper().delete(careportalEvent); MainApp.getDbHelper().delete(careportalEvent);
}
}); });
builder.setNegativeButton(MainApp.gs(R.string.cancel), null); builder.setNegativeButton(MainApp.gs(R.string.cancel), null);
builder.show(); builder.show();
@ -136,12 +134,14 @@ public class TreatmentsCareportalFragment extends SubscriberFragment implements
llm = new LinearLayoutManager(view.getContext()); llm = new LinearLayoutManager(view.getContext());
recyclerView.setLayoutManager(llm); recyclerView.setLayoutManager(llm);
RecyclerViewAdapter adapter = new RecyclerViewAdapter(MainApp.getDbHelper().getCareportalEventsFromTime(false)); RecyclerViewAdapter adapter = new RecyclerViewAdapter(MainApp.getDbHelper().getCareportalEvents(false));
recyclerView.setAdapter(adapter); recyclerView.setAdapter(adapter);
refreshFromNS = (Button) view.findViewById(R.id.careportal_refreshfromnightscout); refreshFromNS = (Button) view.findViewById(R.id.careportal_refreshfromnightscout);
refreshFromNS.setOnClickListener(this); refreshFromNS.setOnClickListener(this);
view.findViewById(R.id.careportal_removeandroidapsstartedevents).setOnClickListener(this);
context = getContext(); context = getContext();
boolean nsUploadOnly = SP.getBoolean(R.string.key_ns_upload_only, false); boolean nsUploadOnly = SP.getBoolean(R.string.key_ns_upload_only, false);
@ -169,6 +169,16 @@ public class TreatmentsCareportalFragment extends SubscriberFragment implements
builder.setNegativeButton(MainApp.gs(R.string.cancel), null); builder.setNegativeButton(MainApp.gs(R.string.cancel), null);
builder.show(); builder.show();
break; break;
case R.id.careportal_removeandroidapsstartedevents:
builder = new AlertDialog.Builder(context);
builder.setTitle(MainApp.gs(R.string.confirmation));
builder.setMessage(MainApp.gs(R.string.careportal_removestartedevents));
builder.setPositiveButton(MainApp.gs(R.string.ok), (dialog, id) -> {
removeAndroidAPSStatedEvents();
});
builder.setNegativeButton(MainApp.gs(R.string.cancel), null);
builder.show();
break;
} }
} }
@ -185,8 +195,24 @@ public class TreatmentsCareportalFragment extends SubscriberFragment implements
activity.runOnUiThread(new Runnable() { activity.runOnUiThread(new Runnable() {
@Override @Override
public void run() { public void run() {
recyclerView.swapAdapter(new RecyclerViewAdapter(MainApp.getDbHelper().getCareportalEventsFromTime(false)), false); recyclerView.swapAdapter(new RecyclerViewAdapter(MainApp.getDbHelper().getCareportalEvents(false)), false);
} }
}); });
} }
private void removeAndroidAPSStatedEvents() {
List<CareportalEvent> events = MainApp.getDbHelper().getCareportalEvents(false);
for (int i = 0; i < events.size(); i++) {
CareportalEvent careportalEvent = events.get(i);
if (careportalEvent.json.contains(MainApp.gs(R.string.androidaps_start))) {
final String _id = careportalEvent._id;
if (NSUpload.isIdValid(_id)) {
NSUpload.removeCareportalEntryFromNS(_id);
} else {
UploadQueue.removeID("dbAdd", _id);
}
MainApp.getDbHelper().delete(careportalEvent);
}
}
}
} }

View file

@ -738,6 +738,7 @@ public class WatchUpdaterService extends WearableListenerService implements
public static int getBatteryLevel(Context context) { public static int getBatteryLevel(Context context) {
Intent batteryIntent = context.registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); Intent batteryIntent = context.registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
if (batteryIntent != null) {
int level = batteryIntent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1); int level = batteryIntent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
int scale = batteryIntent.getIntExtra(BatteryManager.EXTRA_SCALE, -1); int scale = batteryIntent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
if (level == -1 || scale == -1) { if (level == -1 || scale == -1) {
@ -745,4 +746,6 @@ public class WatchUpdaterService extends WearableListenerService implements
} }
return (int) (((float) level / (float) scale) * 100.0f); return (int) (((float) level / (float) scale) * 100.0f);
} }
return 50;
}
} }

View file

@ -26,6 +26,7 @@ import info.nightscout.androidaps.plugins.Overview.Dialogs.BolusProgressHelperAc
import info.nightscout.androidaps.plugins.Overview.events.EventDismissNotification; import info.nightscout.androidaps.plugins.Overview.events.EventDismissNotification;
import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification; import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification;
import info.nightscout.androidaps.plugins.Overview.notifications.Notification; import info.nightscout.androidaps.plugins.Overview.notifications.Notification;
import info.nightscout.androidaps.plugins.Treatments.TreatmentsPlugin;
import info.nightscout.androidaps.queue.commands.Command; import info.nightscout.androidaps.queue.commands.Command;
import info.nightscout.androidaps.queue.commands.CommandBolus; import info.nightscout.androidaps.queue.commands.CommandBolus;
import info.nightscout.androidaps.queue.commands.CommandCancelExtendedBolus; import info.nightscout.androidaps.queue.commands.CommandCancelExtendedBolus;
@ -177,6 +178,18 @@ public class CommandQueue {
public synchronized boolean bolus(DetailedBolusInfo detailedBolusInfo, Callback callback) { public synchronized boolean bolus(DetailedBolusInfo detailedBolusInfo, Callback callback) {
Command.CommandType type = detailedBolusInfo.isSMB ? Command.CommandType.SMB_BOLUS : Command.CommandType.BOLUS; Command.CommandType type = detailedBolusInfo.isSMB ? Command.CommandType.SMB_BOLUS : Command.CommandType.BOLUS;
if (type == Command.CommandType.SMB_BOLUS) {
if (isRunning(Command.CommandType.BOLUS) || bolusInQueue()) {
log.debug("Rejecting SMB since a bolus is queue/running");
return false;
}
if (detailedBolusInfo.lastKnownBolusTime < TreatmentsPlugin.getPlugin().getLastBolusTime()) {
log.debug("Rejecting bolus, another bolus was issued since request time");
return false;
}
}
if(type.equals(Command.CommandType.BOLUS) && detailedBolusInfo.carbs > 0 && detailedBolusInfo.insulin == 0){ if(type.equals(Command.CommandType.BOLUS) && detailedBolusInfo.carbs > 0 && detailedBolusInfo.insulin == 0){
type = Command.CommandType.CARBS_ONLY_TREATMENT; type = Command.CommandType.CARBS_ONLY_TREATMENT;
//Carbs only can be added in parallel as they can be "in the future". //Carbs only can be added in parallel as they can be "in the future".

View file

@ -98,13 +98,6 @@ public class SWDefinition {
add(new SWScreen(R.string.nav_setupwizard) add(new SWScreen(R.string.nav_setupwizard)
.add(new SWInfotext() .add(new SWInfotext()
.label(R.string.welcometosetupwizard)) .label(R.string.welcometosetupwizard))
.add(new SWButton()
.text(R.string.nav_import)
.action(() -> ImportExportPrefs.importSharedPreferences(getActivity()))
.visibility(ImportExportPrefs.file::exists))
.add(new SWInfotext()
.label(R.string.backupismissing)
.visibility(() -> !ImportExportPrefs.file.exists()))
) )
.add(new SWScreen(R.string.language) .add(new SWScreen(R.string.language)
.skippable(false) .skippable(false)
@ -169,6 +162,15 @@ public class SWDefinition {
.visibility(() -> Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !AndroidPermission.checkForPermission(getActivity(), Manifest.permission.WRITE_EXTERNAL_STORAGE)) .visibility(() -> Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !AndroidPermission.checkForPermission(getActivity(), Manifest.permission.WRITE_EXTERNAL_STORAGE))
.validator(() -> !(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !AndroidPermission.checkForPermission(getActivity(), Manifest.permission.WRITE_EXTERNAL_STORAGE))) .validator(() -> !(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !AndroidPermission.checkForPermission(getActivity(), Manifest.permission.WRITE_EXTERNAL_STORAGE)))
) )
.add(new SWScreen(R.string.nav_import)
.add(new SWInfotext()
.label(R.string.storedsettingsfound))
.add(new SWBreak())
.add(new SWButton()
.text(R.string.nav_import)
.action(() -> ImportExportPrefs.importSharedPreferences(getActivity())))
.visibility(() -> ImportExportPrefs.file.exists() && !(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !AndroidPermission.checkForPermission(getActivity(), Manifest.permission.WRITE_EXTERNAL_STORAGE)))
)
.add(new SWScreen(R.string.nsclientinternal_title) .add(new SWScreen(R.string.nsclientinternal_title)
.skippable(true) .skippable(true)
.add(new SWInfotext() .add(new SWInfotext()
@ -223,21 +225,14 @@ public class SWDefinition {
) )
.add(new SWScreen(R.string.configbuilder_insulin) .add(new SWScreen(R.string.configbuilder_insulin)
.skippable(false) .skippable(false)
.add(new SWInfotext() .add(new SWPlugin()
.label(MainApp.gs(R.string.rapid_acting_oref) + ": " + MainApp.gs(R.string.fastactinginsulincomment))) .option(PluginType.INSULIN, R.string.configbuilder_insulin_description)
.add(new SWInfotext() .makeVisible(false)
.label(MainApp.gs(R.string.ultrarapid_oref) + ": " + MainApp.gs(R.string.ultrafastactinginsulincomment))) .label(R.string.configbuilder_insulin))
.add(new SWInfotext()
.label(MainApp.gs(R.string.free_peak_oref) + ": " + MainApp.gs(R.string.free_peak_oref_description)))
.add(new SWBreak()) .add(new SWBreak())
.add(new SWInfotext() .add(new SWInfotext()
.label(R.string.diawarning)) .label(R.string.diawarning))
.add(new SWBreak()) .add(new SWBreak())
.add(new SWPlugin()
.option(PluginType.INSULIN)
.makeVisible(false)
.label(R.string.configbuilder_insulin))
.add(new SWBreak())
.add(new SWButton() .add(new SWButton()
.text(R.string.insulinsourcesetup) .text(R.string.insulinsourcesetup)
.action(() -> { .action(() -> {
@ -253,10 +248,8 @@ public class SWDefinition {
) )
.add(new SWScreen(R.string.configbuilder_bgsource) .add(new SWScreen(R.string.configbuilder_bgsource)
.skippable(false) .skippable(false)
.add(new SWInfotext()
.label(R.string.setupwizard_bgsource_description))
.add(new SWPlugin() .add(new SWPlugin()
.option(PluginType.BGSOURCE) .option(PluginType.BGSOURCE, R.string.configbuilder_bgsource_description)
.label(R.string.configbuilder_bgsource)) .label(R.string.configbuilder_bgsource))
.add(new SWBreak()) .add(new SWBreak())
.add(new SWButton() .add(new SWButton()
@ -278,7 +271,7 @@ public class SWDefinition {
.label(R.string.setupwizard_profile_description)) .label(R.string.setupwizard_profile_description))
.add(new SWBreak()) .add(new SWBreak())
.add(new SWPlugin() .add(new SWPlugin()
.option(PluginType.PROFILE) .option(PluginType.PROFILE, R.string.configbuilder_profile_description)
.label(R.string.configbuilder_profile)) .label(R.string.configbuilder_profile))
.validator(() -> MainApp.getConfigBuilder().getActiveProfileInterface() != null) .validator(() -> MainApp.getConfigBuilder().getActiveProfileInterface() != null)
) )
@ -324,8 +317,9 @@ public class SWDefinition {
.add(new SWScreen(R.string.configbuilder_pump) .add(new SWScreen(R.string.configbuilder_pump)
.skippable(false) .skippable(false)
.add(new SWPlugin() .add(new SWPlugin()
.option(PluginType.PUMP) .option(PluginType.PUMP, R.string.configbuilder_pump_description)
.label(R.string.configbuilder_pump)) .label(R.string.configbuilder_pump))
.add(new SWBreak())
.add(new SWButton() .add(new SWButton()
.text(R.string.pumpsetup) .text(R.string.pumpsetup)
.action(() -> { .action(() -> {
@ -360,7 +354,7 @@ public class SWDefinition {
.label("https://openaps.readthedocs.io/en/latest/")) .label("https://openaps.readthedocs.io/en/latest/"))
.add(new SWBreak()) .add(new SWBreak())
.add(new SWPlugin() .add(new SWPlugin()
.option(PluginType.APS) .option(PluginType.APS, R.string.configbuilder_aps_description)
.label(R.string.configbuilder_aps)) .label(R.string.configbuilder_aps))
.add(new SWButton() .add(new SWButton()
.text(R.string.apssetup) .text(R.string.apssetup)
@ -402,7 +396,7 @@ public class SWDefinition {
.label(R.string.setupwizard_sensitivity_url)) .label(R.string.setupwizard_sensitivity_url))
.add(new SWBreak()) .add(new SWBreak())
.add(new SWPlugin() .add(new SWPlugin()
.option(PluginType.SENSITIVITY) .option(PluginType.SENSITIVITY, R.string.configbuilder_sensitivity_description)
.label(R.string.configbuilder_sensitivity)) .label(R.string.configbuilder_sensitivity))
.add(new SWBreak()) .add(new SWBreak())
.add(new SWButton() .add(new SWButton()
@ -454,13 +448,6 @@ public class SWDefinition {
add(new SWScreen(R.string.nav_setupwizard) add(new SWScreen(R.string.nav_setupwizard)
.add(new SWInfotext() .add(new SWInfotext()
.label(R.string.welcometosetupwizard)) .label(R.string.welcometosetupwizard))
.add(new SWButton()
.text(R.string.nav_import)
.action(() -> ImportExportPrefs.importSharedPreferences(getActivity()))
.visibility(ImportExportPrefs.file::exists))
.add(new SWInfotext()
.label(R.string.backupismissing)
.visibility(() -> !ImportExportPrefs.file.exists()))
) )
.add(new SWScreen(R.string.language) .add(new SWScreen(R.string.language)
.skippable(false) .skippable(false)
@ -513,6 +500,15 @@ public class SWDefinition {
.visibility(() -> Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !AndroidPermission.checkForPermission(getActivity(), Manifest.permission.WRITE_EXTERNAL_STORAGE)) .visibility(() -> Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !AndroidPermission.checkForPermission(getActivity(), Manifest.permission.WRITE_EXTERNAL_STORAGE))
.validator(() -> !(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !AndroidPermission.checkForPermission(getActivity(), Manifest.permission.WRITE_EXTERNAL_STORAGE))) .validator(() -> !(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !AndroidPermission.checkForPermission(getActivity(), Manifest.permission.WRITE_EXTERNAL_STORAGE)))
) )
.add(new SWScreen(R.string.nav_import)
.add(new SWInfotext()
.label(R.string.storedsettingsfound))
.add(new SWBreak())
.add(new SWButton()
.text(R.string.nav_import)
.action(() -> ImportExportPrefs.importSharedPreferences(getActivity())))
.visibility(() -> ImportExportPrefs.file.exists() && !(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !AndroidPermission.checkForPermission(getActivity(), Manifest.permission.WRITE_EXTERNAL_STORAGE)))
)
.add(new SWScreen(R.string.nsclientinternal_title) .add(new SWScreen(R.string.nsclientinternal_title)
.skippable(true) .skippable(true)
.add(new SWInfotext() .add(new SWInfotext()
@ -567,21 +563,14 @@ public class SWDefinition {
) )
.add(new SWScreen(R.string.configbuilder_insulin) .add(new SWScreen(R.string.configbuilder_insulin)
.skippable(false) .skippable(false)
.add(new SWInfotext() .add(new SWPlugin()
.label(MainApp.gs(R.string.rapid_acting_oref) + ": " + MainApp.gs(R.string.fastactinginsulincomment))) .option(PluginType.INSULIN, R.string.configbuilder_insulin_description)
.add(new SWInfotext() .makeVisible(false)
.label(MainApp.gs(R.string.ultrarapid_oref) + ": " + MainApp.gs(R.string.ultrafastactinginsulincomment))) .label(R.string.configbuilder_insulin))
.add(new SWInfotext()
.label(MainApp.gs(R.string.free_peak_oref) + ": " + MainApp.gs(R.string.free_peak_oref_description)))
.add(new SWBreak()) .add(new SWBreak())
.add(new SWInfotext() .add(new SWInfotext()
.label(R.string.diawarning)) .label(R.string.diawarning))
.add(new SWBreak()) .add(new SWBreak())
.add(new SWPlugin()
.option(PluginType.INSULIN)
.makeVisible(false)
.label(R.string.configbuilder_insulin))
.add(new SWBreak())
.add(new SWButton() .add(new SWButton()
.text(R.string.insulinsourcesetup) .text(R.string.insulinsourcesetup)
.action(() -> { .action(() -> {
@ -603,7 +592,7 @@ public class SWDefinition {
.label(R.string.setupwizard_sensitivity_url)) .label(R.string.setupwizard_sensitivity_url))
.add(new SWBreak()) .add(new SWBreak())
.add(new SWPlugin() .add(new SWPlugin()
.option(PluginType.SENSITIVITY) .option(PluginType.SENSITIVITY, R.string.configbuilder_sensitivity_description)
.label(R.string.configbuilder_sensitivity)) .label(R.string.configbuilder_sensitivity))
.add(new SWBreak()) .add(new SWBreak())
.add(new SWButton() .add(new SWButton()

View file

@ -46,11 +46,11 @@ public class SWEventListener extends SWItem {
} }
@Override @Override
public void generateDialog(View view, LinearLayout layout) { public void generateDialog(LinearLayout layout) {
Context context = view.getContext(); Context context = layout.getContext();
textView = new TextView(context); textView = new TextView(context);
textView.setId(view.generateViewId()); textView.setId(layout.generateViewId());
textView.setText((textLabel != 0 ? MainApp.gs(textLabel) : "") + " " + status); textView.setText((textLabel != 0 ? MainApp.gs(textLabel) : "") + " " + status);
layout.addView(textView); layout.addView(textView);
if (listener != null) if (listener != null)

View file

@ -129,7 +129,7 @@ public class SetupWizardActivity extends AppCompatActivity {
LinearLayout layout = SWItem.generateLayout(this.findViewById(R.id.sw_content_fields)); LinearLayout layout = SWItem.generateLayout(this.findViewById(R.id.sw_content_fields));
for (int i = 0; i < currentScreen.items.size(); i++) { for (int i = 0; i < currentScreen.items.size(); i++) {
SWItem currentItem = currentScreen.items.get(i); SWItem currentItem = currentScreen.items.get(i);
currentItem.generateDialog(this.findViewById(R.id.sw_content_fields), layout); currentItem.generateDialog(layout);
} }
scrollView.smoothScrollTo(0,0); scrollView.smoothScrollTo(0,0);
} }

View file

@ -27,8 +27,8 @@ public class SWBreak extends SWItem {
} }
@Override @Override
public void generateDialog(View view, LinearLayout layout) { public void generateDialog(LinearLayout layout) {
Context context = view.getContext(); Context context = layout.getContext();
l = new TextView(context); l = new TextView(context);
l.setId(View.generateViewId()); l.setId(View.generateViewId());

View file

@ -39,8 +39,8 @@ public class SWButton extends SWItem {
} }
@Override @Override
public void generateDialog(View view, LinearLayout layout) { public void generateDialog(LinearLayout layout) {
Context context = view.getContext(); Context context = layout.getContext();
button = new Button(context); button = new Button(context);
button.setText(buttonText); button.setText(buttonText);
@ -50,7 +50,7 @@ public class SWButton extends SWItem {
}); });
processVisibility(); processVisibility();
layout.addView(button); layout.addView(button);
super.generateDialog(view, layout); super.generateDialog(layout);
} }
@Override @Override

View file

@ -40,8 +40,8 @@ public class SWCheckbox extends SWItem {
} }
@Override @Override
public void generateDialog(View view, LinearLayout layout) { public void generateDialog(LinearLayout layout) {
Context context = view.getContext(); Context context = layout.getContext();
// Get if there is already value in SP // Get if there is already value in SP
Boolean previousValue; Boolean previousValue;
previousValue = SP.getBoolean(preferenceId, false); previousValue = SP.getBoolean(preferenceId, false);
@ -68,7 +68,7 @@ public class SWCheckbox extends SWItem {
} }
}); });
layout.addView(checkBox); layout.addView(checkBox);
super.generateDialog(view, layout); super.generateDialog(layout);
} }
public void save(boolean value){ public void save(boolean value){
SP.putBoolean(preferenceID, value); SP.putBoolean(preferenceID, value);

View file

@ -27,28 +27,28 @@ public class SWEditString extends SWItem {
} }
@Override @Override
public void generateDialog(View view, LinearLayout layout) { public void generateDialog(LinearLayout layout) {
Context context = view.getContext(); Context context = layout.getContext();
TextView l = new TextView(context); TextView l = new TextView(context);
l.setId(view.generateViewId()); l.setId(layout.generateViewId());
l.setText(label); l.setText(label);
l.setTypeface(l.getTypeface(), Typeface.BOLD); l.setTypeface(l.getTypeface(), Typeface.BOLD);
layout.addView(l); layout.addView(l);
TextView c = new TextView(context); TextView c = new TextView(context);
c.setId(view.generateViewId()); c.setId(layout.generateViewId());
c.setText(comment); c.setText(comment);
c.setTypeface(c.getTypeface(), Typeface.ITALIC); c.setTypeface(c.getTypeface(), Typeface.ITALIC);
layout.addView(c); layout.addView(c);
EditText editText = new EditText(context); EditText editText = new EditText(context);
editText.setId(view.generateViewId()); editText.setId(layout.generateViewId());
editText.setInputType(InputType.TYPE_CLASS_TEXT); editText.setInputType(InputType.TYPE_CLASS_TEXT);
editText.setMaxLines(1); editText.setMaxLines(1);
editText.setText(SP.getString(preferenceId, "")); editText.setText(SP.getString(preferenceId, ""));
layout.addView(editText); layout.addView(editText);
super.generateDialog(view, layout); super.generateDialog(layout);
editText.addTextChangedListener(new TextWatcher() { editText.addTextChangedListener(new TextWatcher() {
@Override @Override

View file

@ -27,8 +27,8 @@ public class SWEditUrl extends SWItem {
} }
@Override @Override
public void generateDialog(View view, LinearLayout layout) { public void generateDialog(LinearLayout layout) {
Context context = view.getContext(); Context context = layout.getContext();
TextView l = new TextView(context); TextView l = new TextView(context);
l.setId(View.generateViewId()); l.setId(View.generateViewId());
@ -48,7 +48,7 @@ public class SWEditUrl extends SWItem {
editText.setMaxLines(1); editText.setMaxLines(1);
editText.setText(SP.getString(preferenceId, "")); editText.setText(SP.getString(preferenceId, ""));
layout.addView(editText); layout.addView(editText);
super.generateDialog(view, layout); super.generateDialog(layout);
editText.addTextChangedListener(new TextWatcher() { editText.addTextChangedListener(new TextWatcher() {
@Override @Override

View file

@ -27,7 +27,7 @@ public class SWFragment extends SWItem {
} }
@Override @Override
public void generateDialog(View view, LinearLayout layout) { public void generateDialog(LinearLayout layout) {
definition.getActivity().getSupportFragmentManager().beginTransaction().add(layout.getId(), fragment, fragment.getTag()).commit(); definition.getActivity().getSupportFragmentManager().beginTransaction().add(layout.getId(), fragment, fragment.getTag()).commit();
} }

View file

@ -39,8 +39,8 @@ public class SWHtmlLink extends SWItem {
} }
@Override @Override
public void generateDialog(View view, LinearLayout layout) { public void generateDialog(LinearLayout layout) {
Context context = view.getContext(); Context context = layout.getContext();
l = new TextView(context); l = new TextView(context);
l.setId(View.generateViewId()); l.setId(View.generateViewId());

View file

@ -38,8 +38,8 @@ public class SWInfotext extends SWItem {
} }
@Override @Override
public void generateDialog(View view, LinearLayout layout) { public void generateDialog(LinearLayout layout) {
Context context = view.getContext(); Context context = layout.getContext();
l = new TextView(context); l = new TextView(context);
l.setId(View.generateViewId()); l.setId(View.generateViewId());

View file

@ -78,7 +78,7 @@ public class SWItem {
return layout; return layout;
} }
public void generateDialog(View view, LinearLayout layout) { public void generateDialog(LinearLayout layout) {
} }
public void processVisibility() { public void processVisibility() {

View file

@ -2,9 +2,11 @@ package info.nightscout.androidaps.setupwizard.elements;
import android.content.Context; import android.content.Context;
import android.view.View; import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.RadioButton; import android.widget.RadioButton;
import android.widget.RadioGroup; import android.widget.RadioGroup;
import android.widget.TextView;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -24,6 +26,7 @@ public class SWPlugin extends SWItem {
private PluginType pType; private PluginType pType;
private RadioGroup radioGroup; private RadioGroup radioGroup;
private int pluginDescription;
private boolean makeVisible = true; private boolean makeVisible = true;
@ -31,8 +34,9 @@ public class SWPlugin extends SWItem {
super(Type.PLUGIN); super(Type.PLUGIN);
} }
public SWPlugin option(PluginType pType) { public SWPlugin option(PluginType pType, int pluginDescription) {
this.pType = pType; this.pType = pType;
this.pluginDescription = pluginDescription;
return this; return this;
} }
@ -42,8 +46,9 @@ public class SWPlugin extends SWItem {
} }
@Override @Override
public void generateDialog(View view, LinearLayout layout) { public void generateDialog(LinearLayout layout) {
Context context = view.getContext();
Context context = layout.getContext();
radioGroup = new RadioGroup(context); radioGroup = new RadioGroup(context);
radioGroup.clearCheck(); radioGroup.clearCheck();
@ -52,6 +57,13 @@ public class SWPlugin extends SWItem {
radioGroup.setOrientation(LinearLayout.VERTICAL); radioGroup.setOrientation(LinearLayout.VERTICAL);
radioGroup.setVisibility(View.VISIBLE); radioGroup.setVisibility(View.VISIBLE);
TextView pdesc = new TextView(context);
pdesc.setText(pluginDescription);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
params.setMargins(0, 0, 0, 40);
pdesc.setLayoutParams(params);
layout.addView(pdesc);
for (int i = 0; i < pluginsInCategory.size(); i++) { for (int i = 0; i < pluginsInCategory.size(); i++) {
RadioButton rdbtn = new RadioButton(context); RadioButton rdbtn = new RadioButton(context);
PluginBase p = pluginsInCategory.get(i); PluginBase p = pluginsInCategory.get(i);
@ -61,6 +73,12 @@ public class SWPlugin extends SWItem {
rdbtn.setChecked(true); rdbtn.setChecked(true);
rdbtn.setTag(p); rdbtn.setTag(p);
radioGroup.addView(rdbtn); radioGroup.addView(rdbtn);
params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
params.setMargins(80, 0, 0, 0);
TextView desc = new TextView(context);
desc.setText(p.getDescription());
desc.setLayoutParams(params);
radioGroup.addView(desc);
} }
radioGroup.setOnCheckedChangeListener((group, checkedId) -> { radioGroup.setOnCheckedChangeListener((group, checkedId) -> {
@ -74,6 +92,6 @@ public class SWPlugin extends SWItem {
MainApp.bus().post(new EventSWUpdate()); MainApp.bus().post(new EventSWUpdate());
}); });
layout.addView(radioGroup); layout.addView(radioGroup);
super.generateDialog(view, layout); super.generateDialog(layout);
} }
} }

View file

@ -38,8 +38,8 @@ public class SWRadioButton extends SWItem {
} }
@Override @Override
public void generateDialog(View view, LinearLayout layout) { public void generateDialog(LinearLayout layout) {
Context context = view.getContext(); Context context = layout.getContext();
// Get if there is already value in SP // Get if there is already value in SP
String previousValue = SP.getString(preferenceId, "none"); String previousValue = SP.getString(preferenceId, "none");
radioGroup = new RadioGroup(context); radioGroup = new RadioGroup(context);
@ -62,7 +62,7 @@ public class SWRadioButton extends SWItem {
save(values()[i]); save(values()[i]);
}); });
layout.addView(radioGroup); layout.addView(radioGroup);
super.generateDialog(view, layout); super.generateDialog(layout);
} }
public SWRadioButton preferenceId(int preferenceId) { public SWRadioButton preferenceId(int preferenceId) {

View file

@ -135,6 +135,11 @@ public class DateUtil {
return MainApp.gs(R.string.minago, mins); return MainApp.gs(R.string.minago, mins);
} }
public static String minAgoShort(long time) {
Integer mins = (int) ((time - now()) / 1000 / 60);
return (mins > 0 ? "+" : "") + mins.toString();
}
public static String hourAgo(long time) { public static String hourAgo(long time) {
double hours = (now() - time) / 1000d / 60 / 60; double hours = (now() - time) / 1000d / 60 / 60;
return MainApp.gs(R.string.hoursago, hours); return MainApp.gs(R.string.hoursago, hours);

View file

@ -8,14 +8,23 @@ import java.util.regex.Pattern;
*/ */
public class PercentageSplitter { public class PercentageSplitter {
// "Profile name (200%,2h)"
private static final Pattern percentagePattern = Pattern.compile("(.+)\\(\\d+%,\\d+h\\)");
// "Profile name (200%)"
private static final Pattern percentageShiftPattern = Pattern.compile("(.+)\\(\\d+%\\)");
/** Removes the suffix for percentage and timeshift from a profile name. */
public static String pureName(String name) { public static String pureName(String name) {
String newName = name; Matcher percentageMatch = percentagePattern.matcher(name);
String s = "(.*)\\((\\d+)\\%\\)"; if (percentageMatch.find()) {
Pattern r = Pattern.compile(s); return percentageMatch.group(1).trim();
Matcher m = r.matcher(name);
if (m.find()) {
newName = m.group(1);
} }
return newName;
Matcher percentageShiftMatch = percentageShiftPattern.matcher(name);
if (percentageShiftMatch.find()) {
return percentageShiftMatch.group(1).trim();
}
return name;
} }
} }

View file

@ -0,0 +1,20 @@
package info.nightscout.utils;
/**
* class contains useful String functions
*/
public class StringUtils {
private StringUtils() {
// this constructor is private, since this class should not get instantiated
}
public static String removeSurroundingQuotes(String string) {
if (string.length() >= 2 && string.charAt(0) == '"'
&& string.charAt(string.length() - 1) == '"') {
string = string.substring(1, string.length() - 1);
}
return string;
}
}

View file

@ -18,420 +18,10 @@
android:layout_height="match_parent"> android:layout_height="match_parent">
<LinearLayout <LinearLayout
android:id="@+id/categories"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical" android:orientation="vertical"
android:padding="16dp"> android:padding="16dp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/configbuilder_profile"
android:textColor="@color/colorAccent"
android:textSize="16sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/configbuilder_profile_description"
android:textColor="@color/colorAccent"
android:textSize="12sp" />
</LinearLayout>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="4dp"
app:srcCompat="@drawable/ic_visibility" />
</LinearLayout>
<LinearLayout
android:id="@+id/profile_plugins"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" />
<LinearLayout
android:layout_marginTop="16dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/configbuilder_insulin"
android:textColor="@color/colorAccent"
android:textSize="16sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/configbuilder_insulin_description"
android:textColor="@color/colorAccent"
android:textSize="12sp" />
</LinearLayout>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="4dp"
app:srcCompat="@drawable/ic_visibility" />
</LinearLayout>
<LinearLayout
android:id="@+id/insulin_plugins"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" />
<LinearLayout
android:layout_marginTop="16dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/configbuilder_bgsource"
android:textColor="@color/colorAccent"
android:textSize="16sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/configbuilder_bgsource_description"
android:textColor="@color/colorAccent"
android:textSize="12sp" />
</LinearLayout>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="4dp"
app:srcCompat="@drawable/ic_visibility" />
</LinearLayout>
<LinearLayout
android:id="@+id/bgsource_plugins"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" />
<LinearLayout
android:layout_marginTop="16dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/configbuilder_pump"
android:textColor="@color/colorAccent"
android:textSize="16sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/configbuilder_pump_description"
android:textColor="@color/colorAccent"
android:textSize="12sp" />
</LinearLayout>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="4dp"
app:srcCompat="@drawable/ic_visibility" />
</LinearLayout>
<LinearLayout
android:id="@+id/pump_plugins"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" />
<LinearLayout
android:layout_marginTop="16dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/configbuilder_sensitivity"
android:textColor="@color/colorAccent"
android:textSize="16sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/configbuilder_sensitivity_description"
android:textColor="@color/colorAccent"
android:textSize="12sp" />
</LinearLayout>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="4dp"
app:srcCompat="@drawable/ic_visibility" />
</LinearLayout>
<LinearLayout
android:id="@+id/sensitivity_plugins"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" />
<LinearLayout
android:layout_marginTop="16dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/configbuilder_aps"
android:textColor="@color/colorAccent"
android:textSize="16sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/configbuilder_aps_description"
android:textColor="@color/colorAccent"
android:textSize="12sp" />
</LinearLayout>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="4dp"
app:srcCompat="@drawable/ic_visibility" />
</LinearLayout>
<LinearLayout
android:id="@+id/aps_plugins"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" />
<LinearLayout
android:layout_marginTop="16dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/configbuilder_loop"
android:textColor="@color/colorAccent"
android:textSize="16sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/configbuilder_loop_description"
android:textColor="@color/colorAccent"
android:textSize="12sp" />
</LinearLayout>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="4dp"
app:srcCompat="@drawable/ic_visibility" />
</LinearLayout>
<LinearLayout
android:id="@+id/loop_plugins"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" />
<LinearLayout
android:layout_marginTop="16dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/constraints"
android:textColor="@color/colorAccent"
android:textSize="16sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/configbuilder_constraints_description"
android:textColor="@color/colorAccent"
android:textSize="12sp" />
</LinearLayout>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="4dp"
app:srcCompat="@drawable/ic_visibility" />
</LinearLayout>
<LinearLayout
android:id="@+id/constraints_plugins"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" />
<LinearLayout
android:layout_marginTop="16dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/configbuilder_treatments"
android:textColor="@color/colorAccent"
android:textSize="16sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/configbuilder_treatments_description"
android:textColor="@color/colorAccent"
android:textSize="12sp" />
</LinearLayout>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="4dp"
app:srcCompat="@drawable/ic_visibility" />
</LinearLayout>
<LinearLayout
android:id="@+id/treatments_plugins"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" />
<LinearLayout
android:layout_marginTop="16dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/configbuilder_general"
android:textColor="@color/colorAccent"
android:textSize="16sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/configbuilder_general_description"
android:textColor="@color/colorAccent"
android:textSize="12sp" />
</LinearLayout>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="4dp"
app:srcCompat="@drawable/ic_visibility" />
</LinearLayout>
<LinearLayout
android:id="@+id/general_plugins"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" />
</LinearLayout>
</ScrollView> </ScrollView>
</LinearLayout> </LinearLayout>

View file

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:id="@+id/category_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/colorAccent"
android:textSize="16sp" />
<TextView
android:id="@+id/category_description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/colorAccent"
android:textSize="12sp" />
</LinearLayout>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="4dp"
app:srcCompat="@drawable/ic_visibility" />
</LinearLayout>
<LinearLayout
android:id="@+id/category_plugins"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" />
</LinearLayout>

View file

@ -1,46 +1,41 @@
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:paddingTop="2dp" android:orientation="vertical"
tools:context=".plugins.ConstraintsObjectives.ObjectivesFragment"> tools:context=".plugins.ConstraintsObjectives.ObjectivesFragment">
<LinearLayout <LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:id="@+id/objectives_fake_layout" android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:paddingTop="16dp"
android:visibility="gone"> android:visibility="gone">
<CheckBox <CheckBox
android:layout_width="wrap_content" android:id="@+id/objectives_fake"
android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="Enable fake time and progress" android:layout_marginRight="16dp"
android:id="@+id/objectives_fake" /> android:layout_weight="1"
android:text="Enable fake time and progress" />
<TextView <Button
android:id="@+id/objectives_reset"
style="@style/Widget.AppCompat.Button.Borderless.Colored"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="Reset" android:text="Reset" />
android:id="@+id/objectives_reset"
android:textColor="#fef900"
android:gravity="right"
android:layout_weight="0.5"
android:layout_marginRight="10dp" />
</LinearLayout> </LinearLayout>
<android.support.v7.widget.RecyclerView <android.support.v7.widget.RecyclerView
android:id="@+id/objectives_recyclerview" android:id="@+id/objectives_recyclerview"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="0dp"
android:layout_weight="1"
</android.support.v7.widget.RecyclerView> android:clipToPadding="false"
</LinearLayout> android:paddingBottom="16dp" />
</LinearLayout>
</FrameLayout>

View file

@ -1,162 +1,70 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android" <android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/objectives_cardview" xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/objective_cardview"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center" android:layout_gravity="center"
card_view:cardBackgroundColor="@color/cardColorBackground" android:layout_marginLeft="16dp"
card_view:cardCornerRadius="6dp" android:layout_marginRight="16dp"
card_view:cardUseCompatPadding="true" android:layout_marginTop="16dp"
card_view:contentPadding="6dp"> app:cardBackgroundColor="@color/colorPrimary"
app:cardCornerRadius="2dp"
app:cardUseCompatPadding="true"
app:contentPadding="16dp">
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical"> android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal">
<TextView <TextView
android:id="@+id/objectives_position" android:id="@+id/objective_title"
android:layout_width="30dp"
android:layout_height="30dp"
android:background="@drawable/circle"
android:gravity="center"
android:shadowRadius="10.0"
android:text="1"
android:textColor="@color/cardObjectiveText"
android:textSize="18sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:baselineAligned="true"
android:orientation="horizontal">
<TextView
android:id="@+id/objectives_objective_label"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="top" android:fontFamily="sans-serif-medium"
android:paddingRight="10dp" android:textColor="#FFFFFF"
android:text="@string/objectives_objective_label_string" android:textSize="20sp"
android:textAppearance="?android:attr/textAppearanceLarge" tools:text="1. Title" />
android:textColor="@color/cardObjectiveText"
android:textStyle="bold" />
<TextView <TextView
android:id="@+id/objectives_objective" android:id="@+id/objective_objective"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center_vertical" android:layout_marginTop="8dp"
android:maxLines="4" android:textColor="#FFFFFF"
android:minLines="1" tools:text="Objective" />
android:text=""
android:textColor="@color/cardObjectiveText"
android:textStyle="bold" />
<TextView
</LinearLayout> android:id="@+id/objective_gate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:textColor="#FFFFFF"
android:textStyle="bold"
tools:text="Gate" />
<LinearLayout <LinearLayout
android:id="@+id/objective_progress"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:id="@+id/objectives_gate_linearlayout">
<TextView
android:id="@+id/objectives_gate_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="top" android:layout_marginTop="8dp"
android:paddingRight="10dp" android:orientation="vertical" />
android:text="@string/objectives_gate_label_string"
android:textAppearance="?android:attr/textAppearanceLarge" />
<TextView
android:id="@+id/objectives_gate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:maxLines="4"
android:minLines="1"
android:text="" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:id="@+id/objectives_start_linearlayout">
<Button <Button
android:id="@+id/objectives_start" android:id="@+id/objective_verify"
style="?android:attr/buttonStyle" style="@style/Widget.AppCompat.Button.Borderless.Colored"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/objectives_button_start" />
<TextView
android:id="@+id/objectives_started"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/objectives_duration_linearlayout">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/objectives_duration" />
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/objectives_progresslayout">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/objectives_progress" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:id="@+id/objectives_verify_linearlayout">
<Button
android:id="@+id/objectives_verify"
style="?android:attr/buttonStyle"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/objectives_button_verify" /> android:text="@string/objectives_button_verify" />
<TextView <Button
android:id="@+id/objectives_accomplished" android:id="@+id/objective_start"
style="@style/Widget.AppCompat.Button.Borderless.Colored"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" /> android:layout_height="wrap_content"
android:text="@string/objectives_button_start" />
</LinearLayout>
</LinearLayout> </LinearLayout>
</android.support.v7.widget.CardView> </android.support.v7.widget.CardView>

View file

@ -62,9 +62,9 @@
android:layout_gravity="right" android:layout_gravity="right"
android:layout_weight="1" android:layout_weight="1"
android:gravity="center_vertical|center_horizontal" android:gravity="center_vertical|center_horizontal"
android:text="TempTarget"
android:paddingBottom="3dp" android:paddingBottom="3dp"
android:paddingTop="3dp" android:paddingTop="3dp"
android:text="TempTarget"
android:textAppearance="?android:attr/textAppearanceSmall" android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="@color/mdtp_white" /> android:textColor="@color/mdtp_white" />
@ -83,9 +83,9 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_marginLeft="5dp" android:layout_marginLeft="5dp"
android:layout_marginRight="5dp" android:layout_marginRight="5dp"
android:gravity="center_vertical|center_horizontal"
android:paddingBottom="3dp" android:paddingBottom="3dp"
android:paddingTop="3dp" android:paddingTop="3dp"
android:gravity="center_vertical|center_horizontal"
android:text="@string/initializing" android:text="@string/initializing"
android:textAppearance="?android:attr/textAppearanceSmall" /> android:textAppearance="?android:attr/textAppearanceSmall" />
</LinearLayout> </LinearLayout>
@ -100,77 +100,61 @@
android:id="@+id/overview_bg" android:id="@+id/overview_bg"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="top|left" android:layout_gravity="center_vertical"
android:gravity="center_vertical"
android:text="00.0" android:text="00.0"
android:textSize="70dp" android:textSize="40dp"
android:textStyle="bold" /> android:textStyle="bold" />
<TextView <TextView
android:id="@+id/overview_arrow" android:id="@+id/overview_arrow"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="top|left" android:layout_gravity="center_vertical"
android:layout_marginTop="-15dp" android:layout_marginTop="-15dp"
android:gravity="center_vertical"
android:paddingLeft="-5dp" android:paddingLeft="-5dp"
android:paddingRight="-5dp" android:paddingRight="-5dp"
android:text="→" android:text="→"
android:textSize="70dp" android:textSize="20dp"
android:textStyle="bold" /> android:textStyle="bold" />
<LinearLayout <TextView
android:id="@+id/overview_deltashort"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="top" android:layout_gravity="center_vertical"
android:layout_marginTop="10dp" android:text="-0.5"
android:layout_weight="1" android:textSize="20sp"
android:gravity="top" android:textStyle="bold" />
android:orientation="vertical">
<TextView <TextView
android:id="@+id/overview_timeago" android:id="@+id/overview_sensitivity"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_weight="0.5"
android:textAppearance="?android:attr/textAppearanceMedium" />
<TextView
android:id="@+id/overview_delta"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_weight="0.5"
android:textAppearance="?android:attr/textAppearanceMedium" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical"> android:layout_gravity="center_vertical"
android:layout_weight="0.5"
android:gravity="center_vertical|center_horizontal"
android:text="100%"
android:textSize="20sp"
android:textStyle="bold" />
<TextView <TextView
android:id="@+id/overview_time" android:id="@+id/overview_time"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="fill_vertical" android:layout_gravity="center_vertical"
android:layout_marginTop="10dp"
android:maxWidth="150dp"
android:paddingLeft="10dp"
android:text="8:00 PM" android:text="8:00 PM"
android:textSize="30sp" android:textSize="30sp"
android:textStyle="bold" /> android:textStyle="bold" />
<CheckBox <TextView
android:id="@+id/overview_lockscreen" android:id="@+id/overview_timeagoshort"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/lock_screen_short" android:layout_gravity="center_vertical"
android:textAlignment="center" /> android:gravity="center_vertical"
</LinearLayout> android:text="(-5)"
android:textSize="20sp"
android:textStyle="bold" />
</LinearLayout> </LinearLayout>
@ -519,8 +503,8 @@
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:paddingRight="5dp" android:orientation="horizontal"
android:orientation="horizontal"> android:paddingRight="5dp">
<info.nightscout.utils.SingleClickButton <info.nightscout.utils.SingleClickButton
android:id="@+id/overview_treatmentbutton" android:id="@+id/overview_treatmentbutton"

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