This commit is contained in:
Dimitris
2026-05-29 17:31:48 +02:00
parent 02107256c7
commit 21d9688b99
12 changed files with 70 additions and 77 deletions
+3 -3
View File
@@ -17,8 +17,8 @@ android {
applicationId = "com.kouros.navigation" applicationId = "com.kouros.navigation"
minSdk = 33 minSdk = 33
targetSdk = 37 targetSdk = 37
versionCode = 112 versionCode = 118
versionName = "0.3.0.112" versionName = "0.3.1.118"
base.archivesName = "navi-$versionName" base.archivesName = "navi-$versionName"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
} }
@@ -42,7 +42,7 @@ android {
release { release {
signingConfig = signingConfigs.getByName("release") signingConfig = signingConfigs.getByName("release")
isMinifyEnabled = false isMinifyEnabled = false
isShrinkResources = false //isShrinkResources = false
proguardFiles( proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"), getDefaultProguardFile("proguard-android-optimize.txt"),
@@ -446,6 +446,17 @@ class RouteModelTest {
assertEquals(nextStepData.instruction, "Schmalkaldener Straße") assertEquals(nextStepData.instruction, "Schmalkaldener Straße")
} }
@Test
fun checkArrival() {
location.latitude = 48.116829
location.longitude = 11.594309
routeModel.updateLocation(location, NavigationViewModel(TomTomRepository()))
val stepData = routeModel.currentStep()
assertEquals(stepData.currentManeuverType, ManeuverType.TYPE_DESTINATION_LEFT.value)
assertEquals(stepData.instruction, "Hohenwaldeckstraße")
assertEquals(stepData.leftDistance, 0.0, 5.0)
}
@Test @Test
fun checkSchmalkadener20() { fun checkSchmalkadener20() {
@@ -80,10 +80,10 @@ class DeviceLocationManager(
*/ */
@SuppressLint("MissingPermission") @SuppressLint("MissingPermission")
fun locationFlow(): Flow<Location> = callbackFlow { fun locationFlow(): Flow<Location> = callbackFlow {
val listener = LocationListener { location -> val listener = LocationListener { location ->
if (shouldUseDeviceLocation && isListening) { if (shouldUseDeviceLocation && isListening) {
trySend(location) // Emit the location update to the flow trySend(location) // Emit the location update to the flow
} }
} }
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000L, 5f, listener) locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000L, 5f, listener)
awaitClose { awaitClose {
@@ -101,22 +101,17 @@ class DeviceLocationManager(
@SuppressLint("MissingPermission") @SuppressLint("MissingPermission")
fun startLocationUpdates(minTimeMs: Long = 1000, minDistanceM: Float = 5f) { fun startLocationUpdates(minTimeMs: Long = 1000, minDistanceM: Float = 5f) {
if (isListening) return if (isListening) return
val setIndividualLocation = BuildConfig.DEBUG if (BuildConfig.DEBUG) {
onInitialLocation(homeVogelhart)
// Get and deliver last known location first onLocationUpdate(homeVogelhart)
val lastLocation = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER) } else {
if (lastLocation != null) { // Get and deliver last known location first
if (setIndividualLocation) { val lastLocation = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER)
onInitialLocation(homeVogelhart) if (lastLocation != null) {
onLocationUpdate(homeVogelhart)
} else {
onInitialLocation(lastLocation) onInitialLocation(lastLocation)
onLocationUpdate(lastLocation) onLocationUpdate(lastLocation)
} }
} // Start continuous location updates
// Start continuous location updates
if (!setIndividualLocation) {
locationManager.requestLocationUpdates( locationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER, LocationManager.GPS_PROVIDER,
minTimeMs, minTimeMs,
@@ -479,7 +479,7 @@ class NavigationSession : CarSession(), NavigationListener, NavigationObserverCa
checkArrival() checkArrival()
} }
val end = System.currentTimeMillis() val end = System.currentTimeMillis()
// Log.d(TAG, "UpdateLoction ${end-start} ms") Log.d(TAG, "UpdateLocation ${end-start} ms")
} }
/** /**
@@ -493,6 +493,7 @@ class NavigationSession : CarSession(), NavigationListener, NavigationObserverCa
val distance = location.distanceTo(snappedLocation) val distance = location.distanceTo(snappedLocation)
when { when {
distance > MAXIMAL_ROUTE_DEVIATION -> { distance > MAXIMAL_ROUTE_DEVIATION -> {
Log.d(TAG, "Recalculate $distance ")
stopNavigation() stopNavigation()
navigationScreen.calculateNewRoute(routeModel.navState.destination) navigationScreen.calculateNewRoute(routeModel.navState.destination)
return false return false
@@ -548,6 +549,7 @@ class NavigationSession : CarSession(), NavigationListener, NavigationObserverCa
* Checks for arrival * Checks for arrival
*/ */
fun checkArrival() { fun checkArrival() {
Log.d(TAG, "maneuverType ${routeModel.navState.maneuverType} Distance ${routeModel.routeCalculator.leftStepDistance()}")
if (routeModel.isManeuverArrival() if (routeModel.isManeuverArrival()
&& routeModel.routeCalculator.leftStepDistance() < DESTINATION_ARRIVAL_DISTANCE && routeModel.routeCalculator.leftStepDistance() < DESTINATION_ARRIVAL_DISTANCE
) { ) {
@@ -30,6 +30,7 @@ import com.kouros.data.R
import com.kouros.navigation.data.Constants import com.kouros.navigation.data.Constants
import com.kouros.navigation.data.HeavyColor import com.kouros.navigation.data.HeavyColor
import com.kouros.navigation.data.LaneColor import com.kouros.navigation.data.LaneColor
import com.kouros.navigation.data.NavigationCircle
import com.kouros.navigation.data.NavigationColorDark import com.kouros.navigation.data.NavigationColorDark
import com.kouros.navigation.data.NavigationColorLight import com.kouros.navigation.data.NavigationColorLight
import com.kouros.navigation.data.PharmacyColor import com.kouros.navigation.data.PharmacyColor
@@ -161,7 +162,7 @@ fun RouteLayer(routeData: String?) {
fun TrafficLayer(trafficData: Map<String, String>) { fun TrafficLayer(trafficData: Map<String, String>) {
trafficData.forEach { trafficData.forEach {
if (it.key == "closed") { if (it.key == "closed") {
ClosedLayer(it) //ClosedLayer(it)
} else { } else {
val traffic = rememberGeoJsonSource(GeoJsonData.JsonString(it.value)) val traffic = rememberGeoJsonSource(GeoJsonData.JsonString(it.value))
LineLayer( LineLayer(
@@ -464,7 +465,7 @@ fun NavigationImage(
.size(imageSize.dp, imageSize.dp) .size(imageSize.dp, imageSize.dp)
) { ) {
scale(scaleX = 1f, scaleY = scaleY) { scale(scaleX = 1f, scaleY = scaleY) {
drawCircle(navigationColor.copy(alpha = 0.2f)) drawCircle(NavigationCircle.copy(alpha = 0.4f))
} }
} }
Icon( Icon(
@@ -63,7 +63,7 @@ class Simulation {
// Update your app's state as if a real GPS update occurred // Update your app's state as if a real GPS update occurred
updateLocation(fakeLocation) updateLocation(fakeLocation)
// Wait before moving to the next point (e.g., every 1 second) // Wait before moving to the next point (e.g., every 1 second)
delay(1500) delay(1000)
lastLocation = fakeLocation lastLocation = fakeLocation
} }
} }
@@ -5,6 +5,8 @@ import androidx.compose.ui.graphics.Color
val NavigationColorLight = Color(0xFF17A119) val NavigationColorLight = Color(0xFF17A119)
val NavigationColorDark = Color(0xFF2B007A) val NavigationColorDark = Color(0xFF2B007A)
val NavigationCircle = Color(0xFFFFEB3B)
val RouteColor = Color(0xFF5201B4) val RouteColor = Color(0xFF5201B4)
val SpeedColor = Color(0xFF262525) val SpeedColor = Color(0xFF262525)
@@ -132,7 +132,7 @@ object Constants {
val homeHohenwaldeck = location( 11.594322, 48.1164817) val homeHohenwaldeck = location( 11.594322, 48.1164817)
val ioannina = location( 20.826237, 39.690174) val ioannina = location( 20.826237, 39.690174)
val subislawa = location(18.570808, 54.420647) val subislawa = location(18.570808, 54.420647)
val a94 = location(11.872097,48.163449) val a94 = location(11.947101,48.213251)
val a9 = location(11.621556, 48.204402,) val a9 = location(11.621556, 48.204402,)
val a22 = location(10.845749, 45.602507) val a22 = location(10.845749, 45.602507)
@@ -141,7 +141,7 @@ object Constants {
const val MAXIMAL_SNAP_CORRECTION = 50.0 const val MAXIMAL_SNAP_CORRECTION = 50.0
const val MAXIMAL_ROUTE_DEVIATION = 100.0 const val MAXIMAL_ROUTE_DEVIATION = 150.0
const val DESTINATION_ARRIVAL_DISTANCE = 10.0 const val DESTINATION_ARRIVAL_DISTANCE = 10.0
@@ -22,62 +22,42 @@ class RouteCalculator(var routeModel: RouteModel) {
var lastSpeedIndex: Int = 0 var lastSpeedIndex: Int = 0
fun findStep(location: Location) { fun findStep(location: Location) {
val route = routeModel.navState.route
val steps = routeModel.curLeg.steps
// Search from one step prior to handle deviations/U-turns
val startIndex = (route.currentStepIndex - 1).coerceAtLeast(0)
val endIndex = steps.size - 1
var nearestDistance = MAXIMUM_LOCATION_DISTANCE var nearestDistance = MAXIMUM_LOCATION_DISTANCE
var searchCount = 0 var count = 0
var lastDistance = 0F
for (i in startIndex..endIndex) { var increaseDistance = 0
val step = steps[i] for ((index, step) in routeModel.curLeg.steps.withIndex()) {
val waypoints = step.maneuver.waypoints count++
// Only offset search if we are exactly on the current stored step index var distance = 0F
val startWayIndex = if (i == route.currentStepIndex) step.waypointIndex else 0 if (index >= routeModel.navState.route.currentStepIndex) {
for ((wayIndex, waypoint) in step.maneuver.waypoints.withIndex()) {
var lastDistance = Float.MAX_VALUE count++
var increaseCount = 0 if (wayIndex >= step.waypointIndex) {
distance = location.distanceTo(waypoint)
for (j in startWayIndex until waypoints.size) { if (distance < nearestDistance ) {
searchCount++ nearestDistance = distance
val waypoint = waypoints[j] routeModel.navState.route.currentStepIndex = step.index
val distance = location.distanceTo(waypoint) step.waypointIndex = wayIndex
step.wayPointLocation = waypoint
if (distance < nearestDistance) { }
nearestDistance = distance
bestMatch = StepMatch(step.index, j, waypoint)
}
if (distance > lastDistance) {
increaseCount++
} else {
increaseCount = 0
}
if (stopSearch(nearestDistance, distance, increaseCount)) {
bestMatch?.let { match ->
route.currentStepIndex = match.stepIndex
steps[match.stepIndex].waypointIndex = match.waypointIndex
steps[match.stepIndex].wayPointLocation = match.location
} }
return if (stopSearch(nearestDistance, distance)) {
break
}
if (distance > lastDistance) {
increaseDistance++
}
lastDistance = distance
} }
lastDistance = distance
} }
} if (stopSearch(nearestDistance, distance)) {
bestMatch?.let { match -> break
route.currentStepIndex = match.stepIndex }
steps[match.stepIndex].waypointIndex = match.waypointIndex
steps[match.stepIndex].wayPointLocation = match.location
} }
} }
private fun stopSearch(nearestDistance: Float, distance: Float, increaseCount: Int): Boolean { private fun stopSearch(nearestDistance: Float, distance: Float): Boolean {
// Increased multiplier from 10 to 20 to be less aggressive in sharp curves return nearestDistance < NEAREST_LOCATION_DISTANCE && distance > NEAREST_LOCATION_DISTANCE * 10
return (nearestDistance < NEAREST_LOCATION_DISTANCE && distance > NEAREST_LOCATION_DISTANCE * 20)
|| increaseCount > 15
} }
fun travelLeftTime(): Double { fun travelLeftTime(): Double {
@@ -1,10 +1,12 @@
package com.kouros.navigation.model package com.kouros.navigation.model
import android.location.Location import android.location.Location
import android.util.Log
import androidx.car.app.connection.CarConnection.CONNECTION_TYPE_NATIVE import androidx.car.app.connection.CarConnection.CONNECTION_TYPE_NATIVE
import androidx.car.app.connection.CarConnection.CONNECTION_TYPE_PROJECTION import androidx.car.app.connection.CarConnection.CONNECTION_TYPE_PROJECTION
import androidx.car.app.navigation.model.Maneuver import androidx.car.app.navigation.model.Maneuver
import com.kouros.navigation.data.Constants.NEXT_STEP_THRESHOLD import com.kouros.navigation.data.Constants.NEXT_STEP_THRESHOLD
import com.kouros.navigation.data.Constants.TAG
import com.kouros.navigation.data.NavigationState import com.kouros.navigation.data.NavigationState
import com.kouros.navigation.data.Route import com.kouros.navigation.data.Route
import com.kouros.navigation.data.StepData import com.kouros.navigation.data.StepData
@@ -254,7 +254,7 @@ object GeoUtils {
fun movePoint( fun movePoint(
latitude: Double, latitude: Double,
longitude: Double, longitude: Double,
distanceMeters: Double = 8.0, distanceMeters: Double = 5.0,
bearingDegrees: Double = 0.0 bearingDegrees: Double = 0.0
): org.maplibre.spatialk.geojson.Point { ): org.maplibre.spatialk.geojson.Point {
val radius = EARTH_RADIUS * 1000 // meters val radius = EARTH_RADIUS * 1000 // meters
@@ -49,7 +49,7 @@ object NavigationUtils {
} }
fun calculateZoom(speed: Double?): Double { fun calculateZoom(speed: Double?): Double {
val zoom = 16.5 val zoom = 17.0
if (speed == null) { if (speed == null) {
return zoom return zoom
} }