I'm using LocationListener and returned Location always has Bearing as 0.0
Is there anything else I need to do?
I also noticed that with 4.0.3 update I rarely have speed reported. Now I just get positions and accuracy/elevation
public void onLocationChanged(Location loc)
{
Log.d(LOG_TAG, "onLocationChanged");
Position position = new Position();
position.PositionGKey = UUID.randomUUID();
position.GPSTime = new Date(loc.getTime());
position.DeviceTime = new Date();
position.Latitude = loc.getLatitude();
position.Longitude = loc.getLongitude();
position.Altitude = loc.getAltitude();
position.Speed = loc.hasSpeed() ? loc.getSpeed() * 2.23693629 : 0;
position.Accuracy = (int)loc.getAccuracy();
position.Bearing = loc.hasBearing() ? loc.getBearing() : 0;
// There was cases with speed reported 1000+. Just make it real here, round of obvious errors.
if (position.Speed > 120)
{
position.Speed = 0.0;
}
PositionData.InsertPosition(getApplicationContext(), position);
}
When using the GPS provider, Bearing is usually not updated / returned unless the device physically moves and gains speed (check getSpeed()). In practice, speed above 1m/s should produce accurate bearings. I've also found that I have had to occasionally poll and check for the last known location on the GPS provider and grab it's updated bearings to get proper readings.
Related
In my Android application i need to get the traveled road with car and i check it with google android directions API and GPS.
But the problem is that some times the GPS location is not precise and i can get an error of 10Km for some lecture and that means that in a total travel of 150km my "distance traveled" can be 250km and it's wrong!
Yesterday i test it in highway and the problem is that when the marker is located out from highway, the calculation of distance traveled from my current position and the last marker located by road is very wrong (in this case out of the highway).
There is some best way for getting traveled distance with car using the phone?
Maybe some better code for getting more precise GPS position?
Here is my code:
private void getUserLocation() {
Log.d(TAG, "getUserLocation()");
checkLocationPermission();
mFusedLocationClient.getLastLocation()
.addOnSuccessListener(getActivity(), new OnSuccessListener<Location>() {
#Override
public void onSuccess(Location location) {
// Got last known location. In some rare situations this can be null.
if (location != null) {
// Logic to handle location object
String stringStartLat, stringStartLng;
double lat = location.getLatitude();
double lng = location.getLongitude();
//Start position of device
if (travelInfo.getStartLat() == 0 && travelInfo.getStartLng() == 0) {
travelInfo.setStartLat(lat);
travelInfo.setStartLng(lng);
//Set lastcoordinates equals to start
travelInfo.setLastLat(lat);
travelInfo.setLastLng(lng);
}
//Current position of device
travelInfo.setCurrentLat(lat);
travelInfo.setCurrentLng(lng);
stringStartLat = Double.toString(travelInfo.getStartLat());
stringStartLng = Double.toString(travelInfo.getStartLng());
//Set the TextView in the fragment with start coordinates
Log.d(TAG,"LatitudeStart: " + stringStartLat);
Log.d(TAG,"LongitudeStart: " + stringStartLng);
if (startMarker == null) {
//Add the user location to the map with a marker
LatLng userLoction = new LatLng(travelInfo.getStartLat(), travelInfo.getStartLng());
startMarker = googleMap.addMarker(new MarkerOptions()
.position(userLoction)
.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_ORANGE))
.title("Start Position")
.snippet("Show the start position of user"));
// For zooming automatically to the location of the marker
CameraPosition cameraPosition = new CameraPosition.Builder().target(userLoction).zoom(9).build();
googleMap.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));
} else {
LatLng currentLocation = new LatLng(travelInfo.getCurrentLat(), travelInfo.getCurrentLng());
currentPositionMarker = googleMap.addMarker(new MarkerOptions()
.position(currentLocation)
.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_YELLOW))
.title("Current Position")
.snippet("Show the current position of user during travel"));
// For zooming automatically to the location of the marker
CameraPosition cameraPosition = new CameraPosition.Builder().target(currentLocation).zoom(11).build();
googleMap.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));
}
if (travelInfo.getEndLat() != 0 && travelInfo.getEndLng() != 0) {
Log.i(TAG, "Dentro if userlocation");
//Get total distance of travel
getTotalDistanceTime(travelInfo);
//Get the percurred distance from last known coordinates
getPercurredDistance(travelInfo);
}
}
}
});
}
And getpercurredDistance use google direction API with this url
String url = "https://maps.googleapis.com/maps/api/directions/json?origin=" + obj.getLastLat() + "," + obj.getLastLng() + "&destination=" + obj.getCurrentLat() + "," + obj.getCurrentLng() + "&mode=driving&key=AI*******************I";
For getting distance traveled from last marker and current position marker.
But some times it put the localized position too far from real position... how avoid this?
EDIT
The method that i use is good for my work? mFusedLocationClient.getLastLocation()
There is no possibilities to get more precise GPS position from GPS sensor of android device, but you can filter "wrong" points this ways:
1) for each travel point get several values of Lat and Lng, discard the minimum and maximum and average the remaining ones;
2) log timestamps of each travel point and compare it for two neighboring points: speed (distance between that two points divided by time interval of that points) grater than max. car speed (e.g. 250 km/h) that means the second point is wrong (if first point is good of course).
3) use Google Maps Roads API to find best-fit road geometry for a given set of GPS coordinates.
Also take a look at this question.
For real-time location purposes, location updates allow you to request location updates at different intervals. See the android developer location documentation. The function you want is FusedLocationProviderClient.requestLocationUpdates.
There is no reason GPS (or any other widely used location technology) should ever give you 10km error for a single location estimate. If you are getting this, there is a large mismatch between when you the location estimate was made and when you are requesting it.
I am currently trying to get the speed of a user using the GPS (Google Play Location Services).
However, the problem with my code is that the speed is stuck on a very small number - going down to 1.9^E18, basically 0. This value doesn't change even though I move around.
I am currently trying to calculate the speed of the user manually through using speed and time stamps. However, I have also found a function called getSpeed(). I was considering to use it, but there were many complaints I found here that said that it always returned zero.
Firstly - is getSpeed() only used for mock locations, or can it be used safely with location objects obtained by the GPS?
Secondly if getSpeed does not work, I will need to continue obtaining the speed manually. I believe there may be problems with the casting. Can someone help in finding the problem of my current method?
public void onLocationChanged(Location location) {
location.getLatitude();
Toast.makeText(this, "Location Changed", Toast.LENGTH_SHORT).show();
if (settings == null) {
settings = getSharedPreferences(PREFS_NAME, 0);
}
int TimeDifference = (int) (location.getTime() - OldLocation.getTime());
int distance = (int) OldLocation.distanceTo(location);
double speed = distance / TimeDifference;
if (LowerLimit < speed && speed < UpperLimit) {
TimeInstance += TimeDifference;
}
if (TimeInstance>TimeLimit) {
if (!dialogShown) {
dialogShown = true;
ViolationMessage();
TimeInstance = 0;
}
else {
TimeInstance = 0;
}
}
OldLocation = location;
}
I'm wrinting a application and I have to show the distance covered while I'm running.
I use the function "public void onLocationChanged" of the LocationListener. When the user tap a botton and start running I want to show the distance he covered updated to the point in which he is located.
I've written this code:
public void onLocationChanged(Location location) {
if(location != null) {
if(location.hasSpeed()){
if(latitude1 == 0 && longitude1 == 0){
latitude1 = (location.getLatitude()*Math.PI)/180;
longitude1 = (location.getLongitude()*Math.PI)/180;
} else{
latitude2 = (location.getLatitude()*Math.PI)/180;
longitude2 = (location.getLongitude()*Math.PI)/180;
distance = (6372.795477598)*Math.acos(Math.sin(latitude1)
*Math.sin(latitude2)+Math.cos(latitude1)
*Math.cos(latitude2)*Math.cos(longitude1-longitude2));
sumDistance += distance;
latitude1 = latitude2;
longitude1 = longitude2;
}
tv.setText("Distance covered=" + sumDistance + " m");
}
}
}
Is it accurated?
Just a Suggestion:
Store the Latitude and Longitude of the start location and the end location when the user clicks the appropriate button.
and then you could use distanceBetween or distanceTo to get the distance between those two geoPoints.
P.S: This may not work if the user will start and end his run at the same point ;)
Addition:
Check this tutorial:
Recently google has improved its location based API's. They have fused the sensors with the location based api's to share examples of how location can be made more accurate (about 4 times more effective) and consume much lesser power (10 times lesser).
Some interesting links for you to go through will be this and video google io.
SO link for how to use the API's here
I am working with GPS related app. I need to get vertical accuracy but it always gets fix 11.0000. I need it to be dynamic as lat and lng. I have used getAccuracy but it results in horizontal accuracy.
#Override
public void onLocationChanged(Location location) {
if (location != null) {
lat = location.getLatitude();
lon = location.getLongitude();
Geocoder geoCoder = new Geocoder(getBaseContext(), Locale.getDefault());
address = mailOb.getAddress(geoCoder, lat, lon);
if (!meterFootFlag) {
diameter = Math.round(location.getAccuracy()) + " m.";
altitude = Math.round(location.getAltitude()) + " m.";
} else {
diameter = Math.round(location.getAccuracy() * 3.28084) + " ft.";
altitude = Math.round(location.getAltitude() * 3.28084) + " ft.";
}
if (diameter.contains("+"))
diameter.replace("+", "");
else if (altitude.contains("+"))
altitude.replace("+", "");
} else {
lat = 0.0;
lon = 0.0;
if (!meterFootFlag) {
altitude = 0.0 + " m.";
diameter = 0.0 + " m.";
} else {
altitude = 0.0 + " ft.";
diameter = 0.0 + " ft.";
}
}
mlocManager.removeUpdates(MySettings.this);
pDialog.dismiss();
}
How can I get vertical accuracy?
Thanks in advance
Android does not provide the vertical accuracy.
Vertical accuracy usually is 2-3 times worse then horizontal accuracy.
A simple solution: use the androids accuracy for both horizontal and vertical.
advanced solution 1: find out what android uses as total accuracy (it could be a radial error of an error-sphere, including lat,long and altitude)
try to find out a conversion factor, e.g take accuracy and multiply *2,5
Another solution, look at iphone horizontal and vert accuracy, and compare to that of android. find out an average conversion factor from acc to vert acc.
Solution 3: think why you need vertical accuracy at all. why do you need that?
hints:examples from my iphone4: when iphone shows 30m hor, i have 57vert, 10hor: 15-20vert, 5 hor: 10vert
Starting with API 26 you can use getVerticalAccuracyMeters() method
#Override
#RequiresApi(Build.VERSION_CODES.O)
public void onLocationChanged(Location location) {
float accuracy = location.getVerticalAccuracyMeters();
}
Altitude accuracy heavily depends on core GPS accuracy, use of additional sensors as barometer and use of wifi/cell networks plus the fusion algorithms. It is NOT have a constant ratio. If u really want to get accuracy you can try the following: check variance of the signal while motionless, this will not always work as some devices will detect motionless and just repeat last output to save power. Another approach which is bit costly is to check with reference as https://developers.google.com/maps/documentation/elevation/intro
so u basically take lat lon measurement with the lat lon error and check the vertical error u get assuming you are in open area.
Currently I am working on an application, where I want to calculate distance a vehicle travels. My requirement is while driving car, my Android device should calculate total distance I traveled and send this information to server. In order to do this, I used Android's location manager api, set criteria and used getBestProvider. This way we can either use GPS or Network to get latitude and longitude. The following is the code snippet of this:
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
Criteria criteria = new Criteria();
criteria.setAccuracy(Criteria.ACCURACY_FINE);
criteria.setPowerRequirement(Criteria.POWER_HIGH);
provider = locationManager.getBestProvider(criteria, false);
locationManager.requestLocationUpdates(provider,30000,5, this);
onLocationChanged() call back method provide latitude and longitude every time. We always store previous coordinates and when we get new coordinates we find the distance between the two using distanceBetween() api. The following is the code snippet of this:
public void onLocationChanged(Location location) {
findLatLongDistance(location);
}
private void findLatLongDistance(Location location) {
// TODO Auto-generated method stub
try{
Date date = new Date();
TimeStamp2 = sdf.format(date);
getSavedLatLong();//get lat and long from preference
Location locationB = new Location("point B");
locationB.setLatitude(location.getLatitude());
locationB.setLongitude(location.getLongitude());
Location locationA = new Location("point A");
locationA.setLatitude(prelat_val); //lat from pref locationA.setLongitude(prelong_val); //long from pref
if(prelat_val>0.0 && prelong_val>0.0){
Toast.makeText(LocationService.this,"Location Odometer Sum "+odometer_sum, Toast.LENGTH_LONG).show();
float distance2 = getDistance(prelat_val,prelong_val,location.getLatitude(),location.getLongitude());
odometer_sum = odometer_sum + (distance2/1000);
Toast.makeText(LocationService.this,"Lat "+prelat_val+"Long "+prelong_val+"Sum "+odometer_sum, Toast.LENGTH_LONG).show();
}
saveData(lat,lng,odometer_sum);
}catch(Exception e){
e.printStackTrace();
}
}
public float getDistance(double d, double e, double f, double g) {
float [] dist = new float[2];
Location.distanceBetween(d,e,f, g, dist);
return dist[0] ;
}
This is the list of issue that we face here:
The location it provide is not accurate. There is a difference of about 300-400 metres while we testing this app in 5 km distance
When the mobile is in same location for long time, it always provide different latitude and longitude. If you check above code snippet, in requestLocationUpdates(), we are setting 30 seconds time interval and 5m distance. Here what we thought is, if my mobile device move 5m distance AND if it cross 30 seconds interval, it will provide new latitude and longitude. But what really happens is, it provide coordinates every 30 seconds irrespective of device movement. I am not sure how to fix this issue.
While device is moving, how to get accurate value. Do I need to do some more things in the code?
I really spend so many hours trying various options. But I feel I am missing something here. Please help me on this. Thanks in advance..
Thanks,
Your minTime value in requestLocationUpdates() is 30seconds. Thats too long for an app that tries to calculate accurate distances. I have used locationManager.requestLocationUpdates(provider, 0, 5, locationListener);
in my code for long and I get accurate updates. Though this drains the battery very fast. So you would have to try different values to strike a balance between accuracy and battery life and see what suits your app