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
}
Related
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.
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.
We're making a game in Android Studio and we got stuck. The resource (mana) used for specific spells should recover on time, e.g. 1 mana point per 5 minutes. We don't really get how to make it recover while the game is off. Is there a method to check current date/time and count the amount of mana replenished? Converting date and time to String and comparing it with the new date/time seems to be an "exciting" work to do, but we would bypass these mechanics if there is a way.
Thank you in advance.
The best way to do this in the background is to register a receiver in your manifest. This means the receiver will keep listening for broadcasts even if the app is off.
What you need is this particular action when registering your receiver Intent.ACTION_TIME_TICK
There is a more detailed answer about this matter here Time change listener
Another solution is to use the Calendar class in java. With it you can get the exact minutes passed from a point in the past to this moment. This way you don't have to worry about parsing dates and similar. I can't provide you specific examples because me myself have not used the Calendar class very much, but I'm sure you can find lots of stuff in the official documentation and on stackoverflow about it.
No need to work with Date objects, the simple usage of System.currentTimeMillis() should work. Here's a basic outline:
long mLastManaRefreshTime = System.currentTimeMillis();
void refreshMana()
{
long timeDelta = System.currentTimeMillis() - mLastManaRefreshTime;
mLastManaRefreshTime = System.currentTimeMillis();
float totalManaToRefresh = (float)AMOUNT_TO_REFRESH_IN_ONE_MINUTE * ((float)timeDelta / 60000f);
mMana += totalManaToRefresh;
if (mMana > MAX_MANA)
mMana = MAX_MANA;
}
This method is of course just an outline. You will need to call this once every update cycle. It will calculate how much time passed since the last time refreshMana was called, and replenish the required amount.
If you need this to work while the game is off, you can save the mLastManaRefreshTime to a SharedPreferences object and reload it when the game loads up again.
With System.currentTimeMillis() you can a current time-stamp in milliseconds.
You could save the latest time-stamp in your Preferences with every 5 min tick of the running game. For the other case, when your App comes back from a state where it does not do this (i.e. called the first time, woken up etc.).
Something like this:
int manacycles = ((int) (((System.currentTimeMillis() - oldtimestamp) / 1000) / 60) ) % 5;
would give you the number of Mana points you would have to add.
Alternately you could do the same thing with the Calendar class.
Also keep in mind players could cheat this way by simply changing their time. If your game is online you could get the time from the internet, with something like this:
try {
TimeTCPClient client = new TimeTCPClient();
try {
// Set timeout of 60 seconds
client.setDefaultTimeout(60000);
// Connecting to time server
// Other time servers can be found at : http://tf.nist.gov/tf-cgi/servers.cgi#
// Make sure that your program NEVER queries a server more frequently than once every 4 seconds
client.connect("nist.time.nosc.us");
System.out.println(client.getDate());
} finally {
client.disconnect();
}
} catch (IOException e) {
e.printStackTrace();
}
What is a correct way to determine time since last location update on <4.2 Androids?
This is code I've used:
long lastUpdateTime = lastLocation.getTime();
long currentTime = System.currentTimeMillis();
if (( currentTime - lastUpdateTime > 300000) || currentTime - lastUpdateTime < 0){
LocMan.requestLocationUpdates(LocationManager.GPS_PROVIDER,400,1,listener);
}
Is it OK or should I have some other approach?
API Docs state this:
Note that the UTC time on a device is not monotonic: it can jump forwards or backwards unpredictably. So always use getElapsedRealtimeNanos() when calculating time deltas.
However, pre-APIv17 (where getElapsedRealtimeNanos() was added) is still around & needs to be supported.
Thanks for the answers,
I'd leave this as a comment but I don't have that privilege yet. It seems a similar question has been asked already.
"How long ago was the last known location recorded?"
I'm reading timestamp values from SensorEvent data but I can't work out the reference time for these values. Android documentation just says "The time in nanosecond at which the event happened" As an example:
My current Android device date, October 14th 2011 23:29:56.421 (GMT+2)
System.currentTimeMillis * 1000000 (nanosec) = 1318627796431000000 (that's ok)
sensorevent.timestamp (nanosec) = 67578436328000 = 19 hours 46 min ????
May you help me?
thanks
It appears that what you are dealing with is the number of nanoseconds since the operating system started, also known as "uptime".
Further info on the issue: http://code.google.com/p/android/issues/detail?id=7981
I should add that the linked question SensorEvent.timestamp to absolute (utc) timestamp? deals with the same issue and is where I found the answer.
I know that it's a very old question, but, I'm also struggling for converting SensorEvent.timestamp to a human readable time. So I'm writing here what I've understood so far and how I'm converting it in order to get better solutions from you guys. Any comments will be welcomed.
As I understood, SensorEvent.timestamp is an elapsed time since the device's boot-up. So I have to know the uptime of the device. So if there is an API returning device's boot-up, it will be very easy, but, I haven't found it.
So I'm using SystemClock.elapsedRealtime() and System.currentTimeMillis() to 'estimate' a device's uptime. This is my code.
private long mUptimeMillis; // member variable of the activity or service
...
atComponentsStartUp...() {
...
/* Call elapsedRealtime() and currentTimeMillis() in a row
in order to minimize the time gap */
long elapsedRealtime = SystemClock.elapsedRealtime();
long currentTimeMillis = System.currentTimeMillis();
/* Get an uptime. It assume that elapsedRealtime() and
currentTimeMillis() are called at the exact same time.
Actually they don't, but, ignore the gap
because it is not a significant value.
(On my device, it's less than 1 ms) */
mUptimeMillis = (currentTimeMillis - elapsedRealtime);
....
}
...
public void onSensorChanged(SensorEvent event) {
...
eventTimeMillis = ((event.timestamp / 1000000) + mUptimeMillis);
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(eventTimeMillis);
...
}
I think this works for Apps that a millisecond time error is okey. Please, leave your ideas.