AndroidAPS/app/src/main/java/info/nightscout/androidaps/services/LocationService.kt
2020-04-30 17:56:40 +02:00

148 lines
6.1 KiB
Kotlin

package info.nightscout.androidaps.services
import android.Manifest
import android.app.Service
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.location.Location
import android.location.LocationManager
import android.os.Bundle
import android.os.IBinder
import androidx.core.app.ActivityCompat
import com.google.android.gms.location.LocationServices
import dagger.android.DaggerService
import info.nightscout.androidaps.R
import info.nightscout.androidaps.events.EventAppExit
import info.nightscout.androidaps.events.EventLocationChange
import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.T
import info.nightscout.androidaps.utils.androidNotification.NotificationHolder
import info.nightscout.androidaps.utils.sharedPreferences.SP
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.schedulers.Schedulers
import javax.inject.Inject
class LocationService : DaggerService() {
@Inject lateinit var aapsLogger: AAPSLogger
@Inject lateinit var rxBus: RxBusWrapper
@Inject lateinit var sp: SP
@Inject lateinit var fabricPrivacy: FabricPrivacy
@Inject lateinit var notificationHolder: NotificationHolder
@Inject lateinit var lastLocationDataContainer: LastLocationDataContainer
private val disposable = CompositeDisposable()
private var locationManager: LocationManager? = null
private var locationListener: LocationListener? = null
private val LOCATION_INTERVAL_ACTIVE = T.mins(5).msecs()
private val LOCATION_INTERVAL_PASSIVE = T.mins(1).msecs() // this doesn't cost more power
companion object {
private const val LOCATION_DISTANCE = 10f
}
inner class LocationListener internal constructor(val provider: String) : android.location.LocationListener {
init {
aapsLogger.debug(LTag.LOCATION, "LocationListener $provider")
}
override fun onLocationChanged(location: Location) {
aapsLogger.debug(LTag.LOCATION, "onLocationChanged: $location")
lastLocationDataContainer.lastLocation = location
rxBus.send(EventLocationChange(location))
}
override fun onProviderDisabled(provider: String) {
aapsLogger.debug(LTag.LOCATION, "onProviderDisabled: $provider")
}
override fun onProviderEnabled(provider: String) {
aapsLogger.debug(LTag.LOCATION, "onProviderEnabled: $provider")
}
override fun onStatusChanged(provider: String, status: Int, extras: Bundle) {
aapsLogger.debug(LTag.LOCATION, "onStatusChanged: $provider")
}
}
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
super.onStartCommand(intent, flags, startId)
startForeground(notificationHolder.notificationID, notificationHolder.notification)
return Service.START_STICKY
}
override fun onCreate() {
super.onCreate()
startForeground(notificationHolder.notificationID, notificationHolder.notification)
// Get last location once until we get regular update
LocationServices.getFusedLocationProviderClient(this).lastLocation.addOnSuccessListener {
lastLocationDataContainer.lastLocation = it
}
initializeLocationManager()
try {
if (sp.getString(R.string.key_location, "NONE") == "NETWORK") locationManager?.requestLocationUpdates(
LocationManager.NETWORK_PROVIDER,
LOCATION_INTERVAL_ACTIVE,
LOCATION_DISTANCE,
LocationListener(LocationManager.NETWORK_PROVIDER).also { locationListener = it }
)
if (sp.getString(R.string.key_location, "NONE") == "GPS") locationManager?.requestLocationUpdates(
LocationManager.GPS_PROVIDER,
LOCATION_INTERVAL_ACTIVE,
LOCATION_DISTANCE,
LocationListener(LocationManager.GPS_PROVIDER).also { locationListener = it }
)
if (sp.getString(R.string.key_location, "NONE") == "PASSIVE") locationManager?.requestLocationUpdates(
LocationManager.PASSIVE_PROVIDER,
LOCATION_INTERVAL_PASSIVE,
LOCATION_DISTANCE,
LocationListener(LocationManager.PASSIVE_PROVIDER).also { locationListener = it }
)
} catch (ex: SecurityException) {
aapsLogger.error(LTag.LOCATION, "fail to request location update, ignore", ex)
} catch (ex: IllegalArgumentException) {
aapsLogger.error(LTag.LOCATION, "network provider does not exist", ex)
}
disposable.add(rxBus
.toObservable(EventAppExit::class.java)
.observeOn(Schedulers.io())
.subscribe({
aapsLogger.debug(LTag.LOCATION, "EventAppExit received")
stopSelf()
}) { fabricPrivacy.logException(it) }
)
}
override fun onDestroy() {
super.onDestroy()
if (locationManager != null) {
try {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return
}
locationManager!!.removeUpdates(locationListener)
} catch (ex: Exception) {
aapsLogger.error(LTag.LOCATION, "fail to remove location listener, ignore", ex)
}
}
disposable.clear()
}
override fun onBind(intent: Intent?): IBinder? = null
private fun initializeLocationManager() {
aapsLogger.debug(LTag.LOCATION, "initializeLocationManager - Provider: " + sp.getString(R.string.key_location, "NONE"))
if (locationManager == null) {
locationManager = applicationContext.getSystemService(Context.LOCATION_SERVICE) as LocationManager
}
}
}