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