Android Kotlin - FusedLocationProviderClient & Geocoder.getFromLocation Gives Errors

104 Views Asked by At

I'm trying to get device's current country code from its current location from device so I created a class that helps me to get location via using FusedLocationProviderClient. On many devices it works as I expected but on few devices, it gives 2 errors. Here you can find my code:

class MyLocationFetcher {
    var currentLocation: String = ""

    private val _locationFetchingStatus = MutableStateFlow(LocationFetchStatus.DEFAULT)
    val locationFetchingStatus: StateFlow<LocationFetchStatus>
        get() = _locationFetchingStatus

    enum class LocationFetchStatus { DEFAULT, SUCCESSFUL, LOADING, ERROR }

    fun getLocation(activity: Activity) {
        _locationFetchingStatus.value = LocationFetchStatus.LOADING
        if (isLocationEnabled(activity.baseContext)) {
            val fusedLocationClient =
                LocationServices.getFusedLocationProviderClient(activity.baseContext)
            if (ActivityCompat.checkSelfPermission(
                    activity.baseContext,
                    Manifest.permission.ACCESS_FINE_LOCATION
                ) == PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
                    activity.baseContext,
                    Manifest.permission.ACCESS_COARSE_LOCATION
                ) == PackageManager.PERMISSION_GRANTED
            ) {
                try {
                    fusedLocationClient.lastLocation.addOnCompleteListener(activity) { task ->
                        val location: Location? = task.result // Error Case 1
                        if (location != null) {
                            val geocoder = Geocoder(activity.baseContext, Locale.getDefault())
                            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
                                geocoder.getFromLocation(
                                    location.latitude,
                                    location.longitude,
                                    1,
                                    object : Geocoder.GeocodeListener {
                                        override fun onGeocode(addresses: MutableList<Address>) {
                                            if (addresses.size == 0) {
                                                currentLocation = ""
                                                _locationFetchingStatus.value = LocationFetchStatus.ERROR
                                            } else {
                                                currentLocation = addresses[0].countryCode
                                                _locationFetchingStatus.value = LocationFetchStatus.SUCCESSFUL
                                            }
                                        }

                                        override fun onError(errorMessage: String?) {
                                            super.onError(errorMessage)
                                            currentLocation = ""
                                            _locationFetchingStatus.value = LocationFetchStatus.ERROR
                                        }
                                    })
                            } else {
                                val list: List<Address> =
                                    geocoder.getFromLocation( // Error Case 2
                                        location.latitude,
                                        location.longitude,
                                        1
                                    ) as List<Address>
                                if (list.size == 0) {
                                    currentLocation = ""
                                    _locationFetchingStatus.value = LocationFetchStatus.ERROR
                                } else {
                                    currentLocation = list[0].countryCode
                                    _locationFetchingStatus.value = LocationFetchStatus.SUCCESSFUL
                                }
                            }
                        }
                    }
                } catch (e: Exception) {
                    currentLocation = ""
                    _locationFetchingStatus.value = LocationFetchStatus.ERROR
                }
            } else {
                currentLocation = ""
                _locationFetchingStatus.value = LocationFetchStatus.ERROR
            }
        } else {
            currentLocation = ""
            _locationFetchingStatus.value = LocationFetchStatus.ERROR
        }
    }

    fun resetLocation() {
        currentLocation = ""
        _locationFetchingStatus.value = LocationFetchStatus.DEFAULT
    }

    private fun isLocationEnabled(context: Context): Boolean {
        val locationManager: LocationManager =
            context.getSystemService(Context.LOCATION_SERVICE) as LocationManager
        return locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) || locationManager.isProviderEnabled(
            LocationManager.NETWORK_PROVIDER
        )
    }
}

On code, I marked the lines that gives me errors as Error Case 1 and Error Case 2.

Error Case 1 shows me that error: com.google.android.gms.tasks.RuntimeExecutionException com.google.android.gms.common.api.ApiException: 17: API: LocationServices.API is not available on this device. Connection failed with: ConnectionResult{statusCode=SERVICE_INVALID, resolution=null, message=null}

As I researched, I see some comments about enabling Google's API from console, but do I really need that ? Because I haven't do this and it works on many devices.

Error Case 2 shows me that error: Caused by java.io.IOException elgt: UNAVAILABLE

I haven't find anything about this. Also, this line uses deprecated getFromLocation method because of for Android devices that has lower than Tiramisu version. Is there any solution for this also ?

Also I don't understand that why my try catch block is not working. I wrapped those lines in case of any exception, but still I see those.

How can I solve those errors? I'm also open for refactored solutions.

0

There are 0 best solutions below