- more kotlinize, MedtronicHistoryActivity not yet working

This commit is contained in:
Andy Rozman 2021-04-20 16:45:29 +01:00
parent a202178426
commit 6b7efdcb95
16 changed files with 2016 additions and 2615 deletions

View file

@ -111,7 +111,7 @@ android {
defaultConfig { defaultConfig {
multiDexEnabled true multiDexEnabled true
versionCode 1500 versionCode 1500
version "2.8.2.1-dev-e3" version "2.8.2.1-meallink-mdt"
buildConfigField "String", "VERSION", '"' + version + '"' buildConfigField "String", "VERSION", '"' + version + '"'
buildConfigField "String", "BUILDVERSION", '"' + generateGitBuild() + '-' + generateDate() + '"' buildConfigField "String", "BUILDVERSION", '"' + generateGitBuild() + '-' + generateDate() + '"'
buildConfigField "String", "REMOTE", '"' + generateGitRemote() + '"' buildConfigField "String", "REMOTE", '"' + generateGitRemote() + '"'

View file

@ -1,529 +0,0 @@
package info.nightscout.androidaps.plugins.pump.common;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import androidx.annotation.NonNull;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.HashMap;
import java.util.Map;
import dagger.android.HasAndroidInjector;
import info.nightscout.androidaps.core.R;
import info.nightscout.androidaps.data.DetailedBolusInfo;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.data.PumpEnactResult;
import info.nightscout.androidaps.db.TemporaryBasal;
import info.nightscout.androidaps.events.EventAppExit;
import info.nightscout.androidaps.events.EventCustomActionsChanged;
import info.nightscout.androidaps.extensions.PumpStateExtensionKt;
import info.nightscout.androidaps.interfaces.ActivePlugin;
import info.nightscout.androidaps.interfaces.CommandQueueProvider;
import info.nightscout.androidaps.interfaces.Constraints;
import info.nightscout.androidaps.interfaces.PluginDescription;
import info.nightscout.androidaps.interfaces.PumpDescription;
import info.nightscout.androidaps.interfaces.Pump;
import info.nightscout.androidaps.interfaces.PumpPluginBase;
import info.nightscout.androidaps.interfaces.PumpSync;
import info.nightscout.androidaps.logging.AAPSLogger;
import info.nightscout.androidaps.logging.LTag;
import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
import info.nightscout.androidaps.plugins.common.ManufacturerType;
import info.nightscout.androidaps.plugins.general.overview.events.EventOverviewBolusProgress;
import info.nightscout.androidaps.plugins.pump.common.data.PumpDbEntry;
import info.nightscout.androidaps.plugins.pump.common.data.PumpStatus;
import info.nightscout.androidaps.plugins.pump.common.defs.PumpDriverState;
import info.nightscout.androidaps.plugins.pump.common.defs.PumpType;
import info.nightscout.androidaps.plugins.pump.medtronic.util.MedtronicConst;
import info.nightscout.androidaps.utils.DateUtil;
import info.nightscout.androidaps.utils.DecimalFormatter;
import info.nightscout.androidaps.utils.FabricPrivacy;
import info.nightscout.androidaps.utils.resources.ResourceHelper;
import info.nightscout.androidaps.utils.rx.AapsSchedulers;
import info.nightscout.androidaps.utils.sharedPreferences.SP;
import io.reactivex.disposables.CompositeDisposable;
import static info.nightscout.androidaps.extensions.PumpStateExtensionKt.convertedToAbsolute;
import static info.nightscout.androidaps.extensions.PumpStateExtensionKt.getPlannedRemainingMinutes;
/**
* Created by andy on 23.04.18.
*/
// When using this class, make sure that your first step is to create mConnection (see MedtronicPumpPlugin)
public abstract class PumpPluginAbstract extends PumpPluginBase implements Pump, Constraints {
private final CompositeDisposable disposable = new CompositeDisposable();
protected HasAndroidInjector injector;
protected AAPSLogger aapsLogger;
protected RxBusWrapper rxBus;
protected ActivePlugin activePlugin;
protected Context context;
protected FabricPrivacy fabricPrivacy;
protected ResourceHelper resourceHelper;
protected CommandQueueProvider commandQueue;
protected SP sp;
protected DateUtil dateUtil;
protected PumpDescription pumpDescription = new PumpDescription();
protected ServiceConnection serviceConnection;
protected boolean serviceRunning = false;
protected PumpDriverState pumpState = PumpDriverState.NotInitialized;
protected boolean displayConnectionMessages = false;
protected PumpType pumpType;
protected AapsSchedulers aapsSchedulers;
protected PumpSync pumpSync;
protected Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
protected PumpPluginAbstract(
PluginDescription pluginDescription,
PumpType pumpType,
HasAndroidInjector injector,
ResourceHelper resourceHelper,
AAPSLogger aapsLogger,
CommandQueueProvider commandQueue,
RxBusWrapper rxBus,
ActivePlugin activePlugin,
SP sp,
Context context,
FabricPrivacy fabricPrivacy,
DateUtil dateUtil,
AapsSchedulers aapsSchedulers,
PumpSync pumpSync
) {
super(pluginDescription, injector, aapsLogger, resourceHelper, commandQueue);
this.aapsLogger = aapsLogger;
this.rxBus = rxBus;
this.activePlugin = activePlugin;
this.context = context;
this.fabricPrivacy = fabricPrivacy;
this.resourceHelper = resourceHelper;
this.sp = sp;
this.commandQueue = commandQueue;
pumpDescription.setPumpDescription(pumpType);
this.pumpType = pumpType;
this.dateUtil = dateUtil;
this.aapsSchedulers = aapsSchedulers;
this.pumpSync = pumpSync;
}
public abstract void initPumpStatusData();
@Override
protected void onStart() {
super.onStart();
initPumpStatusData();
Intent intent = new Intent(context, getServiceClass());
context.bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
serviceRunning = true;
disposable.add(rxBus
.toObservable(EventAppExit.class)
.observeOn(aapsSchedulers.getIo())
.subscribe(event -> context.unbindService(serviceConnection), fabricPrivacy::logException)
);
onStartCustomActions();
}
@Override
protected void onStop() {
aapsLogger.debug(LTag.PUMP, this.deviceID() + " onStop()");
context.unbindService(serviceConnection);
serviceRunning = false;
disposable.clear();
super.onStop();
}
/**
* If we need to run any custom actions in onStart (triggering events, etc)
*/
public abstract void onStartCustomActions();
/**
* Service class (same one you did serviceConnection for)
*
* @return Class
*/
public abstract Class getServiceClass();
public abstract PumpStatus getPumpStatusData();
public boolean isInitialized() {
return pumpState.isInitialized();
}
public boolean isSuspended() {
return pumpState == PumpDriverState.Suspended;
}
public boolean isBusy() {
return pumpState == PumpDriverState.Busy;
}
public boolean isConnected() {
if (displayConnectionMessages)
aapsLogger.debug(LTag.PUMP, "isConnected [PumpPluginAbstract].");
return pumpState.isConnected();
}
public boolean isConnecting() {
if (displayConnectionMessages)
aapsLogger.debug(LTag.PUMP, "isConnecting [PumpPluginAbstract].");
return pumpState == PumpDriverState.Connecting;
}
public void connect(@NonNull String reason) {
if (displayConnectionMessages)
aapsLogger.debug(LTag.PUMP, "connect (reason={}) [PumpPluginAbstract] - default (empty) implementation." + reason);
}
public void disconnect(@NonNull String reason) {
if (displayConnectionMessages)
aapsLogger.debug(LTag.PUMP, "disconnect (reason={}) [PumpPluginAbstract] - default (empty) implementation." + reason);
}
public void stopConnecting() {
if (displayConnectionMessages)
aapsLogger.debug(LTag.PUMP, "stopConnecting [PumpPluginAbstract] - default (empty) implementation.");
}
@Override
public boolean isHandshakeInProgress() {
if (displayConnectionMessages)
aapsLogger.debug(LTag.PUMP, "isHandshakeInProgress [PumpPluginAbstract] - default (empty) implementation.");
return false;
}
@Override
public void finishHandshaking() {
if (displayConnectionMessages)
aapsLogger.debug(LTag.PUMP, "finishHandshaking [PumpPluginAbstract] - default (empty) implementation.");
}
// Upload to pump new basal profile
@NonNull public PumpEnactResult setNewBasalProfile(@NonNull Profile profile) {
aapsLogger.debug(LTag.PUMP, "setNewBasalProfile [PumpPluginAbstract] - Not implemented.");
return getOperationNotSupportedWithCustomText(R.string.pump_operation_not_supported_by_pump_driver);
}
public boolean isThisProfileSet(@NonNull Profile profile) {
aapsLogger.debug(LTag.PUMP, "isThisProfileSet [PumpPluginAbstract] - Not implemented.");
return true;
}
public long lastDataTime() {
aapsLogger.debug(LTag.PUMP, "lastDataTime [PumpPluginAbstract].");
return getPumpStatusData().getLastConnection();
}
public double getBaseBasalRate() {
aapsLogger.debug(LTag.PUMP, "getBaseBasalRate [PumpPluginAbstract] - Not implemented.");
return 0.0d;
} // base basal rate, not temp basal
public void stopBolusDelivering() {
aapsLogger.debug(LTag.PUMP, "stopBolusDelivering [PumpPluginAbstract] - Not implemented.");
}
@NonNull @Override
public PumpEnactResult setTempBasalAbsolute(double absoluteRate, int durationInMinutes, @NonNull Profile profile, boolean enforceNew, @NonNull PumpSync.TemporaryBasalType tbrType) {
aapsLogger.debug(LTag.PUMP, "setTempBasalAbsolute [PumpPluginAbstract] - Not implemented.");
return getOperationNotSupportedWithCustomText(R.string.pump_operation_not_supported_by_pump_driver);
}
@NonNull @Override
public PumpEnactResult setTempBasalPercent(int percent, int durationInMinutes, @NonNull Profile profile, boolean enforceNew, @NonNull PumpSync.TemporaryBasalType tbrType) {
aapsLogger.debug(LTag.PUMP, "setTempBasalPercent [PumpPluginAbstract] - Not implemented.");
return getOperationNotSupportedWithCustomText(R.string.pump_operation_not_supported_by_pump_driver);
}
@NonNull public PumpEnactResult setExtendedBolus(double insulin, int durationInMinutes) {
aapsLogger.debug(LTag.PUMP, "setExtendedBolus [PumpPluginAbstract] - Not implemented.");
return getOperationNotSupportedWithCustomText(R.string.pump_operation_not_supported_by_pump_driver);
}
// some pumps might set a very short temp close to 100% as cancelling a temp can be noisy
// when the cancel request is requested by the user (forced), the pump should always do a real cancel
@NonNull public PumpEnactResult cancelTempBasal(boolean enforceNew) {
aapsLogger.debug(LTag.PUMP, "cancelTempBasal [PumpPluginAbstract] - Not implemented.");
return getOperationNotSupportedWithCustomText(R.string.pump_operation_not_supported_by_pump_driver);
}
@NonNull public PumpEnactResult cancelExtendedBolus() {
aapsLogger.debug(LTag.PUMP, "cancelExtendedBolus [PumpPluginAbstract] - Not implemented.");
return getOperationNotSupportedWithCustomText(R.string.pump_operation_not_supported_by_pump_driver);
}
// Status to be passed to NS
// public JSONObject getJSONStatus(Profile profile, String profileName) {
// return pumpDriver.getJSONStatus(profile, profileName);
// }
public String deviceID() {
aapsLogger.debug(LTag.PUMP, "deviceID [PumpPluginAbstract] - Not implemented.");
return "FakeDevice";
}
// Pump capabilities
public PumpDescription getPumpDescription() {
return pumpDescription;
}
// Short info for SMS, Wear etc
public boolean isFakingTempsByExtendedBoluses() {
aapsLogger.debug(LTag.PUMP, "isFakingTempsByExtendedBoluses [PumpPluginAbstract] - Not implemented.");
return false;
}
@NonNull @Override
public PumpEnactResult loadTDDs() {
aapsLogger.debug(LTag.PUMP, "loadTDDs [PumpPluginAbstract] - Not implemented.");
return getOperationNotSupportedWithCustomText(R.string.pump_operation_not_supported_by_pump_driver);
}
@NonNull @Override
public JSONObject getJSONStatus(@NonNull Profile profile, @NonNull String profileName, @NonNull String version) {
if ((getPumpStatusData().getLastConnection() + 60 * 60 * 1000L) < System.currentTimeMillis()) {
return new JSONObject();
}
long now = System.currentTimeMillis();
JSONObject pump = new JSONObject();
JSONObject battery = new JSONObject();
JSONObject status = new JSONObject();
JSONObject extended = new JSONObject();
try {
battery.put("percent", getPumpStatusData().getBatteryRemaining());
status.put("status", getPumpStatusData().getPumpStatusType() != null ? getPumpStatusData().getPumpStatusType().getStatus() : "normal");
extended.put("Version", version);
try {
extended.put("ActiveProfile", profileName);
} catch (Exception ignored) {
}
PumpSync.PumpState.TemporaryBasal tb = pumpSync.expectedPumpState().getTemporaryBasal();
if (tb != null) {
extended.put("TempBasalAbsoluteRate", convertedToAbsolute(tb, now, profile));
extended.put("TempBasalStart", dateUtil.dateAndTimeString(tb.getTimestamp()));
extended.put("TempBasalRemaining", getPlannedRemainingMinutes(tb));
}
PumpSync.PumpState.ExtendedBolus eb = pumpSync.expectedPumpState().getExtendedBolus();
if (eb != null) {
extended.put("ExtendedBolusAbsoluteRate", eb.getRate());
extended.put("ExtendedBolusStart", dateUtil.dateAndTimeString(eb.getTimestamp()));
extended.put("ExtendedBolusRemaining", getPlannedRemainingMinutes(eb));
}
status.put("timestamp", dateUtil.toISOString(dateUtil.now()));
pump.put("battery", battery);
pump.put("status", status);
pump.put("extended", extended);
pump.put("reservoir", getPumpStatusData().getReservoirRemainingUnits());
pump.put("clock", dateUtil.toISOString(dateUtil.now()));
} catch (JSONException e) {
aapsLogger.error("Unhandled exception", e);
}
return pump;
}
// FIXME i18n, null checks: iob, TDD
@NonNull @Override
public String shortStatus(boolean veryShort) {
String ret = "";
if (getPumpStatusData().getLastConnection() != 0) {
long agoMsec = System.currentTimeMillis() - getPumpStatusData().getLastConnection();
int agoMin = (int) (agoMsec / 60d / 1000d);
ret += "LastConn: " + agoMin + " min ago\n";
}
if (getPumpStatusData().getLastBolusTime() != null && getPumpStatusData().getLastBolusTime().getTime() != 0) {
ret += "LastBolus: " + DecimalFormatter.INSTANCE.to2Decimal(getPumpStatusData().getLastBolusAmount()) + "U @" + //
android.text.format.DateFormat.format("HH:mm", getPumpStatusData().getLastBolusTime()) + "\n";
}
PumpSync.PumpState.TemporaryBasal activeTemp = pumpSync.expectedPumpState().getTemporaryBasal();
if (activeTemp != null) {
ret += "Temp: " + PumpStateExtensionKt.toStringFull(activeTemp, dateUtil) + "\n";
}
PumpSync.PumpState.ExtendedBolus activeExtendedBolus = pumpSync.expectedPumpState().getExtendedBolus();
if (activeExtendedBolus != null) {
ret += "Extended: " + PumpStateExtensionKt.toStringFull(activeExtendedBolus, dateUtil) + "\n";
}
// if (!veryShort) {
// ret += "TDD: " + DecimalFormatter.to0Decimal(pumpStatus.dailyTotalUnits) + " / "
// + pumpStatus.maxDailyTotalUnits + " U\n";
// }
ret += "IOB: " + getPumpStatusData().getIob() + "U\n";
ret += "Reserv: " + DecimalFormatter.INSTANCE.to0Decimal(getPumpStatusData().getReservoirRemainingUnits()) + "U\n";
ret += "Batt: " + getPumpStatusData().getBatteryRemaining() + "\n";
return ret;
}
@NonNull @Override
public PumpEnactResult deliverTreatment(DetailedBolusInfo detailedBolusInfo) {
try {
if (detailedBolusInfo.insulin == 0 && detailedBolusInfo.carbs == 0) {
// neither carbs nor bolus requested
aapsLogger.error("deliverTreatment: Invalid input");
return new PumpEnactResult(getInjector()).success(false).enacted(false).bolusDelivered(0d).carbsDelivered(0d)
.comment(R.string.invalidinput);
} else if (detailedBolusInfo.insulin > 0) {
// bolus needed, ask pump to deliver it
return deliverBolus(detailedBolusInfo);
} else {
//if (MedtronicHistoryData.doubleBolusDebug)
// aapsLogger.debug("DoubleBolusDebug: deliverTreatment::(carb only entry)");
// TODO fix
// no bolus required, carb only treatment
activePlugin.getActiveTreatments().addToHistoryTreatment(detailedBolusInfo, true);
EventOverviewBolusProgress bolusingEvent = EventOverviewBolusProgress.INSTANCE;
bolusingEvent.setT(new EventOverviewBolusProgress.Treatment(0, 0, detailedBolusInfo.getBolusType() == DetailedBolusInfo.BolusType.SMB));
bolusingEvent.setPercent(100);
rxBus.send(bolusingEvent);
aapsLogger.debug(LTag.PUMP, "deliverTreatment: Carb only treatment.");
return new PumpEnactResult(getInjector()).success(true).enacted(true).bolusDelivered(0d)
.carbsDelivered(detailedBolusInfo.carbs).comment(R.string.common_resultok);
}
} finally {
triggerUIChange();
}
}
protected void refreshCustomActionsList() {
rxBus.send(new EventCustomActionsChanged());
}
@NonNull public ManufacturerType manufacturer() {
return pumpType.getManufacturer();
}
@NonNull
public PumpType model() {
return pumpType;
}
public PumpType getPumpType() {
return pumpType;
}
public void setPumpType(PumpType pumpType) {
this.pumpType = pumpType;
this.pumpDescription.setPumpDescription(pumpType);
}
public boolean canHandleDST() {
return false;
}
protected abstract PumpEnactResult deliverBolus(DetailedBolusInfo detailedBolusInfo);
protected abstract void triggerUIChange();
private PumpEnactResult getOperationNotSupportedWithCustomText(int resourceId) {
return new PumpEnactResult(getInjector()).success(false).enacted(false).comment(resourceId);
}
// PumpSync
Map<Long, PumpDbEntry> driverHistory = new HashMap<>();
public abstract long generateTempId(long timeMillis);
protected boolean addBolusWithTempId(DetailedBolusInfo detailedBolusInfo, boolean writeToInternalHistory) {
long temporaryId = generateTempId(detailedBolusInfo.timestamp);
boolean response = pumpSync.addBolusWithTempId(detailedBolusInfo.timestamp, detailedBolusInfo.insulin,
temporaryId, detailedBolusInfo.getBolusType(),
getPumpType(), serialNumber());
if (response && writeToInternalHistory) {
driverHistory.put(temporaryId, new PumpDbEntry(temporaryId, model(), serialNumber(), detailedBolusInfo));
sp.putString(MedtronicConst.Statistics.InternalTemporaryDatabase, gson.toJson(driverHistory));
}
return response;
}
protected void addTemporaryBasalRateWithTempId(TemporaryBasal temporaryBasal, boolean b) {
// long temporaryId = generateTempId(temporaryBasal.timestamp);
// boolean response = pumpSync.addBolusWithTempId(temporaryBasal.timestamp, detailedBolusInfo.insulin,
// generateTempId(detailedBolusInfo.timestamp), detailedBolusInfo.getBolusType(),
// getPumpType(), serialNumber());
//
// if (response && writeToInternalHistory) {
// driverHistory.put(temporaryId, new PumpDbEntry(temporaryId, model(), serialNumber(), detailedBolusInfo));
// sp.putString(MedtronicConst.Statistics.InternalTemporaryDatabase, gson.toJson(driverHistory));
// }
//
// return response;
}
public void removeTemporaryId(long temporaryId) {
driverHistory.remove(temporaryId);
}
}

View file

@ -0,0 +1,431 @@
package info.nightscout.androidaps.plugins.pump.common
import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.text.format.DateFormat
import com.google.gson.GsonBuilder
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.core.R
import info.nightscout.androidaps.data.DetailedBolusInfo
import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.data.PumpEnactResult
import info.nightscout.androidaps.db.TemporaryBasal
import info.nightscout.androidaps.events.EventAppExit
import info.nightscout.androidaps.events.EventCustomActionsChanged
import info.nightscout.androidaps.extensions.convertedToAbsolute
import info.nightscout.androidaps.extensions.plannedRemainingMinutes
import info.nightscout.androidaps.extensions.toStringFull
import info.nightscout.androidaps.interfaces.*
import info.nightscout.androidaps.interfaces.PumpSync.TemporaryBasalType
import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.common.ManufacturerType
import info.nightscout.androidaps.plugins.general.overview.events.EventOverviewBolusProgress
import info.nightscout.androidaps.plugins.pump.common.data.PumpDbEntry
import info.nightscout.androidaps.plugins.pump.common.data.PumpStatus
import info.nightscout.androidaps.plugins.pump.common.defs.PumpDriverState
import info.nightscout.androidaps.plugins.pump.common.defs.PumpType
import info.nightscout.androidaps.plugins.pump.medtronic.util.MedtronicConst
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.DecimalFormatter.to0Decimal
import info.nightscout.androidaps.utils.DecimalFormatter.to2Decimal
import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.androidaps.utils.sharedPreferences.SP
import io.reactivex.disposables.CompositeDisposable
import org.json.JSONException
import org.json.JSONObject
import java.util.*
/**
* Created by andy on 23.04.18.
*/
// When using this class, make sure that your first step is to create mConnection (see MedtronicPumpPlugin)
abstract class PumpPluginAbstract protected constructor(
pluginDescription: PluginDescription?,
pumpType: PumpType,
injector: HasAndroidInjector?,
resourceHelper: ResourceHelper,
aapsLogger: AAPSLogger,
commandQueue: CommandQueueProvider,
var rxBus: RxBusWrapper,
var activePlugin: ActivePlugin,
var sp: SP,
var context: Context,
var fabricPrivacy: FabricPrivacy,
dateUtil: DateUtil,
aapsSchedulers: AapsSchedulers,
pumpSync: PumpSync
) : PumpPluginBase(pluginDescription!!, injector!!, aapsLogger, resourceHelper, commandQueue), Pump, Constraints {
private val disposable = CompositeDisposable()
//protected override var injector: HasAndroidInjector? = null
protected var dateUtil: DateUtil
// Pump capabilities
final override var pumpDescription = PumpDescription()
//protected set
@JvmField protected var serviceConnection: ServiceConnection? = null
@JvmField protected var serviceRunning = false
@JvmField protected var pumpState = PumpDriverState.NotInitialized
@JvmField protected var displayConnectionMessages = false
var pumpType: PumpType? = null
get() = field
set(value) {
field = value
pumpDescription.setPumpDescription(value!!)
}
protected var aapsSchedulers: AapsSchedulers
protected var pumpSync: PumpSync
protected var gson = GsonBuilder().excludeFieldsWithoutExposeAnnotation().create()
abstract fun initPumpStatusData()
override fun onStart() {
super.onStart()
initPumpStatusData()
val intent = Intent(context, serviceClass)
context.bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE)
serviceRunning = true
disposable.add(rxBus
.toObservable(EventAppExit::class.java)
.observeOn(aapsSchedulers.io)
.subscribe({ event: EventAppExit? -> context.unbindService(serviceConnection) }) { throwable: Throwable? -> fabricPrivacy.logException(throwable!!) }
)
onStartCustomActions()
}
override fun onStop() {
aapsLogger.debug(LTag.PUMP, deviceID() + " onStop()")
context.unbindService(serviceConnection)
serviceRunning = false
disposable.clear()
super.onStop()
}
/**
* If we need to run any custom actions in onStart (triggering events, etc)
*/
abstract fun onStartCustomActions()
/**
* Service class (same one you did serviceConnection for)
*
* @return Class
*/
abstract val serviceClass: Class<*>?
abstract val pumpStatusData: PumpStatus
override fun isInitialized(): Boolean {
return pumpState.isInitialized()
}
override fun isSuspended(): Boolean {
return pumpState === PumpDriverState.Suspended
}
override fun isBusy(): Boolean {
return pumpState === PumpDriverState.Busy
}
override fun isConnected(): Boolean {
if (displayConnectionMessages) aapsLogger.debug(LTag.PUMP, "isConnected [PumpPluginAbstract].")
return pumpState.isConnected()
}
override fun isConnecting(): Boolean {
if (displayConnectionMessages) aapsLogger.debug(LTag.PUMP, "isConnecting [PumpPluginAbstract].")
return pumpState === PumpDriverState.Connecting
}
override fun connect(reason: String) {
if (displayConnectionMessages) aapsLogger.debug(LTag.PUMP, "connect (reason={}) [PumpPluginAbstract] - default (empty) implementation.$reason")
}
override fun disconnect(reason: String) {
if (displayConnectionMessages) aapsLogger.debug(LTag.PUMP, "disconnect (reason={}) [PumpPluginAbstract] - default (empty) implementation.$reason")
}
override fun stopConnecting() {
if (displayConnectionMessages) aapsLogger.debug(LTag.PUMP, "stopConnecting [PumpPluginAbstract] - default (empty) implementation.")
}
override fun isHandshakeInProgress(): Boolean {
if (displayConnectionMessages) aapsLogger.debug(LTag.PUMP, "isHandshakeInProgress [PumpPluginAbstract] - default (empty) implementation.")
return false
}
override fun finishHandshaking() {
if (displayConnectionMessages) aapsLogger.debug(LTag.PUMP, "finishHandshaking [PumpPluginAbstract] - default (empty) implementation.")
}
// Upload to pump new basal profile
override fun setNewBasalProfile(profile: Profile): PumpEnactResult {
aapsLogger.debug(LTag.PUMP, "setNewBasalProfile [PumpPluginAbstract] - Not implemented.")
return getOperationNotSupportedWithCustomText(R.string.pump_operation_not_supported_by_pump_driver)
}
override fun isThisProfileSet(profile: Profile): Boolean {
aapsLogger.debug(LTag.PUMP, "isThisProfileSet [PumpPluginAbstract] - Not implemented.")
return true
}
override fun lastDataTime(): Long {
aapsLogger.debug(LTag.PUMP, "lastDataTime [PumpPluginAbstract].")
return pumpStatusData.lastConnection
}
// base basal rate, not temp basal
override val baseBasalRate: Double
get() {
aapsLogger.debug(LTag.PUMP, "getBaseBasalRate [PumpPluginAbstract] - Not implemented.")
return 0.0
}
override fun stopBolusDelivering() {
aapsLogger.debug(LTag.PUMP, "stopBolusDelivering [PumpPluginAbstract] - Not implemented.")
}
override fun setTempBasalAbsolute(absoluteRate: Double, durationInMinutes: Int, profile: Profile, enforceNew: Boolean, tbrType: TemporaryBasalType): PumpEnactResult {
aapsLogger.debug(LTag.PUMP, "setTempBasalAbsolute [PumpPluginAbstract] - Not implemented.")
return getOperationNotSupportedWithCustomText(R.string.pump_operation_not_supported_by_pump_driver)
}
override fun setTempBasalPercent(percent: Int, durationInMinutes: Int, profile: Profile, enforceNew: Boolean, tbrType: TemporaryBasalType): PumpEnactResult {
aapsLogger.debug(LTag.PUMP, "setTempBasalPercent [PumpPluginAbstract] - Not implemented.")
return getOperationNotSupportedWithCustomText(R.string.pump_operation_not_supported_by_pump_driver)
}
override fun setExtendedBolus(insulin: Double, durationInMinutes: Int): PumpEnactResult {
aapsLogger.debug(LTag.PUMP, "setExtendedBolus [PumpPluginAbstract] - Not implemented.")
return getOperationNotSupportedWithCustomText(R.string.pump_operation_not_supported_by_pump_driver)
}
// some pumps might set a very short temp close to 100% as cancelling a temp can be noisy
// when the cancel request is requested by the user (forced), the pump should always do a real cancel
override fun cancelTempBasal(enforceNew: Boolean): PumpEnactResult {
aapsLogger.debug(LTag.PUMP, "cancelTempBasal [PumpPluginAbstract] - Not implemented.")
return getOperationNotSupportedWithCustomText(R.string.pump_operation_not_supported_by_pump_driver)
}
override fun cancelExtendedBolus(): PumpEnactResult {
aapsLogger.debug(LTag.PUMP, "cancelExtendedBolus [PumpPluginAbstract] - Not implemented.")
return getOperationNotSupportedWithCustomText(R.string.pump_operation_not_supported_by_pump_driver)
}
// Status to be passed to NS
// public JSONObject getJSONStatus(Profile profile, String profileName) {
// return pumpDriver.getJSONStatus(profile, profileName);
// }
open fun deviceID(): String {
aapsLogger.debug(LTag.PUMP, "deviceID [PumpPluginAbstract] - Not implemented.")
return "FakeDevice"
}
// Short info for SMS, Wear etc
override val isFakingTempsByExtendedBoluses: Boolean
get() {
aapsLogger.debug(LTag.PUMP, "isFakingTempsByExtendedBoluses [PumpPluginAbstract] - Not implemented.")
return false
}
override fun loadTDDs(): PumpEnactResult {
aapsLogger.debug(LTag.PUMP, "loadTDDs [PumpPluginAbstract] - Not implemented.")
return getOperationNotSupportedWithCustomText(R.string.pump_operation_not_supported_by_pump_driver)
}
override fun getJSONStatus(profile: Profile, profileName: String, version: String): JSONObject {
if (pumpStatusData.lastConnection + 60 * 60 * 1000L < System.currentTimeMillis()) {
return JSONObject()
}
val now = System.currentTimeMillis()
val pump = JSONObject()
val battery = JSONObject()
val status = JSONObject()
val extended = JSONObject()
try {
battery.put("percent", pumpStatusData.batteryRemaining)
status.put("status", if (pumpStatusData.pumpStatusType != null) pumpStatusData.pumpStatusType.status else "normal")
extended.put("Version", version)
try {
extended.put("ActiveProfile", profileName)
} catch (ignored: Exception) {
}
val tb = pumpSync.expectedPumpState().temporaryBasal
if (tb != null) {
extended.put("TempBasalAbsoluteRate", tb.convertedToAbsolute(now, profile))
extended.put("TempBasalStart", dateUtil.dateAndTimeString(tb.timestamp))
extended.put("TempBasalRemaining", tb.plannedRemainingMinutes)
}
val eb = pumpSync.expectedPumpState().extendedBolus
if (eb != null) {
extended.put("ExtendedBolusAbsoluteRate", eb.rate)
extended.put("ExtendedBolusStart", dateUtil.dateAndTimeString(eb.timestamp))
extended.put("ExtendedBolusRemaining", eb.plannedRemainingMinutes)
}
status.put("timestamp", dateUtil.toISOString(dateUtil.now()))
pump.put("battery", battery)
pump.put("status", status)
pump.put("extended", extended)
pump.put("reservoir", pumpStatusData.reservoirRemainingUnits)
pump.put("clock", dateUtil.toISOString(dateUtil.now()))
} catch (e: JSONException) {
aapsLogger.error("Unhandled exception", e)
}
return pump
}
// FIXME i18n, null checks: iob, TDD
override fun shortStatus(veryShort: Boolean): String {
var ret = ""
if (pumpStatusData.lastConnection==0L) {
ret += "LastConn: never\n"
} else {
val agoMsec = System.currentTimeMillis() - pumpStatusData.lastConnection
val agoMin = (agoMsec / 60.0 / 1000.0).toInt()
ret += "LastConn: $agoMin min ago\n"
}
if (pumpStatusData.lastBolusTime != null && pumpStatusData.lastBolusTime!!.time != 0L) {
ret += """
LastBolus: ${to2Decimal(pumpStatusData.lastBolusAmount!!)}U @${DateFormat.format("HH:mm", pumpStatusData.lastBolusTime)}
""".trimIndent()
}
val activeTemp = pumpSync.expectedPumpState().temporaryBasal
if (activeTemp != null) {
ret += """
Temp: ${activeTemp.toStringFull(dateUtil)}
""".trimIndent()
}
val activeExtendedBolus = pumpSync.expectedPumpState().extendedBolus
if (activeExtendedBolus != null) {
ret += """
Extended: ${activeExtendedBolus.toStringFull(dateUtil)}
""".trimIndent()
}
// if (!veryShort) {
// ret += "TDD: " + DecimalFormatter.to0Decimal(pumpStatus.dailyTotalUnits) + " / "
// + pumpStatus.maxDailyTotalUnits + " U\n";
// }
ret += """
IOB: ${pumpStatusData.iob}U
""".trimIndent()
ret += """
Reserv: ${to0Decimal(pumpStatusData.reservoirRemainingUnits)}U
""".trimIndent()
ret += """
Batt: ${pumpStatusData.batteryRemaining}
""".trimIndent()
return ret
}
override fun deliverTreatment(detailedBolusInfo: DetailedBolusInfo): PumpEnactResult {
return try {
if (detailedBolusInfo.insulin == 0.0 && detailedBolusInfo.carbs == 0.0) {
// neither carbs nor bolus requested
aapsLogger.error("deliverTreatment: Invalid input")
PumpEnactResult(injector).success(false).enacted(false).bolusDelivered(0.0).carbsDelivered(0.0)
.comment(R.string.invalidinput)
} else if (detailedBolusInfo.insulin > 0) {
// bolus needed, ask pump to deliver it
deliverBolus(detailedBolusInfo)
} else {
// TODO fix
// no bolus required, carb only treatment
activePlugin.activeTreatments.addToHistoryTreatment(detailedBolusInfo, true)
val bolusingEvent = EventOverviewBolusProgress
bolusingEvent.t = EventOverviewBolusProgress.Treatment(0.0, 0, detailedBolusInfo.bolusType === DetailedBolusInfo.BolusType.SMB)
bolusingEvent.percent = 100
rxBus.send(bolusingEvent)
aapsLogger.debug(LTag.PUMP, "deliverTreatment: Carb only treatment.")
PumpEnactResult(injector).success(true).enacted(true).bolusDelivered(0.0)
.carbsDelivered(detailedBolusInfo.carbs).comment(R.string.common_resultok)
}
} finally {
triggerUIChange()
}
}
protected fun refreshCustomActionsList() {
rxBus.send(EventCustomActionsChanged())
}
override fun manufacturer(): ManufacturerType {
return pumpType!!.manufacturer!!
}
override fun model(): PumpType {
return pumpType!!
}
override fun canHandleDST(): Boolean {
return false
}
protected abstract fun deliverBolus(detailedBolusInfo: DetailedBolusInfo?): PumpEnactResult
protected abstract fun triggerUIChange()
private fun getOperationNotSupportedWithCustomText(resourceId: Int): PumpEnactResult {
return PumpEnactResult(injector).success(false).enacted(false).comment(resourceId)
}
// PumpSync
var driverHistory: MutableMap<Long, PumpDbEntry> = HashMap()
abstract fun generateTempId(timeMillis: Long): Long
protected fun addBolusWithTempId(detailedBolusInfo: DetailedBolusInfo, writeToInternalHistory: Boolean): Boolean {
val temporaryId = generateTempId(detailedBolusInfo.timestamp)
val response = pumpSync.addBolusWithTempId(detailedBolusInfo.timestamp, detailedBolusInfo.insulin,
temporaryId, detailedBolusInfo.bolusType,
pumpType!!, serialNumber())
if (response && writeToInternalHistory) {
driverHistory[temporaryId] = PumpDbEntry(temporaryId, model(), serialNumber(), detailedBolusInfo)
sp.putString(MedtronicConst.Statistics.InternalTemporaryDatabase, gson.toJson(driverHistory))
}
return response
}
protected fun addTemporaryBasalRateWithTempId(temporaryBasal: TemporaryBasal?, b: Boolean) {
// long temporaryId = generateTempId(temporaryBasal.timestamp);
// boolean response = pumpSync.addBolusWithTempId(temporaryBasal.timestamp, detailedBolusInfo.insulin,
// generateTempId(detailedBolusInfo.timestamp), detailedBolusInfo.getBolusType(),
// getPumpType(), serialNumber());
//
// if (response && writeToInternalHistory) {
// driverHistory.put(temporaryId, new PumpDbEntry(temporaryId, model(), serialNumber(), detailedBolusInfo));
// sp.putString(MedtronicConst.Statistics.InternalTemporaryDatabase, gson.toJson(driverHistory));
// }
//
// return response;
}
fun removeTemporaryId(temporaryId: Long) {
driverHistory.remove(temporaryId)
}
init {
pumpDescription.setPumpDescription(pumpType)
this.pumpType = pumpType
this.dateUtil = dateUtil
this.aapsSchedulers = aapsSchedulers
this.pumpSync = pumpSync
}
}

View file

@ -1,21 +0,0 @@
package info.nightscout.androidaps.plugins.pump.common.data;
import info.nightscout.androidaps.data.DetailedBolusInfo;
import info.nightscout.androidaps.plugins.pump.common.defs.PumpType;
public class PumpDbEntry {
long temporaryId;
PumpType pumpType;
String serialNumber;
DetailedBolusInfo detailedBolusInfo;
public PumpDbEntry(long temporaryId, PumpType pumpType, String serialNumber, DetailedBolusInfo detailedBolusInfo) {
this.temporaryId = temporaryId;
this.pumpType = pumpType;
this.serialNumber = serialNumber;
this.detailedBolusInfo = detailedBolusInfo;
}
}

View file

@ -0,0 +1,9 @@
package info.nightscout.androidaps.plugins.pump.common.data
import info.nightscout.androidaps.data.DetailedBolusInfo
import info.nightscout.androidaps.plugins.pump.common.defs.PumpType
data class PumpDbEntry(var temporaryId: Long,
var pumpType: PumpType,
var serialNumber: String,
var detailedBolusInfo: DetailedBolusInfo)

View file

@ -599,6 +599,44 @@ public class MedtronicCommunicationManager extends RileyLinkCommunicationManager
} }
private <T> T sendAndGetResponseWithCheck(MedtronicCommandType commandType, byte[] bodyData, Class<T> clazz) {
aapsLogger.debug(LTag.PUMPCOMM, "getDataFromPump: " + commandType);
for (int retries = 0; retries < MAX_COMMAND_TRIES; retries++) {
try {
PumpMessage response = sendAndGetResponse(commandType, bodyData, DEFAULT_TIMEOUT + (DEFAULT_TIMEOUT * retries));
String check = checkResponseContent(response, commandType.getCommandDescription(), commandType.getExpectedLength());
if (check == null) {
T dataResponse = (T)medtronicConverter.convertResponse(medtronicPumpPlugin.getPumpDescription().getPumpType(), commandType, response.getRawContent());
if (dataResponse != null) {
this.errorMessage = null;
aapsLogger.debug(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "Converted response for %s is %s.", commandType.name(), dataResponse));
return dataResponse;
} else {
this.errorMessage = "Error decoding response.";
}
} else {
this.errorMessage = check;
// return null;
}
} catch (RileyLinkCommunicationException e) {
aapsLogger.warn(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "Error getting response from RileyLink (error=%s, retry=%d)", e.getMessage(), retries + 1));
}
}
return null;
}
private String checkResponseContent(PumpMessage response, String method, int expectedLength) { private String checkResponseContent(PumpMessage response, String method, int expectedLength) {
if (!response.isValid()) { if (!response.isValid()) {

View file

@ -32,7 +32,8 @@ class BasalProfile {
private val aapsLogger: AAPSLogger private val aapsLogger: AAPSLogger
@Expose var rawData : ByteArray? = null // store as byte array to make transport (via parcel) easier @Expose
lateinit var rawData : ByteArray // store as byte array to make transport (via parcel) easier
private set private set
private var listEntries: MutableList<BasalProfileEntry>? = null private var listEntries: MutableList<BasalProfileEntry>? = null
@ -48,14 +49,11 @@ class BasalProfile {
} }
fun init() { fun init() {
rawData = ByteArray(MAX_RAW_DATA_SIZE) rawData = byteArrayOf(0,0,0x3f)
rawData!![0] = 0
rawData!![1] = 0
rawData!![2] = 0x3f
} }
private fun setRawData(data: ByteArray): Boolean { private fun setRawData(data: ByteArray): Boolean {
var dataInternal: ByteArray? = data var dataInternal: ByteArray = data
if (dataInternal == null) { if (dataInternal == null) {
aapsLogger.error(LTag.PUMPCOMM, "setRawData: buffer is null!") aapsLogger.error(LTag.PUMPCOMM, "setRawData: buffer is null!")
return false return false
@ -81,17 +79,16 @@ class BasalProfile {
return false return false
} }
rawData = ByteArray(MAX_RAW_DATA_SIZE) rawData = ByteArray(MAX_RAW_DATA_SIZE)
val item = 0
var i = 0 var i = 0
while (i < data.size - 2) { while (i < data.size - 2) {
if (data[i] == 0.toByte() && data[i + 1] == 0.toByte() && data[i + 2] == 0.toByte()) { if (data[i] == 0.toByte() && data[i + 1] == 0.toByte() && data[i + 2] == 0.toByte()) {
rawData!![i] = 0 rawData[i] = 0
rawData!![i + 1] = 0 rawData[i + 1] = 0
rawData!![i + 2] = 0 rawData[i + 2] = 0
} }
rawData!![i] = data[i + 1] rawData[i] = data[i + 1]
rawData!![i + 1] = data[i + 2] rawData[i + 1] = data[i + 2]
rawData!![i + 2] = data[i] rawData[i + 2] = data[i]
i += 3 i += 3
} }
return true return true
@ -306,7 +303,7 @@ class BasalProfile {
} }
@JvmStatic @JvmStatic
fun getProfilesByHourToString(data: Array<Double?>): String { fun getProfilesByHourToString(data: Array<Double>): String {
val stringBuilder = StringBuilder() val stringBuilder = StringBuilder()
for (value in data) { for (value in data) {
stringBuilder.append(String.format("%.3f", value)) stringBuilder.append(String.format("%.3f", value))

View file

@ -1,250 +0,0 @@
package info.nightscout.androidaps.plugins.pump.medtronic.dialog;
import android.os.Bundle;
import android.os.SystemClock;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
import android.widget.TextView;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
import java.util.List;
import javax.inject.Inject;
import info.nightscout.androidaps.activities.NoSplashAppCompatActivity;
import info.nightscout.androidaps.plugins.pump.common.defs.PumpHistoryEntryGroup;
import info.nightscout.androidaps.plugins.pump.medtronic.R;
import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.pump.PumpHistoryEntry;
import info.nightscout.androidaps.plugins.pump.medtronic.data.MedtronicHistoryData;
import info.nightscout.androidaps.utils.resources.ResourceHelper;
public class MedtronicHistoryActivity extends NoSplashAppCompatActivity {
@Inject MedtronicHistoryData medtronicHistoryData;
@Inject ResourceHelper resourceHelper;
Spinner historyTypeSpinner;
TextView statusView;
RecyclerView recyclerView;
LinearLayoutManager llm;
static TypeList showingType = null;
static PumpHistoryEntryGroup selectedGroup = PumpHistoryEntryGroup.All;
List<PumpHistoryEntry> filteredHistoryList = new ArrayList<>();
RecyclerViewAdapter recyclerViewAdapter;
boolean manualChange = false;
List<TypeList> typeListFull;
private void filterHistory(PumpHistoryEntryGroup group) {
this.filteredHistoryList.clear();
List<PumpHistoryEntry> list = new ArrayList<>();
list.addAll(medtronicHistoryData.getAllHistory());
//LOG.debug("Items on full list: {}", list.size());
if (group == PumpHistoryEntryGroup.All) {
this.filteredHistoryList.addAll(list);
} else {
for (PumpHistoryEntry pumpHistoryEntry : list) {
if (pumpHistoryEntry.getEntryType().getGroup() == group) {
this.filteredHistoryList.add(pumpHistoryEntry);
}
}
}
if (this.recyclerViewAdapter != null) {
this.recyclerViewAdapter.setHistoryList(this.filteredHistoryList);
this.recyclerViewAdapter.notifyDataSetChanged();
}
//LOG.debug("Items on filtered list: {}", filteredHistoryList.size());
}
@Override
protected void onResume() {
super.onResume();
filterHistory(selectedGroup);
setHistoryTypeSpinner();
}
private void setHistoryTypeSpinner() {
this.manualChange = true;
for (int i = 0; i < typeListFull.size(); i++) {
if (typeListFull.get(i).entryGroup == selectedGroup) {
historyTypeSpinner.setSelection(i);
break;
}
}
SystemClock.sleep(200);
this.manualChange = false;
}
@Override
protected void onPause() {
super.onPause();
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.medtronic_history_activity);
historyTypeSpinner = findViewById(R.id.medtronic_historytype);
statusView = findViewById(R.id.medtronic_historystatus);
recyclerView = findViewById(R.id.medtronic_history_recyclerview);
recyclerView.setHasFixedSize(true);
llm = new LinearLayoutManager(this);
recyclerView.setLayoutManager(llm);
recyclerViewAdapter = new RecyclerViewAdapter(filteredHistoryList);
recyclerView.setAdapter(recyclerViewAdapter);
statusView.setVisibility(View.GONE);
typeListFull = getTypeList(PumpHistoryEntryGroup.getTranslatedList(resourceHelper));
ArrayAdapter<TypeList> spinnerAdapter = new ArrayAdapter<>(this, R.layout.spinner_centered, typeListFull);
historyTypeSpinner.setAdapter(spinnerAdapter);
historyTypeSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
if (manualChange)
return;
TypeList selected = (TypeList) historyTypeSpinner.getSelectedItem();
showingType = selected;
selectedGroup = selected.entryGroup;
filterHistory(selectedGroup);
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
if (manualChange)
return;
filterHistory(PumpHistoryEntryGroup.All);
}
});
}
private List<TypeList> getTypeList(List<PumpHistoryEntryGroup> list) {
ArrayList<TypeList> typeList = new ArrayList<>();
for (PumpHistoryEntryGroup pumpHistoryEntryGroup : list) {
typeList.add(new TypeList(pumpHistoryEntryGroup));
}
return typeList;
}
public static class TypeList {
PumpHistoryEntryGroup entryGroup;
String name;
TypeList(PumpHistoryEntryGroup entryGroup) {
this.entryGroup = entryGroup;
this.name = entryGroup.getTranslated();
}
@Override
public String toString() {
return name;
}
}
public static class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.HistoryViewHolder> {
List<PumpHistoryEntry> historyList;
RecyclerViewAdapter(List<PumpHistoryEntry> historyList) {
this.historyList = historyList;
}
public void setHistoryList(List<PumpHistoryEntry> historyList) {
// this.historyList.clear();
// this.historyList.addAll(historyList);
this.historyList = historyList;
// this.notifyDataSetChanged();
}
@Override
public HistoryViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.medtronic_history_item, //
viewGroup, false);
return new HistoryViewHolder(v);
}
@Override
public void onBindViewHolder(HistoryViewHolder holder, int position) {
PumpHistoryEntry record = historyList.get(position);
if (record != null) {
holder.timeView.setText(record.getDateTimeString());
holder.typeView.setText(record.getEntryType().getDescription());
holder.valueView.setText(record.getDisplayableValue());
}
}
@Override
public int getItemCount() {
return historyList.size();
}
@Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
}
static class HistoryViewHolder extends RecyclerView.ViewHolder {
TextView timeView;
TextView typeView;
TextView valueView;
HistoryViewHolder(View itemView) {
super(itemView);
// cv = (CardView)itemView.findViewById(R.id.rileylink_history_item);
timeView = itemView.findViewById(R.id.medtronic_history_time);
typeView = itemView.findViewById(R.id.medtronic_history_source);
valueView = itemView.findViewById(R.id.medtronic_history_description);
}
}
}
}

View file

@ -0,0 +1,200 @@
package info.nightscout.androidaps.plugins.pump.medtronic.dialog
import android.os.Bundle
import android.os.SystemClock
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.AdapterView
import android.widget.ArrayAdapter
import android.widget.Spinner
import android.widget.TextView
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import dagger.android.DaggerActivity
import dagger.android.DispatchingAndroidInjector
import info.nightscout.androidaps.plugins.pump.common.defs.PumpHistoryEntryGroup
import info.nightscout.androidaps.plugins.pump.common.defs.PumpHistoryEntryGroup.Companion.getTranslatedList
import info.nightscout.androidaps.plugins.pump.medtronic.R
import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.pump.PumpHistoryEntry
import info.nightscout.androidaps.plugins.pump.medtronic.data.MedtronicHistoryData
import info.nightscout.androidaps.plugins.pump.medtronic.databinding.MedtronicHistoryActivityBinding
import info.nightscout.androidaps.utils.resources.ResourceHelper
import java.util.*
import javax.inject.Inject
class MedtronicHistoryActivity : DaggerActivity() {
@Inject lateinit var medtronicHistoryData: MedtronicHistoryData
@Inject lateinit var resourceHelper: ResourceHelper
lateinit var historyTypeSpinner: Spinner
lateinit var statusView: TextView
lateinit var recyclerView: RecyclerView
lateinit var llm: LinearLayoutManager
lateinit var recyclerViewAdapter: RecyclerViewAdapter
var filteredHistoryList: MutableList<PumpHistoryEntry> = ArrayList()
var manualChange = false
var typeListFull: List<TypeList>? = null
private var _binding: MedtronicHistoryActivityBinding? = null
//@Inject
//var fragmentInjector: DispatchingAndroidInjector<Fragment>? = null
// This property is only valid between onCreateView and
// onDestroyView.
private val binding get() = _binding!!
private fun filterHistory(group: PumpHistoryEntryGroup) {
filteredHistoryList.clear()
val list: MutableList<PumpHistoryEntry> = ArrayList()
list.addAll(medtronicHistoryData.allHistory)
//LOG.debug("Items on full list: {}", list.size());
if (group === PumpHistoryEntryGroup.All) {
filteredHistoryList.addAll(list)
} else {
for (pumpHistoryEntry in list) {
if (pumpHistoryEntry.entryType!!.group === group) {
filteredHistoryList.add(pumpHistoryEntry)
}
}
}
recyclerViewAdapter.setHistoryListInternal(filteredHistoryList)
recyclerViewAdapter.notifyDataSetChanged()
//LOG.debug("Items on filtered list: {}", filteredHistoryList.size());
}
override fun onResume() {
super.onResume()
filterHistory(selectedGroup)
setHistoryTypeSpinner()
}
private fun setHistoryTypeSpinner() {
manualChange = true
for (i in typeListFull!!.indices) {
if (typeListFull!![i].entryGroup === selectedGroup) {
historyTypeSpinner.setSelection(i)
break
}
}
SystemClock.sleep(200)
manualChange = false
}
override fun onPause() {
super.onPause()
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
//setContentView(R.layout.medtronic_history_activity)
_binding = MedtronicHistoryActivityBinding.inflate(getLayoutInflater()) //(inflater, container, false)
historyTypeSpinner = binding.medtronicHistorytype //findViewById(R.id.medtronic_historytype)
statusView = binding.medtronicHistorystatus //findViewById(R.id.medtronic_historystatus)
recyclerView = binding.medtronicHistoryRecyclerview //findViewById(R.id.medtronic_history_recyclerview)
recyclerView.setHasFixedSize(true)
llm = LinearLayoutManager(this)
recyclerView.setLayoutManager(llm)
recyclerViewAdapter = RecyclerViewAdapter(filteredHistoryList)
recyclerView.setAdapter(recyclerViewAdapter)
statusView.setVisibility(View.GONE)
typeListFull = getTypeList(getTranslatedList(resourceHelper!!))
val spinnerAdapter = ArrayAdapter(this, R.layout.spinner_centered, typeListFull)
historyTypeSpinner.setAdapter(spinnerAdapter)
historyTypeSpinner.setOnItemSelectedListener(object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(parent: AdapterView<*>?, view: View, position: Int, id: Long) {
if (manualChange) return
val selected = historyTypeSpinner.getSelectedItem() as TypeList
showingType = selected
selectedGroup = selected.entryGroup
filterHistory(selectedGroup)
}
override fun onNothingSelected(parent: AdapterView<*>?) {
if (manualChange) return
filterHistory(PumpHistoryEntryGroup.All)
}
})
}
private fun getTypeList(list: List<PumpHistoryEntryGroup>?): List<TypeList> {
val typeList = ArrayList<TypeList>()
for (pumpHistoryEntryGroup in list!!) {
typeList.add(TypeList(pumpHistoryEntryGroup))
}
return typeList
}
class TypeList internal constructor(var entryGroup: PumpHistoryEntryGroup) {
var name: String
override fun toString(): String {
return name
}
init {
name = entryGroup.translated!!
}
}
class RecyclerViewAdapter internal constructor(var historyList: List<PumpHistoryEntry>) : RecyclerView.Adapter<RecyclerViewAdapter.HistoryViewHolder>() {
fun setHistoryListInternal(historyList: List<PumpHistoryEntry>) {
// this.historyList.clear();
// this.historyList.addAll(historyList);
this.historyList = historyList
// this.notifyDataSetChanged();
}
override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): HistoryViewHolder {
val v = LayoutInflater.from(viewGroup.context).inflate(R.layout.medtronic_history_item, //
viewGroup, false)
return HistoryViewHolder(v)
}
override fun onBindViewHolder(holder: HistoryViewHolder, position: Int) {
val record = historyList[position]
if (record != null) {
holder.timeView.text = record.dateTimeString
holder.typeView.text = record.entryType!!.description
holder.valueView.text = record.displayableValue
}
}
override fun getItemCount(): Int {
return historyList.size
}
override fun onAttachedToRecyclerView(recyclerView: RecyclerView) {
super.onAttachedToRecyclerView(recyclerView)
}
class HistoryViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
var timeView: TextView
var typeView: TextView
var valueView: TextView
init {
// cv = (CardView)itemView.findViewById(R.id.rileylink_history_item);
timeView = itemView.findViewById(R.id.medtronic_history_time)
typeView = itemView.findViewById(R.id.medtronic_history_source)
valueView = itemView.findViewById(R.id.medtronic_history_description)
}
}
}
companion object {
var showingType: TypeList? = null
var selectedGroup = PumpHistoryEntryGroup.All
}
}

View file

@ -1,166 +0,0 @@
package info.nightscout.androidaps.plugins.pump.medtronic.dialog;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
import javax.inject.Inject;
import dagger.android.support.DaggerFragment;
import info.nightscout.androidaps.plugins.pump.common.dialog.RefreshableInterface;
import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.data.RLHistoryItem;
import info.nightscout.androidaps.plugins.pump.common.utils.StringUtil;
import info.nightscout.androidaps.plugins.pump.medtronic.R;
import info.nightscout.androidaps.utils.DateUtil;
import info.nightscout.androidaps.utils.resources.ResourceHelper;
/**
* Created by andy on 5/19/18.
* <p>
* This is for 3rd tab, called Medtronic (in RileyLink stats), that should work similarly as the one in Loop.
* <p>
* Showing currently selected RL, speed of RL, ability to issue simple commands (getModel, tuneUp, gerProfile)
*/
// TODO needs to be implemented
public class RileyLinkStatusDeviceMedtronic extends DaggerFragment implements RefreshableInterface {
@Inject ResourceHelper resourceHelper;
@Inject DateUtil dateUtil;
// @BindView(R.id.rileylink_history_list)
ListView listView;
RileyLinkCommandListAdapter adapter;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.rileylink_status_device, container, false);
adapter = new RileyLinkCommandListAdapter();
return rootView;
}
@Override
public void onStart() {
super.onStart();
this.listView = getActivity().findViewById(R.id.rileylink_history_list);
listView.setAdapter(adapter);
refreshData();
}
@Override
public void refreshData() {
// adapter.addItemsAndClean(RileyLinkUtil.getRileyLinkHistory());
}
static class ViewHolder {
TextView itemTime;
TextView itemSource;
TextView itemDescription;
}
private class RileyLinkCommandListAdapter extends BaseAdapter {
private final List<RLHistoryItem> historyItemList;
private final LayoutInflater mInflator;
public RileyLinkCommandListAdapter() {
super();
historyItemList = new ArrayList<>();
mInflator = RileyLinkStatusDeviceMedtronic.this.getLayoutInflater();
}
public void addItem(RLHistoryItem item) {
if (!historyItemList.contains(item)) {
historyItemList.add(item);
notifyDataSetChanged();
}
}
public RLHistoryItem getHistoryItem(int position) {
return historyItemList.get(position);
}
public void addItemsAndClean(List<RLHistoryItem> items) {
this.historyItemList.clear();
for (RLHistoryItem item : items) {
if (!historyItemList.contains(item)) {
historyItemList.add(item);
}
}
notifyDataSetChanged();
}
public void clear() {
historyItemList.clear();
notifyDataSetChanged();
}
@Override
public int getCount() {
return historyItemList.size();
}
@Override
public Object getItem(int i) {
return historyItemList.get(i);
}
@Override
public long getItemId(int i) {
return i;
}
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
RileyLinkStatusDeviceMedtronic.ViewHolder viewHolder;
// General ListView optimization code.
if (view == null) {
view = mInflator.inflate(R.layout.rileylink_status_device_item, null);
viewHolder = new RileyLinkStatusDeviceMedtronic.ViewHolder();
viewHolder.itemTime = view.findViewById(R.id.rileylink_history_time);
viewHolder.itemSource = view.findViewById(R.id.rileylink_history_source);
viewHolder.itemDescription = view.findViewById(R.id.rileylink_history_description);
view.setTag(viewHolder);
} else {
viewHolder = (RileyLinkStatusDeviceMedtronic.ViewHolder) view.getTag();
}
RLHistoryItem item = historyItemList.get(i);
viewHolder.itemTime.setText(StringUtil.toDateTimeString(dateUtil, item.getDateTime()));
viewHolder.itemSource.setText("Riley Link"); // for now
viewHolder.itemDescription.setText(item.getDescription(resourceHelper));
return view;
}
}
}

View file

@ -0,0 +1,137 @@
package info.nightscout.androidaps.plugins.pump.medtronic.dialog
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.BaseAdapter
import android.widget.ListView
import android.widget.TextView
import dagger.android.support.DaggerFragment
import info.nightscout.androidaps.plugins.pump.common.dialog.RefreshableInterface
import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.data.RLHistoryItem
import info.nightscout.androidaps.plugins.pump.common.utils.StringUtil
import info.nightscout.androidaps.plugins.pump.medtronic.R
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.resources.ResourceHelper
import io.reactivex.disposables.CompositeDisposable
import java.util.*
import javax.inject.Inject
/**
* Created by andy on 5/19/18.
* NOTE: This class is not used yet, so it has no Bindings
*
* This is for 3rd tab, called Medtronic (in RileyLink stats), that should work similarly as the one in Loop.
*
*
* Showing currently selected RL, speed of RL, ability to issue simple commands (getModel, tuneUp, gerProfile)
*/
// TODO needs to be implemented
class RileyLinkStatusDeviceMedtronic : DaggerFragment(), RefreshableInterface {
@Inject lateinit var resourceHelper: ResourceHelper
@Inject lateinit var dateUtil: DateUtil
var listView: ListView? = null
var adapter: RileyLinkCommandListAdapter? = null
private var disposable: CompositeDisposable = CompositeDisposable()
//private var _binding: RileyLinkStatusDeviceBinding? = null
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
// _binding = LoopFragmentBinding.inflate(inflater, container, false)
// return binding.root
val rootView = inflater.inflate(R.layout.rileylink_status_device, container, false)
adapter = RileyLinkCommandListAdapter()
return rootView
}
override fun onStart() {
super.onStart()
//listView = activity!!.findViewById(R.id.rileylink_history_list)
//listView.setAdapter(adapter)
refreshData()
}
override fun refreshData() {
// adapter.addItemsAndClean(RileyLinkUtil.getRileyLinkHistory());
}
internal class ViewHolder {
var itemTime: TextView? = null
var itemSource: TextView? = null
var itemDescription: TextView? = null
}
inner class RileyLinkCommandListAdapter : BaseAdapter() {
private val historyItemList: MutableList<RLHistoryItem>
private val mInflator: LayoutInflater
fun addItem(item: RLHistoryItem) {
if (!historyItemList.contains(item)) {
historyItemList.add(item)
notifyDataSetChanged()
}
}
fun getHistoryItem(position: Int): RLHistoryItem {
return historyItemList[position]
}
fun addItemsAndClean(items: List<RLHistoryItem>) {
historyItemList.clear()
for (item in items) {
if (!historyItemList.contains(item)) {
historyItemList.add(item)
}
}
notifyDataSetChanged()
}
fun clear() {
historyItemList.clear()
notifyDataSetChanged()
}
override fun getCount(): Int {
return historyItemList.size
}
override fun getItem(i: Int): Any {
return historyItemList[i]
}
override fun getItemId(i: Int): Long {
return i.toLong()
}
override fun getView(i: Int, view: View, viewGroup: ViewGroup): View {
var view = view
val viewHolder: ViewHolder
// General ListView optimization code.
if (view == null) {
view = mInflator.inflate(R.layout.rileylink_status_device_item, null)
viewHolder = ViewHolder()
viewHolder.itemTime = view.findViewById(R.id.rileylink_history_time)
viewHolder.itemSource = view.findViewById(R.id.rileylink_history_source)
viewHolder.itemDescription = view.findViewById(R.id.rileylink_history_description)
view.tag = viewHolder
} else {
viewHolder = view.tag as ViewHolder
}
val item = historyItemList[i]
viewHolder.itemTime!!.text = StringUtil.toDateTimeString(dateUtil, item.dateTime)
viewHolder.itemSource!!.text = "Riley Link" // for now
viewHolder.itemDescription!!.text = item.getDescription(resourceHelper)
return view
}
init {
historyItemList = ArrayList()
mInflator = this@RileyLinkStatusDeviceMedtronic.layoutInflater
}
}
}

View file

@ -49,6 +49,7 @@ class RileyLinkMedtronicService // This empty constructor must be kept, otherwi
private var encodingType: RileyLinkEncodingType? = null private var encodingType: RileyLinkEncodingType? = null
private var encodingChanged = false private var encodingChanged = false
private var inPreInit = true private var inPreInit = true
override fun onCreate() { override fun onCreate() {
super.onCreate() super.onCreate()
aapsLogger.debug(LTag.PUMPCOMM, "RileyLinkMedtronicService newly created") aapsLogger.debug(LTag.PUMPCOMM, "RileyLinkMedtronicService newly created")
@ -267,19 +268,19 @@ class RileyLinkMedtronicService // This empty constructor must be kept, otherwi
} }
private fun checkParameterValue(key: Int, defaultValue: String, defaultValueDouble: Double): Double { private fun checkParameterValue(key: Int, defaultValue: String, defaultValueDouble: Double): Double {
var `val`: Double var valueDouble: Double
val value = sp.getString(key, defaultValue) val value = sp.getString(key, defaultValue)
`val` = try { valueDouble = try {
value.toDouble() value.toDouble()
} catch (ex: Exception) { } catch (ex: Exception) {
aapsLogger.error("Error parsing setting: %s, value found %s", key, value) aapsLogger.error("Error parsing setting: %s, value found %s", key, value)
defaultValueDouble defaultValueDouble
} }
if (`val` > defaultValueDouble) { if (valueDouble > defaultValueDouble) {
sp.putString(key, defaultValue) sp.putString(key, defaultValue)
`val` = defaultValueDouble valueDouble = defaultValueDouble
} }
return `val` return valueDouble
} }
fun setNotInPreInit(): Boolean { fun setNotInPreInit(): Boolean {

View file

@ -33,6 +33,7 @@ enum class PumpHistoryEntryGroup(val resourceId: Int) {
companion object { companion object {
private var translatedList: MutableList<PumpHistoryEntryGroup>? = null private var translatedList: MutableList<PumpHistoryEntryGroup>? = null
private fun doTranslation(resourceHelper: ResourceHelper) { private fun doTranslation(resourceHelper: ResourceHelper) {
translatedList = ArrayList() translatedList = ArrayList()
for (pumpHistoryEntryGroup in values()) { for (pumpHistoryEntryGroup in values()) {
@ -41,7 +42,8 @@ enum class PumpHistoryEntryGroup(val resourceId: Int) {
} }
} }
@JvmStatic fun getTranslatedList(resourceHelper: ResourceHelper): List<PumpHistoryEntryGroup>? { @JvmStatic
fun getTranslatedList(resourceHelper: ResourceHelper): List<PumpHistoryEntryGroup>? {
if (translatedList == null) doTranslation(resourceHelper) if (translatedList == null) doTranslation(resourceHelper)
return translatedList return translatedList
} }

View file

@ -2,7 +2,7 @@
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"
tools:context=".plugins.pump.common.hw.rileylink.dialog.RileyLinkStatusDevice"> tools:context=".plugins.pump.medtronic.dialog.RileyLinkStatusDevice">
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"