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.Service
import android.content.Intent
import android.os.Binder
import android.os.IBinder
import dagger.android.DaggerService
import info.nightscout.androidaps.events.EventAppExit
@ -27,7 +28,13 @@ class DummyService : DaggerService() {
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() {
super.onCreate()

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

View file

@ -1,14 +1,17 @@
package info.nightscout.androidaps.receivers
import android.content.BroadcastReceiver
import android.content.Context
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) {
super.onReceive(context, intent)
if (intent.action == Intent.ACTION_BOOT_COMPLETED)
context.startForegroundService(Intent(context, DummyService::class.java))
dummyServiceHelper.startService(context)
}
}