diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/WearPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/WearPlugin.kt index 61f0558009..e705b0b8bb 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/WearPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/WearPlugin.kt @@ -1,7 +1,6 @@ package info.nightscout.androidaps.plugins.general.wear import android.content.Context -import android.content.Intent import dagger.android.HasAndroidInjector import info.nightscout.androidaps.R import info.nightscout.androidaps.events.EventAutosensCalculationFinished @@ -10,14 +9,14 @@ import info.nightscout.androidaps.events.EventPreferenceChange import info.nightscout.androidaps.interfaces.PluginBase import info.nightscout.androidaps.interfaces.PluginDescription import info.nightscout.androidaps.interfaces.PluginType +import info.nightscout.androidaps.interfaces.ResourceHelper import info.nightscout.androidaps.plugins.aps.loop.events.EventLoopUpdateGui import info.nightscout.androidaps.plugins.bus.RxBus import info.nightscout.androidaps.plugins.general.overview.events.EventDismissBolusProgressIfRunning import info.nightscout.androidaps.plugins.general.overview.events.EventOverviewBolusProgress import info.nightscout.androidaps.plugins.general.wear.wearintegration.DataHandlerMobile -import info.nightscout.androidaps.plugins.general.wear.wearintegration.DataLayerListenerServiceMobile +import info.nightscout.androidaps.plugins.general.wear.wearintegration.DataLayerListenerServiceMobileHelper import info.nightscout.androidaps.utils.FabricPrivacy -import info.nightscout.androidaps.interfaces.ResourceHelper import info.nightscout.androidaps.utils.rx.AapsSchedulers import info.nightscout.shared.logging.AAPSLogger import info.nightscout.shared.sharedPreferences.SP @@ -37,7 +36,8 @@ class WearPlugin @Inject constructor( private val fabricPrivacy: FabricPrivacy, private val rxBus: RxBus, private val context: Context, - private val dataHandlerMobile: DataHandlerMobile + private val dataHandlerMobile: DataHandlerMobile, + val dataLayerListenerServiceMobileHelper: DataLayerListenerServiceMobileHelper ) : PluginBase( PluginDescription() @@ -57,7 +57,7 @@ class WearPlugin @Inject constructor( override fun onStart() { super.onStart() - context.startService(Intent(context, DataLayerListenerServiceMobile::class.java)) + dataLayerListenerServiceMobileHelper.startService(context) disposable += rxBus .toObservable(EventDismissBolusProgressIfRunning::class.java) .observeOn(aapsSchedulers.io) @@ -94,6 +94,6 @@ class WearPlugin @Inject constructor( override fun onStop() { disposable.clear() super.onStop() - context.stopService(Intent(context, DataLayerListenerServiceMobile::class.java)) + dataLayerListenerServiceMobileHelper.stopService(context) } } \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/wearintegration/DataLayerListenerServiceMobile.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/wearintegration/DataLayerListenerServiceMobile.kt index 916dcb526b..1a3cd7f601 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/wearintegration/DataLayerListenerServiceMobile.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/wearintegration/DataLayerListenerServiceMobile.kt @@ -1,5 +1,6 @@ package info.nightscout.androidaps.plugins.general.wear.wearintegration +import android.os.Binder import android.os.Handler import android.os.HandlerThread import com.google.android.gms.tasks.Tasks @@ -44,6 +45,11 @@ class DataLayerListenerServiceMobile : WearableListenerService() { @Inject lateinit var rxBus: RxBus @Inject lateinit var aapsSchedulers: AapsSchedulers + inner class LocalBinder : Binder() { + + fun getService(): DataLayerListenerServiceMobile = this@DataLayerListenerServiceMobile + } + private val dataClient by lazy { Wearable.getDataClient(this) } private val messageClient by lazy { Wearable.getMessageClient(this) } private val capabilityClient by lazy { Wearable.getCapabilityClient(this) } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/wearintegration/DataLayerListenerServiceMobileHelper.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/wearintegration/DataLayerListenerServiceMobileHelper.kt new file mode 100644 index 0000000000..941e04eb53 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/wearintegration/DataLayerListenerServiceMobileHelper.kt @@ -0,0 +1,62 @@ +package info.nightscout.androidaps.plugins.general.wear.wearintegration + +import android.content.ComponentName +import android.content.Context +import android.content.Intent +import android.content.ServiceConnection +import android.os.IBinder +import info.nightscout.androidaps.interfaces.NotificationHolder +import javax.inject.Inject +import javax.inject.Singleton + +/* + This code replaces following + val alarm = Intent(context, DataLayerListenerServiceMobile::class.java) + 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.DataLayerListenerServiceMobile} + + */ +@Singleton +class DataLayerListenerServiceMobileHelper @Inject constructor( + private val notificationHolder: NotificationHolder +) { + + 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: DataLayerListenerServiceMobile.LocalBinder = service as DataLayerListenerServiceMobile.LocalBinder + + val dataLayerListenerServiceMobile: DataLayerListenerServiceMobile = binder.getService() + + context.startForegroundService(Intent(context, DataLayerListenerServiceMobile::class.java)) + + // This is the key: Without waiting Android Framework to call this method + // inside Service.onCreate(), immediately call here to post the notification. + dataLayerListenerServiceMobile.startForeground(notificationHolder.notificationID, notificationHolder.notification) + + // Release the connection to prevent leaks. + context.unbindService(this) + } + + override fun onServiceDisconnected(name: ComponentName?) { + } + } + + try { + context.bindService(Intent(context, DataLayerListenerServiceMobile::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, DataLayerListenerServiceMobile::class.java)) + } + } + + fun stopService(context: Context) { + context.stopService(Intent(context, DataLayerListenerServiceMobile::class.java)) + } +} \ No newline at end of file