diff --git a/app/src/main/java/info/nightscout/androidaps/queue/QueueThread.java b/app/src/main/java/info/nightscout/androidaps/queue/QueueThread.java deleted file mode 100644 index 9dbd2c3ef4..0000000000 --- a/app/src/main/java/info/nightscout/androidaps/queue/QueueThread.java +++ /dev/null @@ -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"); - } - } -} diff --git a/app/src/main/java/info/nightscout/androidaps/queue/QueueThread.kt b/app/src/main/java/info/nightscout/androidaps/queue/QueueThread.kt new file mode 100644 index 0000000000..bc2f4786e8 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/queue/QueueThread.kt @@ -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") + } + } +} \ No newline at end of file diff --git a/app/src/test/java/info/nightscout/androidaps/queue/CommandQueueTest.kt b/app/src/test/java/info/nightscout/androidaps/queue/CommandQueueTest.kt index 03c69c0727..da805527b5 100644 --- a/app/src/test/java/info/nightscout/androidaps/queue/CommandQueueTest.kt +++ b/app/src/test/java/info/nightscout/androidaps/queue/CommandQueueTest.kt @@ -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