1

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.

  • 1
    If you are in a building you wont be getting a GPS point so your last position will be the somewhere else. 30 meters is a small radius leaving very little buffer room for GPS so if you are expecting that kind of accuracy you are probably going to have very sporadic results since many things effect GPS signals. Nothing is wrong with your code so you will have to adjust your bosses expectations – tyczj Feb 20 '18 at 20:02
  • That's sad. They keep asking me to develop something more accurate... Do you think the first location obtained in `onLocationResult` is not as accurate as the second, the third,etc... ? Or will they be almost identical? – Juan Carlos Durini Feb 20 '18 at 21:33
  • 1
    You can check each locations accuracy with `getAccuracy` but if they are looking for something more accurate you will need something like military grade GPS which phones certainly do not have – tyczj Feb 21 '18 at 14:15
  • Bluetooth beacons (iBeacon, Eddystone, AltBeacon) can also provide a rough estimate of "proximity" based on the received signal strength. It too may fluctuate a few meters even if the person remains mostly still. – Markus Kauppinen Feb 21 '18 at 17:31

0 Answers0