Add findNearestLocation & refactor callbacks management

feature/top10
Aurelien Hubert 7 years ago
parent 02b05d99f1
commit 7476af5e6c
  1. 55
      app/src/main/java/net/pokeranalytics/android/ui/activity/components/PokerAnalyticsActivity.kt
  2. 91
      app/src/main/java/net/pokeranalytics/android/util/LocationManager.kt

@ -10,8 +10,8 @@ import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import com.google.android.libraries.places.api.model.PlaceLikelihood import com.google.android.libraries.places.api.model.PlaceLikelihood
import io.realm.Realm import io.realm.Realm
import net.pokeranalytics.android.model.realm.Location
import net.pokeranalytics.android.util.LocationManager import net.pokeranalytics.android.util.LocationManager
import java.util.*
open class PokerAnalyticsActivity : AppCompatActivity() { open class PokerAnalyticsActivity : AppCompatActivity() {
@ -21,8 +21,7 @@ open class PokerAnalyticsActivity : AppCompatActivity() {
} }
private val realm = Realm.getDefaultInstance() private val realm = Realm.getDefaultInstance()
private var askFromPlaces = false private var permissionCallback: ((granted: Boolean) -> Unit)? = null
private var currentCallback: ((success: Boolean, places: ArrayList<PlaceLikelihood>) -> Unit)? = null
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@ -36,8 +35,9 @@ open class PokerAnalyticsActivity : AppCompatActivity() {
if (permissions.isNotEmpty() && permissions[0] == Manifest.permission.ACCESS_FINE_LOCATION if (permissions.isNotEmpty() && permissions[0] == Manifest.permission.ACCESS_FINE_LOCATION
&& grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED && grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED
) { ) {
locationPermissionGranted() permissionCallback?.invoke(true)
} else { } else {
permissionCallback?.invoke(false)
// permission denied, boo! Disable the // permission denied, boo! Disable the
// functionality that depends on this permission. // functionality that depends on this permission.
// showMessage(getString(R.string.error)); // showMessage(getString(R.string.error));
@ -71,35 +71,50 @@ open class PokerAnalyticsActivity : AppCompatActivity() {
/** /**
* Ask for location permission * Ask for location permission
*/ */
private fun askForLocationPermission() { private fun askForLocationPermission(permissionCallback: ((granted: Boolean) -> Unit)) {
this.permissionCallback = permissionCallback
ActivityCompat.requestPermissions( ActivityCompat.requestPermissions(
this, arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), this, arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), PERMISSION_REQUEST_ACCESS_FINE_LOCATION
PERMISSION_REQUEST_ACCESS_FINE_LOCATION
) )
} }
/**
* Called when the permission location has been granted
*/
open fun locationPermissionGranted() {
if (askFromPlaces) {
askFromPlaces = false
askForPlacesRequest(currentCallback)
}
}
/** /**
* Ask for places request * Ask for places request
*/ */
fun askForPlacesRequest(callback: ((success: Boolean, places: ArrayList<PlaceLikelihood>) -> Unit)?) { fun askForPlacesRequest(callback: ((success: Boolean, places: ArrayList<PlaceLikelihood>) -> Unit)?) {
// Call findCurrentPlace and handle the response (first check that the user has granted permission). // Call findCurrentPlace and handle the response (first check that the user has granted permission).
if (ContextCompat.checkSelfPermission(this, ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) { if (ContextCompat.checkSelfPermission(this, ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
LocationManager(this).askForPlacesRequest(callback) LocationManager(this).askForPlacesRequest(callback)
} else { } else {
askFromPlaces = true askForLocationPermission { granted ->
currentCallback = callback if (granted) {
askForLocationPermission() LocationManager(this).askForPlacesRequest(callback)
} else {
callback?.invoke(false, ArrayList())
}
}
}
}
/**
* Find the nearest location from the user
*/
fun findNearestLocation(callback: ((location: Location?) -> Unit)?) {
if (LocationManager(this).databaseContainsLocationsWithCoordinates()) {
if (ContextCompat.checkSelfPermission(this, ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
LocationManager(this).findNearestLocationFromUser(callback)
} else {
askForLocationPermission { granted ->
if (granted) {
LocationManager(this).findNearestLocationFromUser(callback)
} else {
callback?.invoke(null)
}
}
}
} else {
callback?.invoke(null)
} }
} }

@ -5,15 +5,25 @@ import android.content.Context
import android.content.pm.PackageManager import android.content.pm.PackageManager
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import com.google.android.gms.common.api.ApiException 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.Places
import com.google.android.libraries.places.api.model.Place 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.model.PlaceLikelihood
import com.google.android.libraries.places.api.net.FindCurrentPlaceRequest 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 timber.log.Timber
import java.util.* import java.util.*
import kotlin.collections.ArrayList
class LocationManager(private var context: Context) { class LocationManager(private var context: Context) {
companion object {
const val MAXIMUM_DISTANCE_FROM_USER = 5000 // in meters
}
/** /**
* Return the [places] around the user * Return the [places] around the user
*/ */
@ -50,8 +60,89 @@ class LocationManager(private var context: Context) {
callback?.invoke(task.isSuccessful, places) 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)
} }
}
} }
Loading…
Cancel
Save