Loading cardinal-android/app/src/main/java/earth/maps/cardinal/data/LocationRepository.kt +5 −1 Original line number Original line Diff line number Diff line Loading @@ -54,7 +54,7 @@ class LocationRepository @Inject constructor( private companion object { private companion object { private const val LOCATION_REQUEST_INTERVAL_MS = 15000L // 15 seconds private const val LOCATION_REQUEST_INTERVAL_MS = 15000L // 15 seconds private const val LOCATION_REQUEST_TIMEOUT_MS = 5000L // 5 seconds private const val LOCATION_REQUEST_TIMEOUT_MS = 5000L // 5 seconds private const val CONTINUOUS_LOCATION_UPDATE_INTERVAL_MS = 5000L // 5 seconds private const val CONTINUOUS_LOCATION_UPDATE_INTERVAL_MS = 1000L // 1 second private const val CONTINUOUS_LOCATION_UPDATE_DISTANCE_M = 5f // 5 meters private const val CONTINUOUS_LOCATION_UPDATE_DISTANCE_M = 5f // 5 meters private const val GPS_PROVIDER_TIMEOUT_MS = private const val GPS_PROVIDER_TIMEOUT_MS = 10_000L // 10 seconds - discard fused locations if fused has updated within this timeout 10_000L // 10 seconds - discard fused locations if fused has updated within this timeout Loading Loading @@ -130,6 +130,10 @@ class LocationRepository @Inject constructor( } } } } fun getLastLocation(): Location? { return lastRequestedLocation } fun fromNameAndLatLng(name: String?, latLng: LatLng): Place { fun fromNameAndLatLng(name: String?, latLng: LatLng): Place { return Place( return Place( name = name ?: context.getString(R.string.unnamed_location), name = name ?: context.getString(R.string.unnamed_location), Loading cardinal-android/app/src/main/java/earth/maps/cardinal/routing/FerrostarWrapper.kt +57 −2 Original line number Original line Diff line number Diff line Loading @@ -20,25 +20,40 @@ package earth.maps.cardinal.routing import android.content.Context import android.content.Context import com.stadiamaps.ferrostar.composeui.notification.DefaultForegroundNotificationBuilder import com.stadiamaps.ferrostar.composeui.notification.DefaultForegroundNotificationBuilder import com.stadiamaps.ferrostar.core.AndroidSystemLocationProvider import com.stadiamaps.ferrostar.core.AndroidTtsObserver import com.stadiamaps.ferrostar.core.AndroidTtsObserver import com.stadiamaps.ferrostar.core.FerrostarCore import com.stadiamaps.ferrostar.core.FerrostarCore import com.stadiamaps.ferrostar.core.LocationProvider import com.stadiamaps.ferrostar.core.LocationUpdateListener import com.stadiamaps.ferrostar.core.http.OkHttpClientProvider import com.stadiamaps.ferrostar.core.http.OkHttpClientProvider import com.stadiamaps.ferrostar.core.service.FerrostarForegroundServiceManager import com.stadiamaps.ferrostar.core.service.FerrostarForegroundServiceManager import com.stadiamaps.ferrostar.core.service.ForegroundServiceManager import com.stadiamaps.ferrostar.core.service.ForegroundServiceManager import com.stadiamaps.ferrostar.core.toUserLocation import earth.maps.cardinal.data.LocationRepository import earth.maps.cardinal.data.OrientationRepository import earth.maps.cardinal.data.RoutingMode import earth.maps.cardinal.data.RoutingMode import earth.maps.cardinal.data.room.RoutingProfileRepository import earth.maps.cardinal.data.room.RoutingProfileRepository import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import okhttp3.OkHttpClient import okhttp3.OkHttpClient import uniffi.ferrostar.CourseFiltering import uniffi.ferrostar.CourseFiltering import uniffi.ferrostar.Heading import uniffi.ferrostar.NavigationControllerConfig import uniffi.ferrostar.NavigationControllerConfig import uniffi.ferrostar.RouteAdapter import uniffi.ferrostar.RouteAdapter import uniffi.ferrostar.RouteDeviationTracking import uniffi.ferrostar.RouteDeviationTracking import uniffi.ferrostar.UserLocation import uniffi.ferrostar.WaypointAdvanceMode import uniffi.ferrostar.WaypointAdvanceMode import uniffi.ferrostar.stepAdvanceDistanceEntryAndExit import uniffi.ferrostar.stepAdvanceDistanceEntryAndExit import uniffi.ferrostar.stepAdvanceDistanceToEndOfStep import uniffi.ferrostar.stepAdvanceDistanceToEndOfStep import java.util.concurrent.Executor import kotlin.time.Clock import kotlin.time.ExperimentalTime import kotlin.time.toJavaInstant class FerrostarWrapper( class FerrostarWrapper( context: Context, context: Context, private val locationRepository: LocationRepository, private val orientationRepository: OrientationRepository, private val mode: RoutingMode, private val mode: RoutingMode, private val localValhallaEndpoint: String, private val localValhallaEndpoint: String, private val androidTtsObserver: AndroidTtsObserver, private val androidTtsObserver: AndroidTtsObserver, Loading @@ -46,12 +61,52 @@ class FerrostarWrapper( routingOptions: RoutingOptions? = null routingOptions: RoutingOptions? = null ) { ) { private val coroutineScope = CoroutineScope(Dispatchers.Main) private val foregroundServiceManager: ForegroundServiceManager = private val foregroundServiceManager: ForegroundServiceManager = FerrostarForegroundServiceManager( FerrostarForegroundServiceManager( context = context, context = context, DefaultForegroundNotificationBuilder(context) DefaultForegroundNotificationBuilder(context) ) ) private val locationProvider = AndroidSystemLocationProvider(context = context) @OptIn(ExperimentalTime::class) private val locationProvider = object: LocationProvider { private val listeners = mutableListOf<LocationUpdateListener>() override val lastLocation: UserLocation? get() = locationRepository.getLastLocation()?.toUserLocation() override val lastHeading: Heading? get() { val heading = ((orientationRepository.azimuth.value.toInt() + 360) % 360).toUShort() return Heading( heading, 0u, Clock.System.now().toJavaInstant() ) } init { coroutineScope.launch { locationRepository.locationFlow.collect { location -> listeners.forEach { listener -> location?.toUserLocation()?.let { userLocation -> listener.onLocationUpdated(userLocation) } } } } } override fun addListener( listener: LocationUpdateListener, executor: Executor ) { listeners.add(listener) } override fun removeListener(listener: LocationUpdateListener) { listeners.remove(listener) } } private var previousRouteOptions: RoutingOptions? = null private var previousRouteOptions: RoutingOptions? = null var core = var core = Loading cardinal-android/app/src/main/java/earth/maps/cardinal/routing/FerrostarWrapperRepository.kt +16 −0 Original line number Original line Diff line number Diff line Loading @@ -21,6 +21,8 @@ package earth.maps.cardinal.routing import android.content.Context import android.content.Context import com.stadiamaps.ferrostar.core.AndroidTtsObserver import com.stadiamaps.ferrostar.core.AndroidTtsObserver import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.android.qualifiers.ApplicationContext import earth.maps.cardinal.data.LocationRepository import earth.maps.cardinal.data.OrientationRepository import earth.maps.cardinal.data.RoutingMode import earth.maps.cardinal.data.RoutingMode import earth.maps.cardinal.data.room.RoutingProfileRepository import earth.maps.cardinal.data.room.RoutingProfileRepository import javax.inject.Inject import javax.inject.Inject Loading @@ -30,6 +32,8 @@ import javax.inject.Singleton class FerrostarWrapperRepository @Inject constructor( class FerrostarWrapperRepository @Inject constructor( @param:ApplicationContext @param:ApplicationContext private val context: Context, private val context: Context, private val locationRepository: LocationRepository, private val orientationRepository: OrientationRepository, private val routingProfileRepository: RoutingProfileRepository private val routingProfileRepository: RoutingProfileRepository ) { ) { lateinit var walking: FerrostarWrapper lateinit var walking: FerrostarWrapper Loading @@ -44,6 +48,8 @@ class FerrostarWrapperRepository @Inject constructor( fun setValhallaEndpoint(endpoint: String) { fun setValhallaEndpoint(endpoint: String) { walking = FerrostarWrapper( walking = FerrostarWrapper( context, context, locationRepository, orientationRepository, RoutingMode.PEDESTRIAN, RoutingMode.PEDESTRIAN, endpoint, endpoint, androidTtsObserver, androidTtsObserver, Loading @@ -51,6 +57,8 @@ class FerrostarWrapperRepository @Inject constructor( ) ) cycling = FerrostarWrapper( cycling = FerrostarWrapper( context, context, locationRepository, orientationRepository, RoutingMode.BICYCLE, RoutingMode.BICYCLE, endpoint, endpoint, androidTtsObserver, androidTtsObserver, Loading @@ -58,6 +66,8 @@ class FerrostarWrapperRepository @Inject constructor( ) ) driving = FerrostarWrapper( driving = FerrostarWrapper( context, context, locationRepository, orientationRepository, RoutingMode.AUTO, RoutingMode.AUTO, endpoint, endpoint, androidTtsObserver, androidTtsObserver, Loading @@ -65,6 +75,8 @@ class FerrostarWrapperRepository @Inject constructor( ) ) truck = FerrostarWrapper( truck = FerrostarWrapper( context, context, locationRepository, orientationRepository, RoutingMode.TRUCK, RoutingMode.TRUCK, endpoint, endpoint, androidTtsObserver, androidTtsObserver, Loading @@ -72,6 +84,8 @@ class FerrostarWrapperRepository @Inject constructor( ) ) motorScooter = FerrostarWrapper( motorScooter = FerrostarWrapper( context, context, locationRepository, orientationRepository, RoutingMode.MOTOR_SCOOTER, RoutingMode.MOTOR_SCOOTER, endpoint, endpoint, androidTtsObserver, androidTtsObserver, Loading @@ -79,6 +93,8 @@ class FerrostarWrapperRepository @Inject constructor( ) ) motorcycle = FerrostarWrapper( motorcycle = FerrostarWrapper( context, context, locationRepository, orientationRepository, RoutingMode.MOTORCYCLE, RoutingMode.MOTORCYCLE, endpoint, endpoint, androidTtsObserver, androidTtsObserver, Loading Loading
cardinal-android/app/src/main/java/earth/maps/cardinal/data/LocationRepository.kt +5 −1 Original line number Original line Diff line number Diff line Loading @@ -54,7 +54,7 @@ class LocationRepository @Inject constructor( private companion object { private companion object { private const val LOCATION_REQUEST_INTERVAL_MS = 15000L // 15 seconds private const val LOCATION_REQUEST_INTERVAL_MS = 15000L // 15 seconds private const val LOCATION_REQUEST_TIMEOUT_MS = 5000L // 5 seconds private const val LOCATION_REQUEST_TIMEOUT_MS = 5000L // 5 seconds private const val CONTINUOUS_LOCATION_UPDATE_INTERVAL_MS = 5000L // 5 seconds private const val CONTINUOUS_LOCATION_UPDATE_INTERVAL_MS = 1000L // 1 second private const val CONTINUOUS_LOCATION_UPDATE_DISTANCE_M = 5f // 5 meters private const val CONTINUOUS_LOCATION_UPDATE_DISTANCE_M = 5f // 5 meters private const val GPS_PROVIDER_TIMEOUT_MS = private const val GPS_PROVIDER_TIMEOUT_MS = 10_000L // 10 seconds - discard fused locations if fused has updated within this timeout 10_000L // 10 seconds - discard fused locations if fused has updated within this timeout Loading Loading @@ -130,6 +130,10 @@ class LocationRepository @Inject constructor( } } } } fun getLastLocation(): Location? { return lastRequestedLocation } fun fromNameAndLatLng(name: String?, latLng: LatLng): Place { fun fromNameAndLatLng(name: String?, latLng: LatLng): Place { return Place( return Place( name = name ?: context.getString(R.string.unnamed_location), name = name ?: context.getString(R.string.unnamed_location), Loading
cardinal-android/app/src/main/java/earth/maps/cardinal/routing/FerrostarWrapper.kt +57 −2 Original line number Original line Diff line number Diff line Loading @@ -20,25 +20,40 @@ package earth.maps.cardinal.routing import android.content.Context import android.content.Context import com.stadiamaps.ferrostar.composeui.notification.DefaultForegroundNotificationBuilder import com.stadiamaps.ferrostar.composeui.notification.DefaultForegroundNotificationBuilder import com.stadiamaps.ferrostar.core.AndroidSystemLocationProvider import com.stadiamaps.ferrostar.core.AndroidTtsObserver import com.stadiamaps.ferrostar.core.AndroidTtsObserver import com.stadiamaps.ferrostar.core.FerrostarCore import com.stadiamaps.ferrostar.core.FerrostarCore import com.stadiamaps.ferrostar.core.LocationProvider import com.stadiamaps.ferrostar.core.LocationUpdateListener import com.stadiamaps.ferrostar.core.http.OkHttpClientProvider import com.stadiamaps.ferrostar.core.http.OkHttpClientProvider import com.stadiamaps.ferrostar.core.service.FerrostarForegroundServiceManager import com.stadiamaps.ferrostar.core.service.FerrostarForegroundServiceManager import com.stadiamaps.ferrostar.core.service.ForegroundServiceManager import com.stadiamaps.ferrostar.core.service.ForegroundServiceManager import com.stadiamaps.ferrostar.core.toUserLocation import earth.maps.cardinal.data.LocationRepository import earth.maps.cardinal.data.OrientationRepository import earth.maps.cardinal.data.RoutingMode import earth.maps.cardinal.data.RoutingMode import earth.maps.cardinal.data.room.RoutingProfileRepository import earth.maps.cardinal.data.room.RoutingProfileRepository import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import okhttp3.OkHttpClient import okhttp3.OkHttpClient import uniffi.ferrostar.CourseFiltering import uniffi.ferrostar.CourseFiltering import uniffi.ferrostar.Heading import uniffi.ferrostar.NavigationControllerConfig import uniffi.ferrostar.NavigationControllerConfig import uniffi.ferrostar.RouteAdapter import uniffi.ferrostar.RouteAdapter import uniffi.ferrostar.RouteDeviationTracking import uniffi.ferrostar.RouteDeviationTracking import uniffi.ferrostar.UserLocation import uniffi.ferrostar.WaypointAdvanceMode import uniffi.ferrostar.WaypointAdvanceMode import uniffi.ferrostar.stepAdvanceDistanceEntryAndExit import uniffi.ferrostar.stepAdvanceDistanceEntryAndExit import uniffi.ferrostar.stepAdvanceDistanceToEndOfStep import uniffi.ferrostar.stepAdvanceDistanceToEndOfStep import java.util.concurrent.Executor import kotlin.time.Clock import kotlin.time.ExperimentalTime import kotlin.time.toJavaInstant class FerrostarWrapper( class FerrostarWrapper( context: Context, context: Context, private val locationRepository: LocationRepository, private val orientationRepository: OrientationRepository, private val mode: RoutingMode, private val mode: RoutingMode, private val localValhallaEndpoint: String, private val localValhallaEndpoint: String, private val androidTtsObserver: AndroidTtsObserver, private val androidTtsObserver: AndroidTtsObserver, Loading @@ -46,12 +61,52 @@ class FerrostarWrapper( routingOptions: RoutingOptions? = null routingOptions: RoutingOptions? = null ) { ) { private val coroutineScope = CoroutineScope(Dispatchers.Main) private val foregroundServiceManager: ForegroundServiceManager = private val foregroundServiceManager: ForegroundServiceManager = FerrostarForegroundServiceManager( FerrostarForegroundServiceManager( context = context, context = context, DefaultForegroundNotificationBuilder(context) DefaultForegroundNotificationBuilder(context) ) ) private val locationProvider = AndroidSystemLocationProvider(context = context) @OptIn(ExperimentalTime::class) private val locationProvider = object: LocationProvider { private val listeners = mutableListOf<LocationUpdateListener>() override val lastLocation: UserLocation? get() = locationRepository.getLastLocation()?.toUserLocation() override val lastHeading: Heading? get() { val heading = ((orientationRepository.azimuth.value.toInt() + 360) % 360).toUShort() return Heading( heading, 0u, Clock.System.now().toJavaInstant() ) } init { coroutineScope.launch { locationRepository.locationFlow.collect { location -> listeners.forEach { listener -> location?.toUserLocation()?.let { userLocation -> listener.onLocationUpdated(userLocation) } } } } } override fun addListener( listener: LocationUpdateListener, executor: Executor ) { listeners.add(listener) } override fun removeListener(listener: LocationUpdateListener) { listeners.remove(listener) } } private var previousRouteOptions: RoutingOptions? = null private var previousRouteOptions: RoutingOptions? = null var core = var core = Loading
cardinal-android/app/src/main/java/earth/maps/cardinal/routing/FerrostarWrapperRepository.kt +16 −0 Original line number Original line Diff line number Diff line Loading @@ -21,6 +21,8 @@ package earth.maps.cardinal.routing import android.content.Context import android.content.Context import com.stadiamaps.ferrostar.core.AndroidTtsObserver import com.stadiamaps.ferrostar.core.AndroidTtsObserver import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.android.qualifiers.ApplicationContext import earth.maps.cardinal.data.LocationRepository import earth.maps.cardinal.data.OrientationRepository import earth.maps.cardinal.data.RoutingMode import earth.maps.cardinal.data.RoutingMode import earth.maps.cardinal.data.room.RoutingProfileRepository import earth.maps.cardinal.data.room.RoutingProfileRepository import javax.inject.Inject import javax.inject.Inject Loading @@ -30,6 +32,8 @@ import javax.inject.Singleton class FerrostarWrapperRepository @Inject constructor( class FerrostarWrapperRepository @Inject constructor( @param:ApplicationContext @param:ApplicationContext private val context: Context, private val context: Context, private val locationRepository: LocationRepository, private val orientationRepository: OrientationRepository, private val routingProfileRepository: RoutingProfileRepository private val routingProfileRepository: RoutingProfileRepository ) { ) { lateinit var walking: FerrostarWrapper lateinit var walking: FerrostarWrapper Loading @@ -44,6 +48,8 @@ class FerrostarWrapperRepository @Inject constructor( fun setValhallaEndpoint(endpoint: String) { fun setValhallaEndpoint(endpoint: String) { walking = FerrostarWrapper( walking = FerrostarWrapper( context, context, locationRepository, orientationRepository, RoutingMode.PEDESTRIAN, RoutingMode.PEDESTRIAN, endpoint, endpoint, androidTtsObserver, androidTtsObserver, Loading @@ -51,6 +57,8 @@ class FerrostarWrapperRepository @Inject constructor( ) ) cycling = FerrostarWrapper( cycling = FerrostarWrapper( context, context, locationRepository, orientationRepository, RoutingMode.BICYCLE, RoutingMode.BICYCLE, endpoint, endpoint, androidTtsObserver, androidTtsObserver, Loading @@ -58,6 +66,8 @@ class FerrostarWrapperRepository @Inject constructor( ) ) driving = FerrostarWrapper( driving = FerrostarWrapper( context, context, locationRepository, orientationRepository, RoutingMode.AUTO, RoutingMode.AUTO, endpoint, endpoint, androidTtsObserver, androidTtsObserver, Loading @@ -65,6 +75,8 @@ class FerrostarWrapperRepository @Inject constructor( ) ) truck = FerrostarWrapper( truck = FerrostarWrapper( context, context, locationRepository, orientationRepository, RoutingMode.TRUCK, RoutingMode.TRUCK, endpoint, endpoint, androidTtsObserver, androidTtsObserver, Loading @@ -72,6 +84,8 @@ class FerrostarWrapperRepository @Inject constructor( ) ) motorScooter = FerrostarWrapper( motorScooter = FerrostarWrapper( context, context, locationRepository, orientationRepository, RoutingMode.MOTOR_SCOOTER, RoutingMode.MOTOR_SCOOTER, endpoint, endpoint, androidTtsObserver, androidTtsObserver, Loading @@ -79,6 +93,8 @@ class FerrostarWrapperRepository @Inject constructor( ) ) motorcycle = FerrostarWrapper( motorcycle = FerrostarWrapper( context, context, locationRepository, orientationRepository, RoutingMode.MOTORCYCLE, RoutingMode.MOTORCYCLE, endpoint, endpoint, androidTtsObserver, androidTtsObserver, Loading