DummyServiceHelper

This commit is contained in:
Milos Kozak 2021-01-17 13:23:59 +01:00
parent 8a683ee571
commit 68faba8951
4 changed files with 106 additions and 28 deletions

View file

@ -3,6 +3,7 @@ package info.nightscout.androidaps.plugins.general.persistentNotification
import android.app.Notification import android.app.Notification
import android.app.Service import android.app.Service
import android.content.Intent import android.content.Intent
import android.os.Binder
import android.os.IBinder import android.os.IBinder
import dagger.android.DaggerService import dagger.android.DaggerService
import info.nightscout.androidaps.events.EventAppExit import info.nightscout.androidaps.events.EventAppExit
@ -27,7 +28,13 @@ class DummyService : DaggerService() {
private val disposable = CompositeDisposable() private val disposable = CompositeDisposable()
override fun onBind(intent: Intent?): IBinder? = null inner class LocalBinder : Binder() {
fun getService(): DummyService = this@DummyService
}
private val binder = LocalBinder()
override fun onBind(intent: Intent): IBinder = binder
override fun onCreate() { override fun onCreate() {
super.onCreate() super.onCreate()
@ -44,7 +51,7 @@ class DummyService : DaggerService() {
.subscribe({ .subscribe({
aapsLogger.debug(LTag.CORE, "EventAppExit received") aapsLogger.debug(LTag.CORE, "EventAppExit received")
stopSelf() stopSelf()
}, fabricPrivacy::logException ) }, fabricPrivacy::logException)
) )
} }

View file

@ -0,0 +1,66 @@
package info.nightscout.androidaps.plugins.general.persistentNotification
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.os.Build
import android.os.IBinder
import androidx.annotation.RequiresApi
import info.nightscout.androidaps.interfaces.NotificationHolderInterface
import javax.inject.Inject
import javax.inject.Singleton
/*
This code replaces following
val alarm = Intent(context, DummyService::class.java)
alarm.putExtra("soundid", n.soundId)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) context.startForegroundService(alarm) else context.startService(alarm)
it fails randomly with error
Context.startForegroundService() did not then call Service.startForeground(): ServiceRecord{e317f7e u0 info.nightscout.nsclient/info.nightscout.androidaps.services.DummyService}
*/
@RequiresApi(Build.VERSION_CODES.O)
@Singleton
class DummyServiceHelper @Inject constructor(
private val notificationHolder: NotificationHolderInterface
) {
fun startService(context: Context) {
val connection = object : ServiceConnection {
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
// The binder of the service that returns the instance that is created.
val binder: DummyService.LocalBinder = service as DummyService.LocalBinder
val dummyService: DummyService = binder.getService()
context.startForegroundService(Intent(context, DummyService::class.java))
// This is the key: Without waiting Android Framework to call this method
// inside Service.onCreate(), immediately call here to post the notification.
dummyService.startForeground(notificationHolder.notificationID, notificationHolder.notification)
// Release the connection to prevent leaks.
context.unbindService(this)
}
override fun onServiceDisconnected(name: ComponentName?) {
}
}
try {
context.bindService(Intent(context, DummyService::class.java), connection, Context.BIND_AUTO_CREATE)
} catch (ignored: RuntimeException) {
// This is probably a broadcast receiver context even though we are calling getApplicationContext().
// Just call startForegroundService instead since we cannot bind a service to a
// broadcast receiver context. The service also have to call startForeground in
// this case.
context.startForegroundService(Intent(context, DummyService::class.java))
}
}
fun stopService(context: Context) {
context.stopService(Intent(context, DummyService::class.java))
}
}

View file

@ -30,18 +30,20 @@ import io.reactivex.schedulers.Schedulers
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@Suppress("PrivatePropertyName")
@Singleton @Singleton
class PersistentNotificationPlugin @Inject constructor( class PersistentNotificationPlugin @Inject constructor(
injector: HasAndroidInjector, injector: HasAndroidInjector,
aapsLogger: AAPSLogger, aapsLogger: AAPSLogger,
resourceHelper: ResourceHelper, resourceHelper: ResourceHelper,
private var profileFunction: ProfileFunction, private val profileFunction: ProfileFunction,
private var fabricPrivacy: FabricPrivacy, private val fabricPrivacy: FabricPrivacy,
private var activePlugins: ActivePluginProvider, private val activePlugins: ActivePluginProvider,
private var iobCobCalculatorPlugin: IobCobCalculatorPlugin, private val iobCobCalculatorPlugin: IobCobCalculatorPlugin,
private var rxBus: RxBusWrapper, private val rxBus: RxBusWrapper,
private var context: Context, private val context: Context,
private var notificationHolder: NotificationHolder, private val notificationHolder: NotificationHolder,
private val dummyServiceHelper: DummyServiceHelper,
private val iconsProvider: IconsProvider, private val iconsProvider: IconsProvider,
private val databaseHelper: DatabaseHelperInterface private val databaseHelper: DatabaseHelperInterface
) : PluginBase(PluginDescription() ) : PluginBase(PluginDescription()
@ -112,13 +114,13 @@ class PersistentNotificationPlugin @Inject constructor(
override fun onStop() { override fun onStop() {
disposable.clear() disposable.clear()
context.stopService(Intent(context, DummyService::class.java)) dummyServiceHelper.stopService(context)
super.onStop() super.onStop()
} }
private fun triggerNotificationUpdate() { private fun triggerNotificationUpdate() {
updateNotification() updateNotification()
context.startForegroundService(Intent(context, DummyService::class.java)) dummyServiceHelper.startService(context)
} }
private fun updateNotification() { private fun updateNotification() {
@ -128,31 +130,31 @@ class PersistentNotificationPlugin @Inject constructor(
var line3: String? = null var line3: String? = null
var unreadConversationBuilder: NotificationCompat.CarExtender.UnreadConversation.Builder? = null var unreadConversationBuilder: NotificationCompat.CarExtender.UnreadConversation.Builder? = null
if (profileFunction.isProfileValid("Notification")) { if (profileFunction.isProfileValid("Notification")) {
var line1_aa: String var line1aa: String
val units = profileFunction.getUnits() val units = profileFunction.getUnits()
val lastBG = iobCobCalculatorPlugin.lastBg() val lastBG = iobCobCalculatorPlugin.lastBg()
val glucoseStatus = GlucoseStatus(injector).glucoseStatusData val glucoseStatus = GlucoseStatus(injector).glucoseStatusData
if (lastBG != null) { if (lastBG != null) {
line1_aa = lastBG.valueToUnitsToString(units) line1aa = lastBG.valueToUnitsToString(units)
line1 = line1_aa line1 = line1aa
if (glucoseStatus != null) { if (glucoseStatus != null) {
line1 += (" Δ" + Profile.toSignedUnitsString(glucoseStatus.delta, glucoseStatus.delta * Constants.MGDL_TO_MMOLL, units) line1 += (" Δ" + Profile.toSignedUnitsString(glucoseStatus.delta, glucoseStatus.delta * Constants.MGDL_TO_MMOLL, units)
+ " avgΔ" + Profile.toSignedUnitsString(glucoseStatus.avgdelta, glucoseStatus.avgdelta * Constants.MGDL_TO_MMOLL, units)) + " avgΔ" + Profile.toSignedUnitsString(glucoseStatus.avgdelta, glucoseStatus.avgdelta * Constants.MGDL_TO_MMOLL, units))
line1_aa += " " + lastBG.directionToSymbol(databaseHelper) line1aa += " " + lastBG.directionToSymbol(databaseHelper)
} else { } else {
line1 += " " + line1 += " " +
resourceHelper.gs(R.string.old_data) + resourceHelper.gs(R.string.old_data) +
" " " "
line1_aa += "$line1." line1aa += "$line1."
} }
} else { } else {
line1_aa = resourceHelper.gs(R.string.missed_bg_readings) line1aa = resourceHelper.gs(R.string.missed_bg_readings)
line1 = line1_aa line1 = line1aa
} }
val activeTemp = activePlugins.activeTreatments.getTempBasalFromHistory(System.currentTimeMillis()) val activeTemp = activePlugins.activeTreatments.getTempBasalFromHistory(System.currentTimeMillis())
if (activeTemp != null) { if (activeTemp != null) {
line1 += " " + activeTemp.toStringShort() line1 += " " + activeTemp.toStringShort()
line1_aa += " " + activeTemp.toStringShort() + "." line1aa += " " + activeTemp.toStringShort() + "."
} }
//IOB //IOB
activePlugins.activeTreatments.updateTotalIOBTreatments() activePlugins.activeTreatments.updateTotalIOBTreatments()
@ -160,11 +162,11 @@ class PersistentNotificationPlugin @Inject constructor(
val bolusIob = activePlugins.activeTreatments.lastCalculationTreatments.round() val bolusIob = activePlugins.activeTreatments.lastCalculationTreatments.round()
val basalIob = activePlugins.activeTreatments.lastCalculationTempBasals.round() val basalIob = activePlugins.activeTreatments.lastCalculationTempBasals.round()
line2 = resourceHelper.gs(R.string.treatments_iob_label_string) + " " + DecimalFormatter.to2Decimal(bolusIob.iob + basalIob.basaliob) + "U " + resourceHelper.gs(R.string.cob) + ": " + iobCobCalculatorPlugin.getCobInfo(false, "PersistentNotificationPlugin").generateCOBString() line2 = resourceHelper.gs(R.string.treatments_iob_label_string) + " " + DecimalFormatter.to2Decimal(bolusIob.iob + basalIob.basaliob) + "U " + resourceHelper.gs(R.string.cob) + ": " + iobCobCalculatorPlugin.getCobInfo(false, "PersistentNotificationPlugin").generateCOBString()
val line2_aa = resourceHelper.gs(R.string.treatments_iob_label_string) + " " + DecimalFormatter.to2Decimal(bolusIob.iob + basalIob.basaliob) + "U. " + resourceHelper.gs(R.string.cob) + ": " + iobCobCalculatorPlugin.getCobInfo(false, "PersistentNotificationPlugin").generateCOBString() + "." val line2aa = resourceHelper.gs(R.string.treatments_iob_label_string) + " " + DecimalFormatter.to2Decimal(bolusIob.iob + basalIob.basaliob) + "U. " + resourceHelper.gs(R.string.cob) + ": " + iobCobCalculatorPlugin.getCobInfo(false, "PersistentNotificationPlugin").generateCOBString() + "."
line3 = DecimalFormatter.to2Decimal(pump.baseBasalRate) + " U/h" line3 = DecimalFormatter.to2Decimal(pump.baseBasalRate) + " U/h"
var line3_aa = DecimalFormatter.to2Decimal(pump.baseBasalRate) + " U/h." var line3aa = DecimalFormatter.to2Decimal(pump.baseBasalRate) + " U/h."
line3 += " - " + profileFunction.getProfileName() line3 += " - " + profileFunction.getProfileName()
line3_aa += " - " + profileFunction.getProfileName() + "." line3aa += " - " + profileFunction.getProfileName() + "."
/// For Android Auto /// For Android Auto
val msgReadIntent = Intent() val msgReadIntent = Intent()
.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES) .addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES)
@ -188,12 +190,12 @@ class PersistentNotificationPlugin @Inject constructor(
// Build a RemoteInput for receiving voice input from devices // Build a RemoteInput for receiving voice input from devices
val remoteInput = RemoteInput.Builder(EXTRA_VOICE_REPLY).build() val remoteInput = RemoteInput.Builder(EXTRA_VOICE_REPLY).build()
// Create the UnreadConversation // Create the UnreadConversation
unreadConversationBuilder = NotificationCompat.CarExtender.UnreadConversation.Builder(line1_aa + "\n" + line2_aa) unreadConversationBuilder = NotificationCompat.CarExtender.UnreadConversation.Builder(line1aa + "\n" + line2aa)
.setLatestTimestamp(System.currentTimeMillis()) .setLatestTimestamp(System.currentTimeMillis())
.setReadPendingIntent(msgReadPendingIntent) .setReadPendingIntent(msgReadPendingIntent)
.setReplyAction(msgReplyPendingIntent, remoteInput) .setReplyAction(msgReplyPendingIntent, remoteInput)
/// Add dot to produce a "more natural sounding result" /// Add dot to produce a "more natural sounding result"
unreadConversationBuilder.addMessage(line3_aa) unreadConversationBuilder.addMessage(line3aa)
/// End Android Auto /// End Android Auto
} else { } else {
line1 = resourceHelper.gs(R.string.noprofileset) line1 = resourceHelper.gs(R.string.noprofileset)

View file

@ -1,14 +1,17 @@
package info.nightscout.androidaps.receivers package info.nightscout.androidaps.receivers
import android.content.BroadcastReceiver
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import info.nightscout.androidaps.plugins.general.persistentNotification.DummyService import dagger.android.DaggerBroadcastReceiver
import info.nightscout.androidaps.plugins.general.persistentNotification.DummyServiceHelper
class AutoStartReceiver : BroadcastReceiver() { class AutoStartReceiver constructor(
private val dummyServiceHelper: DummyServiceHelper
) : DaggerBroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) { override fun onReceive(context: Context, intent: Intent) {
super.onReceive(context, intent)
if (intent.action == Intent.ACTION_BOOT_COMPLETED) if (intent.action == Intent.ACTION_BOOT_COMPLETED)
context.startForegroundService(Intent(context, DummyService::class.java)) dummyServiceHelper.startService(context)
} }
} }