2014-11-04 17 views
12

La mia applicazione esegue il conteggio degli step in background usando step detector sensor API's introdotto in Android 4.4.X.Incoerenza SensorEvent.timestamp

È essenziale che la mia app conosca l'ora esatta (almeno la precisione di un secondo) che ogni evento del passaggio ha accumulato.

perché mi esibisco sensor batching, il tempo onSensorChanged(SensorEvent event) stato chiamato non è lo stesso momento in cui l'evento ha avuto luogo passo - devo utilizzare il campo event.timestamp per ottenere il tempo dell'evento.

la documentazione di questo campo è:

Il tempo in nanosecondo in cui l'evento è accaduto

Il problema:

In alcuni dispositivi (come Moto X 2013) sembra che questo timestamp sia il tempo in nano secondi dall'avvio, mentre in alcuni dispositivi (come Nexus 5) in realtà restituisce il tempo di sistema universale in nano secondi uguale a System.currentTimeMills()/1000.

ho capito, c'è già un old open issue a tale proposito, ma dal momento che il dosaggio del sensore viene introdotto - diventa importante utilizzare questo campo di conoscere l'ora dell'evento, e non è possibile fare affidamento più sulla System.currentTimeMills()

La mia domanda:

Cosa devo fare per ottenere sempre l'evento in millisecondi di sistema su tutti i dispositivi?

risposta

4

Invece di vostro confronto "2 giorni", si può solo controllare se event.timestamp è minore di esempio 1262304000000000000 - in questo modo si avrebbe un problema solo se l'orologio dell'utente è impostato in passato, o il loro telefono è in corso da 40 anni ...

Solo che un commento sulla this issue indica che a volte è anche millisecondi invece di nanosecondi. E altri commenti indicano che è applicato un offset, nel qual caso non sarà né il tempo di sistema né il tempo di attività.

Se avete davvero per essere precisi, l'unico modo che posso vedere è quello di catturare inizialmente un evento (o due, per il confronto) con max_report_latency_ns set per 0 (cioè non-batch) e confrontare il timestamp per l'ora di sistema e/o elapsedRealtime. Quindi utilizzare tale confronto per calcolare un offset (e potenzialmente decidere se è necessario compensare per millisecondi vs nanosecondi) e utilizzare tale offset per gli eventi batch.

E.g.afferrare un paio di eventi, preferibilmente un paio di secondi di distanza, registrando il System.currentTimeMillis() ogni volta e poi fare qualcosa del genere:

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); 

E poi per i vostri eventi batch

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

Un ultimo avvertimento - anche se fai tutto questo, se l'ora del sistema cambia durante la cattura, potrebbe influire sui tuoi timestamp. In bocca al lupo!

+0

Credo che la tua soluzione sia la migliore risposta che potrei ottenere. grazie –

+0

Wow, questo è incredibile. – Michael

2

Ho trovato una soluzione che risolve il problema. la soluzione presuppone che il timestamp può essere solo uno dei due: timestamp del sistema, o il tempo di avvio:

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; 
} 
+0

puzza come un hack. –

2

Secondo il link nella tua domanda:

Questo è, infatti, "funziona come previsto". I timestamp non sono definiti come il tempo Unix; sono solo "un tempo" che è solo valido per un determinato sensore. Ciò significa che i timestamp possono essere solo confrontati se provengono dallo stesso sensore.

Così, la -field timestamp potrebbe essere completamente estranei a l'ora di sistema corrente.

Tuttavia; se all'avvio dovessi prendere due campioni di sensore, senza batch, potresti calcolare la differenza tra lo System.currentTimeMillis() e il timestamp, nonché il quoziente tra le diverse volte che dovresti essere in grado di convertire tra i diversi orari :

//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); 

Ora, qualsiasi timestamp da quel sensore può essere convertito

long sensorTimeMillis = event.timestamp * rateoffset + startoffset; 
+0

Vedo che abbiamo riflettuto su linee molto simili. Immagino che il tuo calcolo del "tassooffset" comporterà una deriva nel tempo (a parte gli eventi di esempio, meno un problema dovrebbe essere, ma non sarà mai perfetto, soprattutto perché ci sarà un ritardo imprevedibile tra il tempo dell'evento e il tempo di sistema associato). Ecco perché nella mia risposta l'ho bloccato a 1 o a 1.000.000. – CupawnTae

+0

Sì, leggendo il tuo anwer mi rendo conto che è fondamentalmente la stessa idea. Il serraggio del valore risolve definitivamente il problema con la deriva, ma una media di diversi campioni, combinata con i ricalcoli periodici è un'alternativa da considerare, a seconda di cosa è necessario. – Jave

+0

questo è disgustoso! – Michael

Problemi correlati