Gokarna pantha
Gokarna pantha

Reputation: 53

location api does not give exact current location sometime in android using google fused api

I have used the following code to get the current location and path the route in google map. The problem i faced is that the current device location is not stable all the time. It shows correct location sometime but shows different location like 1km away from actual location.

package com.colors.organisatiom.activity.colors;


import android.Manifest;
import android.annotation.TargetApi;
import android.app.AlertDialog;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.location.Location;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.content.ContextCompat;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.Toast;

import com.colors.organisatiom.activity.colors.classes.ConnectionManager;
import com.colors.organisatiom.activity.colors.interfaces.PolyLineCallback;
import com.colors.organisatiom.activity.colors.json.GetDistanceFromServer;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.maps.CameraUpdate;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;
import com.google.android.gms.maps.model.Polyline;
import com.google.android.gms.maps.model.PolylineOptions;

import java.util.ArrayList;
import java.util.List;

public class LocationMap extends AppCompatActivity implements LocationListener, GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {
    private GoogleMap map;
    private String serviceCentreLongitude, serviceCentreLatitude, serviceCenhterLocation;
    final private int REQUEST_CODE_ASK_PERMISSIONS = 123;
    private RelativeLayout connectingParent;
    private PolylineOptions polylineOptions;
    private Polyline polyline;
    private List<Polyline> polylines = new ArrayList<>();
    private GoogleApiClient googleApiClient;
    private LocationRequest locationRequest;
    private static final long INTERVAL = 1 * 5;
    private static final long FASTEST_INTERVAL = 10;
    protected BroadcastReceiver mNotificationReceiver;
    private Marker currentLocationMarker;


    protected void createLocationRequest() {
        locationRequest = new LocationRequest();
        locationRequest.setInterval(INTERVAL);
        locationRequest.setFastestInterval(FASTEST_INTERVAL);
        locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        serviceCentreLatitude = getIntent().getStringExtra("latitude");
        serviceCentreLongitude = getIntent().getStringExtra("longitude");
        serviceCenhterLocation = getIntent().getStringExtra("service_center_location");
        setContentView(R.layout.content_google_map);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        Window window = this.getWindow();
        window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
        window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
        if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            window.setStatusBarColor(ContextCompat.getColor(this, R.color.colorPrimaryDark));
        }
        mNotificationReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                if (!LocationMap.this.isFinishing()) {
                    AlertDialog.Builder builder = new AlertDialog.Builder(LocationMap.this);
                    builder.setTitle(intent.getStringExtra("title"));
                    builder.setMessage(intent.getStringExtra("message"));
                    builder.setPositiveButton("Dismiss", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            //alertDialog.dismiss();
                        }
                    });
                    final AlertDialog alertDialog = builder.create();
                    alertDialog.show();
                }
            }
        };
        if (!isGooglePlayServicesAvailable()) {
            Toast.makeText(this, "Google play service not supported", Toast.LENGTH_LONG).show();
        }
        createLocationRequest();
        googleApiClient = new GoogleApiClient.Builder(this)
                .addApi(LocationServices.API)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .build();
        map = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map))
                .getMap();
        connectingParent = (RelativeLayout) findViewById(R.id.connecting_parent);
        if (!new ConnectionManager(this).isConnectionToInternet()) {
            connectingParent.setVisibility(View.GONE);
            Toast.makeText(LocationMap.this, "No internet connection to route path", Toast.LENGTH_LONG).show();
        }
        ImageView search = (ImageView) findViewById(R.id.search);
        search.setVisibility(View.INVISIBLE);
        if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            int hasAccessCoarseLocationPermission = checkSelfPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION);
            int hasAccessFineLocationPermission = checkSelfPermission(android.Manifest.permission.ACCESS_FINE_LOCATION);
            if (hasAccessCoarseLocationPermission != PackageManager.PERMISSION_GRANTED && hasAccessFineLocationPermission != PackageManager.PERMISSION_GRANTED) {
                requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION},
                        REQUEST_CODE_ASK_PERMISSIONS);
            } else {
                showMapWithLocation();
                if (googleApiClient.isConnected()) {
                    startLocationUpdates();
                }
            }

        } else {
            showMapWithLocation();
            if (googleApiClient.isConnected()) {
                startLocationUpdates();
            }
        }

    }

    @Override
    public void onStart() {
        super.onStart();
        Log.d("Started:", "onStart fired ..............");
        googleApiClient.connect();
    }

    @Override
    public void onStop() {
        super.onStop();
        Log.d("Stopped", "onStop fired ..............");
        googleApiClient.disconnect();
        Log.d("Is connected status", "isConnected ...............: " + googleApiClient.isConnected());
    }

    private void showMapWithLocation() {
        map.setMapType(GoogleMap.MAP_TYPE_NORMAL);
        LatLng latLng = new LatLng(Double.parseDouble(serviceCentreLatitude), Double.parseDouble(serviceCentreLongitude));
        map.addMarker(new MarkerOptions()
                .position(latLng)
                .title(serviceCenhterLocation)).showInfoWindow();
        map.getUiSettings().setMapToolbarEnabled(false);
        CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngZoom(latLng, 14);
        map.animateCamera(cameraUpdate);
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
                                           @NonNull int[] grantResults) {
        switch (requestCode) {
            case REQUEST_CODE_ASK_PERMISSIONS:
                if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    startLocationUpdates();
                    if (googleApiClient.isConnected()) {
                        startLocationUpdates();
                    }
                } else {
                    Toast.makeText(LocationMap.this, "Cannot show map", Toast.LENGTH_SHORT)
                            .show();
                }
                break;
            default:
                super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        }
    }

    private List<LatLng> decodePoly(String encoded) {
        List<LatLng> poly = new ArrayList<>();
        int index = 0, len = encoded.length();
        int lat = 0, lng = 0;
        while (index < len) {
            int b, shift = 0, result = 0;
            do {
                b = encoded.charAt(index++) - 63;
                result |= (b & 0x1f) << shift;
                shift += 5;
            } while (b >= 0x20);
            int dlat = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
            lat += dlat;
            shift = 0;
            result = 0;
            do {
                b = encoded.charAt(index++) - 63;
                result |= (b & 0x1f) << shift;
                shift += 5;
            } while (b >= 0x20);
            int dlng = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
            lng += dlng;
            LatLng p = new LatLng((((double) lat / 1E5)),
                    (((double) lng / 1E5)));
            poly.add(p);
        }
        return poly;
    }


    @Override
    public void onConnected(Bundle bundle) {
        Log.e("Connection status:", "onConnected - isConnected ...............: " + googleApiClient.isConnected());
        startLocationUpdates();
    }

    protected void startLocationUpdates() {
        LocationServices.FusedLocationApi.requestLocationUpdates(googleApiClient, locationRequest, this);
        Log.e("Update started:", "Location update started ..............: ");
    }

    @Override
    public void onLocationChanged(Location location) {

            final double myLocationlatitude = location.getLatitude();
            final double myLocationlongitude = location.getLongitude();
            Log.e("Latitude", String.valueOf(myLocationlatitude));
            Log.e("Longitude", String.valueOf(myLocationlongitude));
            LatLng latLng = new LatLng(myLocationlatitude, myLocationlongitude);
            //drawing the path in google map
            //zoom the camera for the first time
            if (currentLocationMarker != null) {
                currentLocationMarker.remove();
            }
            MarkerOptions markerOptions = new MarkerOptions();
            markerOptions.position(latLng);
            markerOptions.title("My current location");
            markerOptions.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_ORANGE));
            currentLocationMarker = map.addMarker(markerOptions);
            if (polylines == null) {
                CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngZoom(latLng, 14);
                map.animateCamera(cameraUpdate);
            }
            new AsyncTask<Void, Void, Void>() {
                @Override
                protected Void doInBackground(Void... params) {
                    new GetDistanceFromServer(String.valueOf(myLocationlatitude), String.valueOf(myLocationlongitude), serviceCentreLatitude, serviceCentreLongitude).drawPath(new PolyLineCallback() {
                        @Override
                        public void polyLinePointsHolder(String points) {
                            //remove the path and draw the path in google map while updating
                            if (polylines != null) {
                                for (Polyline line : polylines) {
                                    line.remove();
                                }
                            }
                            List<LatLng> list = decodePoly(points);
                            polylineOptions = new PolylineOptions()
                                    .addAll(list)
                                    .width(12)
                                    .color(Color.parseColor("#05b1fb"))
                                    .geodesic(true);
                            polyline = map.addPolyline(polylineOptions);
                            polylines.add(polyline);

                        }
                    });
                    return null;
                }

                @Override
                protected void onPostExecute(Void aVoid) {
                    connectingParent.setVisibility(View.GONE);

                    super.onPostExecute(aVoid);
                }
            }.execute();



    }

    @Override
    public void onConnectionSuspended(int i) {

    }

    @Override
    public void onConnectionFailed(ConnectionResult connectionResult) {
        Log.e("Connection Failed", connectionResult.getErrorMessage());
    }

    @Override
    protected void onPause() {
        super.onPause();
        stopLocationUpdates();
    }

    protected void stopLocationUpdates() {
        LocationServices.FusedLocationApi.removeLocationUpdates(
                googleApiClient, this);
        Log.d("TAG", "Location update stopped .......................");
    }

    private boolean isGooglePlayServicesAvailable() {
        int status = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
        if (ConnectionResult.SUCCESS == status) {
            return true;
        } else {
            GooglePlayServicesUtil.getErrorDialog(status, this, 0).show();
            return false;
        }
    }

    @Override
    public void onResume() {
        super.onResume();
        LocalBroadcastManager.getInstance(this).registerReceiver(mNotificationReceiver, new IntentFilter("1000"));
        if (googleApiClient.isConnected()) {
            startLocationUpdates();
            Log.d("TAG", "Location update resumed .....................");
        }
    }
}

Upvotes: 0

Views: 965

Answers (1)

Much Overflow
Much Overflow

Reputation: 3140

The accuracy of location can be affected due to many factors including GPS coverage, device quality and wifi availability around the area. What you can do is to check the accuracy of the location you obtained and decide whether to proceed or not. For this you can use hasAccuracy() and getAccuracy() methods of the Location object.

Here is a quote from the documentation about getAccuracy method

Get the estimated accuracy of this location, in meters.

We define accuracy as the radius of 68% confidence. In other words, if you draw a circle centered at this location's latitude and longitude, and with a radius equal to the accuracy, then there is a 68% probability that the true location is inside the circle.

In statistical terms, it is assumed that location errors are random with a normal distribution, so the 68% confidence circle represents one standard deviation. Note that in practice, location errors do not always follow such a simple distribution.

This accuracy estimation is only concerned with horizontal accuracy, and does not indicate the accuracy of bearing, velocity or altitude if those are included in this Location.

If this location does not have an accuracy, then 0.0 is returned. All locations generated by the LocationManager include an accuracy.

In your onLocationChanged method, you can do the following

@Override
public void onLocationChanged(Location location) {
     if(location.hasAccuracy() && location.getAccuracy() < 100F) {
        // the location has accuracy and has an accuracy span within 100m radius
        // do whatever you want with this location and stop location listener
        stopLocationUpdates();
     }

     // if the above code did not get executed, the location listener will work 
     // until a location with acceptable accuracy is obtained
}

Upvotes: 1

Related Questions