Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 25521192 authored by mitulsheth's avatar mitulsheth
Browse files

fix(Race Condition): FerrostarWarapper race condition

parent 098942fe
Loading
Loading
Loading
Loading
+126 −76
Original line number Diff line number Diff line
@@ -25,8 +25,13 @@ import earth.maps.cardinal.data.LocationRepository
import earth.maps.cardinal.data.OrientationRepository
import earth.maps.cardinal.data.RoutingMode
import earth.maps.cardinal.data.room.RoutingProfileRepository
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.first
import javax.inject.Inject
import javax.inject.Singleton
import kotlin.concurrent.thread

@Singleton
class FerrostarWrapperRepository @Inject constructor(
@@ -36,17 +41,38 @@ class FerrostarWrapperRepository @Inject constructor(
    private val orientationRepository: OrientationRepository,
    private val routingProfileRepository: RoutingProfileRepository
) {
    lateinit var walking: FerrostarWrapper
    lateinit var cycling: FerrostarWrapper
    lateinit var driving: FerrostarWrapper
    lateinit var truck: FerrostarWrapper
    lateinit var motorScooter: FerrostarWrapper
    lateinit var motorcycle: FerrostarWrapper
    private val _isInitialized = MutableStateFlow(false)
    val isInitialized = _isInitialized.asStateFlow()

    private var _walking: FerrostarWrapper? = null
    private var _cycling: FerrostarWrapper? = null
    private var _driving: FerrostarWrapper? = null
    private var _truck: FerrostarWrapper? = null
    private var _motorScooter: FerrostarWrapper? = null
    private var _motorcycle: FerrostarWrapper? = null

    val walking: FerrostarWrapper get() = _walking ?: throw IllegalStateException("Walking wrapper not initialized")
    val cycling: FerrostarWrapper get() = _cycling ?: throw IllegalStateException("Cycling wrapper not initialized")
    val driving: FerrostarWrapper get() = _driving ?: throw IllegalStateException("Driving wrapper not initialized")
    val truck: FerrostarWrapper get() = _truck ?: throw IllegalStateException("Truck wrapper not initialized")
    val motorScooter: FerrostarWrapper get() = _motorScooter ?: throw IllegalStateException("MotorScooter wrapper not initialized")
    val motorcycle: FerrostarWrapper get() = _motorcycle ?: throw IllegalStateException("Motorcycle wrapper not initialized")

    private val pendingOptions = mutableMapOf<RoutingMode, RoutingOptions>()

    val androidTtsObserver = AndroidTtsObserver(context)

    /**
     * Suspends until the repository is initialized with a Valhalla endpoint.
     */
    suspend fun awaitInitialization() {
        _isInitialized.filter { it }.first()
    }

    fun setValhallaEndpoint(endpoint: String) {
        walking = FerrostarWrapper(
        thread {
            Thread.sleep(30000)
            _walking = FerrostarWrapper(
                context,
                locationRepository,
                orientationRepository,
@@ -55,7 +81,7 @@ class FerrostarWrapperRepository @Inject constructor(
                androidTtsObserver,
                routingProfileRepository
            )
        cycling = FerrostarWrapper(
            _cycling = FerrostarWrapper(
                context,
                locationRepository,
                orientationRepository,
@@ -64,7 +90,7 @@ class FerrostarWrapperRepository @Inject constructor(
                androidTtsObserver,
                routingProfileRepository
            )
        driving = FerrostarWrapper(
            _driving = FerrostarWrapper(
                context,
                locationRepository,
                orientationRepository,
@@ -73,7 +99,7 @@ class FerrostarWrapperRepository @Inject constructor(
                androidTtsObserver,
                routingProfileRepository
            )
        truck = FerrostarWrapper(
            _truck = FerrostarWrapper(
                context,
                locationRepository,
                orientationRepository,
@@ -82,7 +108,7 @@ class FerrostarWrapperRepository @Inject constructor(
                androidTtsObserver,
                routingProfileRepository
            )
        motorScooter = FerrostarWrapper(
            _motorScooter = FerrostarWrapper(
                context,
                locationRepository,
                orientationRepository,
@@ -91,7 +117,7 @@ class FerrostarWrapperRepository @Inject constructor(
                androidTtsObserver,
                routingProfileRepository
            )
        motorcycle = FerrostarWrapper(
            _motorcycle = FerrostarWrapper(
                context,
                locationRepository,
                orientationRepository,
@@ -100,36 +126,60 @@ class FerrostarWrapperRepository @Inject constructor(
                androidTtsObserver,
                routingProfileRepository
            )

            _isInitialized.value = true

        }

        // Apply pending options
        synchronized(pendingOptions) {
            pendingOptions.forEach { (mode, options) ->
                setOptionsForMode(mode, options)
            }
            pendingOptions.clear()
        }
    }

    /**
     * Updates the routing options for the specified mode by modifying the existing wrapper.
     * If the wrapper is not yet initialized, the options are stored and applied once initialized.
     */
    fun setOptionsForMode(mode: RoutingMode, routingOptions: RoutingOptions) {
        when (mode) {
            RoutingMode.PEDESTRIAN -> walking.setOptions(routingOptions)
            RoutingMode.BICYCLE -> cycling.setOptions(routingOptions)
            RoutingMode.AUTO -> driving.setOptions(routingOptions)
            RoutingMode.TRUCK -> truck.setOptions(routingOptions)
            RoutingMode.MOTOR_SCOOTER -> motorScooter.setOptions(routingOptions)
            RoutingMode.MOTORCYCLE -> motorcycle.setOptions(routingOptions)
            else -> {}
        val wrapper = getWrapperForMode(mode)
        if (wrapper != null) {
            wrapper.setOptions(routingOptions)
        } else {
            synchronized(pendingOptions) {
                pendingOptions[mode] = routingOptions
            }
        }
    }

    /**
     * Resets the routing options for the specified mode to defaults by recreating the wrapper.
     * If the wrapper is not yet initialized, the default options are stored and applied once initialized.
     */
    fun resetOptionsToDefaultsForMode(mode: RoutingMode) {
        val defaultOptions = routingProfileRepository.createDefaultOptionsForMode(mode)
        when (mode) {
            RoutingMode.PEDESTRIAN -> walking.setOptions(defaultOptions)
            RoutingMode.BICYCLE -> cycling.setOptions(defaultOptions)
            RoutingMode.AUTO -> driving.setOptions(defaultOptions)
            RoutingMode.TRUCK -> truck.setOptions(defaultOptions)
            RoutingMode.MOTOR_SCOOTER -> motorScooter.setOptions(defaultOptions)
            RoutingMode.MOTORCYCLE -> motorcycle.setOptions(defaultOptions)
            else -> {}
        val wrapper = getWrapperForMode(mode)
        if (wrapper != null) {
            wrapper.setOptions(defaultOptions)
        } else {
            defaultOptions?.let {
                synchronized(pendingOptions) {
                    pendingOptions[mode] = it
                }
            }
        }
    }

    private fun getWrapperForMode(mode: RoutingMode): FerrostarWrapper? = when (mode) {
        RoutingMode.PEDESTRIAN -> _walking
        RoutingMode.BICYCLE -> _cycling
        RoutingMode.AUTO -> _driving
        RoutingMode.TRUCK -> _truck
        RoutingMode.MOTOR_SCOOTER -> _motorScooter
        RoutingMode.MOTORCYCLE -> _motorcycle
        else -> null
    }
}
+6 −0
Original line number Diff line number Diff line
@@ -108,6 +108,9 @@ class DirectionsViewModel @Inject constructor(


    suspend fun initializeRoutingMode() {
        // Wait for FerrostarWrapperRepository to be initialized before setting options
        ferrostarWrapperRepository.awaitInitialization()

        // Set initial routing mode from preferences
        selectedRoutingMode = appPreferenceRepository.lastRoutingMode.value.let { modeString ->
            RoutingMode.entries.find { it.value == modeString } ?: RoutingMode.AUTO
@@ -161,6 +164,9 @@ class DirectionsViewModel @Inject constructor(

    private fun fetchDrivingDirections(origin: Place, destination: Place) {
        viewModelScope.launch {
            // Wait for FerrostarWrapperRepository to be initialized
            ferrostarWrapperRepository.awaitInitialization()

            routeStateRepository.setLoading(true)

            try {