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.