You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
poker-analytics/app/src/main/java/net/pokeranalytics/android/util/LocationManager.kt

174 lines
5.7 KiB

package net.pokeranalytics.android.util
import android.Manifest.permission.ACCESS_FINE_LOCATION
import android.content.Context
import android.content.pm.PackageManager
import androidx.core.content.ContextCompat
import com.google.android.gms.common.api.ApiException
import com.google.android.gms.location.FusedLocationProviderClient
import com.google.android.gms.location.LocationServices
import com.google.android.libraries.places.api.Places
import com.google.android.libraries.places.api.model.Place
import com.google.android.libraries.places.api.model.PlaceLikelihood
import com.google.android.libraries.places.api.net.FindCurrentPlaceRequest
import io.realm.Realm
import io.realm.kotlin.where
import net.pokeranalytics.android.model.realm.Location
import timber.log.Timber
import java.util.*
import kotlin.collections.ArrayList
class LocationManager(private var context: Context) {
companion object {
const val MAXIMUM_DISTANCE_FROM_USER = 5000 // in meters
}
/**
* Return the [places] around the user
*/
fun askForPlacesRequest(callback: ((success: Boolean, places: ArrayList<PlaceLikelihood>) -> Unit)?) {
// Initialize Places.
Places.initialize(context, context.getString(net.pokeranalytics.android.R.string.google_places_api))
// Create a new Places client instance.
val placesClient = Places.createClient(context)
// Use fields to define the data types to return.
val placeFields = Arrays.asList(Place.Field.NAME, Place.Field.ADDRESS, Place.Field.LAT_LNG)
// Use the builder to buildAndShow a FindCurrentPlaceRequest.
val request = FindCurrentPlaceRequest.builder(placeFields).build()
// Call findCurrentPlace and handle the response (first check that the user has granted permission).
if (ContextCompat.checkSelfPermission(context, ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
val placeResponse = placesClient.findCurrentPlace(request)
placeResponse.addOnCompleteListener { task ->
val places = ArrayList<PlaceLikelihood>()
if (task.isSuccessful) {
val response = task.result
response?.placeLikelihoods?.let {
places.addAll(it)
}
} else {
val exception = task.exception
if (exception is ApiException) {
Timber.d("Error: ${"Place not found: " + exception.statusCode}")
}
}
callback?.invoke(task.isSuccessful, places)
}
} else {
// If we don't have the permission, return
callback?.invoke(false, ArrayList())
}
}
/**
* Return if the database contains one or many locations with coordinates
*/
fun databaseContainsLocationsWithCoordinates(): Boolean {
val realm = Realm.getDefaultInstance()
val result = realm.where<Location>().isNotNull("latitude")
.and().isNotNull("longitude").findAll().isNotEmpty()
realm.close()
return result
}
/**
* Find the nearest location from user
*/
fun findNearestLocationFromUser(callback: ((location: Location?) -> Unit)?) {
val locations = ArrayList<net.pokeranalytics.android.model.realm.Location>()
val realm = Realm.getDefaultInstance()
val realmResults = realm.where<Location>().isNotNull("latitude")
.and().isNotNull("longitude").findAll()
locations.addAll(realm.copyFromRealm(realmResults))
realm.close()
// If we have no locations with coordinates, return null
if (realmResults.size == 0) {
callback?.invoke(null)
return
}
val fusedLocationClient: FusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(context)
if (ContextCompat.checkSelfPermission(context, ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
fusedLocationClient.lastLocation.addOnSuccessListener { location: android.location.Location? ->
// Got last known location. In some rare situations this can be null.
location?.let { currentLocation ->
locations.sortBy {
val locationToSort = android.location.Location("")
locationToSort.latitude = it.latitude!!
locationToSort.longitude = it.longitude!!
currentLocation.distanceTo(locationToSort)
}
val nearestLocation = locations.firstOrNull()
nearestLocation?.let {
val locationForDistance = android.location.Location("")
locationForDistance.latitude = it.latitude ?: 0.0
locationForDistance.longitude = it.longitude ?: 0.0
// Final check: if the distance between the location and the user is lower than MAXIMUM_DISTANCE_FROM_USER
if (currentLocation.distanceTo(locationForDistance) < MAXIMUM_DISTANCE_FROM_USER) {
callback?.invoke(nearestLocation)
} else {
callback?.invoke(null)
}
} ?: run {
callback?.invoke(null)
}
} ?: run {
// If the current location is null, return null
callback?.invoke(null)
}
}.addOnCanceledListener {
// If there was a problem during the call to last location, return null
callback?.invoke(null)
}
} else {
// If we don't have the permission, return null
callback?.invoke(null)
}
}
/**
* Return the current location of the user
*/
fun findCurrentLocation(callback: ((location: android.location.Location?) -> Unit)?) {
val fusedLocationClient: FusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(context)
if (ContextCompat.checkSelfPermission(context, ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
fusedLocationClient.lastLocation.addOnSuccessListener { location: android.location.Location? ->
// Got last known location. In some rare situations this can be null.
location?.let { currentLocation ->
callback?.invoke(currentLocation)
} ?: run {
// If the current location is null, return null
callback?.invoke(null)
}
}.addOnCanceledListener {
// If there was a problem during the call to last location, return null
callback?.invoke(null)
}
} else {
callback?.invoke(null)
}
}
}