From a4227c80d3775fb2f031a891dd1efde2fc493d80 Mon Sep 17 00:00:00 2001 From: Dimitris Date: Sat, 28 Mar 2026 10:41:58 +0100 Subject: [PATCH] NavigationService --- .../car/DeviceLocationManagerService.kt | 97 +++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 common/car/src/main/java/com/kouros/navigation/car/DeviceLocationManagerService.kt diff --git a/common/car/src/main/java/com/kouros/navigation/car/DeviceLocationManagerService.kt b/common/car/src/main/java/com/kouros/navigation/car/DeviceLocationManagerService.kt new file mode 100644 index 0000000..eebf5e1 --- /dev/null +++ b/common/car/src/main/java/com/kouros/navigation/car/DeviceLocationManagerService.kt @@ -0,0 +1,97 @@ +package com.kouros.navigation.car + +import android.annotation.SuppressLint +import android.content.Context +import android.location.Location +import android.location.LocationManager +import androidx.car.app.CarContext +import androidx.core.location.LocationListenerCompat +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.lifecycleScope +import androidx.lifecycle.repeatOnLifecycle +import com.kouros.navigation.car.navigation.NavigationService +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.launch + +/** + * Manages device GPS location updates for navigation. + * Coordinates with car hardware sensors to avoid duplicate location sources. + * + * @param carContext The car context for accessing system services + * @param serviceOwner Owner of the lifecycle for coroutine management + * @param shouldUseCarLocationFlow Flow indicating whether car location hardware should be used + * @param onLocationUpdate Callback invoked when location updates are received + * @param onInitialLocation Callback invoked with the last known location when starting + */ +class DeviceLocationManagerService( + private val carContext: CarContext, + private val onLocationUpdate: (Location) -> Unit, + private val onInitialLocation: (Location) -> Unit +) { + + private val locationManager: LocationManager = + carContext.getSystemService(Context.LOCATION_SERVICE) as LocationManager + + private var shouldUseDeviceLocation = true + private var isListening = false + + /** + * Location listener that receives GPS updates from the device. + * Only processes location if car location hardware is not being used. + */ + private val locationListener: LocationListenerCompat = LocationListenerCompat { location -> + if (shouldUseDeviceLocation) { + onLocationUpdate(location) + } + } + + init { + + } + + /** + * Starts requesting location updates from device GPS. + * Provides initial location via callback and then starts continuous updates. + * + * @param minTimeMs Minimum time interval between updates in milliseconds (default: 500ms) + * @param minDistanceM Minimum distance between updates in meters (default: 5m) + */ + @SuppressLint("MissingPermission") + fun startLocationUpdates(minTimeMs: Long = 1000, minDistanceM: Float = 1.0f) { + if (isListening) return + + // Get and deliver last known location first + val lastLocation = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER) + if (lastLocation != null) { + onInitialLocation(lastLocation) + onLocationUpdate(lastLocation) + } + + // Start continuous location updates + locationManager.requestLocationUpdates( + LocationManager.GPS_PROVIDER, + minTimeMs, + minDistanceM, + locationListener + ) + isListening = true + } + + /** + * Stops receiving location updates from device GPS. + * Should be called when the session is destroyed to prevent memory leaks. + */ + fun stopLocationUpdates() { + if (!isListening) return + + locationManager.removeUpdates(locationListener) + isListening = false + } + + /** + * Checks if location updates are currently active. + */ + fun isListeningForUpdates(): Boolean = isListening +}