Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Unverified Commit 827a8b91 authored by Marvin W.'s avatar Marvin W. 🐿️
Browse files

Location: Improve update delivery

parent 539dd67b
Loading
Loading
Loading
Loading
+35 −12
Original line number Diff line number Diff line
@@ -41,6 +41,7 @@ import java.io.PrintWriter
import java.lang.Math.pow
import java.nio.ByteBuffer
import java.util.LinkedList
import kotlin.math.max
import kotlin.math.min

class NetworkLocationService : LifecycleService(), WifiDetailsCallback, CellDetailsCallback {
@@ -271,10 +272,6 @@ class NetworkLocationService : LifecycleService(), WifiDetailsCallback, CellDeta
        val scanResultTimestamp = min(wifis.maxOf { it.timestamp ?: Long.MAX_VALUE }, System.currentTimeMillis())
        val scanResultRealtimeMillis =
            if (SDK_INT >= 17) SystemClock.elapsedRealtime() - (System.currentTimeMillis() - scanResultTimestamp) else scanResultTimestamp
        if (scanResultRealtimeMillis < lastWifiDetailsRealtimeMillis + interval / 2 && lastWifiDetailsRealtimeMillis != 0L) {
            Log.d(TAG, "Ignoring wifi details, similar age as last ($scanResultRealtimeMillis < $lastWifiDetailsRealtimeMillis + $interval / 2)")
            return
        }
        @Suppress("DEPRECATION")
        currentLocalMovingWifi = getSystemService<WifiManager>()?.connectionInfo
            ?.let { wifiInfo -> wifis.filter { it.macAddress == wifiInfo.bssid && it.isMoving } }
@@ -294,6 +291,10 @@ class NetworkLocationService : LifecycleService(), WifiDetailsCallback, CellDeta
    }

    private fun updateWifiLocation(requestableWifis: List<WifiDetails>, scanResultRealtimeMillis: Long = 0, scanResultTimestamp: Long = 0) {
        if (scanResultRealtimeMillis < lastWifiDetailsRealtimeMillis + interval / 2 && lastWifiDetailsRealtimeMillis != 0L) {
            Log.d(TAG, "Ignoring wifi details, similar age as last ($scanResultRealtimeMillis < $lastWifiDetailsRealtimeMillis + $interval / 2)")
            return
        }
        val previousLastRealtimeMillis = lastWifiDetailsRealtimeMillis
        if (scanResultRealtimeMillis != 0L) lastWifiDetailsRealtimeMillis = scanResultRealtimeMillis
        lifecycleScope.launch {
@@ -302,9 +303,9 @@ class NetworkLocationService : LifecycleService(), WifiDetailsCallback, CellDeta
                lastWifiDetailsRealtimeMillis = previousLastRealtimeMillis
                return@launch
            }
            if (scanResultTimestamp != 0L && location.time == 0L) location.time = scanResultTimestamp
            if (SDK_INT >= 17 && scanResultRealtimeMillis != 0L && location.elapsedRealtimeNanos == 0L) location.elapsedRealtimeNanos =
                scanResultRealtimeMillis * 1_000_000L
            if (scanResultTimestamp != 0L) location.time = max(scanResultTimestamp, location.time)
            if (SDK_INT >= 17 && scanResultRealtimeMillis != 0L) location.elapsedRealtimeNanos =
                max(location.elapsedRealtimeNanos, scanResultRealtimeMillis * 1_000_000L)
            synchronized(locationLock) {
                lastWifiLocation = location
            }
@@ -372,22 +373,43 @@ class NetworkLocationService : LifecycleService(), WifiDetailsCallback, CellDeta
    }

    private fun sendLocationUpdate(now: Boolean = false) {
        fun cliffLocations(old: Location?, new: Location?): Location? {
            // We move from wifi towards cell with accuracy
            if (old == null) return new
            if (new == null) return old
            val diff = new.elapsedMillis - old.elapsedMillis
            if (diff < LOCATION_TIME_CLIFF_START_MS) return old
            if (diff > LOCATION_TIME_CLIFF_END_MS) return new
            val pct = (diff - LOCATION_TIME_CLIFF_START_MS).toDouble() / (LOCATION_TIME_CLIFF_END_MS - LOCATION_TIME_CLIFF_START_MS).toDouble()
            return Location(old).apply {
                provider = "cliff"
                latitude = old.latitude * (1.0-pct) + new.latitude * pct
                longitude = old.longitude * (1.0-pct) + new.longitude * pct
                accuracy = (old.accuracy * (1.0-pct) + new.accuracy * pct).toFloat()
                altitude = old.altitude * (1.0-pct) + new.altitude * pct
                time = (old.time.toDouble() * (1.0-pct) + new.time.toDouble() * pct).toLong()
                elapsedRealtimeNanos = (old.elapsedRealtimeNanos.toDouble() * (1.0-pct) + new.elapsedRealtimeNanos.toDouble() * pct).toLong()
            }
        }
        val location = synchronized(locationLock) {
            if (lastCellLocation == null && lastWifiLocation == null) return
            when {
                // Only non-null
                lastCellLocation == null -> lastWifiLocation
                lastWifiLocation == null -> lastCellLocation
                // Consider cliff
                lastCellLocation!!.elapsedMillis > lastWifiLocation!!.elapsedMillis + LOCATION_TIME_CLIFF_MS -> lastCellLocation
                lastWifiLocation!!.elapsedMillis > lastCellLocation!!.elapsedMillis + LOCATION_TIME_CLIFF_MS -> lastWifiLocation
                // Consider cliff end
                lastCellLocation!!.elapsedMillis > lastWifiLocation!!.elapsedMillis + LOCATION_TIME_CLIFF_END_MS -> lastCellLocation
                lastWifiLocation!!.elapsedMillis > lastCellLocation!!.elapsedMillis + LOCATION_TIME_CLIFF_START_MS -> lastWifiLocation
                // Wifi out of cell range with higher precision
                lastCellLocation!!.precision > lastWifiLocation!!.precision && lastWifiLocation!!.distanceTo(lastCellLocation!!) > 2 * lastCellLocation!!.accuracy -> lastCellLocation
                // Consider cliff start
                lastCellLocation!!.elapsedMillis > lastWifiLocation!!.elapsedMillis + LOCATION_TIME_CLIFF_START_MS -> cliffLocations(lastWifiLocation, lastCellLocation)
                else -> lastWifiLocation
            }
        } ?: return
        if (location == lastLocation) return
        if (lastLocation == lastWifiLocation && location == lastCellLocation && !now) {
        if (lastLocation == lastWifiLocation && lastLocation.let { it != null && location.accuracy > it.accuracy } && !now) {
            Log.d(TAG, "Debounce inaccurate location update")
            handler.postDelayed({
                sendLocationUpdate(true)
            }, DEBOUNCE_DELAY_MS)
@@ -456,7 +478,8 @@ class NetworkLocationService : LifecycleService(), WifiDetailsCallback, CellDeta
        const val GPS_BUFFER_SIZE = 60
        const val GPS_PASSIVE_INTERVAL = 1000L
        const val GPS_PASSIVE_MIN_ACCURACY = 25f
        const val LOCATION_TIME_CLIFF_MS = 30000L
        const val LOCATION_TIME_CLIFF_START_MS = 30000L
        const val LOCATION_TIME_CLIFF_END_MS = 60000L
        const val DEBOUNCE_DELAY_MS = 5000L
        const val MAX_WIFI_SCAN_CACHE_AGE = 1000L * 60 * 60 * 24 // 1 day
        const val MAX_LOCAL_WIFI_AGE_NS = 60_000_000_000L // 1 minute
+4 −4
Original line number Diff line number Diff line
@@ -6,8 +6,8 @@
package org.microg.gms.location.network.ichnaea

data class GeolocateResponse(
    val location: ResponseLocation?,
    val accuracy: Double?,
    val fallback: String?,
    val error: ResponseError?
    val location: ResponseLocation? = null,
    val accuracy: Double? = null,
    val fallback: String? = null,
    val error: ResponseError? = null
)
 No newline at end of file
+24 −1
Original line number Diff line number Diff line
@@ -11,8 +11,10 @@ import android.net.Uri
import android.os.Bundle
import android.util.Log
import com.android.volley.Request.Method
import com.android.volley.VolleyError
import com.android.volley.toolbox.JsonObjectRequest
import com.android.volley.toolbox.Volley
import org.json.JSONObject
import org.microg.gms.location.LocationSettings
import org.microg.gms.location.network.cell.CellDetails
import org.microg.gms.location.network.precision
@@ -20,6 +22,7 @@ import org.microg.gms.location.network.wifi.WifiDetails
import org.microg.gms.location.network.wifi.isMoving
import org.microg.gms.location.provider.BuildConfig
import org.microg.gms.utils.singleInstanceOf
import kotlin.coroutines.Continuation
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
import kotlin.coroutines.suspendCoroutine
@@ -75,12 +78,32 @@ class IchnaeaServiceClient(private val context: Context) {
        }
    }

    private fun continueError(continuation: Continuation<GeolocateResponse>, error: VolleyError) {
        try {
            val response = JSONObject(error.networkResponse.data.decodeToString()).toGeolocateResponse()
            if (response.error != null) {
                continuation.resume(response)
                return
            } else if (response.location?.lat != null){
                Log.w(TAG, "Received location in response with error code")
            } else {
                Log.w(TAG, "Received valid json without error in response with error code")
            }
        } catch (_: Exception) {
        }
        if (error.networkResponse != null) {
            continuation.resume(GeolocateResponse(error = ResponseError(error.networkResponse.statusCode, error.message)))
            return
        }
        continuation.resumeWithException(error)
    }

    private suspend fun rawGeoLocate(request: GeolocateRequest): GeolocateResponse = suspendCoroutine { continuation ->
        val url = Uri.parse(settings.ichneaeEndpoint).buildUpon().appendPath("v1").appendPath("geolocate").build().toString()
        queue.add(object : JsonObjectRequest(Method.POST, url, request.toJson(), {
            continuation.resume(it.toGeolocateResponse())
        }, {
            continuation.resumeWithException(it)
            continueError(continuation, it)
        }) {
            override fun getHeaders(): Map<String, String> = getRequestHeaders()
        })
+2 −2
Original line number Diff line number Diff line
@@ -6,6 +6,6 @@
package org.microg.gms.location.network.ichnaea

data class ResponseError(
    val code: Int,
    val message: String
    val code: Int? = null,
    val message: String? = null
)
 No newline at end of file
+3 −6
Original line number Diff line number Diff line
@@ -299,13 +299,9 @@ class MovingWifiHelper(private val context: Context) {
            "CDWiFi", "MAVSTART-WIFI" -> parsePassengera(location, data)
            "AegeanWiFi" -> parseDisplayUgo(location, data)
            "Cathay Pacific", "Telekom_FlyNet", "KrisWorld", "SWISS Connect", "Edelweiss Entertainment" -> parsePanasonic(location, data)
            "FlyNet" -> parseBoardConnect(location, data)
            "FlyNet", "Austrian FlyNet" -> parseBoardConnect(location, data)
            "ACWiFi" -> parseAirCanada(location, data)
            "OUIFI" -> parseSncf(location, data)
            "_SNCF_WIFI_INOUI" -> parseSncf(location, data)
            "_SNCF_WIFI_INTERCITES" -> parseSncf(location, data)
            "_WIFI_LYRIA" -> parseSncf(location, data)
            "NormandieTrainConnecte" -> parseSncf(location, data)
            "OUIFI", "_SNCF_WIFI_INOUI", "_SNCF_WIFI_INTERCITES", "_WIFI_LYRIA", "NormandieTrainConnecte" -> parseSncf(location, data)
            "agilis-Wifi" -> parseHotsplots(location, data)
            else -> throw UnsupportedOperationException()
        }
@@ -337,6 +333,7 @@ class MovingWifiHelper(private val context: Context) {
            "_WIFI_LYRIA" to "https://wifi.tgv-lyria.com/router/api/train/gps",
            "NormandieTrainConnecte" to "https://wifi.normandie.fr/router/api/train/gps",
            "agilis-Wifi" to "http://hsp.hotsplots.net/status.json",
            "Austrian FlyNet" to "https://www.austrian-flynet.com/map/api/flightData",
        )
    }
}
Loading