DEVIATION depends on speed

This commit is contained in:
Dimitris
2026-06-05 15:01:05 +02:00
parent df1ceb5c44
commit a3b22c386b
13 changed files with 63 additions and 50 deletions
+2 -2
View File
@@ -17,8 +17,8 @@ android {
applicationId = "com.kouros.navigation" applicationId = "com.kouros.navigation"
minSdk = 33 minSdk = 33
targetSdk = 37 targetSdk = 37
versionCode = 121 versionCode = 125
versionName = "0.3.1.121" versionName = "0.3.2.125"
base.archivesName = "navi-$versionName" base.archivesName = "navi-$versionName"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
} }
+1 -1
View File
@@ -7,7 +7,7 @@ plugins {
android { android {
namespace = "com.kouros.navigation" namespace = "com.kouros.navigation"
compileSdk { compileSdk {
version = release(36) version = release(37)
} }
defaultConfig { defaultConfig {
+1 -1
View File
@@ -6,7 +6,7 @@ plugins {
android { android {
namespace = "com.kouros.android.cars.carappservice" namespace = "com.kouros.android.cars.carappservice"
compileSdk = 36 compileSdk = 37
defaultConfig { defaultConfig {
minSdk = 33 minSdk = 33
@@ -132,12 +132,12 @@ class CarSensorManager(
val carSensors = carHardwareManager.carSensors val carSensors = carHardwareManager.carSensors
carSensors.addCompassListener( carSensors.addCompassListener(
CarSensors.UPDATE_RATE_NORMAL, CarSensors.UPDATE_RATE_FASTEST,
carContext.mainExecutor, carContext.mainExecutor,
carCompassListener carCompassListener
) )
carSensors.addCarHardwareLocationListener( carSensors.addCarHardwareLocationListener(
CarSensors.UPDATE_RATE_UI, CarSensors.UPDATE_RATE_FASTEST,
carContext.mainExecutor, carContext.mainExecutor,
carLocationListener carLocationListener
) )
@@ -12,14 +12,8 @@ import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle import androidx.lifecycle.repeatOnLifecycle
import com.kouros.data.BuildConfig import com.kouros.data.BuildConfig
import com.kouros.navigation.data.Constants.a22
import com.kouros.navigation.data.Constants.a9
import com.kouros.navigation.data.Constants.a94
import com.kouros.navigation.data.Constants.homeHohenwaldeck
import com.kouros.navigation.data.Constants.homeVogelhart import com.kouros.navigation.data.Constants.homeVogelhart
import com.kouros.navigation.data.Constants.ioannina import com.kouros.navigation.data.Constants.widenmayer
import com.kouros.navigation.data.Constants.isarring
import com.kouros.navigation.data.Constants.subislawa
import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow import kotlinx.coroutines.flow.callbackFlow
@@ -4,7 +4,9 @@ import android.Manifest.permission
import android.content.Intent import android.content.Intent
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.location.Location import android.location.Location
import android.os.Build
import android.util.Log import android.util.Log
import androidx.annotation.RequiresApi
import androidx.car.app.CarContext import androidx.car.app.CarContext
import androidx.car.app.CarToast import androidx.car.app.CarToast
import androidx.car.app.Screen import androidx.car.app.Screen
@@ -111,7 +113,6 @@ class NavigationSession : CarSession(), NavigationListener, NavigationObserverCa
var speedCameras = listOf<Elements>() var speedCameras = listOf<Elements>()
private var lastRouteCheckLocation = location(0.0, 0.0) private var lastRouteCheckLocation = location(0.0, 0.0)
var navigationManagerStarted = false var navigationManagerStarted = false
@@ -463,8 +464,8 @@ class NavigationSession : CarSession(), NavigationListener, NavigationObserverCa
*/ */
private fun handleNavigationLocation(location: Location) { private fun handleNavigationLocation(location: Location) {
val start = System.currentTimeMillis() val start = System.currentTimeMillis()
routeModel.updateLocation(location, navigationViewModel)
val snappedLocation = snapLocation(location, routeModel.route.maneuverLocations()) val snappedLocation = snapLocation(location, routeModel.route.maneuverLocations())
routeModel.updateLocation(snappedLocation, navigationViewModel)
val streetName = routeModel.currentStep().street val streetName = routeModel.currentStep().street
if (checkLocationDeviation(location, snappedLocation, streetName)) { if (checkLocationDeviation(location, snappedLocation, streetName)) {
if (routeModel.navState.arrived) return if (routeModel.navState.arrived) return
@@ -490,11 +491,21 @@ class NavigationSession : CarSession(), NavigationListener, NavigationObserverCa
snappedLocation: Location, snappedLocation: Location,
streetName: String streetName: String
): Boolean { ): Boolean {
var maximalRouteDeviation = MAXIMAL_ROUTE_DEVIATION
val speed = surfaceRenderer.speed.value
if (speed != null) {
when (speed) {
in 0.0..10.0 -> maximalRouteDeviation = MAXIMAL_ROUTE_DEVIATION
in 10.0..20.0 -> maximalRouteDeviation = MAXIMAL_ROUTE_DEVIATION + 200
in 20.0..30.0 -> maximalRouteDeviation = MAXIMAL_ROUTE_DEVIATION + 400
in 30.0..100.0 -> maximalRouteDeviation = MAXIMAL_ROUTE_DEVIATION + 500
}
}
val distance = location.distanceTo(snappedLocation) val distance = location.distanceTo(snappedLocation)
when { when {
distance > MAXIMAL_ROUTE_DEVIATION && distance < MAXIMAL_ROUTE_DEVIATION * 10-> { distance > maximalRouteDeviation -> {
stopNavigation() stopNavigation()
navigationScreen.calculateNewRoute(routeModel.navState.destination) navigationScreen.calculateNewRoute(routeModel.navState.destination, distance)
return false return false
} }
@@ -813,18 +824,25 @@ class NavigationSession : CarSession(), NavigationListener, NavigationObserverCa
if (camera.distance < 80) { if (camera.distance < 80) {
if ((bearingSpeedCamera - bearingRoute).absoluteValue < 15.0) { if ((bearingSpeedCamera - bearingRoute).absoluteValue < 15.0) {
routeModel.showSpeedCamera(carContext, camera.distance, camera.tags.maxspeed) routeModel.showSpeedCamera(carContext, camera.distance, camera.tags.maxspeed)
camera.distance = 1000.0 val cameras = mutableListOf<Elements>()
speedCameras.forEach {
if (!(camera.lon == it.lon && camera.lat == it.lat)) {
cameras.add(it)
}
}
speedCameras = cameras
} }
} }
} }
} }
/** /**
* Checks if a new route is needed based on the time since the last update. * Checks if a new route is needed based on the time since the last update.
*/ */
private fun checkRoute(location: Location) { private fun checkRoute(location: Location) {
val distance = location.distanceTo(lastRouteCheckLocation) val distance = location.distanceTo(lastRouteCheckLocation)
if (distance > checkDistance(routeModel)) { if (distance > checkDistance(routeModel)) {
if (lastRouteCheckLocation.latitude != 0.0) { if (lastRouteCheckLocation.latitude != 0.0) {
val destination = location( val destination = location(
routeModel.navState.destination.longitude, routeModel.navState.destination.longitude,
@@ -2,7 +2,6 @@ package com.kouros.navigation.car.screen
import android.os.CountDownTimer import android.os.CountDownTimer
import android.os.Handler import android.os.Handler
import android.util.Log
import androidx.car.app.CarContext import androidx.car.app.CarContext
import androidx.car.app.Screen import androidx.car.app.Screen
import androidx.car.app.model.Action import androidx.car.app.model.Action
@@ -33,7 +32,6 @@ import com.kouros.data.R
import com.kouros.navigation.car.SurfaceRenderer import com.kouros.navigation.car.SurfaceRenderer
import com.kouros.navigation.car.screen.settings.SettingsScreen import com.kouros.navigation.car.screen.settings.SettingsScreen
import com.kouros.navigation.data.Constants import com.kouros.navigation.data.Constants
import com.kouros.navigation.data.Constants.TAG
import com.kouros.navigation.data.Place import com.kouros.navigation.data.Place
import com.kouros.navigation.data.ViewStyle import com.kouros.navigation.data.ViewStyle
import com.kouros.navigation.model.NavigationViewModel import com.kouros.navigation.model.NavigationViewModel
@@ -53,6 +51,7 @@ open class NavigationScreen(
private val navigationViewModel: NavigationViewModel private val navigationViewModel: NavigationViewModel
) : Screen(carContext) { ) : Screen(carContext) {
var deviation = 0F
var recentPlaces = mutableListOf<Place>() var recentPlaces = mutableListOf<Place>()
var recentPlace: Place = Place() var recentPlace: Place = Place()
@@ -151,10 +150,11 @@ open class NavigationScreen(
.setDestinationTravelEstimate(destinationTravelEstimate) .setDestinationTravelEstimate(destinationTravelEstimate)
.setActionStrip(actionStripBuilder.build()) .setActionStrip(actionStripBuilder.build())
.setMapActionStrip( .setMapActionStrip(
mapActionStrip(carContext, mapActionStrip(
carContext,
surfaceRenderer.viewStyle, surfaceRenderer.viewStyle,
{ zoomPlus() }, { zoomMinus() }, { { zoomPlus() }, { zoomMinus() }, {
Action.Builder() Action.Builder()
.setIcon(createCarIcon(carContext, R.drawable.ic_recenter_24)) .setIcon(createCarIcon(carContext, R.drawable.ic_recenter_24))
.setFlags(0) .setFlags(0)
.setOnClickListener { .setOnClickListener {
@@ -173,17 +173,18 @@ open class NavigationScreen(
* Creates and returns a template for the default view state. * Creates and returns a template for the default view state.
*/ */
private fun navigationView(actionStripBuilder: ActionStrip.Builder): Template { private fun navigationView(actionStripBuilder: ActionStrip.Builder): Template {
val mapActionStrip = mapActionStrip(carContext, val mapActionStrip = mapActionStrip(
surfaceRenderer.viewStyle, carContext,
{ zoomPlus() }, { zoomMinus() }, { surfaceRenderer.viewStyle,
createAction( { zoomPlus() }, { zoomMinus() }, {
carContext = carContext, R.drawable.ic_recenter_24, createAction(
0, carContext = carContext, R.drawable.ic_recenter_24,
onClickAction = { 0,
surfaceRenderer.setStandardView() onClickAction = {
invalidate() surfaceRenderer.setStandardView()
}) invalidate()
}) })
})
return NavigationTemplate.Builder() return NavigationTemplate.Builder()
.setBackgroundColor(backGroundColor) .setBackgroundColor(backGroundColor)
.setActionStrip(actionStripBuilder.build()) .setActionStrip(actionStripBuilder.build())
@@ -215,14 +216,10 @@ open class NavigationScreen(
* Creates and returns a NavigationTemplate specifically for when the destination is reached. * Creates and returns a NavigationTemplate specifically for when the destination is reached.
*/ */
fun navigationArrived(actionStripBuilder: ActionStrip.Builder): NavigationTemplate { fun navigationArrived(actionStripBuilder: ActionStrip.Builder): NavigationTemplate {
var street = ""
if (destinations.first().address != null) {
street = destinations.first().address.toString()
}
return NavigationTemplate.Builder() return NavigationTemplate.Builder()
.setNavigationInfo( .setNavigationInfo(
MessageInfo.Builder( MessageInfo.Builder(
carContext.getString(R.string.arrived_exclamation_msg) carContext.getString(R.string.arrived_exclamation_msg)
) )
.setText(message) .setText(message)
.setImage( .setImage(
@@ -239,7 +236,8 @@ open class NavigationScreen(
.setBackgroundColor(backGroundColor) .setBackgroundColor(backGroundColor)
.setActionStrip(actionStripBuilder.build()) .setActionStrip(actionStripBuilder.build())
.setMapActionStrip( .setMapActionStrip(
mapActionStrip(carContext, mapActionStrip(
carContext,
surfaceRenderer.viewStyle, surfaceRenderer.viewStyle,
{ zoomPlus() }, { zoomMinus() }, { { zoomPlus() }, { zoomMinus() }, {
createAction( createAction(
@@ -300,7 +298,8 @@ open class NavigationScreen(
val builder = MapWithContentTemplate.Builder() val builder = MapWithContentTemplate.Builder()
.setContentTemplate(contentTemplate) .setContentTemplate(contentTemplate)
.setActionStrip( .setActionStrip(
mapActionStrip(carContext, mapActionStrip(
carContext,
ViewStyle.VIEW, ViewStyle.VIEW,
{ settingsAction() }, { settingsAction() },
{ {
@@ -472,13 +471,14 @@ open class NavigationScreen(
/** /**
* Initiates recalculation for a new route to the destination. * Initiates recalculation for a new route to the destination.
*/ */
fun calculateNewRoute(destination: Place) { fun calculateNewRoute(destination: Place, distance: Float) {
deviation = distance
navigationType = NavigationType.REROUTE navigationType = NavigationType.REROUTE
invalidate() invalidate()
val mainThreadHandler = Handler(carContext.mainLooper) val mainThreadHandler = Handler(carContext.mainLooper)
mainThreadHandler.post { mainThreadHandler.post {
reRouteTimer?.cancel() reRouteTimer?.cancel()
reRouteTimer = object : CountDownTimer(2000, 1000) { reRouteTimer = object : CountDownTimer(5000, 1000) {
override fun onTick(millisUntilFinished: Long) {} override fun onTick(millisUntilFinished: Long) {}
override fun onFinish() { override fun onFinish() {
navigationType = NavigationType.NAVIGATION navigationType = NavigationType.NAVIGATION
@@ -75,7 +75,7 @@ class PlaceListScreen(
override fun onGetTemplate(): Template { override fun onGetTemplate(): Template {
val itemListBuilder = ItemList.Builder() val itemListBuilder = ItemList.Builder()
.setNoItemsMessage(carContext.getString(R.string.no_places)) .setNoItemsMessage(carContext.getString(R.string.no_places))
recentPlaces.filter { it.category == category }.forEach { recentPlaces.filter { it.category == category && it.distance > 500F }.forEach {
val street = it.street.ifEmpty { val street = it.street.ifEmpty {
it.name it.name
} }
@@ -107,7 +107,7 @@ class NavigationScreenTest {
navigationScreen.navigationType = NavigationType.NAVIGATION navigationScreen.navigationType = NavigationType.NAVIGATION
// Act // Act
navigationScreen.calculateNewRoute(Place()) navigationScreen.calculateNewRoute(Place(), distance)
// Assert // Assert
assertThat(navigationScreen.navigationType).isEqualTo(NavigationType.REROUTE) assertThat(navigationScreen.navigationType).isEqualTo(NavigationType.REROUTE)
+1 -1
View File
@@ -12,7 +12,7 @@ plugins {
android { android {
namespace = "com.kouros.data" namespace = "com.kouros.data"
compileSdk = 36 compileSdk = 37
val properties = Properties().apply { val properties = Properties().apply {
@@ -129,6 +129,8 @@ object Constants {
const val RESTAURANT: String ="restaurant" const val RESTAURANT: String ="restaurant"
/** The initial location to use as an anchor for searches. */ /** The initial location to use as an anchor for searches. */
val widenmayer = location( 11.595721, 48.146113)
val homeVogelhart = location(11.5793748, 48.185749) val homeVogelhart = location(11.5793748, 48.185749)
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)
@@ -140,7 +142,7 @@ object Constants {
val isarring = location( 11.609696, 48.155116) val isarring = location( 11.609696, 48.155116)
const val NEXT_STEP_THRESHOLD = 500.0 const val NEXT_STEP_THRESHOLD = 500.0
const val MAXIMAL_SNAP_CORRECTION = 40.0 const val MAXIMAL_SNAP_CORRECTION = 50.0
const val MAXIMAL_ROUTE_DEVIATION = 100.0 const val MAXIMAL_ROUTE_DEVIATION = 100.0
@@ -185,9 +185,7 @@ class NavigationViewModel(private val repository: NavigationRepository) : ViewMo
place.id = id place.id = id
id += 1 id += 1
} }
if (place.distance == 0F || place.distance > 500F) { pl.add(place)
pl.add(place)
}
} }
} }
} }
+1
View File
@@ -21,6 +21,7 @@ kotlin.code.style=official
# thereby reducing the size of the R class for that library # thereby reducing the size of the R class for that library
android.nonTransitiveRClass=true android.nonTransitiveRClass=true
org.gradle.daemon=true
org.gradle.parallel=true org.gradle.parallel=true
org.gradle.caching=true org.gradle.caching=true
org.gradle.configuration-cache=true org.gradle.configuration-cache=true