I'm developing an app for my work. It's main goal is to verify if workers are in the place they're supposed to be. So, they Check-in at a pint of sale, and immediately a tracking Job is fired, getting user's location every hour. When they leave the place, the job is stopped.
I'm using JobScheduler, as I read this is the best way to handle this, and it's working propertly, so this is fine. The problem is, location is not always accurate, and this is a MUST, because the bosses of the workers need to verify that they are at their point of sale.
There have been many cases when a user is inside the POS, but the app shows like he/she was some meters away from the allowed area. (We are using a 30m radius as the "allowed area"). So, if the app is not showing reliable information, our client won't trust our app anymore.
This is my code (I'm showing just location stuff) I took as reference this google sample. :
//Package and imports...
public class TrackingJob extends JobService{
// Some variables...
private static final long UPDATE_INTERVAL_IN_MILLISECONDS = 5000;
private static final long FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS = UPDATE_INTERVAL_IN_MILLISECONDS / 2;
private LocationCallback mLocationCallback;
private Location mLastLocation;
private LocationRequest mLocationRequest;
private LocationSettingsRequest mLocationSettingsRequest;
private FusedLocationProviderClient mFusedLocationProviderClient;
@Override
public boolean onStartJob(JobParameters jobParameters) {
createLocationCallback(jobParameters);
createLocationRequest();
buildLocationSettingsRequest();
startLocationServices();
return true; // Async stuff will be done, so true is returned
}
@Override
public boolean onStopJob(JobParameters jobParameters) { return false; }
private void createLocationRequest() {
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(UPDATE_INTERVAL_IN_MILLISECONDS);
mLocationRequest.setFastestInterval(FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
}
private void createLocationCallback(final JobParameters jobParameters) {
mLocationCallback = new LocationCallback() {
@Override
public void onLocationResult(LocationResult locationResult) {
super.onLocationResult(locationResult);
mLastLocation = locationResult.getLastLocation();
// Save data locally, and then, upload it to server
saveLocalData(jobParameters.getExtras(), true);
syncData(jobParameters);
// We stop locationProvider here, because we got a location already
mFusedLocationProviderClient.removeLocationUpdates(mLocationCallback);
}
};
}
private void buildLocationSettingsRequest(){
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder();
builder.addLocationRequest(mLocationRequest);
mLocationSettingsRequest = builder.build();
}
@SuppressLint("MissingPermission") // Permissions WILL BE accepted before the job is called
private void startLocationServices() {
SettingsClient mSettingsClient = LocationServices.getSettingsClient(this);
mSettingsClient.checkLocationSettings(mLocationSettingsRequest)
.addOnSuccessListener(new OnSuccessListener<LocationSettingsResponse>() {
@Override
public void onSuccess(LocationSettingsResponse locationSettingsResponse) {
mFusedLocationProviderClient =
LocationServices.getFusedLocationProviderClient(TrackingJob.this);
// We ask for location updates
mFusedLocationProviderClient.requestLocationUpdates(
mLocationRequest,
mLocationCallback,
Looper.myLooper()
);
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
// If problem can be solved by user, we send a push noty
}
});
}
private void saveLocalData(PersistableBundle bundle, boolean gps){
// We save data to REALM
}
private void syncData(final JobParameters jobParameters){
// We get data to sync from REALM
// If data was succesfully synced, we delete it from REALM
// We stop the job
jobFinished(jobParameters, false);
}
}
Am I doing something wrong? Is there a better and more accurate way of getting user's location? Is this a "phone-related" problem?
Before using this new FusedLocationProvider, I was using GoogleApiClient connectionCallbacks and LocationListeners, and accuracy was a problem too.