@@ -78,6 +78,9 @@ class NetworkLocationService : LifecycleService(), WifiDetailsCallback, CellDeta
7878 @GuardedBy(" gpsLocationBuffer" )
7979 private val gpsLocationBuffer = LinkedList <Location >()
8080
81+ @GuardedBy(" lowAccuracyGpsLocationBuffer" )
82+ private val lowAccuracyGpsLocationBuffer = LinkedList <Location >()
83+
8184 private var currentLocalMovingWifi: WifiDetails ? = null
8285 private var lastLocalMovingWifiLocationCandidate: Location ? = null
8386
@@ -391,7 +394,22 @@ class NetworkLocationService : LifecycleService(), WifiDetailsCallback, CellDeta
391394 elapsedRealtimeNanos = (old.elapsedRealtimeNanos.toDouble() * (1.0 - pct) + new.elapsedRealtimeNanos.toDouble() * pct).toLong()
392395 }
393396 }
397+ fun Location.isUnreasonableComparedTo (other : Location ): Boolean {
398+ val distance = distanceTo(other)
399+ if (distance > 2 * other.accuracy) {
400+ Log .d(TAG , " Unreasonable location ${this .provider} vs ${other.provider} (accuracy ${other.accuracy} ): distance $distance " )
401+ return true
402+ }
403+ return false
404+ }
405+ fun Location.reasonableOrNull (): Location ? {
406+ val gpsLocation = getGpsLocation(elapsedMillis, includeLowAccuracy = true ) ? : return this
407+ if (isUnreasonableComparedTo(gpsLocation)) return null
408+ return this
409+ }
394410 val location = synchronized(locationLock) {
411+ lastCellLocation = lastCellLocation?.reasonableOrNull()
412+ lastWifiLocation = lastWifiLocation?.reasonableOrNull()
395413 if (lastCellLocation == null && lastWifiLocation == null ) return
396414 when {
397415 // Only non-null
@@ -401,7 +419,7 @@ class NetworkLocationService : LifecycleService(), WifiDetailsCallback, CellDeta
401419 lastCellLocation!! .elapsedMillis > lastWifiLocation!! .elapsedMillis + LOCATION_TIME_CLIFF_END_MS -> lastCellLocation
402420 lastWifiLocation!! .elapsedMillis > lastCellLocation!! .elapsedMillis + LOCATION_TIME_CLIFF_START_MS -> lastWifiLocation
403421 // Wifi out of cell range with higher precision
404- lastCellLocation!! .precision > lastWifiLocation!! .precision && lastWifiLocation!! .distanceTo (lastCellLocation!! ) > 2 * lastCellLocation !! .accuracy -> lastCellLocation
422+ lastCellLocation!! .precision > lastWifiLocation!! .precision && lastWifiLocation!! .isUnreasonableComparedTo (lastCellLocation!! ) -> lastCellLocation
405423 // Consider cliff start
406424 lastCellLocation!! .elapsedMillis > lastWifiLocation!! .elapsedMillis + LOCATION_TIME_CLIFF_START_MS -> cliffLocations(lastWifiLocation, lastCellLocation)
407425 else -> lastWifiLocation
@@ -429,7 +447,9 @@ class NetworkLocationService : LifecycleService(), WifiDetailsCallback, CellDeta
429447 }
430448
431449 private fun onNewGpsLocation (location : Location ) {
432- if (location.accuracy > GPS_PASSIVE_MIN_ACCURACY ) return
450+ if (location.accuracy > GPS_PASSIVE_MIN_ACCURACY_LOW ) return
451+ // gpsLocationBuffer field is shadowed by the low accuracy buffer if inaccurate enough.
452+ val gpsLocationBuffer = if (location.accuracy > GPS_PASSIVE_MIN_ACCURACY ) lowAccuracyGpsLocationBuffer else this .gpsLocationBuffer
433453 synchronized(gpsLocationBuffer) {
434454 if (gpsLocationBuffer.isNotEmpty() && gpsLocationBuffer.last.elapsedMillis < SystemClock .elapsedRealtime() - GPS_BUFFER_SIZE * GPS_PASSIVE_INTERVAL ) {
435455 gpsLocationBuffer.clear()
@@ -440,16 +460,20 @@ class NetworkLocationService : LifecycleService(), WifiDetailsCallback, CellDeta
440460 }
441461 }
442462
443- private fun getGpsLocation (elapsedMillis : Long ): Location ? {
463+ private fun getGpsLocation (elapsedMillis : Long , includeLowAccuracy : Boolean = false ): Location ? {
444464 if (elapsedMillis + GPS_BUFFER_SIZE * GPS_PASSIVE_INTERVAL < SystemClock .elapsedRealtime()) return null
445- synchronized(gpsLocationBuffer) {
446- if (gpsLocationBuffer.isEmpty()) return null
447- for (location in gpsLocationBuffer.descendingIterator()) {
448- if (location.elapsedMillis in (elapsedMillis - GPS_PASSIVE_INTERVAL ).. (elapsedMillis + GPS_PASSIVE_INTERVAL )) return location
449- if (location.elapsedMillis < elapsedMillis) return null
465+ fun getGpsLocationFromBuffer (gpsLocationBuffer : LinkedList <Location >): Location ? {
466+ // gpsLocationBuffer field is shadowed by the argument provided.
467+ synchronized(gpsLocationBuffer) {
468+ if (gpsLocationBuffer.isEmpty()) return null
469+ for (location in gpsLocationBuffer.descendingIterator()) {
470+ if (location.elapsedMillis in (elapsedMillis - GPS_PASSIVE_INTERVAL ).. (elapsedMillis + GPS_PASSIVE_INTERVAL )) return location
471+ if (location.elapsedMillis < elapsedMillis) return null
472+ }
450473 }
474+ return null
451475 }
452- return null
476+ return getGpsLocationFromBuffer(gpsLocationBuffer) ? : if (includeLowAccuracy) getGpsLocationFromBuffer(lowAccuracyGpsLocationBuffer) else null
453477 }
454478
455479 override fun dump (fd : FileDescriptor ? , writer : PrintWriter , args : Array <out String >? ) {
@@ -463,6 +487,7 @@ class NetworkLocationService : LifecycleService(), WifiDetailsCallback, CellDeta
463487 writer.println (" Ichnaea settings: endpoint=${settings.ichneaeEndpoint} contribute=${settings.ichnaeaContribute} " )
464488 writer.println (" Wifi scan cache size=${wifiScanCache.size()} hits=${wifiScanCache.hitCount()} miss=${wifiScanCache.missCount()} puts=${wifiScanCache.putCount()} evicts=${wifiScanCache.evictionCount()} " )
465489 writer.println (" GPS location buffer size=${gpsLocationBuffer.size} first=${gpsLocationBuffer.firstOrNull()?.elapsedMillis?.formatRealtime()} last=${gpsLocationBuffer.lastOrNull()?.elapsedMillis?.formatRealtime()} " )
490+ writer.println (" Low-accuracy GPS location buffer size=${lowAccuracyGpsLocationBuffer.size} first=${lowAccuracyGpsLocationBuffer.firstOrNull()?.elapsedMillis?.formatRealtime()} last=${lowAccuracyGpsLocationBuffer.lastOrNull()?.elapsedMillis?.formatRealtime()} " )
466491 cache.dump(writer)
467492 synchronized(activeRequests) {
468493 if (activeRequests.isNotEmpty()) {
@@ -478,6 +503,7 @@ class NetworkLocationService : LifecycleService(), WifiDetailsCallback, CellDeta
478503 const val GPS_BUFFER_SIZE = 60
479504 const val GPS_PASSIVE_INTERVAL = 1000L
480505 const val GPS_PASSIVE_MIN_ACCURACY = 25f
506+ const val GPS_PASSIVE_MIN_ACCURACY_LOW = 10000f // 10 kilometers
481507 const val LOCATION_TIME_CLIFF_START_MS = 30000L
482508 const val LOCATION_TIME_CLIFF_END_MS = 60000L
483509 const val DEBOUNCE_DELAY_MS = 5000L
0 commit comments