Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android GPS time is 15 seconds faster

Tags:

android

gps

I'm synchronizing my apps time with android.location.Location's method getTime() inside onLocationChanged method call. The problem is that on some devices result is right, on some - 15 seconds faster. As I know, it's because of GPS time and UTC difference.

How to check the device knows about this difference? I need my app shows the same time on all the devices.

I can't use network syncronizing as solution.

like image 449
Ircover Avatar asked Apr 24 '15 09:04

Ircover


2 Answers

There maybe a couple of different factors in play here.

GPS & UTC

First is that as you point out GPS time is different to UTC. GPS has a message that advertises the current offset from UTC, see here. It's possible that not all GPS chips in mobiles pay attention to it, or haven't yet received the GPS offset message yet at the moment you're asking for GPS time data.

Unless there is support in the Android API for discovering this sort of condition you will be reduced to interpreting the NMEA sentences yourself (I don't know if Android makes them available), and even then it will depend on exactly what the manufacturer has decided to put in to those sentences.

According to this PDF, it can take up to half an hour for the complete almanac data to be received by a GPS receiver. The almanac contains the current GPS/UTC offset.

My guess is that because mobile GPS chips are built around AGPS (assisted GPS), they're probably expecting to get GPS almanac data fed to them sourced from a cellular network and might not be too clever at retaining or receiving almanac data for themselves.

So if you're out of range of WiFi and mobile phone networks (you say you cannot use network synchronisation to get time of day...) it might take anything from 12.5 minutes to half an hour before the phone's GPS chip starts giving you UTC time instead of GPS time.

That's a long time for a mobile's GPS chip to be switched on. I'm guessing that often they're not powered up by the OS long enough to ever receive the whole almanac.

If this is indeed the cause of your problem then you may be sunk. GPS almanac data doesn't change very often AFAIK, so you might be able to cache it yourself and somehow supply it to the OS / GPS somehow in leiu of it being read from a local cell basestation. That's starting to sound awfully low level though, and I doubt that Android supports that kind of almanac injection (it's a horrendous denial of service opportunity for malware...).

Clock Drift

The other less likely factor is that the mobiles aren't necessarily running an NTP client in the same way a desktop can. Most Linux desktop distros install an NTP client that constantly runs in the background keeping the local clock in step with some NTP server somewhere. Mobiles (including AFAIK Android) generally don't need that level of time accuracy, so they correct their clock quite rarely in the interests of saving battery life, so it is possible for plenty of drift to accumulate. However I would be surprised if it got as bad as 15 seconds, so it might not be due to this.

like image 198
bazza Avatar answered Oct 25 '22 04:10

bazza


According to docs:

public long getTime ()

Return the UTC time of this fix, in milliseconds since January 1,
1970.

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.

On the other hand, getTime() is useful for presenting a human readable
time to the user, or for carefully comparing location fixes across
reboot or across devices.

All locations generated by the LocationManager are guaranteed to have
a valid UTC time, however remember that the system time may have
changed since the location was generated. 

Returns

time of fix, in milliseconds since January 1, 1970.

Did you try getElapsedRealtimeNanos()?

To convert it to Date, use:

Date date = new Date(System.currentTimeMillis() 
                   - SystemClock.elapsedRealtime() 
                   + location.getElapsedRealtimeNanos());
like image 20
Christian Avatar answered Oct 25 '22 05:10

Christian