I want to preface this by saying that I'm in China where Google location services sometimes have issues.
I'm using the LocationClient to get user's current location.
protected void onCreate(Bundle savedInstanceState) {
...
mLocationClient = new LocationClient(this, this, this);
...
}
Very straightforward. Then in my onConnected callback, I get the location.
public void onConnected(Bundle connectionHint) {
Location location = mLocationClient.getLastLocation();
...
}
The location I get back is always the same, but it is about ~500m away from my actual location. GPS is enabled, although the icon indicating it is being used does not come on. I am also on WiFi and have 3G.
When I open the actual Google Maps app, my location is perfectly accurate (unlike the location I get in my own app). I also see the icon indicating GPS is being used.
Questions
What is the Google Map app doing differently to get a more accurate location and how do I do what they do?
If the wrong location I get back is always the same what does that mean? Without overthinking too much, it is a truth of China that foreign map data companies have coordinates the are skewed off by a factor and they have to use a specific algorithm to correct for that difference; is the Google Maps app doing that?
Thanks!
When using the method 'getLastLocation()', it offers the best last known location stored by the Location. It is also in respect to what level of permission you have given the app in the manifest file.
Try using both:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
in your manifest file and see if it improves the accuracy.
China has a special dealing with GPS data, because the government force the related map producing company to add some bias.
I'm stuck with it for a period of time.
Ad. 1 Google Maps updates location continually. Try following these inductions: http://developer.android.com/training/location/receive-location-updates.html
Ad. 2 getLastLocation probably retrieves last location stored when it is updated like in point 1. If it's not updated, you will just get the same value. Location object has time attached and you can see when it was received.
turn on the Satellite view. The normal "vector" view is obfuscated in China. For some reason, the Google Maps app doesn't have this issue.
the location returned by the GPS is correct, even in China (considering a WGS84 projection). Only the maps are not.
Other maps providers like Baidu force you to use their own custom implementation of LocationClient. This way you get locations ready to be used on their map tiles.
A late answer, but this hasn't been said:
You can set the accuracy of the locationClient, using the locationRequest.
E.g.
mLocationRequest = LocationRequest.create();
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
mLocationClient.requestLocationUpdates(mLocationRequest, (LocationListener) this);
You can also set the frequency of updates. If you need something highly precise, take a bunch of readings over a few seconds. Then look at the "accuracy" number on each reading. Toss out any readings whose accuracy is significantly less accurate than the others. Then average the rest...
That's a pretty basic algorithm, and i'm getting accuracy within 1-2 feet on a galaxy S5 in the US.
If you use lower accuracy, it's going to average gps data with wifi and cellular results. GPS consumes more battery, so it uses it less often on this setting. Wifi uses a physical address lookup, since its always moving me towards the public road near my house, even when I'm in the middle of it.
Related
I am using FusedLocationProviderClient to get location updates in a foreground service. On testing and observing for few days, I found wrong locations which was far away from my actual location by around 4 kms similar to this, but the LocationResult had an accuracy of 24 meters. How is this even possible?
It can be eliminated if the accuracy was around 4 kms. This behavior does not occur very often but occurs atleast once in 4 among 10 devices. It becomes a problem when I calculate distance traveled.
I can tell it's not a cached location because I used to turn off and on Location Services everyday. (As per docs, turning off Location Services clears cache location.)
Any idea why it's giving wrong location and how to eliminate it? And also clearing cache locations without turning off Location Services?
FusedLocationProvider CAN give incorrect results like that when gps connectivity for device is down(or insufficient satellites are in "view" to provide accurate data). It will use the nearest cell tower/location data provided by the wifi router(google tracks this automatically) giving WILDLY incorrect results in places where google doesn't have a strong location mapping presence - which is anywhere outside an urban center.
You have imho two options:
Use the non googleplay based solution based on location service - this has an option for ignoring non-gps location data(wifi/cellular).
LocationManager locationManager = (LocationManager)
getApplicationContext().getSystemService(LOCATION_SERVICE);
Location location = locationManager.getLastKnownLocation(LocationManager.GPS_Provider);
You can even specify the number of satellites required for acceptable data so you can get REALLY accurate location data. You will lose information when the gps doesn't receive coordinates (like indoors), but in exchange will have less "noise" from incorrectly mapped location, as per your requirement.
Use a "snap to roads" API. There is a free version using open street map data called Project OSRM(Open Source Routing Machine) that provides a backend when hosted (locally or in cloud) using docker or building source yourself (details in link).
curl "http://127.0.0.1:5000/route/v1/driving/13.388860,52.517037;13.385983,52.496891?steps=true"
This request will return a location that is "snapped" to the nearest road. There are various options such as giving priority to highways etc. You can then discard the points that are not on the "path" that the user was previously on as rapidly shifting to a road 4km away and then coming back again is not likely.
So I know you can use getAccuracy() to find the accuracy of a location but if you set up a cut off for the accuracy, can you prevent recording down one of those locations where it's hugely off mark of where the user is? Like if the user is still, most location updates cluster around his area but occasionally the location provider will hiccup and report the location as somewhere miles away.
Do these locations simply appear as "accurate" with getAccuracy? Or would they turn up as some insanely high getAccuracy() result? Programming a cut off point is easy enough but I was wondering if I would have to code extra checks such as if a location is way too different from the previous ones then it's a wayward one.
Accuracy is not the only deciding factor here. You should also look at the age of the location, and the provider if you get it (the Google Play Services location doesn't tell you, but the original Android LocationManager does).
In fact, Google has some useful sample code for maintaining a current best estimate. I have used a variation of this to filter out wild jumps in incoming location data. Essentially a location is not even reported if it doesn't pass this gate.
My app works fine if the area has GPS (such as outside) or in houses/first or second floor buildings but it does not receive a location update if the area is something like the 4th-10th floor of a tall building, is this expected behavior or is this a limitation of location services?
Even with an internet connection on a high floor it still does not receive an update, this makes me believe that it is not falling back to Wi-Fi/mobile networks but I tried setting my Location method to Wi-Fi/Mobile only in the Android settings but it still works in normal environments.
Can anyone give me advice on what is happening? Do location services simply not work at higher altitudes or certain areas with very poor reception? I have not tested it in underground parking areas though.
I am using PRIORITY_HIGH_ACCURACY as my priority.
I am using PRIORITY_HIGH_ACCURACY as my priority.
That's the reason you are not getting Location change inside a building. Because HIGH_ACCURACY gets location from GPS provider. As we know GPS doesn't work well inside houses as it collects location from satellite.
You can try out other options.
PRIORITY_BALANCED_POWER_ACCURACY (About 100 meter)
PRIORITY_LOW_POWER (About 10km)
PRIORITY_NO_POWER (Act as a passive listener )
You may visit here if you havn't yet. Hope this helps.
I'm starting to develop an app that will stay in background forever and detect when a user is staying in a certain location for a while (and then display a notification to invite the user to open the app to obtain informations about that place).
It's something very similar to what Google Maps does when you're in a restaurant and it shows you a notification to check ratings about it.
What I want is to have a minimal impact on device, so location updates should be very "passive", getting the location only when user is not moving and, if possible, recycling location data that is already got by other activities - maybe by Google Maps itself or other location apps that are running on the devices.
This is not a navigation app, so I don't need to have the live fine location but simply the approximate place with the best accuracy and minimal effort, and only if user is not moving.
LocationListener and onLocationChanged seems to be my men, but can I specify that I don't want to trigger device's sensors and only re-use location data when it's available for other scopes? My app should check these informations and then decide to do a reverse geocode if and when they are accurate enough.
Yes, LocationListener and onLocationChanged are your men, though for a passive implementation, there are a few options you can go through.
First you can check for the last known location, maybe compare it in terms of its time; i.e. getTime() and verify whether it is of use to you.
In terms of code, literally...
Google samples, android location has what is relevant for the last location part:
/**
* Runs when a GoogleApiClient object successfully connects.
*/
#Override
public void onConnected(Bundle connectionHint) {
// Provides a simple way of getting a device's location and is well suited for
// applications that do not require a fine-grained location and that do not need location
// updates. Gets the best and most recent location currently available, which may be null
// in rare cases when a location is not available.
mLastLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
Further, you can combine it with LocationRequest object, this helps your implementation as you can call it right after trying getLastLocation() and basically have a more reliable arrangement for obtaining location.
// Create the location request
mLocationRequest = LocationRequest.create()
//priority object needs to be set, the following will definitely get results for you
.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY)
//interval updates can be on the lines of 15mins or 30... acc to your requirement
.setInterval(UPDATE_INTERVAL)
.setFastestInterval(FASTEST_INTERVAL);
// Request location updates
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient,
mLocationRequest, this);
i suggest give PRIORITY_NO_POWER a try, could work well in combination with getLastLocation(). These power modes have been added specifically for optimising battery/power consumption and efficiency for retrieving location.
I have referred many questions on this topic, but it seems some of my requirements are missing:
I want to get the GPS location at ~0.0001 accuracy
Don't want to use internet; Though GSM/CDMA network is ok
Should be obtained programmatically when the app starts
Should be quicker, say within a minute (like iPhone, which probably works in Airplane mode as well!)
The code should work in most of the devices
The phone may switch-on/off anytime and travel any distance
Is there any way to get just the co-ordinates with above mentioned requirements? Any sample code snippet will be much appreciated.
Checking various apps like "Locate Me", "Maverick", which claim to show offline locations. But in various scenarios without internet, they don't give track the location (in India).
I have referred plenty of old/new questions inside/outside SO. Below are few:
Is it possible to have the gps location while offline with the nexus
7?
Does GPS require
Internet?
How to get current exact location in android without internet
connection?
[Note: I am asking this question on behalf of my Android team and will be happy to clarify the details if asked for. Should you feel that this post belongs to Android.Stackexchange, then kindly move it.]
1. I want to get the GPS location at ~0.0001 accuracy
You can listen only to GPS provider and discard a location when it doesn't have the minimun accuracy you want:
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 5, myLocationListener); // "myLocationListener" must be an object from a class that implements LocationListener
// "myLocationListener" implementation of LocationListener.onLocationChanged
public void onLocationChanged(Location location)
{
int MIN_ACCURACY = 5; // in metters
if ((!location.hasAccuracy()) || (location.getAccuracy() > MIN_ACCURACY))
{
// discard this location and keep listening to new location readings
}
else
{
// that's a good reading!
// do somethings you want... blah, blah, blah...
// stop updates when you get the location to preserve users' battery.
locationManager.removeUpdates(myLocationListener);
}
}
2. Don't want to use internet; Though GSM/CDMA network is ok
Yes, GPS works totally off-line. Android can make use of internet ONLY to update A-GPS data cache and provide faster reads in cold-start updates.
3. Should be obtained programmatically when the app starts
Then call item locationManager.requestLocationUpdates on mainActivity's onCreate event.
4. Should be quicker, say within a minute (like iPhone, which probably
works in Airplane mode as well!)
Keep in mind that iPhone works with "high quality hardware". Android can be run on crappy devices. So it'll depend of:
The device's hardware quality;
The number of satellites that are visible in the sky at that moment;
The age of almanac and ephemeris data on gps cache;
GPS can fail to read satellites because user is inside a building or something.
5. The code should work in most of the devices
What is the oldest Android's API you want it to run?
6. The phone may switch-on/off anytime and travel any distance
I didn't get it. What is your concern about this?
------------------------------------------------------------------------------
Update 1:
"...I would like to use Android 4.0 and above..."
I've tested GPS features from Android 2.3 to 5.0 devices. Everything runs pretty fine on all of them.
"...I have observed that 1 geo-coordinates based demo app which was working in other devices, din't work in my LGG3 with Android 5.0. Any idea on that?..."
Did you check GPS permissions on Android settings? (Maybe it's disabled) Or can be a hardware issue? Did you try in another similar device?
"...Suppose the GPS is showing correct location in New York,
I switch off the phone and then switch on after reaching to London,
then will it still show correct location (without internet)?..."
Sounds you're confusing things: reading a GPS location is one thing. Showing that location into a MAP is another different thing!
You don't need to be connected to the internet to do GPS location reading. But, if you want to show that location into a MAP, probably you're gonna need internet (to load map resources, etc.).
If you nedd to stay collecting GPS locations periodically (let's say, from 10 to 10 minutes), then it will be better to use AlarmManager to schedule a timer that will "finger" your app and say "hey, time to make a GPS reading!".
"...Also what is your opinion about the latest Fused API?..."
I've tested it and used it for a while, but I gave it up. It needs that Google Play Services be installed to work (not a problem, most users have it on their devices). But if you need ACCURACY (as I do), it will not work. It uses "fused sensors" (accelerometer, gps, wifi, compass, etc...) to try to get user location with minimum power possibile. Sometimes, it says you're 10 miles away from where you're really is. I couldn't make it work fine to keep the "path" where user has been. But it really saves battery.
Suggestion is to use Google Location Services
It takes the best possible and accurate location as accurate as it can at current moment. It automatically (with configuration of course) takes best current accuracy too - whatever is available GPS, network, internet, GSM/CDMA/LTE... It also cashes last known location so, basically, you know it every moment - the best what you can.
Of course you have to realize that each service provides its own accuracy and in it's own time. Look, for example, GPS Test App on Android and see how accuracy increases with time and used satellites.
Also Location Services is good for you because it simply provides coordinates - just as you asked and hides a lot of work to determine what real service to use based on time and accuracy. However, of course, if none of the services on your particular device and location can give you required accuracy then there is no way to get it. That's why services also provide accuracy measurement.
Here is another link
Use fused location API provided by Android SDK.Implement fused location in a Service and call it in your application MainActivity.