Skip to content
This repository was archived by the owner on Aug 31, 2021. It is now read-only.

Commit 3c1004a

Browse files
Merge pull request #4085 from livecodefraser/fix_android_gps
Improve GPS timestamps on Android
2 parents 09abc72 + aaaf02f commit 3c1004a

File tree

5 files changed

+65
-18
lines changed

5 files changed

+65
-18
lines changed

config.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,7 @@ WIN_PERL=${WIN_PERL:-"C:/perl/bin/perl.exe"}
275275
# Android default settings and tools
276276
if test "${OS}" = "android" ; then
277277
ANDROID_NDK_VERSION=${ANDROID_NDK_VERSION:-r10d}
278-
ANDROID_PLATFORM=${ANDROID_PLATFORM:-android-10}
278+
ANDROID_PLATFORM=${ANDROID_PLATFORM:-android-17}
279279

280280
# Attempt to locate an Android NDK
281281
if [ -z "${ANDROID_NDK}" -a "${OS}" = "android" ] ; then

docs/notes/bugfix-17661.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Improve Android timestamp accuracy for GPS and sensors
2+
3+
Timestamps for sensors on Android were previously passed in a low-precision
4+
format, resulting in "sticky" timestamps that did not change more than a few
5+
times a minute. This has now been resolved and timestamps are now reported to
6+
microsecond resolution (though the accuracy is unlikely to be at the microsecond
7+
level).
8+
9+
In addition to this change, the timestamps are now reported in "monotonic" time
10+
rather than "wall-clock" time ("wall-clock" time is the time you see reported
11+
as the current time). This means that the timestamps are now independent of
12+
changes to the device clock as a result of adjustments or daylight savings
13+
changes. If you want to match the readings to the device time instead, get the
14+
current time when receiving the location update rather than using the timestamp
15+
in the update.
16+

engine/src/java/com/runrev/android/Engine.java

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1478,30 +1478,30 @@ public boolean stopTrackingRotationRate()
14781478
return m_sensor_module.stopTrackingRotationRate();
14791479
}
14801480

1481-
public void onAccelerationChanged(float p_x, float p_y, float p_z, float p_timestamp)
1481+
public void onAccelerationChanged(float p_x, float p_y, float p_z, double p_timestamp)
14821482
{
14831483
doAccelerationChanged(p_x, p_y, p_z, p_timestamp);
14841484
if (m_wake_on_event)
14851485
doProcess(false);
14861486
}
14871487

1488-
public void onLocationChanged(double p_latitude, double p_longitude, double p_altitude, float p_timestamp, float p_accuracy, double p_speed, double p_course)
1488+
public void onLocationChanged(double p_latitude, double p_longitude, double p_altitude, double p_timestamp, float p_accuracy, double p_speed, double p_course)
14891489
{
14901490
// MM-2013-02-21: Added spead and course to location readings.
14911491
doLocationChanged(p_latitude, p_longitude, p_altitude, p_timestamp, p_accuracy, p_speed, p_course);
14921492
if (m_wake_on_event)
14931493
doProcess(false);
14941494
}
14951495

1496-
public void onHeadingChanged(double p_heading, double p_magnetic_heading, double p_true_heading, float p_timestamp,
1496+
public void onHeadingChanged(double p_heading, double p_magnetic_heading, double p_true_heading, double p_timestamp,
14971497
float p_x, float p_y, float p_z, float p_accuracy)
14981498
{
14991499
doHeadingChanged(p_heading, p_magnetic_heading, p_true_heading, p_timestamp, p_x, p_y, p_z, p_accuracy);
15001500
if (m_wake_on_event)
15011501
doProcess(false);
15021502
}
15031503

1504-
public void onRotationRateChanged(float p_x, float p_y, float p_z, float p_timestamp)
1504+
public void onRotationRateChanged(float p_x, float p_y, float p_z, double p_timestamp)
15051505
{
15061506
doRotationRateChanged(p_x, p_y, p_z, p_timestamp);
15071507
if (m_wake_on_event)
@@ -3452,11 +3452,11 @@ public static native void doPurchaseStateChanged(boolean verified, int purchaseS
34523452
public static native void doWait(double time, boolean dispatch, boolean anyevent);
34533453

34543454
// sensor handlers
3455-
public static native void doLocationChanged(double p_latitude, double p_longitude, double p_altitude, float p_timestamp, float p_accuracy, double p_speed, double p_course);
3456-
public static native void doHeadingChanged(double p_heading, double p_magnetic_heading, double p_true_heading, float p_timestamp,
3455+
public static native void doLocationChanged(double p_latitude, double p_longitude, double p_altitude, double p_timestamp, float p_accuracy, double p_speed, double p_course);
3456+
public static native void doHeadingChanged(double p_heading, double p_magnetic_heading, double p_true_heading, double p_timestamp,
34573457
float p_x, float p_y, float p_z, float p_accuracy);
3458-
public static native void doAccelerationChanged(float x, float y, float z, float timestamp);
3459-
public static native void doRotationRateChanged(float x, float y, float z, float timestamp);
3458+
public static native void doAccelerationChanged(float x, float y, float z, double timestamp);
3459+
public static native void doRotationRateChanged(float x, float y, float z, double timestamp);
34603460

34613461
// input event handlers
34623462
public static native void doBackPressed();

engine/src/java/com/runrev/android/SensorModule.java

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,9 @@ class LocationTracker extends Tracker
219219
boolean m_use_gps;
220220
boolean m_gps_available;
221221

222+
// Offset (in seconds) between GPS monotonic timestamps and wall-clock time
223+
double m_timestamp_offset;
224+
222225
Location m_last_location;
223226

224227
LocationManager m_location_manager;
@@ -228,6 +231,20 @@ class LocationTracker extends Tracker
228231

229232
public LocationTracker()
230233
{
234+
// Get the number of seconds since the device was booted
235+
double t_seconds_since_boot;
236+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1)
237+
t_seconds_since_boot = SystemClock.elapsedRealtimeNanos() / 1.0e9;
238+
else
239+
t_seconds_since_boot = SystemClock.elapsedRealtime() / 1.0e3;
240+
241+
// Get the current wall-clock time in seconds since the Unix epoch
242+
double t_seconds_since_epoch = System.currentTimeMillis() / 1000.0;
243+
244+
// Calculate the offset between the since-boot monotonic clock and
245+
// the current wall-clock time
246+
m_timestamp_offset = t_seconds_since_epoch - t_seconds_since_boot;
247+
231248
m_location_manager = (LocationManager)m_engine.getContext().getSystemService(Context.LOCATION_SERVICE);
232249
m_network_location_listener = new LocationListener()
233250
{
@@ -345,8 +362,22 @@ protected void onLocationChanged(Location location)
345362
else
346363
t_course = -1.0f;
347364

365+
// Get an approximate wall-clock time of the fix. This can drift
366+
// over time if the wall-clock time is adjusted (forwards or
367+
// backwards) but for location-tracking purposes, a monotonic
368+
// timestamp is more important than one that matches the wall-
369+
// clock time.
370+
//
371+
// For devices before Jelly Bean, this isn't possible and so the
372+
// normal wall-clock time has to be used instead.
373+
double t_timestamp;
374+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1)
375+
t_timestamp = (location.getElapsedRealtimeNanos() / 1.0e9) + m_timestamp_offset;
376+
else
377+
t_timestamp = location.getTime() / 1000.0;
378+
348379
m_engine.onLocationChanged(location.getLatitude(), location.getLongitude(), location.getAltitude(),
349-
location.getTime() / 1.0e3f, location.getAccuracy(), t_speed, t_course);
380+
t_timestamp, location.getAccuracy(), t_speed, t_course);
350381
}
351382
}
352383

engine/src/mblandroidsensor.cpp

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -227,9 +227,9 @@ bool MCSystemGetLocationAuthorizationStatus(MCStringRef& r_status)
227227

228228
////////////////////////////////////////////////////////////////////////////////
229229

230-
extern "C" JNIEXPORT void JNICALL Java_com_runrev_android_Engine_doAccelerationChanged(JNIEnv *env, jobject object, jfloat x, jfloat y, jfloat z, jfloat timestamp) __attribute__((visibility("default")));
230+
extern "C" JNIEXPORT void JNICALL Java_com_runrev_android_Engine_doAccelerationChanged(JNIEnv *env, jobject object, jfloat x, jfloat y, jfloat z, jdouble timestamp) __attribute__((visibility("default")));
231231

232-
JNIEXPORT void JNICALL Java_com_runrev_android_Engine_doAccelerationChanged(JNIEnv *env, jobject object, jfloat x, jfloat y, jfloat z, jfloat timestamp)
232+
JNIEXPORT void JNICALL Java_com_runrev_android_Engine_doAccelerationChanged(JNIEnv *env, jobject object, jfloat x, jfloat y, jfloat z, jdouble timestamp)
233233
{
234234
// MM-2012-03-13: Create first reading value only when we get a callback.
235235
// This means we can properly handle the case where the user requests a reading before one has been taken.
@@ -245,9 +245,9 @@ JNIEXPORT void JNICALL Java_com_runrev_android_Engine_doAccelerationChanged(JNIE
245245
MCSensorPostChangeMessage(kMCSensorTypeAcceleration);
246246
}
247247

248-
extern "C" JNIEXPORT void JNICALL Java_com_runrev_android_Engine_doLocationChanged(JNIEnv *env, jobject object, jdouble latitude, jdouble longitude, jdouble altitude, jfloat timestamp, jfloat accuracy, jdouble speed, jdouble course) __attribute__((visibility("default")));
248+
extern "C" JNIEXPORT void JNICALL Java_com_runrev_android_Engine_doLocationChanged(JNIEnv *env, jobject object, jdouble latitude, jdouble longitude, jdouble altitude, jdouble timestamp, jfloat accuracy, jdouble speed, jdouble course) __attribute__((visibility("default")));
249249

250-
JNIEXPORT void JNICALL Java_com_runrev_android_Engine_doLocationChanged(JNIEnv *env, jobject object, jdouble latitude, jdouble longitude, jdouble altitude, jfloat timestamp, jfloat accuracy, jdouble speed, jdouble course)
250+
JNIEXPORT void JNICALL Java_com_runrev_android_Engine_doLocationChanged(JNIEnv *env, jobject object, jdouble latitude, jdouble longitude, jdouble altitude, jdouble timestamp, jfloat accuracy, jdouble speed, jdouble course)
251251
{
252252
// MM-2012-03-13: Create first reading value only when we get a callback.
253253
// This means we can properly handle the case where the user requests a reading before one has been taken.
@@ -269,9 +269,9 @@ JNIEXPORT void JNICALL Java_com_runrev_android_Engine_doLocationChanged(JNIEnv *
269269
MCSensorPostChangeMessage(kMCSensorTypeLocation);
270270
}
271271

272-
extern "C" JNIEXPORT void JNICALL Java_com_runrev_android_Engine_doHeadingChanged(JNIEnv *env, jobject object, jdouble heading, jdouble magnetic_heading, jdouble true_heading, jfloat timestamp, jfloat x, jfloat y, jfloat z, jfloat accuracy) __attribute__((visibility("default")));
272+
extern "C" JNIEXPORT void JNICALL Java_com_runrev_android_Engine_doHeadingChanged(JNIEnv *env, jobject object, jdouble heading, jdouble magnetic_heading, jdouble true_heading, jdouble timestamp, jfloat x, jfloat y, jfloat z, jfloat accuracy) __attribute__((visibility("default")));
273273

274-
JNIEXPORT void JNICALL JNICALL Java_com_runrev_android_Engine_doHeadingChanged(JNIEnv *env, jobject object, jdouble heading, jdouble magnetic_heading, jdouble true_heading, jfloat timestamp, jfloat x, jfloat y, jfloat z, jfloat accuracy)
274+
JNIEXPORT void JNICALL JNICALL Java_com_runrev_android_Engine_doHeadingChanged(JNIEnv *env, jobject object, jdouble heading, jdouble magnetic_heading, jdouble true_heading, jdouble timestamp, jfloat x, jfloat y, jfloat z, jfloat accuracy)
275275
{
276276
// MM-2012-03-13: Create first reading value only when we get a callback.
277277
// This means we can properly handle the case where the user requests a reading before one has been taken.
@@ -291,9 +291,9 @@ JNIEXPORT void JNICALL JNICALL Java_com_runrev_android_Engine_doHeadingChanged(J
291291
MCSensorPostChangeMessage(kMCSensorTypeHeading);
292292
}
293293

294-
extern "C" JNIEXPORT void JNICALL Java_com_runrev_android_Engine_doRotationRateChanged(JNIEnv *env, jobject object, jfloat x, jfloat y, jfloat z, jfloat timestamp) __attribute__((visibility("default")));
294+
extern "C" JNIEXPORT void JNICALL Java_com_runrev_android_Engine_doRotationRateChanged(JNIEnv *env, jobject object, jfloat x, jfloat y, jfloat z, jdouble timestamp) __attribute__((visibility("default")));
295295

296-
JNIEXPORT void JNICALL Java_com_runrev_android_Engine_doRotationRateChanged(JNIEnv *env, jobject object, jfloat x, jfloat y, jfloat z, jfloat timestamp)
296+
JNIEXPORT void JNICALL Java_com_runrev_android_Engine_doRotationRateChanged(JNIEnv *env, jobject object, jfloat x, jfloat y, jfloat z, jdouble timestamp)
297297
{
298298
// MM-2012-03-13: Create first reading value only when we get a callback.
299299
// This means we can properly handle the case where the user requests a reading before one has been taken.

0 commit comments

Comments
 (0)