GPS: lyssna på alla platsproviders (gps/fused/network) + kartmarkör
All checks were successful
release / build-release (push) Successful in 4m13s
All checks were successful
release / build-release (push) Successful in 4m13s
Fälttest visade noll callbacks från råa GPS_PROVIDER på wheatek WP19 — telefonen levererar via fused/network. Nu: - Lyssning på gps + fused + network (FUSED_PROVIDER finns fr.o.m. API 31); loggen visar vilka providers som finns/är på och varje fix per provider - Kartan centreras direkt på senast kända position (lastKnownLocation) och visar en positionsmarkör — ingen blå 0°,0°-ocean längre - Spårpunkter filtreras på noggrannhet (≤35 m) istället för provider; positionen på kartan uppdateras oavsett kvalitet Version 0.8.1 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01C2GA94E1f3cmrvdQLQhYdg
This commit is contained in:
@@ -29,7 +29,7 @@ android {
|
||||
minSdk = 31
|
||||
targetSdk = 35
|
||||
versionCode = ciRunNumber ?: 1
|
||||
versionName = "0.8.0" + (ciRunNumber?.let { "+build.$it" } ?: "-dev")
|
||||
versionName = "0.8.1" + (ciRunNumber?.let { "+build.$it" } ?: "-dev")
|
||||
}
|
||||
|
||||
signingConfigs {
|
||||
|
||||
@@ -48,6 +48,8 @@ data class TrackingState(
|
||||
val elevationGainMeters: Double = 0.0,
|
||||
/** Senaste GPS-position (lat, lon) + hela spåret */
|
||||
val points: List<Pair<Double, Double>> = emptyList(),
|
||||
/** Senast kända position oavsett kvalitet — för kartcentrering/markör */
|
||||
val currentPosition: Pair<Double, Double>? = null,
|
||||
val currentSpeedKmh: Double? = null,
|
||||
val kcal: Double? = null,
|
||||
val gpsFix: Boolean = false,
|
||||
@@ -164,15 +166,34 @@ class TrackingService : Service(), LocationListener {
|
||||
TrackLog.log("FEL: platsbehörighet saknas — ingen GPS-lyssning")
|
||||
return
|
||||
}
|
||||
locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager
|
||||
TrackLog.log("GPS-lyssning begärd (GPS_PROVIDER, 2 s / 3 m)")
|
||||
runCatching {
|
||||
locationManager?.requestLocationUpdates(
|
||||
LocationManager.GPS_PROVIDER,
|
||||
2000L, // ms
|
||||
3f, // meter
|
||||
this,
|
||||
Looper.getMainLooper(),
|
||||
val lm = getSystemService(Context.LOCATION_SERVICE) as LocationManager
|
||||
locationManager = lm
|
||||
|
||||
// Billiga telefoner levererar ofta bara via fused/network — lyssna på
|
||||
// allt som finns och filtrera på noggrannhet istället för provider.
|
||||
val providers = listOf(
|
||||
LocationManager.GPS_PROVIDER,
|
||||
LocationManager.FUSED_PROVIDER,
|
||||
LocationManager.NETWORK_PROVIDER,
|
||||
)
|
||||
for (provider in providers) {
|
||||
val exists = runCatching { lm.allProviders.contains(provider) }.getOrDefault(false)
|
||||
val enabled = exists && runCatching { lm.isProviderEnabled(provider) }.getOrDefault(false)
|
||||
TrackLog.log("provider $provider: ${if (!exists) "saknas" else if (enabled) "på" else "AVSTÄNGD"}")
|
||||
if (!enabled) continue
|
||||
runCatching {
|
||||
lm.requestLocationUpdates(provider, 2000L, 0f, this, Looper.getMainLooper())
|
||||
TrackLog.log("lyssnar på $provider (2 s)")
|
||||
}.onFailure { TrackLog.log("FEL: kunde inte lyssna på $provider: ${it.message}") }
|
||||
}
|
||||
|
||||
// Senast kända position → omedelbar kartcentrering (läggs inte i spåret)
|
||||
providers.firstNotNullOfOrNull { p ->
|
||||
runCatching { lm.getLastKnownLocation(p) }.getOrNull()
|
||||
}?.let { last ->
|
||||
TrackLog.log("lastKnown: ${last.provider} acc=${if (last.hasAccuracy()) "%.0f".format(last.accuracy) else "?"} m")
|
||||
_state.value = _state.value.copy(
|
||||
currentPosition = last.latitude to last.longitude,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -192,16 +213,21 @@ class TrackingService : Service(), LocationListener {
|
||||
val s = _state.value
|
||||
if (!s.isActive || !s.isDistanceBased) return
|
||||
val acc = if (location.hasAccuracy()) location.accuracy else -1f
|
||||
// Släng riktigt dåliga fixar
|
||||
if (location.hasAccuracy() && location.accuracy > 30f) {
|
||||
TrackLog.log("fix förkastad: noggrannhet ${"%.0f".format(acc)} m (>30)")
|
||||
|
||||
// Position för kartan uppdateras alltid, oavsett kvalitet
|
||||
_state.value = _state.value.copy(currentPosition = location.latitude to location.longitude)
|
||||
|
||||
// Spårpunkter kräver hygglig noggrannhet
|
||||
if (location.hasAccuracy() && location.accuracy > 35f) {
|
||||
TrackLog.log("${location.provider}: förkastad för spåret, acc=${"%.0f".format(acc)} m (>35)")
|
||||
return
|
||||
}
|
||||
TrackLog.log(
|
||||
"fix: acc=${"%.0f".format(acc)} m alt=${if (location.hasAltitude()) "%.0f".format(location.altitude) else "?"}" +
|
||||
"${location.provider}: fix acc=${"%.0f".format(acc)} m" +
|
||||
" alt=${if (location.hasAltitude()) "%.0f".format(location.altitude) else "?"}" +
|
||||
" fart=${if (location.hasSpeed()) "%.1f".format(location.speed * 3.6) else "?"} km/h"
|
||||
)
|
||||
if (s.phase == TrackingPhase.SEARCHING_GPS) activate("GPS-fix")
|
||||
if (s.phase == TrackingPhase.SEARCHING_GPS) activate("fix från ${location.provider}")
|
||||
|
||||
var distance = s.distanceMeters
|
||||
var elevGain = s.elevationGainMeters
|
||||
|
||||
@@ -339,6 +339,7 @@ private fun LiveContent(
|
||||
if (tracking.isDistanceBased) {
|
||||
TrackMap(
|
||||
points = tracking.points,
|
||||
currentPosition = tracking.currentPosition,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.weight(1f),
|
||||
@@ -484,7 +485,11 @@ private fun StatBox(label: String, value: String, modifier: Modifier = Modifier)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TrackMap(points: List<Pair<Double, Double>>, modifier: Modifier = Modifier) {
|
||||
private fun TrackMap(
|
||||
points: List<Pair<Double, Double>>,
|
||||
currentPosition: Pair<Double, Double>?,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
val lineColor = MaterialTheme.colorScheme.primary.toArgb()
|
||||
|
||||
@@ -506,6 +511,14 @@ private fun TrackMap(points: List<Pair<Double, Double>>, modifier: Modifier = Mo
|
||||
outlinePaint.strokeWidth = 10f
|
||||
}.also { mapView.overlays.add(it) }
|
||||
}
|
||||
val positionMarker = remember {
|
||||
org.osmdroid.views.overlay.Marker(mapView).apply {
|
||||
setAnchor(org.osmdroid.views.overlay.Marker.ANCHOR_CENTER, org.osmdroid.views.overlay.Marker.ANCHOR_CENTER)
|
||||
setInfoWindow(null)
|
||||
}.also { mapView.overlays.add(it) }
|
||||
}
|
||||
// Centrera bara automatiskt tills användaren själv panorerat
|
||||
var hasCentered by remember { mutableStateOf(false) }
|
||||
|
||||
DisposableEffect(Unit) {
|
||||
mapView.onResume()
|
||||
@@ -518,13 +531,25 @@ private fun TrackMap(points: List<Pair<Double, Double>>, modifier: Modifier = Mo
|
||||
AndroidView(
|
||||
factory = { mapView },
|
||||
modifier = modifier,
|
||||
update = {
|
||||
update = { map ->
|
||||
val pos = points.lastOrNull() ?: currentPosition
|
||||
if (pos != null) {
|
||||
positionMarker.position = GeoPoint(pos.first, pos.second)
|
||||
positionMarker.isEnabled = true
|
||||
if (!hasCentered) {
|
||||
map.controller.setZoom(17.0)
|
||||
map.controller.setCenter(GeoPoint(pos.first, pos.second))
|
||||
hasCentered = true
|
||||
} else {
|
||||
map.controller.animateTo(GeoPoint(pos.first, pos.second))
|
||||
}
|
||||
} else {
|
||||
positionMarker.isEnabled = false
|
||||
}
|
||||
if (points.isNotEmpty()) {
|
||||
polyline.setPoints(points.map { (lat, lon) -> GeoPoint(lat, lon) })
|
||||
val last = points.last()
|
||||
it.controller.animateTo(GeoPoint(last.first, last.second))
|
||||
it.invalidate()
|
||||
}
|
||||
map.invalidate()
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user