BlindlyTeam/Blindly

View on GitHub
app/src/main/java/ch/epfl/sdp/blindly/location/AndroidLocationService.kt

Summary

Maintainability
A
1 hr
Test Coverage
C
72%
package ch.epfl.sdp.blindly.location

import android.content.Context
import android.location.Geocoder
import android.location.Location
import android.location.LocationManager
import android.net.InetAddresses
import android.util.Log
import ch.epfl.sdp.blindly.user.User
import java.net.InetAddress.getByName

private const val MIN_TIME_FOR_UPDATE = 1L
private const val MIN_DISTANCE_FOR_UPDTAE = 1F
private const val EPFL_LAT = 46.518
private const val EPFL_LONG = 6.567
private const val MAX_RESULTS = 2

/**
 * The purpose of this class is to get the position of the user
 *
 * @property context
 */
class AndroidLocationService(private var context: Context) : LocationService {

    private val listeners: MutableList<LocationChangeListener> = ArrayList(1)
    private var isGPSEnable = false
    private var isNetworkEnable = false
    private var canGetLocation = false
    private var location: Location? = null

    private lateinit var locationManager: LocationManager

    init {
        getCurrentLocation()
    }

    /**
     * Get the current location of the user
     * Get the location from the GPS and if disabled from the network
     *
     * @return the user's location or null if GPS and network are disabled
     */
    override fun getCurrentLocation(): Location? {
        try {
            locationManager = context.getSystemService(Context.LOCATION_SERVICE) as LocationManager

            //check for GPS
            isGPSEnable = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)

            //check for network
            isNetworkEnable = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)

            if ((isGPSEnable) || (isNetworkEnable)) {
                canGetLocation = true
                location = if (isGPSEnable) {
                    //get location from GPS
                    locationManager.requestLocationUpdates(
                        LocationManager.GPS_PROVIDER,
                        MIN_TIME_FOR_UPDATE,
                        MIN_DISTANCE_FOR_UPDTAE,
                        this
                    )
                    locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER)
                } else {
                    //get location from Network
                    locationManager.requestLocationUpdates(
                        LocationManager.NETWORK_PROVIDER,
                        MIN_TIME_FOR_UPDATE,
                        MIN_DISTANCE_FOR_UPDTAE,
                        this
                    )
                    locationManager.getLastKnownLocation((LocationManager.NETWORK_PROVIDER))
                }
            }
        } catch (e: SecurityException) {
            throw e
        }
        return location
    }

    /**
     * Change the user's location if the previous one is different from the actual one and call the callbacks
     *
     * @param loc the user's previous location
     */
    override fun onLocationChanged(loc: Location) {
        location = getCurrentLocation()
        listeners.forEach { listener -> listener.onLocationChange(BlindlyLatLng(location)) }
    }

    fun addLocationChangeListener(listener: LocationChangeListener) {
        listeners.add(listener)
    }

    fun removeLocationChangeListener(listener: LocationChangeListener) {
        listeners.add(listener)
    }

    abstract class LocationChangeListener {
        abstract fun onLocationChange(pos: BlindlyLatLng)
    }

    companion object {
        fun createLocationTableEPFL(): List<Double> {
            return listOf(EPFL_LAT, EPFL_LONG)
        }
        const val TAG = "AndroidLocationService"

        /**
         * Compute the user's location, either get the most recent one or take the one stored
         * in the user
         *
         * @param context the context
         * @param user the user
         * @return the user's location
         */
        fun getCurrentLocationStringFromUser(context: Context, user: User?): String {
            if (user != null) {
                //if(isInternetAvailable()) {
                    Log.d("TAG", "Network is enable: can get location from geocoder")
                    val geocoder = Geocoder(context)
                    val lat = user.location?.get(0)
                    val lon = user.location?.get(1)
                    if (lat != null && lon != null) {
                        return toAddress(geocoder, lat, lon)
                    }
                //}
            }
            return "Location not found"
        }

        fun getCurrentLocationStringFromLocation(context: Context, location: Location): String {
            Log.d(TAG, "Getting current location from a location")
            val latitude = location.latitude
            val longitude = location.longitude
            val geocoder = Geocoder(context)
            return toAddress(geocoder, latitude, longitude)
        }

        private fun toAddress(geocoder: Geocoder, latitude: Double, longitude: Double): String {
            val address = geocoder.getFromLocation(latitude, longitude, MAX_RESULTS)
            val country = address[0].countryName
            val city = address[0].locality
            return "$city, $country"
        }

        private fun isInternetAvailable(): Boolean {
            return try {
                val ipAddr = getByName("google.com")
                !ipAddr.equals("")
            } catch (e: Exception) {
                false
            }
        }
    }
}