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.
174 lines
5.7 KiB
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)
|
|
}
|
|
}
|
|
|
|
} |