Skip to content

Instantly share code, notes, and snippets.

@nathanmkaya
Created May 15, 2023 13:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nathanmkaya/1203f130325a405663a1ff187a8d911d to your computer and use it in GitHub Desktop.
Save nathanmkaya/1203f130325a405663a1ff187a8d911d to your computer and use it in GitHub Desktop.
import android.annotation.SuppressLint
import android.app.Activity
import android.content.Context
import android.location.Location
import android.location.LocationListener
import android.location.LocationManager
import android.os.Looper
import androidx.core.content.getSystemService
import com.google.android.gms.common.api.ResolvableApiException
import com.google.android.gms.location.FusedLocationProviderClient
import com.google.android.gms.location.LocationAvailability
import com.google.android.gms.location.LocationCallback
import com.google.android.gms.location.LocationRequest
import com.google.android.gms.location.LocationServices
import com.google.android.gms.location.LocationSettingsRequest
import com.google.android.gms.location.Priority
import com.google.android.gms.location.SettingsClient
import com.google.android.gms.maps.model.LatLng
import io.reactivex.Completable
import io.reactivex.Maybe
import io.reactivex.Observable
import io.reactivex.Scheduler
class LocationProvider @JvmOverloads constructor(
private val context: Context,
private val scheduler: Scheduler,
private val locationClient: FusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(context),
private val settingsClient: SettingsClient = LocationServices.getSettingsClient(context),
private val locationManager: LocationManager? = context.getSystemService(),
) {
private val locationRequest = LocationRequest.Builder(DEFAULT_LOCATION_INTERVAL).apply { // every 60 seconds
setMaxUpdateAgeMillis(DEFAULT_LOCATION_MAX_WAIT_TIME) // every ~3.5 minutes
setMinUpdateIntervalMillis(DEFAULT_LOCATION_FAST_INTERVAL) // every 30 seconds
setPriority(Priority.PRIORITY_BALANCED_POWER_ACCURACY)
}.build()
private val locationSettingsRequest = LocationSettingsRequest.Builder()
.addLocationRequest(locationRequest)
/**
* Observe the location on a prepared looper
* Permission is called in the view that calls this method
*/
@SuppressLint("MissingPermission")
fun location(): Maybe<LatLng> =
Maybe.create<LatLng> { subscriber ->
locationClient.lastLocation.addOnSuccessListener { location ->
subscriber.onSuccess(location.toLatLng())
}.addOnFailureListener { error ->
subscriber.onError(error)
}.addOnCompleteListener {
if (!subscriber.isDisposed) {
subscriber.onComplete()
}
}.addOnCanceledListener {
if (!subscriber.isDisposed) {
subscriber.onComplete()
}
}
}.observeOn(scheduler)
fun checkLocationSettings() =
Completable.create { subscriber ->
settingsClient.checkLocationSettings(locationSettingsRequest.build())
.addOnFailureListener { exception ->
if (exception is ResolvableApiException) {
exception.startResolutionForResult(context as Activity, LOCATION_SETTINGS_RC)
} else {
subscriber.onError(exception)
}
}
.addOnCanceledListener {
if (!subscriber.isDisposed) {
subscriber.onComplete()
}
}
.addOnCompleteListener {
if (!subscriber.isDisposed) {
subscriber.onComplete()
}
}
}.observeOn(scheduler)
@SuppressLint("MissingPermission")
fun isGPSOnline() =
Observable.create<Boolean> { emitter ->
locationManager?.requestLocationUpdates(
LocationManager.GPS_PROVIDER, DEFAULT_LOCATION_FAST_INTERVAL, 2f, object : LocationListener {
override fun onLocationChanged(p0: Location) = Unit
override fun onProviderDisabled(provider: String) {
super.onProviderDisabled(provider)
emitter.onNext(false)
}
override fun onProviderEnabled(provider: String) {
super.onProviderEnabled(provider)
emitter.onNext(true)
}
})
}
private fun Location?.toLatLng(): LatLng =
this?.let { LatLng(this.latitude, this.longitude) } ?: LatLng(0.0, 0.0)
companion object {
private const val DEFAULT_LOCATION_INTERVAL: Long = 60000
private const val DEFAULT_LOCATION_FAST_INTERVAL: Long = 30000
private const val DEFAULT_LOCATION_MAX_WAIT_TIME: Long = 200000
private const val LOCATION_SETTINGS_RC = 100002
}
}
fun LatLng.toStringValue(): String =
"${this.latitude}, ${this.longitude}"
fun String.toLatLng(): LatLng {
val list = this.split(",").map { it.trim().toDouble() }
return LatLng(list[0], list[1])
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment