This commit is contained in:
Dimitris
2026-04-03 12:30:39 +02:00
parent 8af2d3ad0b
commit 2ce079a7c1
5 changed files with 117 additions and 95 deletions
@@ -61,6 +61,8 @@ import com.kouros.navigation.data.tomtom.TomTomRepository
import com.kouros.navigation.data.valhalla.ValhallaRepository import com.kouros.navigation.data.valhalla.ValhallaRepository
import com.kouros.navigation.model.NavigationViewModel import com.kouros.navigation.model.NavigationViewModel
import com.kouros.navigation.model.RouteModel import com.kouros.navigation.model.RouteModel
import com.kouros.navigation.model.SettingsViewModel
import com.kouros.navigation.repository.SettingsRepository
import com.kouros.navigation.utils.GeoUtils import com.kouros.navigation.utils.GeoUtils
import com.kouros.navigation.utils.GeoUtils.snapLocation import com.kouros.navigation.utils.GeoUtils.snapLocation
import com.kouros.navigation.utils.NavigationUtils.getViewModel import com.kouros.navigation.utils.NavigationUtils.getViewModel
@@ -90,7 +92,7 @@ class NavigationSession : CarSession(), NavigationListener, NavigationObserverCa
// Model for managing route state and navigation logic for Android Auto // Model for managing route state and navigation logic for Android Auto
lateinit var routeModel: RouteCarModel lateinit var routeModel: RouteCarModel
var route = "" var route = ""
// Main navigation screen displayed to the user // Main navigation screen displayed to the user
lateinit var navigationScreen: NavigationScreen lateinit var navigationScreen: NavigationScreen
@@ -102,9 +104,12 @@ class NavigationSession : CarSession(), NavigationListener, NavigationObserverCa
lateinit var carSensorManager: CarSensorManager lateinit var carSensorManager: CarSensorManager
// Manages device GPS location updates // Manages device GPS location updates
val useDeviceLocationManager = false
lateinit var deviceLocationManager: DeviceLocationManager lateinit var deviceLocationManager: DeviceLocationManager
lateinit var navigationManager: NavigationManager var initialLocation = true;
// lateinit var navigationManager: NavigationManager
lateinit var textToSpeechManager: TextToSpeechManager lateinit var textToSpeechManager: TextToSpeechManager
@@ -146,7 +151,20 @@ class NavigationSession : CarSession(), NavigationListener, NavigationObserverCa
shouldShowLanes: Boolean, shouldShowLanes: Boolean,
junctionImage: CarIcon? junctionImage: CarIcon?
) { ) {
TODO("Not yet implemented")
}
override fun updateServiceLocation(location: Location) {
if (initialLocation) {
Log.d(TAG, "RecentPlaces $location")
navigationViewModel.loadRecentPlaces(
carContext,
location,
surfaceRenderer.carOrientation,
)
initialLocation = false
}
updateLocation(location)
} }
} }
@@ -167,6 +185,7 @@ class NavigationSession : CarSession(), NavigationListener, NavigationObserverCa
navigationService = null navigationService = null
} }
} }
/** /**
* Lifecycle observer for managing session lifecycle events. * Lifecycle observer for managing session lifecycle events.
* Cleans up resources when the session is destroyed. * Cleans up resources when the session is destroyed.
@@ -200,9 +219,9 @@ class NavigationSession : CarSession(), NavigationListener, NavigationObserverCa
} }
override fun onDestroy(owner: LifecycleOwner) { override fun onDestroy(owner: LifecycleOwner) {
if (::navigationManager.isInitialized) { // if (::navigationManager.isInitialized) {
navigationManager.clearNavigationManagerCallback() // navigationManager.clearNavigationManagerCallback()
} // }
if (::carSensorManager.isInitialized) { if (::carSensorManager.isInitialized) {
carSensorManager.cleanup() carSensorManager.cleanup()
} }
@@ -249,6 +268,7 @@ class NavigationSession : CarSession(), NavigationListener, NavigationObserverCa
* Creates appropriate repository based on user selection. * Creates appropriate repository based on user selection.
*/ */
fun onRoutingEngineStateUpdated(routeEngine: Int) { fun onRoutingEngineStateUpdated(routeEngine: Int) {
Log.d(TAG, "onRoutingEngineStateUpdated $routeEngine")
if (!::navigationViewModel.isInitialized || routeEngine != routingEngine) { if (!::navigationViewModel.isInitialized || routeEngine != routingEngine) {
navigationViewModel = when (routeEngine) { navigationViewModel = when (routeEngine) {
RouteEngine.VALHALLA.ordinal -> NavigationViewModel(ValhallaRepository()) RouteEngine.VALHALLA.ordinal -> NavigationViewModel(ValhallaRepository())
@@ -359,26 +379,26 @@ class NavigationSession : CarSession(), NavigationListener, NavigationObserverCa
* Initializes managers for rendering, sensors, and location. * Initializes managers for rendering, sensors, and location.
*/ */
private fun initializeManagers() { private fun initializeManagers() {
navigationManager = carContext.getCarService(NavigationManager::class.java) // navigationManager = carContext.getCarService(NavigationManager::class.java)
navigationManager.setNavigationManagerCallback(object : NavigationManagerCallback { // navigationManager.setNavigationManagerCallback(object : NavigationManagerCallback {
override fun onAutoDriveEnabled() { // override fun onAutoDriveEnabled() {
// Called when the app should simulate navigation (e.g., for testing) // // Called when the app should simulate navigation (e.g., for testing)
deviceLocationManager.stopLocationUpdates() // //deviceLocationManager.stopLocationUpdates()
autoDriveEnabled = true // autoDriveEnabled = true
startNavigation() // startNavigation()
CarToast.makeText(carContext, "Auto drive enabled", CarToast.LENGTH_LONG) // CarToast.makeText(carContext, "Auto drive enabled", CarToast.LENGTH_LONG)
.show() // .show()
} // }
//
override fun onStopNavigation() { // override fun onStopNavigation() {
// Called when the user stops navigation in the car screen // // Called when the user stops navigation in the car screen
// Stop turn-by-turn logic and clean up // // Stop turn-by-turn logic and clean up
stopNavigation() // stopNavigation()
if (autoDriveEnabled) { // if (autoDriveEnabled) {
deviceLocationManager.startLocationUpdates() // //deviceLocationManager.startLocationUpdates()
} // }
} // }
}) // })
surfaceRenderer = SurfaceRenderer(carContext, lifecycle, viewModelStoreOwner, this) surfaceRenderer = SurfaceRenderer(carContext, lifecycle, viewModelStoreOwner, this)
carSensorManager = CarSensorManager( carSensorManager = CarSensorManager(
@@ -389,19 +409,21 @@ class NavigationSession : CarSession(), NavigationListener, NavigationObserverCa
onSpeedUpdate = { speed -> surfaceRenderer.updateCarSpeed(speed) } onSpeedUpdate = { speed -> surfaceRenderer.updateCarSpeed(speed) }
) )
deviceLocationManager = DeviceLocationManager( if (useDeviceLocationManager) {
carContext = carContext, deviceLocationManager = DeviceLocationManager(
lifecycleOwner = this, carContext = carContext,
shouldUseCarLocationFlow = carSensorManager.shouldUseCarLocation(), lifecycleOwner = this,
onLocationUpdate = ::updateLocation, shouldUseCarLocationFlow = carSensorManager.shouldUseCarLocation(),
onInitialLocation = { location -> onLocationUpdate = ::updateLocation,
navigationViewModel.loadRecentPlaces( onInitialLocation = { location ->
carContext, navigationViewModel.loadRecentPlaces(
location, carContext,
surfaceRenderer.carOrientation, location,
) surfaceRenderer.carOrientation,
} )
) }
)
}
textToSpeechManager = TextToSpeechManager(carContext) textToSpeechManager = TextToSpeechManager(carContext)
@@ -435,7 +457,8 @@ class NavigationSession : CarSession(), NavigationListener, NavigationObserverCa
carContext.checkSelfPermission(permission.READ_CONTACTS) == PackageManager.PERMISSION_GRANTED carContext.checkSelfPermission(permission.READ_CONTACTS) == PackageManager.PERMISSION_GRANTED
return if (hasLocationPermission && hasContactsPermission) { return if (hasLocationPermission && hasContactsPermission) {
deviceLocationManager.startLocationUpdates() if (useDeviceLocationManager)
deviceLocationManager.startLocationUpdates()
navigationScreen navigationScreen
} else { } else {
showPermissionScreen() showPermissionScreen()
@@ -509,6 +532,7 @@ class NavigationSession : CarSession(), NavigationListener, NavigationObserverCa
* Handles route snapping, deviation detection for rerouting, and map updates. * Handles route snapping, deviation detection for rerouting, and map updates.
*/ */
fun updateLocation(location: Location) { fun updateLocation(location: Location) {
Log.d(TAG, "update location $location")
val streetName = if (routeModel.isNavigating()) { val streetName = if (routeModel.isNavigating()) {
routeModel.currentStep().street routeModel.currentStep().street
} else { } else {
@@ -657,10 +681,13 @@ class NavigationSession : CarSession(), NavigationListener, NavigationObserverCa
* Called when user starts navigation * Called when user starts navigation
*/ */
override fun startNavigation() { override fun startNavigation() {
if (useDeviceLocationManager)
deviceLocationManager.stopLocationUpdates()
Log.d(TAG, "startNavigation") Log.d(TAG, "startNavigation")
navigationService!!.startNavigation()
surfaceRenderer.navigation = true surfaceRenderer.navigation = true
surfaceRenderer.viewStyle = ViewStyle.VIEW surfaceRenderer.viewStyle = ViewStyle.VIEW
navigationManager.navigationStarted() // navigationManager.navigationStarted()
navigationManagerStarted = true navigationManagerStarted = true
if (autoDriveEnabled) { if (autoDriveEnabled) {
simulation.startSimulation( simulation.startSimulation(
@@ -679,9 +706,12 @@ class NavigationSession : CarSession(), NavigationListener, NavigationObserverCa
*/ */
override fun stopNavigation() { override fun stopNavigation() {
Log.d(TAG, "stopNavigation") Log.d(TAG, "stopNavigation")
if (useDeviceLocationManager)
deviceLocationManager.startLocationUpdates()
navigationService!!.stopNavigation()
surfaceRenderer.navigation = false surfaceRenderer.navigation = false
routeModel.stopNavigation() routeModel.stopNavigation()
navigationManager.navigationEnded() //navigationManager.navigationEnded()
if (autoDriveEnabled) { if (autoDriveEnabled) {
simulation.stopSimulation() simulation.stopSimulation()
autoDriveEnabled = false autoDriveEnabled = false
@@ -697,7 +727,7 @@ class NavigationSession : CarSession(), NavigationListener, NavigationObserverCa
override fun updateTrip(trip: Trip) { override fun updateTrip(trip: Trip) {
if (navigationManagerStarted) { if (navigationManagerStarted) {
navigationManager.updateTrip(trip) //navigationManager.updateTrip(trip)
} }
} }
@@ -372,6 +372,7 @@ class SurfaceRenderer(
* Uses car orientation sensor if available, otherwise falls back to location bearing. * Uses car orientation sensor if available, otherwise falls back to location bearing.
*/ */
fun updateLocation(location: Location, streetName: String) { fun updateLocation(location: Location, streetName: String) {
Log.d(TAG, "updateLocation Surface $location $streetName")
synchronized(this) { synchronized(this) {
street.value = streetName street.value = streetName
if (viewStyle == ViewStyle.VIEW || viewStyle == ViewStyle.PAN_VIEW) { if (viewStyle == ViewStyle.VIEW || viewStyle == ViewStyle.PAN_VIEW) {
@@ -61,7 +61,6 @@ class NavigationService : Service() {
val simulation = Simulation() val simulation = Simulation()
private lateinit var listener: Listener private lateinit var listener: Listener
// Model for managing route state and navigation logic for Android Auto // Model for managing route state and navigation logic for Android Auto
@@ -149,49 +148,50 @@ class NavigationService : Service() {
) { ) {
Log.d(TAG, "in setCarContext") Log.d(TAG, "in setCarContext")
this.carContext = carContext this.carContext = carContext
this.listener = listener
deviceLocationManager = DeviceLocationManagerService( deviceLocationManager = DeviceLocationManagerService(
carContext = carContext, carContext = carContext,
onLocationUpdate = ::updateLocation, onLocationUpdate = ::updateLocation,
onInitialLocation = { location -> onInitialLocation = { location ->
Log.d(TAG, "Initial location: $location") Log.d(TAG, "Initial location: $location")
updateLocation(location)
} }
) )
deviceLocationManager.startLocationUpdates()
navigationManagerInitialized = true navigationManagerInitialized = true
// navigationManager = navigationManager =
// carContext.getCarService(NavigationManager::class.java) carContext.getCarService(NavigationManager::class.java)
// navigationManager.setNavigationManagerCallback(object : NavigationManagerCallback { navigationManager.setNavigationManagerCallback(object : NavigationManagerCallback {
// override fun onAutoDriveEnabled() { override fun onAutoDriveEnabled() {
// // Called when the app should simulate navigation (e.g., for testing) Log.d(TAG, "onAutoDriveEnabled")
// deviceLocationManager.stopLocationUpdates() // Called when the app should simulate navigation (e.g., for testing)
// autoDriveEnabled = true deviceLocationManager.stopLocationUpdates()
// autoDriveEnabled = true
// simulation() simulation()
// //startNavigation()
// startNavigation() CarToast.makeText(carContext, "Auto drive enabled", CarToast.LENGTH_LONG)
// CarToast.makeText(carContext, "Auto drive enabled", CarToast.LENGTH_LONG) .show()
// .show() }
// }
// private fun simulation() {
// private fun simulation() { simulation.gpxSimulation {
// //simulation.gpxSimulation() { listener.updateServiceLocation(it)
// // listener.updateServiceLocation(it) }
// //} }
// }
// override fun onStopNavigation() {
// override fun onStopNavigation() { // Called when the user stops navigation in the car screen
// // Called when the user stops navigation in the car screen // Stop turn-by-turn logic and clean up
// // Stop turn-by-turn logic and clean up stopNavigation()
// stopNavigation() if (autoDriveEnabled) {
// if (autoDriveEnabled) { deviceLocationManager.startLocationUpdates()
// deviceLocationManager.startLocationUpdates() }
// } }
// } })
// })
this.listener = listener
// Uncomment if navigating // Uncomment if navigating
// mNavigationManager.navigationStarted(); // mNavigationManager.navigationStarted();
@@ -201,12 +201,12 @@ class NavigationService : Service() {
fun clearCarContext() { fun clearCarContext() {
Log.i(TAG, "clearContext"); Log.i(TAG, "clearContext");
carContext = null; carContext = null;
//navigationManager.clearNavigationManagerCallback(); navigationManager.clearNavigationManagerCallback();
} }
/** Starts navigation. */ /** Starts navigation. */
fun startNavigation() { fun startNavigation() {
//deviceLocationManager.startLocationUpdates()
Log.i(TAG, "Starting Navigation") Log.i(TAG, "Starting Navigation")
startService(Intent(applicationContext, NavigationService::class.java)) startService(Intent(applicationContext, NavigationService::class.java))
Log.i(TAG, "Starting foreground service") Log.i(TAG, "Starting foreground service")
@@ -231,9 +231,8 @@ class NavigationService : Service() {
if (autoDriveEnabled) { if (autoDriveEnabled) {
autoDriveEnabled = false autoDriveEnabled = false
} }
deviceLocationManager.stopLocationUpdates() if (navigationManagerInitialized)
// if (navigationManagerInitialized) navigationManager.navigationEnded()
// navigationManager.navigationEnded()
listener.navigationStateChanged( listener.navigationStateChanged(
false, false,
isRerouting = false, isRerouting = false,
@@ -246,20 +245,11 @@ class NavigationService : Service() {
shouldShowLanes = false, shouldShowLanes = false,
junctionImage = null, junctionImage = null,
) )
//stopForeground(STOP_FOREGROUND_REMOVE) stopForeground(STOP_FOREGROUND_REMOVE)
stopSelf() stopSelf()
} }
fun updateLocation(location: Location) { fun updateLocation(location: Location) {
Log.d(TAG, "Update location: $location") listener.updateServiceLocation(location)
if (autoDriveEnabled) {
}
} }
// private fun createMainActivityPendingIntent(): PendingIntent? {
// val intent: Intent = Intent(this, MainActivity::class.java)
// intent.putExtra(EXTRA_STARTED_FROM_NOTIFICATION, true)
// return PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_IMMUTABLE)
// }
} }
@@ -138,7 +138,7 @@ class Simulation {
simulationJob?.cancel() simulationJob?.cancel()
} }
private fun gpxSimulation( fun gpxSimulation(
updateLocation: (Location) -> Unit updateLocation: (Location) -> Unit
) { ) {
Runnable { Runnable {
@@ -186,7 +186,7 @@ class Simulation {
if (duration > 100) { if (duration > 100) {
// delay(duration / 4) // delay(duration / 4)
} }
Thread.sleep(500) Thread.sleep(2000)
lastTime = p.time lastTime = p.time
lastLocation = fakeLocation lastLocation = fakeLocation
} }
@@ -85,6 +85,7 @@ open class NavigationScreen(
private var showAlternativeRoute = false private var showAlternativeRoute = false
val observerRecentPlaces = Observer<List<Place>> { newPlaces -> val observerRecentPlaces = Observer<List<Place>> { newPlaces ->
Log.d(TAG, "RecentPlaces $newPlaces")
recentPlaces.addAll(newPlaces) recentPlaces.addAll(newPlaces)
if (newPlaces.isNotEmpty() && !tripSuggestionCalled) { if (newPlaces.isNotEmpty() && !tripSuggestionCalled) {
tripSuggestionCalled = true tripSuggestionCalled = true
@@ -99,6 +100,7 @@ open class NavigationScreen(
} }
repository.tripSuggestionFlow.asLiveData().observe(this, Observer { repository.tripSuggestionFlow.asLiveData().observe(this, Observer {
Log.d(TAG, "tripSuggestion $it")
navigationViewModel.recentPlaces.observe(this, observerRecentPlaces) navigationViewModel.recentPlaces.observe(this, observerRecentPlaces)
tripSuggestion = it tripSuggestion = it
}) })
@@ -519,7 +521,6 @@ open class NavigationScreen(
this.shouldShowLanes = shouldShowLanes this.shouldShowLanes = shouldShowLanes
this.junctionImage = junctionImage this.junctionImage = junctionImage
this.backGroundColor = backGroundColor this.backGroundColor = backGroundColor
navigationType = NavigationType.NAVIGATION navigationType = NavigationType.NAVIGATION
invalidate() invalidate()
} }