From 517bb074efcfb1375a160a4a1d02dd6c81781f91 Mon Sep 17 00:00:00 2001 From: Thomas Date: Tue, 26 May 2026 20:55:48 +0200 Subject: [PATCH 1/4] report cell-based location accuracy as 1-sigma The Wi-Fi path divides the 6-sigma estimate by 6 to report the 1-sigma accuracy Location expects, but the cell path reported the raw 6-sigma value, making cell-based fixes report a radius 6 times too large. --- .../grapheneos/networklocation/LocationReportingTask.kt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/app/grapheneos/networklocation/LocationReportingTask.kt b/src/app/grapheneos/networklocation/LocationReportingTask.kt index 72d1c37..8999d4e 100644 --- a/src/app/grapheneos/networklocation/LocationReportingTask.kt +++ b/src/app/grapheneos/networklocation/LocationReportingTask.kt @@ -540,10 +540,14 @@ class LocationReportingTask( val estimatedGeoPoint = enuPointToGeoPoint(enuPoint, refGeoPoint) loc.longitude = estimatedGeoPoint.longitude loc.latitude = estimatedGeoPoint.latitude - loc.accuracy = sqrt(max(result.x.sixSigmaSquared, result.y.sixSigmaSquared)).toFloat() + val accuracySixSigma = sqrt(max(result.x.sixSigmaSquared, result.y.sixSigmaSquared)) + // Convert from 6-sigma to 1-sigma + loc.accuracy = accuracySixSigma.div(6.0).toFloat() estimatedGeoPoint.altitude?.let { estimatedAltitude -> loc.altitude = estimatedAltitude - loc.verticalAccuracyMeters = sqrt(result.z.sixSigmaSquared).toFloat() + val verticalAccuracySixSigma = sqrt(result.z.sixSigmaSquared) + // Convert from 6-sigma to 1-sigma + loc.verticalAccuracyMeters = verticalAccuracySixSigma.div(6.0).toFloat() } return loc } From f324cd0b4f6c3694f5f7dd133dc08f800ae3c23c Mon Sep 17 00:00:00 2001 From: Thomas Date: Tue, 26 May 2026 20:55:48 +0200 Subject: [PATCH 2/4] skip geocoder features with fewer than two coordinates An empty or single-element coordinates array would throw IndexOutOfBoundsException, which isn't an IOException and so escapes the handler in GeocodeProviderImpl, leaving the request's callback uncompleted. --- src/app/grapheneos/geocoder/NominatimGeocoder.kt | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/app/grapheneos/geocoder/NominatimGeocoder.kt b/src/app/grapheneos/geocoder/NominatimGeocoder.kt index 54aac58..a98e211 100644 --- a/src/app/grapheneos/geocoder/NominatimGeocoder.kt +++ b/src/app/grapheneos/geocoder/NominatimGeocoder.kt @@ -139,12 +139,17 @@ class NominatimGeocoder : Geocoder { } val result = mutableListOf
() for (feature in response.features?.take(expectedMaxResults) ?: emptyList()) { + val coordinates = feature.geometry.coordinates + if (coordinates.size < 2) { + Log.w(TAG, "skipping feature with invalid coordinates size: ${coordinates.size}") + continue + } val extra = feature.properties.geocoding.extra?.toMutableMap() // we don't know which locale was actually used, so we just assume it was the one // we requested val address = Address(preferredLocale) - address.latitude = feature.geometry.coordinates[1] - address.longitude = feature.geometry.coordinates[0] + address.latitude = coordinates[1] + address.longitude = coordinates[0] with(feature.properties.geocoding) { address.postalCode = this.postcode address.featureName = this.name From 8a781e5356cab2d4795f201fb2a92ef262808ab5 Mon Sep 17 00:00:00 2001 From: Thomas Date: Tue, 26 May 2026 20:55:48 +0200 Subject: [PATCH 3/4] reuse a single executor in WifiApRanger Each range() call created a new single-thread executor that was only reclaimed by finalization. --- src/app/grapheneos/networklocation/wifi/WifiApRanger.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/app/grapheneos/networklocation/wifi/WifiApRanger.kt b/src/app/grapheneos/networklocation/wifi/WifiApRanger.kt index 9f7e663..31f3054 100644 --- a/src/app/grapheneos/networklocation/wifi/WifiApRanger.kt +++ b/src/app/grapheneos/networklocation/wifi/WifiApRanger.kt @@ -8,6 +8,7 @@ import android.net.wifi.rtt.RangingResultCallback import android.net.wifi.rtt.WifiRttManager import android.os.WorkSource import app.grapheneos.verboseLog +import java.util.concurrent.ExecutorService import java.util.concurrent.Executors import kotlin.coroutines.resume import kotlin.coroutines.resumeWithException @@ -19,6 +20,7 @@ private const val TAG = "WifiApRanger" * TODO: WIP Wi-Fi RTT AP ranger, not currently used. */ class WifiApRanger(private val context: Context) { + private val rangingExecutor: ExecutorService = Executors.newSingleThreadExecutor() @Throws(WifiRangerUnavailableException::class, WifiRangerFailedException::class) suspend fun range(scanResults: List, workSource: WorkSource): List { @@ -51,11 +53,10 @@ class WifiApRanger(private val context: Context) { } } verboseLog(TAG) { "calling startRanging" } - val executor = Executors.newSingleThreadExecutor() wifiRttManager.startRanging( workSource, request, - executor, + rangingExecutor, rangingResultCallback ) continuation.invokeOnCancellation { From 5070be23fc0a12114e235cddf295abd5744d65d9 Mon Sep 17 00:00:00 2001 From: Thomas Date: Tue, 26 May 2026 20:55:48 +0200 Subject: [PATCH 4/4] fix forward geocode parameter logging --- src/app/grapheneos/geocoder/GeocodeProviderImpl.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/grapheneos/geocoder/GeocodeProviderImpl.kt b/src/app/grapheneos/geocoder/GeocodeProviderImpl.kt index 6197aee..f30b5e1 100644 --- a/src/app/grapheneos/geocoder/GeocodeProviderImpl.kt +++ b/src/app/grapheneos/geocoder/GeocodeProviderImpl.kt @@ -23,8 +23,8 @@ class GeocodeProviderImpl(private val context: Context) : GeocodeProviderBase(co ) { verboseLog(TAG) { "forward geocode parameters: locationName: ${request.locationName}, " + - "lowerLeftLatitude: ${request.lowerLeftLongitude}, lowerLeftLongitude: ${request.lowerLeftLongitude}, " + - "upperRightLatitude: ${request.upperRightLatitude}, upperrightlongitude: ${request.upperRightLongitude}, " + + "lowerLeftLatitude: ${request.lowerLeftLatitude}, lowerLeftLongitude: ${request.lowerLeftLongitude}, " + + "upperRightLatitude: ${request.upperRightLatitude}, upperRightLongitude: ${request.upperRightLongitude}, " + "maxResults: ${request.maxResults}, locale: ${request.locale}" } try {