16

my application performs in background step counting using the step detector sensor API's introduced in android 4.4.X.

It's essential to my app to know the exact time (at least accuracy of a second) each step event has accrued.

because I perform sensor batching , the time onSensorChanged(SensorEvent event) been called is not the same time when the step event took place - I must use the event.timestampfield to get the event time.

the documentation about this field is:

The time in nanosecond at which the event happened

The problem:

In some devices (such Moto X 2013) seems like this timestamp is time in nano seconds since boot, while in some devices (such Nexus 5) it's actually returns universal system time in nano seconds same as System.currentTimeMills() / 1000.

I understand, there's already an old open issue about that, but since sensor batching is introduced - it becomes important to use this field to know the event time, and it's not possible to rely anymore on the System.currentTimeMills()

My question:

What should I do to get always the event time in system milliseconds across all devices?

4

3 回答 3

7

而不是您的“2天”比较,您可以只检查是否event.timestamp小于例如1262304000000000000- 这样,如果用户的时钟设置在过去,或者他们的手机已经运行了 40 年,您只会遇到问题。 .

除了对此问题的评论表明有时甚至是毫秒而不是纳秒。其他评论表明应用了偏移量,在这种情况下,它既不是基于系统时间,也不是基于正常运行时间。

如果您真的必须准确,我能看到的唯一方法是最初捕获一个事件(或两个,用于比较)并max_report_latency_ns设置为0(即非批处理)并将时间戳与系统时间和/或elapsedRealtime. 然后使用该比较来计算偏移量(并可能决定是否需要补偿毫秒与纳秒)并将该偏移量用于批处理事件。

例如,抓取几个事件,最好间隔几秒钟,记录System.currentTimeMillis()每次,然后执行以下操作:

long timestampDelta = event2.timestamp - event1.timestamp;
long sysTimeDelta = sysTimeMillis2 - sysTimeMillis1;
long divisor; // to get from timestamp to milliseconds
long offset; // to get from event milliseconds to system milliseconds

if (timestampDelta/sysTimeDelta > 1000) { // in reality ~1 vs ~1,000,000
    // timestamps are in nanoseconds
    divisor = 1000000;
} else {
    // timestamps are in milliseconds
    divisor = 1;
}

offset = sysTimeMillis1 - (event1.timestamp / divisor);

然后为您的批处理事件

long eventTimeMillis = (event.timestamp / divisor) + offset;

最后一个警告 - 即使你做了所有这些,如果系统时间在你的捕获过程中发生变化,它可能会影响你的时间戳。祝你好运!

于 2015-04-07T23:57:43.273 回答
4

我找到了解决问题的解决方案。该解决方案假定时间戳只能是以下两者之一:系统时间戳或启动时间:

protected long getEventTimestampInMills(SensorEvent event) {
    long timestamp = event.timestamp / 1000 / 1000;

    /**
     * work around the problem that in some devices event.timestamp is
     * actually returns nano seconds since last boot.
     */
    if (System.currentTimeMillis() - timestamp > Consts.ONE_DAY * 2) {
        /**
         * if we getting from the original event timestamp a value that does
         * not make sense(it is very very not unlikely that will be batched
         * events of two days..) then assume that the event time is actually
         * nano seconds since boot
         */
        timestamp = System.currentTimeMillis()
                + (event.timestamp - System.nanoTime()) / 1000000L;
    }

    return timestamp;
}
于 2014-11-11T06:17:09.807 回答
3

根据您问题中的链接

这实际上是“按预期工作”。时间戳未定义为 Unix 时间;它们只是仅对给定传感器有效的“时间”。这意味着只有来自同一个传感器的时间戳才能进行比较。

因此,timestamp-field 可能与当前系统时间完全无关。

然而; 如果在启动时您要采集两个传感器样本,而不进行批处理,您可以计算System.currentTimeMillis()和时间戳之间的差异,以及不同时间之间差异的商,您应该能够在不同时间之间进行转换:

//receive event1:
long t1Sys = System.currentTimeMillis();
long t1Evt = event.timestamp;

//receive event2:
long t2Sys = System.currentTimeMillis();
long t2Evt = event.timestamp;

//Unregister sensor


long startoffset = t1Sys - t1Evt; //not exact, but should definitely be less than a second, possibly use an averaged value.
long rateoffset = (t2Sys - t1Sys) / (t2Evt - t1Evt);

现在可以转换来自该传感器的任何时间戳

long sensorTimeMillis = event.timestamp * rateoffset + startoffset;
于 2015-04-08T09:12:53.503 回答