KeepAlive -> WorkManager
This commit is contained in:
parent
1c3ba6b380
commit
784cd37528
5 changed files with 188 additions and 213 deletions
|
@ -126,9 +126,6 @@
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</receiver>
|
</receiver>
|
||||||
|
|
||||||
<!-- Receiver keep alive, scheduled every 30 min -->
|
|
||||||
<receiver android:name=".receivers.KeepAliveReceiver" />
|
|
||||||
|
|
||||||
<!-- Receive ignore 5m, 15m, 30m requests for carb notifications -->
|
<!-- Receive ignore 5m, 15m, 30m requests for carb notifications -->
|
||||||
<receiver android:name=".plugins.aps.loop.CarbSuggestionReceiver" />
|
<receiver android:name=".plugins.aps.loop.CarbSuggestionReceiver" />
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,10 @@ import android.net.ConnectivityManager
|
||||||
import android.net.wifi.WifiManager
|
import android.net.wifi.WifiManager
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import androidx.lifecycle.ProcessLifecycleOwner
|
import androidx.lifecycle.ProcessLifecycleOwner
|
||||||
|
import androidx.work.Data
|
||||||
|
import androidx.work.ExistingPeriodicWorkPolicy
|
||||||
|
import androidx.work.PeriodicWorkRequest
|
||||||
|
import androidx.work.WorkManager
|
||||||
import com.uber.rxdogtag.RxDogTag
|
import com.uber.rxdogtag.RxDogTag
|
||||||
import dagger.android.AndroidInjector
|
import dagger.android.AndroidInjector
|
||||||
import dagger.android.DaggerApplication
|
import dagger.android.DaggerApplication
|
||||||
|
@ -27,14 +31,11 @@ import info.nightscout.androidaps.plugins.constraints.versionChecker.VersionChec
|
||||||
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification
|
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification
|
||||||
import info.nightscout.androidaps.plugins.general.overview.notifications.NotificationStore
|
import info.nightscout.androidaps.plugins.general.overview.notifications.NotificationStore
|
||||||
import info.nightscout.androidaps.plugins.general.themes.ThemeSwitcherPlugin
|
import info.nightscout.androidaps.plugins.general.themes.ThemeSwitcherPlugin
|
||||||
import info.nightscout.androidaps.receivers.BTReceiver
|
import info.nightscout.androidaps.receivers.*
|
||||||
import info.nightscout.androidaps.receivers.ChargingStateReceiver
|
|
||||||
import info.nightscout.androidaps.receivers.KeepAliveReceiver.KeepAliveManager
|
|
||||||
import info.nightscout.androidaps.receivers.NetworkChangeReceiver
|
|
||||||
import info.nightscout.androidaps.receivers.TimeDateOrTZChangeReceiver
|
|
||||||
import info.nightscout.androidaps.services.AlarmSoundServiceHelper
|
import info.nightscout.androidaps.services.AlarmSoundServiceHelper
|
||||||
import info.nightscout.androidaps.utils.ActivityMonitor
|
import info.nightscout.androidaps.utils.ActivityMonitor
|
||||||
import info.nightscout.androidaps.utils.DateUtil
|
import info.nightscout.androidaps.utils.DateUtil
|
||||||
|
import info.nightscout.androidaps.utils.LocalAlertUtils
|
||||||
import info.nightscout.androidaps.utils.ProcessLifecycleListener
|
import info.nightscout.androidaps.utils.ProcessLifecycleListener
|
||||||
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
|
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
|
||||||
import info.nightscout.androidaps.utils.locale.LocaleHelper
|
import info.nightscout.androidaps.utils.locale.LocaleHelper
|
||||||
|
@ -48,6 +49,7 @@ import io.reactivex.rxjava3.plugins.RxJavaPlugins
|
||||||
import net.danlew.android.joda.JodaTimeAndroid
|
import net.danlew.android.joda.JodaTimeAndroid
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.net.SocketException
|
import java.net.SocketException
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class MainApp : DaggerApplication() {
|
class MainApp : DaggerApplication() {
|
||||||
|
@ -62,7 +64,6 @@ class MainApp : DaggerApplication() {
|
||||||
@Inject lateinit var config: Config
|
@Inject lateinit var config: Config
|
||||||
@Inject lateinit var buildHelper: BuildHelper
|
@Inject lateinit var buildHelper: BuildHelper
|
||||||
@Inject lateinit var configBuilder: ConfigBuilder
|
@Inject lateinit var configBuilder: ConfigBuilder
|
||||||
@Inject lateinit var keepAliveManager: KeepAliveManager
|
|
||||||
@Inject lateinit var plugins: List<@JvmSuppressWildcards PluginBase>
|
@Inject lateinit var plugins: List<@JvmSuppressWildcards PluginBase>
|
||||||
@Inject lateinit var compatDBHelper: CompatDBHelper
|
@Inject lateinit var compatDBHelper: CompatDBHelper
|
||||||
@Inject lateinit var repository: AppRepository
|
@Inject lateinit var repository: AppRepository
|
||||||
|
@ -73,6 +74,7 @@ class MainApp : DaggerApplication() {
|
||||||
@Inject lateinit var notificationStore: NotificationStore
|
@Inject lateinit var notificationStore: NotificationStore
|
||||||
@Inject lateinit var processLifecycleListener: ProcessLifecycleListener
|
@Inject lateinit var processLifecycleListener: ProcessLifecycleListener
|
||||||
@Inject lateinit var profileSwitchPlugin: ThemeSwitcherPlugin
|
@Inject lateinit var profileSwitchPlugin: ThemeSwitcherPlugin
|
||||||
|
@Inject lateinit var localAlertUtils: LocalAlertUtils
|
||||||
|
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
super.onCreate()
|
super.onCreate()
|
||||||
|
@ -118,7 +120,17 @@ class MainApp : DaggerApplication() {
|
||||||
// Register all tabs in app here
|
// Register all tabs in app here
|
||||||
pluginStore.plugins = plugins
|
pluginStore.plugins = plugins
|
||||||
configBuilder.initialize()
|
configBuilder.initialize()
|
||||||
keepAliveManager.setAlarm(this)
|
|
||||||
|
WorkManager.getInstance(this).enqueueUniquePeriodicWork(
|
||||||
|
"KeepAlive",
|
||||||
|
ExistingPeriodicWorkPolicy.REPLACE,
|
||||||
|
PeriodicWorkRequest.Builder(KeepAliveWorker::class.java, 15, TimeUnit.MINUTES)
|
||||||
|
.setInputData(Data.Builder().putString("schedule", "KeepAlive").build())
|
||||||
|
.setInitialDelay(5, TimeUnit.SECONDS)
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
localAlertUtils.shortenSnoozeInterval()
|
||||||
|
localAlertUtils.preSnoozeAlarms()
|
||||||
doMigrations()
|
doMigrations()
|
||||||
uel.log(UserEntry.Action.START_AAPS, UserEntry.Sources.Aaps)
|
uel.log(UserEntry.Action.START_AAPS, UserEntry.Sources.Aaps)
|
||||||
}
|
}
|
||||||
|
@ -190,7 +202,6 @@ class MainApp : DaggerApplication() {
|
||||||
override fun onTerminate() {
|
override fun onTerminate() {
|
||||||
aapsLogger.debug(LTag.CORE, "onTerminate")
|
aapsLogger.debug(LTag.CORE, "onTerminate")
|
||||||
unregisterActivityLifecycleCallbacks(activityMonitor)
|
unregisterActivityLifecycleCallbacks(activityMonitor)
|
||||||
keepAliveManager.cancelAlarm(this)
|
|
||||||
alarmSoundServiceHelper.stopService(this)
|
alarmSoundServiceHelper.stopService(this)
|
||||||
super.onTerminate()
|
super.onTerminate()
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,12 +2,11 @@ package info.nightscout.androidaps.di
|
||||||
|
|
||||||
import dagger.Module
|
import dagger.Module
|
||||||
import dagger.android.ContributesAndroidInjector
|
import dagger.android.ContributesAndroidInjector
|
||||||
|
import info.nightscout.androidaps.plugins.aps.loop.CarbSuggestionReceiver
|
||||||
import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.RileyLinkBluetoothStateReceiver
|
import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.RileyLinkBluetoothStateReceiver
|
||||||
import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.RileyLinkBroadcastReceiver
|
import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.RileyLinkBroadcastReceiver
|
||||||
import info.nightscout.androidaps.plugins.aps.loop.CarbSuggestionReceiver
|
|
||||||
import info.nightscout.androidaps.receivers.*
|
import info.nightscout.androidaps.receivers.*
|
||||||
|
|
||||||
|
|
||||||
@Module
|
@Module
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
abstract class ReceiversModule {
|
abstract class ReceiversModule {
|
||||||
|
@ -16,8 +15,7 @@ abstract class ReceiversModule {
|
||||||
@ContributesAndroidInjector abstract fun contributesBTReceiver(): BTReceiver
|
@ContributesAndroidInjector abstract fun contributesBTReceiver(): BTReceiver
|
||||||
@ContributesAndroidInjector abstract fun contributesChargingStateReceiver(): ChargingStateReceiver
|
@ContributesAndroidInjector abstract fun contributesChargingStateReceiver(): ChargingStateReceiver
|
||||||
@ContributesAndroidInjector abstract fun contributesDataReceiver(): DataReceiver
|
@ContributesAndroidInjector abstract fun contributesDataReceiver(): DataReceiver
|
||||||
@ContributesAndroidInjector abstract fun contributesKeepAliveReceiver(): KeepAliveReceiver
|
@ContributesAndroidInjector abstract fun contributesKeepAliveWorker(): KeepAliveWorker
|
||||||
@ContributesAndroidInjector abstract fun contributesKeepAliveWorker(): KeepAliveReceiver.KeepAliveWorker
|
|
||||||
@ContributesAndroidInjector abstract fun contributesRileyLinkBluetoothStateReceiver(): RileyLinkBluetoothStateReceiver
|
@ContributesAndroidInjector abstract fun contributesRileyLinkBluetoothStateReceiver(): RileyLinkBluetoothStateReceiver
|
||||||
@ContributesAndroidInjector abstract fun contributesSmsReceiver(): SmsReceiver
|
@ContributesAndroidInjector abstract fun contributesSmsReceiver(): SmsReceiver
|
||||||
@ContributesAndroidInjector abstract fun contributesTimeDateOrTZChangeReceiver(): TimeDateOrTZChangeReceiver
|
@ContributesAndroidInjector abstract fun contributesTimeDateOrTZChangeReceiver(): TimeDateOrTZChangeReceiver
|
||||||
|
|
|
@ -1,198 +0,0 @@
|
||||||
package info.nightscout.androidaps.receivers
|
|
||||||
|
|
||||||
import android.app.AlarmManager
|
|
||||||
import android.app.PendingIntent
|
|
||||||
import android.app.PendingIntent.CanceledException
|
|
||||||
import android.app.PendingIntent.FLAG_IMMUTABLE
|
|
||||||
import android.content.Context
|
|
||||||
import android.content.Intent
|
|
||||||
import android.os.SystemClock
|
|
||||||
import androidx.work.*
|
|
||||||
import com.google.common.util.concurrent.ListenableFuture
|
|
||||||
import dagger.android.DaggerBroadcastReceiver
|
|
||||||
import dagger.android.HasAndroidInjector
|
|
||||||
import info.nightscout.androidaps.BuildConfig
|
|
||||||
import info.nightscout.androidaps.R
|
|
||||||
import info.nightscout.androidaps.data.ProfileSealed
|
|
||||||
import info.nightscout.androidaps.database.AppRepository
|
|
||||||
import info.nightscout.androidaps.events.EventProfileSwitchChanged
|
|
||||||
import info.nightscout.androidaps.extensions.buildDeviceStatus
|
|
||||||
import info.nightscout.androidaps.interfaces.*
|
|
||||||
import info.nightscout.shared.logging.AAPSLogger
|
|
||||||
import info.nightscout.shared.logging.LTag
|
|
||||||
import info.nightscout.androidaps.plugins.bus.RxBus
|
|
||||||
import info.nightscout.androidaps.plugins.configBuilder.RunningConfiguration
|
|
||||||
import info.nightscout.androidaps.plugins.general.maintenance.MaintenancePlugin
|
|
||||||
import info.nightscout.androidaps.queue.commands.Command
|
|
||||||
import info.nightscout.androidaps.utils.DateUtil
|
|
||||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
|
||||||
import info.nightscout.androidaps.utils.LocalAlertUtils
|
|
||||||
import info.nightscout.androidaps.utils.T
|
|
||||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
|
||||||
import javax.inject.Inject
|
|
||||||
import kotlin.math.abs
|
|
||||||
|
|
||||||
class KeepAliveReceiver : DaggerBroadcastReceiver() {
|
|
||||||
|
|
||||||
@Inject lateinit var aapsLogger: AAPSLogger
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
|
|
||||||
private val KEEP_ALIVE_MILLISECONDS = T.mins(5).msecs()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onReceive(context: Context, intent: Intent) {
|
|
||||||
super.onReceive(context, intent)
|
|
||||||
aapsLogger.debug(LTag.CORE, "KeepAlive received")
|
|
||||||
|
|
||||||
WorkManager.getInstance(context)
|
|
||||||
.enqueue(OneTimeWorkRequest.Builder(KeepAliveWorker::class.java).build())
|
|
||||||
}
|
|
||||||
|
|
||||||
class KeepAliveWorker(
|
|
||||||
private val context: Context,
|
|
||||||
params: WorkerParameters
|
|
||||||
) : Worker(context, params) {
|
|
||||||
|
|
||||||
@Inject lateinit var aapsLogger: AAPSLogger
|
|
||||||
@Inject lateinit var localAlertUtils: LocalAlertUtils
|
|
||||||
@Inject lateinit var repository: AppRepository
|
|
||||||
@Inject lateinit var config: Config
|
|
||||||
@Inject lateinit var iobCobCalculator: IobCobCalculator
|
|
||||||
@Inject lateinit var loop: Loop
|
|
||||||
@Inject lateinit var dateUtil: DateUtil
|
|
||||||
@Inject lateinit var activePlugin: ActivePlugin
|
|
||||||
@Inject lateinit var profileFunction: ProfileFunction
|
|
||||||
@Inject lateinit var runningConfiguration: RunningConfiguration
|
|
||||||
@Inject lateinit var receiverStatusStore: ReceiverStatusStore
|
|
||||||
@Inject lateinit var rxBus: RxBus
|
|
||||||
@Inject lateinit var commandQueue: CommandQueue
|
|
||||||
@Inject lateinit var fabricPrivacy: FabricPrivacy
|
|
||||||
@Inject lateinit var maintenancePlugin: MaintenancePlugin
|
|
||||||
@Inject lateinit var rh: ResourceHelper
|
|
||||||
|
|
||||||
init {
|
|
||||||
(context.applicationContext as HasAndroidInjector).androidInjector().inject(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
|
|
||||||
private val STATUS_UPDATE_FREQUENCY = T.mins(15).msecs()
|
|
||||||
private const val IOB_UPDATE_FREQUENCY_IN_MINUTES = 5L
|
|
||||||
|
|
||||||
private var lastReadStatus: Long = 0
|
|
||||||
private var lastRun: Long = 0
|
|
||||||
private var lastIobUpload: Long = 0
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun doWork(): Result {
|
|
||||||
localAlertUtils.shortenSnoozeInterval()
|
|
||||||
localAlertUtils.checkStaleBGAlert()
|
|
||||||
checkPump()
|
|
||||||
checkAPS()
|
|
||||||
maintenancePlugin.deleteLogs(30)
|
|
||||||
workerDbStatus()
|
|
||||||
|
|
||||||
return Result.success()
|
|
||||||
}
|
|
||||||
|
|
||||||
// When Worker DB grows too much, work operations become slow
|
|
||||||
// Library is cleaning DB every 7 days which may not be sufficient for NSClient full sync
|
|
||||||
private fun workerDbStatus() {
|
|
||||||
val workQuery = WorkQuery.Builder
|
|
||||||
.fromStates(listOf(WorkInfo.State.FAILED, WorkInfo.State.SUCCEEDED))
|
|
||||||
.build()
|
|
||||||
|
|
||||||
val workInfo: ListenableFuture<List<WorkInfo>> = WorkManager.getInstance(context).getWorkInfos(workQuery)
|
|
||||||
aapsLogger.debug(LTag.CORE, "WorkManager size is ${workInfo.get().size}")
|
|
||||||
if (workInfo.get().size > 1000) {
|
|
||||||
WorkManager.getInstance(context).pruneWork()
|
|
||||||
aapsLogger.debug(LTag.CORE, "WorkManager pruning ....")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Usually deviceStatus is uploaded through LoopPlugin after every loop cycle.
|
|
||||||
// if there is no BG available, we have to upload anyway to have correct
|
|
||||||
// IOB displayed in NS
|
|
||||||
private fun checkAPS() {
|
|
||||||
var shouldUploadStatus = false
|
|
||||||
if (config.NSCLIENT) return
|
|
||||||
if (config.PUMPCONTROL) shouldUploadStatus = true
|
|
||||||
else if (!(loop as PluginBase).isEnabled() || iobCobCalculator.ads.actualBg() == null)
|
|
||||||
shouldUploadStatus = true
|
|
||||||
else if (dateUtil.isOlderThan(activePlugin.activeAPS.lastAPSRun, 5)) shouldUploadStatus = true
|
|
||||||
if (dateUtil.isOlderThan(lastIobUpload, IOB_UPDATE_FREQUENCY_IN_MINUTES) && shouldUploadStatus) {
|
|
||||||
lastIobUpload = dateUtil.now()
|
|
||||||
buildDeviceStatus(dateUtil, loop, iobCobCalculator, profileFunction,
|
|
||||||
activePlugin.activePump, receiverStatusStore, runningConfiguration,
|
|
||||||
BuildConfig.VERSION_NAME + "-" + BuildConfig.BUILDVERSION)?.also {
|
|
||||||
repository.insert(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun checkPump() {
|
|
||||||
val pump = activePlugin.activePump
|
|
||||||
val ps = profileFunction.getRequestedProfile() ?: return
|
|
||||||
val requestedProfile = ProfileSealed.PS(ps)
|
|
||||||
val runningProfile = profileFunction.getProfile()
|
|
||||||
val lastConnection = pump.lastDataTime()
|
|
||||||
val isStatusOutdated = lastConnection + STATUS_UPDATE_FREQUENCY < System.currentTimeMillis()
|
|
||||||
val isBasalOutdated = abs(requestedProfile.getBasal() - pump.baseBasalRate) > pump.pumpDescription.basalStep
|
|
||||||
aapsLogger.debug(LTag.CORE, "Last connection: " + dateUtil.dateAndTimeString(lastConnection))
|
|
||||||
// sometimes keep alive broadcast stops
|
|
||||||
// as as workaround test if readStatus was requested before an alarm is generated
|
|
||||||
if (lastReadStatus != 0L && lastReadStatus > System.currentTimeMillis() - T.mins(5).msecs()) {
|
|
||||||
localAlertUtils.checkPumpUnreachableAlarm(lastConnection, isStatusOutdated, loop.isDisconnected)
|
|
||||||
}
|
|
||||||
if (loop.isDisconnected) {
|
|
||||||
// do nothing if pump is disconnected
|
|
||||||
} else if (runningProfile == null || ((!pump.isThisProfileSet(requestedProfile) || !requestedProfile.isEqual(runningProfile)) && !commandQueue.isRunning(Command.CommandType.BASAL_PROFILE))) {
|
|
||||||
rxBus.send(EventProfileSwitchChanged())
|
|
||||||
} else if (isStatusOutdated && !pump.isBusy()) {
|
|
||||||
lastReadStatus = System.currentTimeMillis()
|
|
||||||
commandQueue.readStatus(rh.gs(R.string.keepalive_status_outdated), null)
|
|
||||||
} else if (isBasalOutdated && !pump.isBusy()) {
|
|
||||||
lastReadStatus = System.currentTimeMillis()
|
|
||||||
commandQueue.readStatus(rh.gs(R.string.keepalive_basal_outdated), null)
|
|
||||||
}
|
|
||||||
if (lastRun != 0L && System.currentTimeMillis() - lastRun > T.mins(10).msecs()) {
|
|
||||||
aapsLogger.error(LTag.CORE, "KeepAlive fail")
|
|
||||||
fabricPrivacy.logCustom("KeepAliveFail")
|
|
||||||
}
|
|
||||||
lastRun = System.currentTimeMillis()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class KeepAliveManager @Inject constructor(
|
|
||||||
private val aapsLogger: AAPSLogger,
|
|
||||||
private val localAlertUtils: LocalAlertUtils
|
|
||||||
) {
|
|
||||||
|
|
||||||
//called by MainApp at first app start
|
|
||||||
fun setAlarm(context: Context) {
|
|
||||||
aapsLogger.debug(LTag.CORE, "KeepAlive scheduled")
|
|
||||||
SystemClock.sleep(5000) // wait for app initialization
|
|
||||||
localAlertUtils.shortenSnoozeInterval()
|
|
||||||
localAlertUtils.preSnoozeAlarms()
|
|
||||||
val am = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
|
|
||||||
val i = Intent(context, KeepAliveReceiver::class.java)
|
|
||||||
val pi = PendingIntent.getBroadcast(context, 0, i, FLAG_IMMUTABLE)
|
|
||||||
try {
|
|
||||||
pi.send()
|
|
||||||
} catch (e: CanceledException) {
|
|
||||||
}
|
|
||||||
am.cancel(pi)
|
|
||||||
am.setInexactRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), KEEP_ALIVE_MILLISECONDS, pi)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun cancelAlarm(context: Context) {
|
|
||||||
aapsLogger.debug(LTag.CORE, "KeepAlive canceled")
|
|
||||||
val intent = Intent(context, KeepAliveReceiver::class.java)
|
|
||||||
val sender = PendingIntent.getBroadcast(context, 0, intent, FLAG_IMMUTABLE)
|
|
||||||
val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
|
|
||||||
alarmManager.cancel(sender)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,167 @@
|
||||||
|
package info.nightscout.androidaps.receivers
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.work.*
|
||||||
|
import com.google.common.util.concurrent.ListenableFuture
|
||||||
|
import dagger.android.HasAndroidInjector
|
||||||
|
import info.nightscout.androidaps.BuildConfig
|
||||||
|
import info.nightscout.androidaps.R
|
||||||
|
import info.nightscout.androidaps.data.ProfileSealed
|
||||||
|
import info.nightscout.androidaps.database.AppRepository
|
||||||
|
import info.nightscout.androidaps.events.EventProfileSwitchChanged
|
||||||
|
import info.nightscout.androidaps.extensions.buildDeviceStatus
|
||||||
|
import info.nightscout.androidaps.interfaces.*
|
||||||
|
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||||
|
import info.nightscout.androidaps.plugins.configBuilder.RunningConfiguration
|
||||||
|
import info.nightscout.androidaps.plugins.general.maintenance.MaintenancePlugin
|
||||||
|
import info.nightscout.androidaps.queue.commands.Command
|
||||||
|
import info.nightscout.androidaps.utils.DateUtil
|
||||||
|
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||||
|
import info.nightscout.androidaps.utils.LocalAlertUtils
|
||||||
|
import info.nightscout.androidaps.utils.T
|
||||||
|
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||||
|
import info.nightscout.shared.logging.AAPSLogger
|
||||||
|
import info.nightscout.shared.logging.LTag
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
import javax.inject.Inject
|
||||||
|
import kotlin.math.abs
|
||||||
|
|
||||||
|
class KeepAliveWorker(
|
||||||
|
private val context: Context,
|
||||||
|
params: WorkerParameters
|
||||||
|
) : Worker(context, params) {
|
||||||
|
|
||||||
|
@Inject lateinit var aapsLogger: AAPSLogger
|
||||||
|
@Inject lateinit var localAlertUtils: LocalAlertUtils
|
||||||
|
@Inject lateinit var repository: AppRepository
|
||||||
|
@Inject lateinit var config: Config
|
||||||
|
@Inject lateinit var iobCobCalculator: IobCobCalculator
|
||||||
|
@Inject lateinit var loop: Loop
|
||||||
|
@Inject lateinit var dateUtil: DateUtil
|
||||||
|
@Inject lateinit var activePlugin: ActivePlugin
|
||||||
|
@Inject lateinit var profileFunction: ProfileFunction
|
||||||
|
@Inject lateinit var runningConfiguration: RunningConfiguration
|
||||||
|
@Inject lateinit var receiverStatusStore: ReceiverStatusStore
|
||||||
|
@Inject lateinit var rxBus: RxBus
|
||||||
|
@Inject lateinit var commandQueue: CommandQueue
|
||||||
|
@Inject lateinit var fabricPrivacy: FabricPrivacy
|
||||||
|
@Inject lateinit var maintenancePlugin: MaintenancePlugin
|
||||||
|
@Inject lateinit var rh: ResourceHelper
|
||||||
|
|
||||||
|
init {
|
||||||
|
(context.applicationContext as HasAndroidInjector).androidInjector().inject(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
private val STATUS_UPDATE_FREQUENCY = T.mins(15).msecs()
|
||||||
|
private const val IOB_UPDATE_FREQUENCY_IN_MINUTES = 5L
|
||||||
|
|
||||||
|
private var lastReadStatus: Long = 0
|
||||||
|
private var lastRun: Long = 0
|
||||||
|
private var lastIobUpload: Long = 0
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun doWork(): Result {
|
||||||
|
aapsLogger.debug(LTag.CORE, "KeepAlive received from: " + inputData.getString("schedule"))
|
||||||
|
|
||||||
|
// 15 min interval is WorkManager minimum so schedule another instances to have 5 min interval
|
||||||
|
if (inputData.getString("schedule") == "KeepAlive") {
|
||||||
|
WorkManager.getInstance(context).enqueueUniqueWork(
|
||||||
|
"KeepAlive_5",
|
||||||
|
ExistingWorkPolicy.REPLACE,
|
||||||
|
OneTimeWorkRequest.Builder(KeepAliveWorker::class.java)
|
||||||
|
.setInputData(Data.Builder().putString("schedule", "KeepAlive_5").build())
|
||||||
|
.setInitialDelay(5, TimeUnit.MINUTES)
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
WorkManager.getInstance(context).enqueueUniqueWork(
|
||||||
|
"KeepAlive_10",
|
||||||
|
ExistingWorkPolicy.REPLACE,
|
||||||
|
OneTimeWorkRequest.Builder(KeepAliveWorker::class.java)
|
||||||
|
.setInputData(Data.Builder().putString("schedule", "KeepAlive_10").build())
|
||||||
|
.setInitialDelay(10, TimeUnit.MINUTES)
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
localAlertUtils.shortenSnoozeInterval()
|
||||||
|
localAlertUtils.checkStaleBGAlert()
|
||||||
|
checkPump()
|
||||||
|
checkAPS()
|
||||||
|
maintenancePlugin.deleteLogs(30)
|
||||||
|
workerDbStatus()
|
||||||
|
|
||||||
|
return Result.success()
|
||||||
|
}
|
||||||
|
|
||||||
|
// When Worker DB grows too much, work operations become slow
|
||||||
|
// Library is cleaning DB every 7 days which may not be sufficient for NSClient full sync
|
||||||
|
private fun workerDbStatus() {
|
||||||
|
val workQuery = WorkQuery.Builder
|
||||||
|
.fromStates(listOf(WorkInfo.State.FAILED, WorkInfo.State.SUCCEEDED))
|
||||||
|
.build()
|
||||||
|
|
||||||
|
val workInfo: ListenableFuture<List<WorkInfo>> = WorkManager.getInstance(context).getWorkInfos(workQuery)
|
||||||
|
aapsLogger.debug(LTag.CORE, "WorkManager size is ${workInfo.get().size}")
|
||||||
|
if (workInfo.get().size > 1000) {
|
||||||
|
WorkManager.getInstance(context).pruneWork()
|
||||||
|
aapsLogger.debug(LTag.CORE, "WorkManager pruning ....")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Usually deviceStatus is uploaded through LoopPlugin after every loop cycle.
|
||||||
|
// if there is no BG available, we have to upload anyway to have correct
|
||||||
|
// IOB displayed in NS
|
||||||
|
private fun checkAPS() {
|
||||||
|
var shouldUploadStatus = false
|
||||||
|
if (config.NSCLIENT) return
|
||||||
|
if (config.PUMPCONTROL) shouldUploadStatus = true
|
||||||
|
else if (!(loop as PluginBase).isEnabled() || iobCobCalculator.ads.actualBg() == null)
|
||||||
|
shouldUploadStatus = true
|
||||||
|
else if (dateUtil.isOlderThan(activePlugin.activeAPS.lastAPSRun, 5)) shouldUploadStatus = true
|
||||||
|
if (dateUtil.isOlderThan(lastIobUpload, IOB_UPDATE_FREQUENCY_IN_MINUTES) && shouldUploadStatus) {
|
||||||
|
lastIobUpload = dateUtil.now()
|
||||||
|
buildDeviceStatus(
|
||||||
|
dateUtil, loop, iobCobCalculator, profileFunction,
|
||||||
|
activePlugin.activePump, receiverStatusStore, runningConfiguration,
|
||||||
|
BuildConfig.VERSION_NAME + "-" + BuildConfig.BUILDVERSION
|
||||||
|
)?.also {
|
||||||
|
repository.insert(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun checkPump() {
|
||||||
|
val pump = activePlugin.activePump
|
||||||
|
val ps = profileFunction.getRequestedProfile() ?: return
|
||||||
|
val requestedProfile = ProfileSealed.PS(ps)
|
||||||
|
val runningProfile = profileFunction.getProfile()
|
||||||
|
val lastConnection = pump.lastDataTime()
|
||||||
|
val isStatusOutdated = lastConnection + STATUS_UPDATE_FREQUENCY < System.currentTimeMillis()
|
||||||
|
val isBasalOutdated = abs(requestedProfile.getBasal() - pump.baseBasalRate) > pump.pumpDescription.basalStep
|
||||||
|
aapsLogger.debug(LTag.CORE, "Last connection: " + dateUtil.dateAndTimeString(lastConnection))
|
||||||
|
// sometimes keep alive broadcast stops
|
||||||
|
// as as workaround test if readStatus was requested before an alarm is generated
|
||||||
|
if (lastReadStatus != 0L && lastReadStatus > System.currentTimeMillis() - T.mins(5).msecs()) {
|
||||||
|
localAlertUtils.checkPumpUnreachableAlarm(lastConnection, isStatusOutdated, loop.isDisconnected)
|
||||||
|
}
|
||||||
|
if (loop.isDisconnected) {
|
||||||
|
// do nothing if pump is disconnected
|
||||||
|
} else if (runningProfile == null || ((!pump.isThisProfileSet(requestedProfile) || !requestedProfile.isEqual(runningProfile)) && !commandQueue.isRunning(Command.CommandType.BASAL_PROFILE))) {
|
||||||
|
rxBus.send(EventProfileSwitchChanged())
|
||||||
|
} else if (isStatusOutdated && !pump.isBusy()) {
|
||||||
|
lastReadStatus = System.currentTimeMillis()
|
||||||
|
commandQueue.readStatus(rh.gs(R.string.keepalive_status_outdated), null)
|
||||||
|
} else if (isBasalOutdated && !pump.isBusy()) {
|
||||||
|
lastReadStatus = System.currentTimeMillis()
|
||||||
|
commandQueue.readStatus(rh.gs(R.string.keepalive_basal_outdated), null)
|
||||||
|
}
|
||||||
|
if (lastRun != 0L && System.currentTimeMillis() - lastRun > T.mins(10).msecs()) {
|
||||||
|
aapsLogger.error(LTag.CORE, "KeepAlive fail")
|
||||||
|
fabricPrivacy.logCustom("KeepAliveFail")
|
||||||
|
}
|
||||||
|
lastRun = System.currentTimeMillis()
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue