location-samples icon indicating copy to clipboard operation
location-samples copied to clipboard

LocationUpdatesForegroundService doesn't implement onLocationAvailability() - which stopped working "recently"

Open chnt opened this issue 4 years ago • 8 comments

com.google.android.gms.location.sample.locationupdatesforegroundservice.LocationUpdatesService ln-137 The LocationCallback does not override onLocationAvailability(availability: LocationAvailability?) to provide info on whether location updates will actually be provided by this service at all.

Cheers Christian

chnt avatar Sep 09 '21 07:09 chnt

Is this with the current "master" of the example, and which version of Android is it not working on for you?

I'm going through a few of these examples and updating them to target the latest API and dependency versions to ensure they work with all of the changes imposed on us by Google. Would be nice if they updated the samples, but luckily it's open source so we can do it.

See https://github.com/android/location-samples/pull/285 for the background location sample.

joostfunkekupper avatar Oct 25 '21 04:10 joostfunkekupper

The issue here is more of a suggestion. The LocationCallback has two parts: onLocationResult and onLocationAvailability, and in your sample, you only demonstrate use of the former - in my opinion, you should demonstrate the use of both; specifically because Google's https://developer.android.com/training/location/request-updates links directly here as "Additional resources".

What was not working for me wasn't an issue with the sample itself, but i came here to see if i could find a solution. It turned out that Google Play Services (at least v21.33.xx - 21.36.xx) made an error: They would always call onLocationAvailability with availability.isLocationAvailable =false , thus indicating that noone could expect any locations to be received. They have fixed this now (after many weeks of work, trying to describe the issue and demonstrations: https://issuetracker.google.com/issues/198176818) so from Google Play Services v21.39.xx, it is working again. It would have been a great help in my debugging-process to be able to use this Location Samples project as a sanity-check that it wasn't myself who were doing something wrong, and also to be able to point the Google Play developers here. This would have highlighted the bug, they introduced easily.

chnt avatar Oct 25 '21 07:10 chnt

I understand that the locationAvailabilityis not a guarantee that results will actually be received, but the opposite case is great for indicating that the user might have turned-off location from the phone's settings while your app/service is running. May i suggest you add the following to the samples: if the availability is false, show a warning icon or similar indicator, then dismiss it once the next actual location arrives. Something like:

override fun onLocationAvailability(availability: LocationAvailability?) {
    if(availability?.isLocationAvailable == false) {
        // ... show warning-indicator that the services will not be working correctly ...
    }
}
override fun onLocationResult(locationResult: LocationResult?) {
    if (locationResult?.locations?.isNullOrEmpty() == true) {
        // ... dismiss the warning ...
    }
}

chnt avatar Oct 25 '21 07:10 chnt

Thanks for the detailed responses. I'm not a maintainer of this repository, just an interested dev. Great work on pushing them to get that issue fixed!

Definitely agree that the samples should include the onLocationAvailability as part of that callback, something I actually didn't know was available, so thank you for highlighting that. I was using checkLocationSettings after the permissions were granted to also verify that the Location Services was enabled in one of my apps.

fun requestLocationServices(activity: Activity) {
         val settingsClient = LocationServices.getSettingsClient(activity)
         val locationRequest = LocationRequest.create()
         val locationSettingsRequest = LocationSettingsRequest.Builder()
             .addLocationRequest(locationRequest)
             .build()

         settingsClient.checkLocationSettings(locationSettingsRequest)
             .addOnFailureListener {
                 val statusCode = (it as ApiException).statusCode
                 if (statusCode == LocationSettingsStatusCodes.RESOLUTION_REQUIRED) {
                     val resolvable = it as ResolvableApiException
                     resolvable.startResolutionForResult(activity, REQUEST_LOCATION_SETTINGS)
                 }
             }
     }

I'll update my PR to include this as part of the background location sample.

joostfunkekupper avatar Oct 25 '21 08:10 joostfunkekupper

Had a quick look at the background sample and it handles the locationAvailability in the BroadcastReceiver through the LocationAvailability.extractLocationAvailability on the Intent, and logs it. Would be better if the user was also notified though.

https://developers.google.com/android/reference/com/google/android/gms/location/FusedLocationProviderClient#requestLocationUpdates(com.google.android.gms.location.LocationRequest,%20android.app.PendingIntent)

joostfunkekupper avatar Oct 25 '21 08:10 joostfunkekupper

Hi @chnt, from my understanding based on the discussion on the issue tracker is that locationAvailability should not be used to check if the user has turned off their location services through their device settings. Instead, it is better to use the LocationManagerCompat.isLocationEnabled() method to determine that. I've been testing this and have found this much more reliable to know if the user has manually disabled it.

joostfunkekupper avatar Nov 08 '21 01:11 joostfunkekupper

@joostfunkekupper locationAvailability works very well for the use case of getting an indication that locations will not be available while an app is running. LocationManagerCompat.isLocationEnabled() is fine when first starting to set up a location-tracking feature or similar, but while that is running, you might also be interested if it changes. (It does in my situation where different features are available to the user, depending of whether they can get, and maintain a precise location fix or not) The only other solution, i can think of is to set up a timer that polls LocationManagerCompat.isLocationEnabled() once a second or so. This seems so silly when we got the onLocationAvailability(availability: LocationAvailability?) in the listener already.

It works 100% of the time for me, and has done so for years ... except for the months of September 2021 and most of October 2021 when Google Play Services 21.33.xx - 21.36.xx introduced the error of having it false all the time. Thankfully, they've fixed it by now, so all is good once again.

chnt avatar Nov 08 '21 08:11 chnt

Glad to hear its working again for you @chnt. Based on my testing with Play Service 21.39.17, I'm still receiving false from LocationAvailability when I don't expect it, i.e. "allow all the time" permission granted, location services turned on, full reception on cellular and wifi, and BLE is on. I agree that it is useful to know if locations are available or not (for whatever reason). And depending on your use case it might be of value to inform the user that location is unavailable at the time.

What I am doing is that if I receive a false value, is to check for a possible reason for the lack of location availability. Like checking if the permissions have changed, or using LocationManagerCompat.isLocationEnabled() to ask the user to turn it back on. This way I don't need a timer of sorts to constantly check that.

joostfunkekupper avatar Nov 08 '21 22:11 joostfunkekupper