Android Fused Location Won't Deliver Periodic Updates - android

I want to get a hard location fix every certain minutes & a soft location fix every certain minutes and if user has moved more then certain meters. I been testing the logic with following piece of code walking (tried it with larger parameters as well while driving) but it doesn't really return me periodic location fixes. It would return a location fix right away when request starts then sometime return 1 location fix few minutes later that but then for up-to an hour it won't return a location fix.
LocationRequest locationRequest = LocationRequest.create();
int priority = PRIORITY_BALANCED_POWER_ACCURACY;
locationRequest.setPriority(priority);
locationRequest.setInterval(localInterval); //set to 6 minutes
locationRequest.setFastestInterval(localFastestInterval); //set to 3 minutes
locationRequest.setSmallestDisplacement(smallestDisplacement); //set to 10 meters
locationRequest.setNumUpdates(numUpdates); //set to Int.MAX_VALUE
locationRequest.setExpirationDuration(expirationDuration); // set to Long.MAX_VALUE
LocationServices.FusedLocationApi.requestLocationUpdates(locationClient, locationRequest, pendingIntent);
If I set displacement to 0 then I get periodic location updates. Any idea what is going on?

After long exhaustive testing & experimentation I've found that if you don't call setFastestInterval you will get periodic updates exactly according to the interval set with setInterval.
However as other applications can cause location fixes to be delivered very fast to you so just put a check for ignoring location fixes delivered faster than a certain threshold of time passed.
According to documentation: If setFastestInterval(long) is set slower than setInterval(long), then your effective fastest interval is setInterval(long) but that doesn’t happen: e.g. setting following parameters should give you a hard location fix every 1 minute but it does not (on Marshmallow at-least):
interval = 1 min
fastestInterval = 20 min
displacement = 0
If anyone can disprove my findings with a piece of code that would be great.

Related

How to get location updates in certain time interval only?

In my android application I want to get location updates only for certain time interval say like from morning 9 to evening 9.
How is that doable. Please share your thoughts on it.
Thanks in Advance.!
This is my solution to this problem.
use it in a running background service or something like this:
Calendar c = Calendar.getInstance();
int hofday = c.get(Calendar.HOUR_OF_DAY); //getting the current hour of day
if (hofday<21 && hofday>9){ //between 9am. and 9pm.
//start collecting gps data
}
else{
//it is not between 9am. and 9pm.
}
You set an alarm for 9 am and 9 pm. Then in your broadcast receiver for the first you turn on location updates, and for the second you turn it off.
This is a good tutorial on how to schedule repeating alarms. For location updates I recommend using LocationListener.

Enabling "High Accuracy" Location using Settings API in Google Play Service

I'm trying to enable the location from application using Settings API. In location dialog it shows message Use WiFi and cellular networks for location. On selection of Yes it is enabling the location but not the GPS.
But while I was playing with Google Maps in same device, it displays the message
Use GPS, WiFi and cellular networks for location as like below screenshot.
And this is enabling the GPS also. How can I achieve the same as Google Maps.
Before posting here I hope I have checked all the possible options. Find my tryouts list below.
I have set the priority as HIGH_ACCURACY and min interval to 5 seconds
locationRequest = LocationRequest.create();
// Set the priority of the request
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
// Set the update interval to 10 seconds
locationRequest.setInterval(1000 * 10);
// Set the fastest update interval to 5 seconds
locationRequest.setFastestInterval(1000 * 5);
Using only FINE_LOCATION permission
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
Also referred few links but nothing gave exact solutions. All I need is I would like to enable the location with HIGH_ACCURACY by default which enables the GPS Any help on this?
I had this problem, but after clicking the YES button to permit use GPS, the activity stops and runs the method onPause and then the activity begins in the method onResume.
So my solution was start again the localizacion in onResume method
#Override onResume public void () {
//your code
         LocationRequest = LocationRequest.create ();
// Set the priority of the request
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
// Set the update interval to 10 seconds
locationRequest.setInterval (1000 * 10);
// Set the fastest update interval to 5 seconds
locationRequest.setFastestInterval (1000 * 5);
.....
//start again the localizacion
LocationServices.FusedLocationApi.requestLocationUpdates(apiClient, locRequest, this);

Cordova geolocation watchPosition frequency is higher than the options allow it

in my ionic/angularjs application I'm using the geolocation plugin: https://github.com/apache/cordova-plugin-geolocation
Like in the documentation I use this to configure the watch:
var watchOptions = {
frequency : 10*1000,
timeout : 60*60*1000,
enableHighAccuracy: true // may cause errors if true
};
watch = navigator.geolocation.watchPosition(on_success,on_error,watchOptions);
But however on android the frequency is much higher than 10 seconds (about 0.5 Seconds). On iOS it works great. What is the problem here?
Updated in light of comments below
There is no frequency parameter available in the geolocation options for watchPosition() hence any value you pass will be ignored. The success callback registered via watchPosition() is invoked each time the native location manager receives a position update from the GPS hardware (in the case of enableHighAccuracy=true) so it's not called on a fixed interval.
The native location managers (both Android and iOS) are event-driven, i.e. they receive updates from the GPS hardware as and when it delivers them at a non-fixed interval. Hence trying to apply a fixed frequency to this is trying to fit a square peg in a round hole - you cannot demand that the GPS hardware deliver you a location update exactly ever N seconds.
While you can call getCurrentPosition() on a fixed interval, this method simply returns last received position or requests a new one.
If the problem is that the updates are too frequent, you could log the time each update is received at, and only accept the next update after N seconds, e.g.
var lastUpdateTime,
minFrequency = 10*1000,
watchOptions = {
timeout : 60*60*1000,
maxAge: 0,
enableHighAccuracy: true
};
function on_success(position){
var now = new Date();
if(lastUpdateTime && now.getTime() - lastUpdateTime.getTime() < minFrequency){
console.log("Ignoring position update");
return;
}
lastUpdateTime = now;
// do something with position
}
navigator.geolocation.watchPosition(on_success,on_error,watchOptions);
This, however, will not stop the device requesting updates more frequently, hence consuming a relatively large amount of battery.
The native Android LocationManager does allow you to specify a minimum time between updates when requesting location in order to minimise battery drain, however cordova-plugin-geolocation on Android doesn't implement use LocationManager directly, but instead uses the W3C Geolocation API Specification in the native webview, which does not allow you to specify this.
However, you can use this plugin to do this: cordova-plugin-locationservices
It will allow you to specify:
interval: Set the desired interval for active location updates, in milliseconds.
fastInterval: Explicitly set the fastest interval for location updates, in milliseconds.

Age of location returned from LocationServices

I need to ensure the location I use is fresh:
Is there a way of finding out how old the location result returned by LocationServices.FusedLocationApi.getLastLocation is?
If not: if I register a location listener to the LocationServices.FusedLocationApi.requestLocationUpdates (with setNumUpdates(1) and setMaxWaitTime(0)) then will it update if the location has not changed from the one returned by LocationServices.FusedLocationApi.getLastLocation?
Yes, there is a very easy way. You can get the time of a Location fix by calling getTime() like this:
Location currentLocation = LocationServices.FusedLocationApi.getLastLocation(apiClient);
long locationAge = System.currentTimeMillis() - currentLocation.getTime();
if (locationAge <= 60 * 1000) { // not older than 60 seconds
// do something with the location
}
The documentation recommends not to use System.currentTimeMillis() for time comparisons, but I never experienced any flaws with this method. However, you should consider reading the (short) documentation:
https://developer.android.com/reference/android/location/Location.html#getTime()
To expand on Illiminat's answer, as of API 17 the getElapsedRealtimeNanos() method has been added. From the documentation of the method...
Return the time of this fix, in elapsed real-time since system boot.
This value can be reliably compared to SystemClock.elapsedRealtimeNanos(), to calculate the age of a fix and to compare Location fixes. This is reliable because elapsed real-time is guaranteed monotonic for each system boot and continues to increment even when the system is in deep sleep (unlike getTime().
https://developer.android.com/reference/android/location/Location.html#getElapsedRealtimeNanos()
Therefore the following should now be the most precise way of doing calculating this
Location currentLocation = LocationServices.FusedLocationApi.getLastLocation(apiClient);
long locationAge = SystemClock.elapsedRealtimeNanos() - currentLocation.getElapsedRealtimeNanos();
long ageLimitNanoSec = 60_000_000_000; // 60 seconds in nano seconds
if (locationAge <= ageLimitNanoSec) {
// do something with the location
}

Android Locationprovider takes too long to become temporarily unavailable

According to this article (UPD: link removed as it leads to some crap now), setting the minTime when requesting location updates will cause the provider to set itself to TEMPORARILY_UNAVAILABLE for minTime milliseconds in order to conserve battery power. During this period of inactivity, the GPS provider will turn itself off and the GPS icon will disappear.
In my code, I set the minTime to about 30 seconds, but the provider only becomes TEMPORARILY_UNAVAILABLE once every five minutes. When it does, it only stays TEMPORARILY_UNAVAILABLE for ten seconds at most before turning itself back on. I know this because the GPS icon disappears for only ten seconds before reappearing again.
I understand that the minTime setting is only a rough guideline for the Android location provider...but I'm pretty sure that five minutes is entirely different from 30 seconds. Does anyone know what is going on here? How does minTime and requestLocationUpdates actually work?
LocationManager Setup:
locManager = (LocationManager) getSystemService(LOCATION_SERVICE);
locManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,30000L, 0, locListener);
locListener:
public void onLocationChanged(Location loc) {
//Keep track of best location
//Having a location > no location
if (bestLocation == null)
bestLocation = loc;
//More accuracy > Less accuracy
else if (loc.getAccuracy() <= bestLocation.getAccuracy())
bestLocation = loc;
Log.d(TAG, "Location Updated";
}
public void onStatusChanged(String provider, int status, Bundle extras) {
Log.d(TAG, "New status: " + status);
if (status== LocationProvider.TEMPORARILY_UNAVAILABLE)
//Do stuff since the provider is temporarily off
}
Debug output on a real Android device (HTC Incredible 2.2):
Location Updated
Location Updated
New status: 2
Location Updated
Location Updated
Location Updated
New status: 2
... (five minutes later)
New status: 1
From the API:
"Background services should be careful about setting a sufficiently high minTime so that the device doesn't consume too much power by keeping the GPS or wireless radios on all the time. In particular, values under 60000ms are not recommended." (emphasis is mine)
"This field is only used as a hint to conserve power, and actual time between location updates may be greater or lesser than this value." (emphasis is mine).
If you need to know the location immediately, use getLastKnownLocation(String)

Categories

Resources