QueueThread -> kt

This commit is contained in:
Milos Kozak 2021-02-16 19:22:43 +01:00
parent 32df0b9490
commit beb02e9aad
3 changed files with 233 additions and 252 deletions

View file

@ -1,171 +0,0 @@
package info.nightscout.androidaps.queue;
import android.bluetooth.BluetoothAdapter;
import android.content.Context;
import android.os.PowerManager;
import android.os.SystemClock;
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.events.EventPumpStatusChanged;
import info.nightscout.androidaps.interfaces.ActivePluginProvider;
import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.logging.AAPSLogger;
import info.nightscout.androidaps.logging.LTag;
import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
import info.nightscout.androidaps.plugins.general.overview.events.EventDismissBolusProgressIfRunning;
import info.nightscout.androidaps.queue.events.EventQueueChanged;
import info.nightscout.androidaps.utils.T;
import info.nightscout.androidaps.utils.resources.ResourceHelper;
import info.nightscout.androidaps.utils.sharedPreferences.SP;
/**
* Created by mike on 09.11.2017.
*/
public class QueueThread extends Thread {
private final CommandQueue queue;
private final AAPSLogger aapsLogger;
private final RxBusWrapper rxBus;
private final ActivePluginProvider activePlugin;
private final ResourceHelper resourceHelper;
private final SP sp;
private boolean connectLogged = false;
boolean waitingForDisconnect = false;
private PowerManager.WakeLock mWakeLock;
QueueThread(CommandQueue queue, Context context, AAPSLogger aapsLogger, RxBusWrapper rxBus, ActivePluginProvider activePlugin, ResourceHelper resourceHelper, SP sp) {
super();
this.queue = queue;
this.aapsLogger = aapsLogger;
this.rxBus = rxBus;
this.activePlugin = activePlugin;
this.resourceHelper = resourceHelper;
this.sp = sp;
PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
if (powerManager != null)
mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "AndroidAPS:QueueThread");
}
@Override
public final void run() {
if (mWakeLock != null)
mWakeLock.acquire(T.mins(10).msecs());
rxBus.send(new EventQueueChanged());
long lastCommandTime;
long connectionStartTime = lastCommandTime = System.currentTimeMillis();
try {
while (true) {
long secondsElapsed = (System.currentTimeMillis() - connectionStartTime) / 1000;
PumpInterface pump = activePlugin.getActivePump();
if (!pump.isConnected() && secondsElapsed > Constants.PUMP_MAX_CONNECTION_TIME_IN_SECONDS) {
rxBus.send(new EventDismissBolusProgressIfRunning(null));
rxBus.send(new EventPumpStatusChanged(resourceHelper.gs(R.string.connectiontimedout)));
aapsLogger.debug(LTag.PUMPQUEUE, "timed out");
pump.stopConnecting();
//BLUETOOTH-WATCHDOG
boolean watchdog = sp.getBoolean(R.string.key_btwatchdog, false);
long last_watchdog = sp.getLong(R.string.key_btwatchdog_lastbark, 0L);
watchdog = watchdog && System.currentTimeMillis() - last_watchdog > (Constants.MIN_WATCHDOG_INTERVAL_IN_SECONDS * 1000);
if (watchdog) {
aapsLogger.debug(LTag.PUMPQUEUE, "BT watchdog - toggeling the phonest bluetooth");
//write time
sp.putLong(R.string.key_btwatchdog_lastbark, System.currentTimeMillis());
//toggle BT
pump.stopConnecting();
pump.disconnect("watchdog");
SystemClock.sleep(1000);
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (bluetoothAdapter != null) {
bluetoothAdapter.disable();
SystemClock.sleep(1000);
bluetoothAdapter.enable();
SystemClock.sleep(1000);
}
//start over again once after watchdog barked
//Notification notification = new Notification(Notification.OLD_NSCLIENT, "Watchdog", Notification.URGENT);
//rxBus.send(new EventNewNotification(notification));
connectionStartTime = lastCommandTime = System.currentTimeMillis();
pump.connect("watchdog");
} else {
queue.clear();
aapsLogger.debug(LTag.PUMPQUEUE, "no connection possible");
rxBus.send(new EventPumpStatusChanged(EventPumpStatusChanged.Status.DISCONNECTING));
pump.disconnect("Queue empty");
rxBus.send(new EventPumpStatusChanged(EventPumpStatusChanged.Status.DISCONNECTED));
return;
}
}
if (pump.isHandshakeInProgress()) {
aapsLogger.debug(LTag.PUMPQUEUE, "handshaking " + secondsElapsed);
rxBus.send(new EventPumpStatusChanged(EventPumpStatusChanged.Status.HANDSHAKING, (int) secondsElapsed));
SystemClock.sleep(100);
continue;
}
if (pump.isConnecting()) {
aapsLogger.debug(LTag.PUMPQUEUE, "connecting " + secondsElapsed);
rxBus.send(new EventPumpStatusChanged(EventPumpStatusChanged.Status.CONNECTING, (int) secondsElapsed));
SystemClock.sleep(1000);
continue;
}
if (!pump.isConnected()) {
aapsLogger.debug(LTag.PUMPQUEUE, "connect");
rxBus.send(new EventPumpStatusChanged(EventPumpStatusChanged.Status.CONNECTING, (int) secondsElapsed));
pump.connect("Connection needed");
SystemClock.sleep(1000);
continue;
}
if (queue.performing() == null) {
if (!connectLogged) {
connectLogged = true;
aapsLogger.debug(LTag.PUMPQUEUE, "connection time " + secondsElapsed + "s");
}
// Pickup 1st command and set performing variable
if (queue.size() > 0) {
queue.pickup();
if (queue.performing() != null) {
aapsLogger.debug(LTag.PUMPQUEUE, "performing " + queue.performing().status());
rxBus.send(new EventQueueChanged());
queue.performing().execute();
queue.resetPerforming();
rxBus.send(new EventQueueChanged());
lastCommandTime = System.currentTimeMillis();
SystemClock.sleep(100);
continue;
}
}
}
if (queue.size() == 0 && queue.performing() == null) {
long secondsFromLastCommand = (System.currentTimeMillis() - lastCommandTime) / 1000;
if (secondsFromLastCommand >= 5) {
waitingForDisconnect = true;
aapsLogger.debug(LTag.PUMPQUEUE, "queue empty. disconnect");
rxBus.send(new EventPumpStatusChanged(EventPumpStatusChanged.Status.DISCONNECTING));
pump.disconnect("Queue empty");
rxBus.send(new EventPumpStatusChanged(EventPumpStatusChanged.Status.DISCONNECTED));
aapsLogger.debug(LTag.PUMPQUEUE, "disconnected");
return;
} else {
aapsLogger.debug(LTag.PUMPQUEUE, "waiting for disconnect");
SystemClock.sleep(1000);
}
}
}
} finally {
if (mWakeLock != null && mWakeLock.isHeld())
mWakeLock.release();
aapsLogger.debug(LTag.PUMPQUEUE, "thread end");
}
}
}

View file

@ -0,0 +1,149 @@
package info.nightscout.androidaps.queue
import android.bluetooth.BluetoothAdapter
import android.content.Context
import android.os.PowerManager
import android.os.SystemClock
import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.R
import info.nightscout.androidaps.events.EventPumpStatusChanged
import info.nightscout.androidaps.interfaces.ActivePluginProvider
import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.general.overview.events.EventDismissBolusProgressIfRunning
import info.nightscout.androidaps.queue.events.EventQueueChanged
import info.nightscout.androidaps.utils.T
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.sharedPreferences.SP
class QueueThread internal constructor(
private val queue: CommandQueue,
context: Context,
private val aapsLogger: AAPSLogger,
private val rxBus: RxBusWrapper,
private val activePlugin: ActivePluginProvider,
private val resourceHelper: ResourceHelper,
private val sp: SP
) : Thread() {
private var connectLogged = false
var waitingForDisconnect = false
private var mWakeLock: PowerManager.WakeLock? = null
init {
mWakeLock = (context.getSystemService(Context.POWER_SERVICE) as PowerManager).newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, resourceHelper.gs(R.string.app_name) + ":QueueThread")
}
override fun run() {
mWakeLock?.acquire(T.mins(10).msecs())
rxBus.send(EventQueueChanged())
var lastCommandTime: Long
lastCommandTime = System.currentTimeMillis()
var connectionStartTime = lastCommandTime
try {
while (true) {
val secondsElapsed = (System.currentTimeMillis() - connectionStartTime) / 1000
val pump = activePlugin.activePump
if (!pump.isConnected && secondsElapsed > Constants.PUMP_MAX_CONNECTION_TIME_IN_SECONDS) {
rxBus.send(EventDismissBolusProgressIfRunning(null))
rxBus.send(EventPumpStatusChanged(resourceHelper.gs(R.string.connectiontimedout)))
aapsLogger.debug(LTag.PUMPQUEUE, "timed out")
pump.stopConnecting()
//BLUETOOTH-WATCHDOG
var watchdog = sp.getBoolean(R.string.key_btwatchdog, false)
val lastWatchdog = sp.getLong(R.string.key_btwatchdog_lastbark, 0L)
watchdog = watchdog && System.currentTimeMillis() - lastWatchdog > Constants.MIN_WATCHDOG_INTERVAL_IN_SECONDS * 1000
if (watchdog) {
aapsLogger.debug(LTag.PUMPQUEUE, "BT watchdog - toggling the phone bluetooth")
//write time
sp.putLong(R.string.key_btwatchdog_lastbark, System.currentTimeMillis())
//toggle BT
pump.stopConnecting()
pump.disconnect("watchdog")
SystemClock.sleep(1000)
val bluetoothAdapter = BluetoothAdapter.getDefaultAdapter()
if (bluetoothAdapter != null) {
bluetoothAdapter.disable()
SystemClock.sleep(1000)
bluetoothAdapter.enable()
SystemClock.sleep(1000)
}
//start over again once after watchdog barked
//Notification notification = new Notification(Notification.OLD_NSCLIENT, "Watchdog", Notification.URGENT);
//rxBus.send(new EventNewNotification(notification));
lastCommandTime = System.currentTimeMillis()
connectionStartTime = lastCommandTime
pump.connect("watchdog")
} else {
queue.clear()
aapsLogger.debug(LTag.PUMPQUEUE, "no connection possible")
rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.DISCONNECTING))
pump.disconnect("Queue empty")
rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.DISCONNECTED))
return
}
}
if (pump.isHandshakeInProgress) {
aapsLogger.debug(LTag.PUMPQUEUE, "handshaking $secondsElapsed")
rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.HANDSHAKING, secondsElapsed.toInt()))
SystemClock.sleep(100)
continue
}
if (pump.isConnecting) {
aapsLogger.debug(LTag.PUMPQUEUE, "connecting $secondsElapsed")
rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.CONNECTING, secondsElapsed.toInt()))
SystemClock.sleep(1000)
continue
}
if (!pump.isConnected) {
aapsLogger.debug(LTag.PUMPQUEUE, "connect")
rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.CONNECTING, secondsElapsed.toInt()))
pump.connect("Connection needed")
SystemClock.sleep(1000)
continue
}
if (queue.performing() == null) {
if (!connectLogged) {
connectLogged = true
aapsLogger.debug(LTag.PUMPQUEUE, "connection time " + secondsElapsed + "s")
}
// Pickup 1st command and set performing variable
if (queue.size() > 0) {
queue.pickup()
if (queue.performing() != null) {
aapsLogger.debug(LTag.PUMPQUEUE, "performing " + queue.performing()?.status())
rxBus.send(EventQueueChanged())
queue.performing()?.execute()
queue.resetPerforming()
rxBus.send(EventQueueChanged())
lastCommandTime = System.currentTimeMillis()
SystemClock.sleep(100)
continue
}
}
}
if (queue.size() == 0 && queue.performing() == null) {
val secondsFromLastCommand = (System.currentTimeMillis() - lastCommandTime) / 1000
if (secondsFromLastCommand >= 5) {
waitingForDisconnect = true
aapsLogger.debug(LTag.PUMPQUEUE, "queue empty. disconnect")
rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.DISCONNECTING))
pump.disconnect("Queue empty")
rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.DISCONNECTED))
aapsLogger.debug(LTag.PUMPQUEUE, "disconnected")
return
} else {
aapsLogger.debug(LTag.PUMPQUEUE, "waiting for disconnect")
SystemClock.sleep(1000)
}
}
}
} finally {
if (mWakeLock?.isHeld == true) mWakeLock?.release()
aapsLogger.debug(LTag.PUMPQUEUE, "thread end")
}
}
}

View file

@ -1,6 +1,7 @@
package info.nightscout.androidaps.queue package info.nightscout.androidaps.queue
import android.content.Context import android.content.Context
import android.os.PowerManager
import dagger.Lazy import dagger.Lazy
import dagger.android.AndroidInjector import dagger.android.AndroidInjector
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
@ -16,6 +17,7 @@ import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin 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.CustomCommand import info.nightscout.androidaps.queue.commands.CustomCommand
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.ToastUtils import info.nightscout.androidaps.utils.ToastUtils
import info.nightscout.androidaps.utils.buildHelper.BuildHelper import info.nightscout.androidaps.utils.buildHelper.BuildHelper
@ -33,7 +35,7 @@ import java.util.*
@RunWith(PowerMockRunner::class) @RunWith(PowerMockRunner::class)
@PrepareForTest( @PrepareForTest(
ConstraintChecker::class, VirtualPumpPlugin::class, ToastUtils::class, Context::class, ConstraintChecker::class, VirtualPumpPlugin::class, ToastUtils::class, Context::class,
TreatmentsPlugin::class, FabricPrivacy::class, LoggerUtils::class) TreatmentsPlugin::class, FabricPrivacy::class, LoggerUtils::class, PowerManager::class)
class CommandQueueTest : TestBaseWithProfile() { class CommandQueueTest : TestBaseWithProfile() {
@Mock lateinit var constraintChecker: ConstraintChecker @Mock lateinit var constraintChecker: ConstraintChecker
@ -43,6 +45,7 @@ class CommandQueueTest : TestBaseWithProfile() {
@Mock lateinit var virtualPumpPlugin: VirtualPumpPlugin @Mock lateinit var virtualPumpPlugin: VirtualPumpPlugin
@Mock lateinit var sp: SP @Mock lateinit var sp: SP
@Mock lateinit var loggerUtils: LoggerUtils @Mock lateinit var loggerUtils: LoggerUtils
@Mock lateinit var powerManager: PowerManager
val injector = HasAndroidInjector { val injector = HasAndroidInjector {
AndroidInjector { AndroidInjector {
@ -62,6 +65,7 @@ class CommandQueueTest : TestBaseWithProfile() {
val pumpDescription = PumpDescription() val pumpDescription = PumpDescription()
pumpDescription.basalMinimumRate = 0.1 pumpDescription.basalMinimumRate = 0.1
`when`(context.getSystemService(Context.POWER_SERVICE)).thenReturn(powerManager)
`when`(lazyActivePlugin.get()).thenReturn(activePlugin) `when`(lazyActivePlugin.get()).thenReturn(activePlugin)
`when`(activePlugin.activePump).thenReturn(virtualPumpPlugin) `when`(activePlugin.activePump).thenReturn(virtualPumpPlugin)
`when`(virtualPumpPlugin.pumpDescription).thenReturn(pumpDescription) `when`(virtualPumpPlugin.pumpDescription).thenReturn(pumpDescription)
@ -81,105 +85,104 @@ class CommandQueueTest : TestBaseWithProfile() {
`when`(constraintChecker.applyBasalPercentConstraints(anyObject(), anyObject())).thenReturn(percentageConstraint) `when`(constraintChecker.applyBasalPercentConstraints(anyObject(), anyObject())).thenReturn(percentageConstraint)
} }
/* @Test
@Test fun doTests() {
fun doTests() {
// start with empty queue // start with empty queue
Assert.assertEquals(0, commandQueue.size()) Assert.assertEquals(0, commandQueue.size())
// add bolus command // add bolus command
commandQueue.bolus(DetailedBolusInfo(), null) commandQueue.bolus(DetailedBolusInfo(), null)
Assert.assertEquals(1, commandQueue.size()) Assert.assertEquals(1, commandQueue.size())
// add READSTATUS // add READSTATUS
commandQueue.readStatus("anyString", null) commandQueue.readStatus("anyString", null)
Assert.assertEquals(2, commandQueue.size()) Assert.assertEquals(2, commandQueue.size())
// adding another bolus should remove the first one (size still == 2) // adding another bolus should remove the first one (size still == 2)
commandQueue.bolus(DetailedBolusInfo(), null) commandQueue.bolus(DetailedBolusInfo(), null)
Assert.assertEquals(2, commandQueue.size()) Assert.assertEquals(2, commandQueue.size())
// clear the queue should reset size // clear the queue should reset size
commandQueue.clear() commandQueue.clear()
Assert.assertEquals(0, commandQueue.size()) Assert.assertEquals(0, commandQueue.size())
// add tempbasal // add tempbasal
commandQueue.tempBasalAbsolute(0.0, 30, true, validProfile, null) commandQueue.tempBasalAbsolute(0.0, 30, true, validProfile, null)
Assert.assertEquals(1, commandQueue.size()) Assert.assertEquals(1, commandQueue.size())
// add tempbasal percent. it should replace previous TEMPBASAL // add tempbasal percent. it should replace previous TEMPBASAL
commandQueue.tempBasalPercent(0, 30, true, validProfile, null) commandQueue.tempBasalPercent(0, 30, true, validProfile, null)
Assert.assertEquals(1, commandQueue.size()) Assert.assertEquals(1, commandQueue.size())
// add extended bolus // add extended bolus
commandQueue.extendedBolus(1.0, 30, null) commandQueue.extendedBolus(1.0, 30, null)
Assert.assertEquals(2, commandQueue.size()) Assert.assertEquals(2, commandQueue.size())
// add cancel temp basal should remove previous 2 temp basal setting // add cancel temp basal should remove previous 2 temp basal setting
commandQueue.extendedBolus(1.0, 30, null) commandQueue.extendedBolus(1.0, 30, null)
Assert.assertEquals(2, commandQueue.size()) Assert.assertEquals(2, commandQueue.size())
// cancel extended bolus should replace previous extended // cancel extended bolus should replace previous extended
commandQueue.extendedBolus(1.0, 30, null) commandQueue.extendedBolus(1.0, 30, null)
Assert.assertEquals(2, commandQueue.size()) Assert.assertEquals(2, commandQueue.size())
// add setProfile // add setProfile
// TODO: this crash the test // TODO: this crash the test
// commandQueue.setProfile(validProfile, null) // commandQueue.setProfile(validProfile, null)
// Assert.assertEquals(3, commandQueue.size()) // Assert.assertEquals(3, commandQueue.size())
// add loadHistory // add loadHistory
commandQueue.loadHistory(0.toByte(), null) commandQueue.loadHistory(0.toByte(), null)
Assert.assertEquals(3, commandQueue.size()) Assert.assertEquals(3, commandQueue.size())
// add loadEvents // add loadEvents
commandQueue.loadEvents(null) commandQueue.loadEvents(null)
Assert.assertEquals(4, commandQueue.size()) Assert.assertEquals(4, commandQueue.size())
commandQueue.clear() commandQueue.clear()
commandQueue.tempBasalAbsolute(0.0, 30, true, validProfile, null) commandQueue.tempBasalAbsolute(0.0, 30, true, validProfile, null)
commandQueue.pickup() commandQueue.pickup()
Assert.assertEquals(0, commandQueue.size()) Assert.assertEquals(0, commandQueue.size())
Assert.assertNotNull(commandQueue.performing) Assert.assertNotNull(commandQueue.performing)
Assert.assertEquals(Command.CommandType.TEMPBASAL, commandQueue.performing?.commandType) Assert.assertEquals(Command.CommandType.TEMPBASAL, commandQueue.performing?.commandType)
commandQueue.resetPerforming() commandQueue.resetPerforming()
Assert.assertNull(commandQueue.performing) Assert.assertNull(commandQueue.performing)
} }
@Test @Test
fun callingCancelAllBolusesClearsQueue() { fun callingCancelAllBolusesClearsQueue() {
// given // given
Assert.assertEquals(0, commandQueue.size()) Assert.assertEquals(0, commandQueue.size())
val smb = DetailedBolusInfo() val smb = DetailedBolusInfo()
smb.lastKnownBolusTime = DateUtil.now() smb.lastKnownBolusTime = DateUtil.now()
smb.isSMB = true smb.isSMB = true
commandQueue.bolus(smb, null) commandQueue.bolus(smb, null)
commandQueue.bolus(DetailedBolusInfo(), null) commandQueue.bolus(DetailedBolusInfo(), null)
Assert.assertEquals(2, commandQueue.size()) Assert.assertEquals(2, commandQueue.size())
// when // when
commandQueue.cancelAllBoluses() commandQueue.cancelAllBoluses()
// then // then
Assert.assertEquals(0, commandQueue.size()) Assert.assertEquals(0, commandQueue.size())
} }
@Test @Test
fun smbIsRejectedIfABolusIsQueued() { fun smbIsRejectedIfABolusIsQueued() {
// given // given
Assert.assertEquals(0, commandQueue.size()) Assert.assertEquals(0, commandQueue.size())
// when // when
commandQueue.bolus(DetailedBolusInfo(), null) commandQueue.bolus(DetailedBolusInfo(), null)
val smb = DetailedBolusInfo() val smb = DetailedBolusInfo()
smb.isSMB = true smb.isSMB = true
val queued: Boolean = commandQueue.bolus(smb, null) val queued: Boolean = commandQueue.bolus(smb, null)
// then
Assert.assertFalse(queued)
Assert.assertEquals(commandQueue.size(), 1)
}
// then
Assert.assertFalse(queued)
Assert.assertEquals(commandQueue.size(), 1)
}
*/
@Test @Test
fun smbIsRejectedIfLastKnownBolusIsOutdated() { fun smbIsRejectedIfLastKnownBolusIsOutdated() {
// given // given