I have a FusedLocationProviderClient
that requests locations every 2 minutes. We've had the issue for ages now that in a certain circumstance users would not receive location updates and due to how we handled it in the app, we effectively locked the user out of a major section of the app.
After revisiting the topic again, I found that according to the developer guide, the cache of locations is cleared is you disable GPS.
Fine and dandy, so next time the user visits the app, you'd expect that the cache is cleared, it takes a little longer for the client to get an update and you're good to go again. Sadly, that's not the case. I disabled gps at 15:55, left it off until 16:00, reenabled it at 16:00 and still haven't gotten an update at 16:40
I figured that I might be getting an exception somewhere inside the request-task, so I added all 4 callbacks (onFailure, onCanceled, onSuccess, onComplete) and got onSuccess
and onComplete
signalling me that nothing's amiss.
I'm using play-services-base 16.0.1
and play-services-location 16.0.0
. I have granted the permission ACCESS_FINE_LOCATION
and I definitely started my request for location updates using FusedLocationProviderClient::requestLocationUpdates
here is my code
public class LocationHandler extends LocationCallback {
private static final String APPSTART_LOCATION = "APPSTART_LOCATION";
private static final String MOST_RECENT_LOCATION = "MOST_RECENT_LOCATION";
private final static int GPS_TIMEOUT = 3000;
private final Context context;
private final PreferencesHandler preferences;
private final Bus eventBus;
private BehaviorRelay<Location> subject;
private FusedLocationProviderClient client;
private boolean isRequestingLocations = false;
private Disposable timerDisposable;
public LocationHandler(Context context, PreferencesHandler preferences, Bus eventBus) {
this.context = context;
this.preferences = preferences;
this.eventBus = eventBus;
subject = BehaviorRelay.create();
client = new FusedLocationProviderClient(context);
}
@SuppressLint("MissingPermission")
public void connect() {
if (!isRequestingLocations && hasRequiredPermissions()) {
client.requestLocationUpdates(createLocationRequest(), this, null)
.addOnFailureListener(e -> Timber.e(e, "onFailure"))
.addOnCanceledListener(() -> Timber.d("onCanceled"))
.addOnSuccessListener(aVoid -> Timber.d("onSuccess"))
.addOnCompleteListener(task -> Timber.d("onComplete"));
isRequestingLocations = true;
//start a timer so the client will act like nothing's amiss if he didn't receive a location-update within the given timeout
timerDisposable = Observable.timer(GPS_TIMEOUT, TimeUnit.MILLISECONDS).subscribe(ignored -> {
//the reason why this happens is because the provider just uses cached locations. When the user deactivates GPS, the cache is cleared
//once you reactivate gps it should technically work, but it takes a long time nonetheless
ReportingUtil.trackFbEvent(new GPS_NO_LOCATION_RECEIVED((int) TimeUnit.MILLISECONDS.toSeconds(GPS_TIMEOUT)));
preferences.setHasGeolocation(true);
eventBus.post(new NoLocationReceivedEvent());
eventBus.post(new FirstLocationArrivedEvent());
});
}
}
private LocationRequest createLocationRequest() {
LocationRequest request = new LocationRequest();
long interval = TimeUnit.MINUTES.toMillis(Constants.GPSINTERVAL);
request.setInterval(interval);
request.setFastestInterval(interval);
request.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
return request;
}
public void disconnect() {
if (isRequestingLocations) {
timerDisposable.dispose();
client.removeLocationUpdates(this);
isRequestingLocations = false;
}
}
public Observable<Location> getAllLocations() {
return subject;
}
@Override
public void onLocationResult(LocationResult result) {
Timber.d("onLocationResult: %s", result);
if (result != null && result.getLocations().size() != 0) {
Location location = result.getLocations().get(0);
if (location != null) {
if (timerDisposable != null) {
timerDisposable.dispose();
}
subject.accept(new Location(location));
}
}
}
private boolean hasRequiredPermissions() {
return ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED;
}
public void restart() {
disconnect();
connect();
}
}