diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 6eecabd..bfdd12e 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -14,8 +14,8 @@ android { applicationId = "com.kouros.navigation" minSdk = 33 targetSdk = 36 - versionCode = 15 - versionName = "0.1.3.15" + versionCode = 18 + versionName = "0.1.3.18" base.archivesName = "navi-$versionName" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" } diff --git a/app/src/main/java/com/kouros/navigation/MainApplication.kt b/app/src/main/java/com/kouros/navigation/MainApplication.kt index 2fbae36..bb254e9 100644 --- a/app/src/main/java/com/kouros/navigation/MainApplication.kt +++ b/app/src/main/java/com/kouros/navigation/MainApplication.kt @@ -2,26 +2,14 @@ package com.kouros.navigation import android.app.Application import android.content.Context -import com.kouros.navigation.data.Constants.DARK_MODE_SETTINGS -import com.kouros.navigation.data.Constants.ROUTE_ENGINE -import com.kouros.navigation.data.Constants.SHOW_THREED_BUILDING -import com.kouros.navigation.data.NavigationRepository import com.kouros.navigation.data.ObjectBox -import com.kouros.navigation.data.RouteEngine -import com.kouros.navigation.data.osrm.OsrmRepository -import com.kouros.navigation.data.valhalla.ValhallaRepository import com.kouros.navigation.di.appModule -import com.kouros.navigation.model.BaseStyleModel import com.kouros.navigation.model.ViewModel -import com.kouros.navigation.utils.NavigationUtils.getBooleanKeyValue -import com.kouros.navigation.utils.NavigationUtils.getIntKeyValue import com.kouros.navigation.utils.NavigationUtils.getRouteEngine -import com.kouros.navigation.utils.NavigationUtils.setIntKeyValue import org.koin.android.ext.koin.androidContext import org.koin.android.ext.koin.androidLogger import org.koin.core.context.startKoin import org.koin.core.logger.Level -import org.maplibre.compose.expressions.dsl.switch class MainApplication : Application() { @@ -29,7 +17,6 @@ class MainApplication : Application() { super.onCreate() ObjectBox.init(this); appContext = applicationContext - setIntKeyValue(appContext!!, RouteEngine.VALHALLA.ordinal, ROUTE_ENGINE) navigationViewModel = getRouteEngine(appContext!!) startKoin { androidLogger(Level.DEBUG) diff --git a/app/src/main/java/com/kouros/navigation/ui/MainActivity.kt b/app/src/main/java/com/kouros/navigation/ui/MainActivity.kt index 2befa83..f498476 100644 --- a/app/src/main/java/com/kouros/navigation/ui/MainActivity.kt +++ b/app/src/main/java/com/kouros/navigation/ui/MainActivity.kt @@ -47,6 +47,7 @@ import com.kouros.navigation.model.BaseStyleModel import com.kouros.navigation.model.MockLocation import com.kouros.navigation.model.RouteModel import com.kouros.navigation.ui.theme.NavigationTheme +import com.kouros.navigation.utils.GeoUtils.snapLocation import com.kouros.navigation.utils.NavigationUtils.getIntKeyValue import com.kouros.navigation.utils.bearing import com.kouros.navigation.utils.calculateZoom @@ -61,6 +62,7 @@ import org.maplibre.compose.location.Location import org.maplibre.compose.location.rememberDefaultLocationProvider import org.maplibre.compose.location.rememberUserLocationState import org.maplibre.compose.style.BaseStyle +import org.maplibre.geojson.Point import org.maplibre.spatialk.geojson.Position import kotlin.time.Duration.Companion.seconds @@ -102,7 +104,7 @@ class MainActivity : ComponentActivity() { private var overpass = false - lateinit var baseStyle : BaseStyle.Json + lateinit var baseStyle: BaseStyle.Json init { navigationViewModel.route.observe(this, observer) @@ -112,14 +114,14 @@ class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val darkModeSettings = getIntKeyValue(applicationContext, Constants.DARK_MODE_SETTINGS) - baseStyle = BaseStyleModel().readStyle(applicationContext, darkModeSettings, false) + baseStyle = BaseStyleModel().readStyle(applicationContext, darkModeSettings, false) if (useMock) { checkMockLocationEnabled() } locationManager = getSystemService(LOCATION_SERVICE) as LocationManager fusedLocationClient = LocationServices.getFusedLocationProviderClient(this) fusedLocationClient.lastLocation - .addOnSuccessListener { location : android.location.Location? -> + .addOnSuccessListener { location: android.location.Location? -> if (useMock) { mock = MockLocation(locationManager) mock.setMockLocation( @@ -235,6 +237,7 @@ class MainActivity : ComponentActivity() { && lastLocation.longitude != location.position.longitude ) { val currentLocation = location(location.position.longitude, location.position.latitude) + val bearing = bearing(lastLocation, currentLocation, cameraPosition.value!!.bearing) with(routeModel) { if (isNavigating()) { updateLocation(currentLocation, navigationViewModel) @@ -245,13 +248,12 @@ class MainActivity : ComponentActivity() { if (routeState.maneuverType == 39 && leftStepDistance() < DESTINATION_ARRIVAL_DISTANCE ) { - // stopNavigation() + // stopNavigation() routeState = routeState.copy(arrived = true) routeData.value = "" } } } - val bearing = bearing(lastLocation, currentLocation, cameraPosition.value!!.bearing) val zoom = calculateZoom(location.speed) cameraPosition.postValue( cameraPosition.value!!.copy( @@ -303,14 +305,13 @@ class MainActivity : ComponentActivity() { } } - fun simulate() { + fun simulate() { CoroutineScope(Dispatchers.IO).launch { - for ((index, step) in routeModel.legs.steps.withIndex()) { - for ((windex, waypoint) in step.maneuver.waypoints.withIndex()) { - if (routeModel.isNavigating()) { - mock.setMockLocation(waypoint[1], waypoint[0]) - delay(800L) // - } + if (routeModel.isNavigating()) { + for ((index, waypoint) in routeModel.route.waypoints!!.withIndex()) { + var deviation = 0.0 + mock.setMockLocation(waypoint[1] + deviation, waypoint[0]) + delay(500L) // } } } diff --git a/common/car/src/main/java/com/kouros/navigation/car/NavigationSession.kt b/common/car/src/main/java/com/kouros/navigation/car/NavigationSession.kt index fea4e74..791c882 100644 --- a/common/car/src/main/java/com/kouros/navigation/car/NavigationSession.kt +++ b/common/car/src/main/java/com/kouros/navigation/car/NavigationSession.kt @@ -19,7 +19,6 @@ import androidx.car.app.hardware.common.OnCarDataAvailableListener import androidx.car.app.hardware.info.CarHardwareLocation import androidx.car.app.hardware.info.CarSensors import androidx.car.app.hardware.info.Speed -import androidx.compose.foundation.isSystemInDarkTheme import androidx.core.location.LocationListenerCompat import androidx.core.net.toUri import androidx.lifecycle.DefaultLifecycleObserver @@ -33,10 +32,13 @@ import com.kouros.navigation.car.screen.SearchScreen import com.kouros.navigation.data.Constants import com.kouros.navigation.data.Constants.MAXIMAL_ROUTE_DEVIATION import com.kouros.navigation.data.Constants.MAXIMAL_SNAP_CORRECTION +import com.kouros.navigation.data.Constants.ROUTING_ENGINE import com.kouros.navigation.data.Constants.TAG +import com.kouros.navigation.data.RouteEngine +import com.kouros.navigation.data.osrm.OsrmRepository +import com.kouros.navigation.data.valhalla.ValhallaRepository import com.kouros.navigation.model.BaseStyleModel import com.kouros.navigation.model.ViewModel -import com.kouros.navigation.utils.GeoUtils.snapLocation import com.kouros.navigation.utils.NavigationUtils.getIntKeyValue import com.kouros.navigation.utils.NavigationUtils.getRouteEngine import org.maplibre.compose.style.BaseStyle @@ -52,7 +54,10 @@ class NavigationSession : Session(), NavigationScreen.Listener { lateinit var surfaceRenderer: SurfaceRenderer var mLocationListener: LocationListenerCompat = LocationListenerCompat { location: Location? -> - updateLocation(location!!) + val routingEngine = getIntKeyValue(carContext, ROUTING_ENGINE) + if (routingEngine == RouteEngine.VALHALLA.ordinal) { + updateLocation(location!!) + } } private val mLifeCycleObserver: LifecycleObserver = object : DefaultLifecycleObserver { @@ -75,8 +80,8 @@ class NavigationSession : Session(), NavigationScreen.Listener { override fun onDestroy(owner: LifecycleOwner) { val carSensors = carContext.getCarService(CarHardwareManager::class.java).carSensors val carInfo = carContext.getCarService(CarHardwareManager::class.java).carInfo - carSensors.removeCarHardwareLocationListener(locationListener) - carInfo.removeSpeedListener(speedListener) + carSensors.removeCarHardwareLocationListener(carLocationListener) + carInfo.removeSpeedListener(carSpeedListener) Log.i(TAG, "In onDestroy()") val locationManager = carContext.getSystemService(Context.LOCATION_SERVICE) as LocationManager @@ -88,7 +93,7 @@ class NavigationSession : Session(), NavigationScreen.Listener { lateinit var baseStyle: BaseStyle.Json - val locationListener: OnCarDataAvailableListener = + val carLocationListener: OnCarDataAvailableListener = OnCarDataAvailableListener { data -> if (data.location.status == CarValue.STATUS_SUCCESS) { val location = data.location.value @@ -96,7 +101,7 @@ class NavigationSession : Session(), NavigationScreen.Listener { } } - val speedListener = OnCarDataAvailableListener { data -> + val carSpeedListener = OnCarDataAvailableListener { data -> if (data.displaySpeedMetersPerSecond.status == CarValue.STATUS_SUCCESS) { val speed = data.displaySpeedMetersPerSecond.value surfaceRenderer.updateCarSpeed(speed!!) @@ -106,9 +111,19 @@ class NavigationSession : Session(), NavigationScreen.Listener { val lifecycle: Lifecycle = lifecycle lifecycle.addObserver(mLifeCycleObserver) } + + fun onRoutingEngineStateUpdated(routeEngine : Int) { + navigationViewModel = when (routeEngine) { + RouteEngine.VALHALLA.ordinal -> ViewModel(ValhallaRepository()) + else -> ViewModel(OsrmRepository()) + } + } + override fun onCreateScreen(intent: Intent): Screen { navigationViewModel = getRouteEngine(carContext) + + navigationViewModel.routingEngine.observe(this, ::onRoutingEngineStateUpdated) routeModel = RouteCarModel() val darkMode = getIntKeyValue(carContext, Constants.DARK_MODE_SETTINGS) @@ -155,9 +170,9 @@ class NavigationSession : Session(), NavigationScreen.Listener { carSensors.addCarHardwareLocationListener( CarSensors.UPDATE_RATE_NORMAL, carContext.mainExecutor, - locationListener + carLocationListener ) - carInfo.addSpeedListener(carContext.mainExecutor, speedListener) + carInfo.addSpeedListener(carContext.mainExecutor, carSpeedListener) } override fun onNewIntent(intent: Intent) { @@ -221,15 +236,15 @@ class NavigationSession : Session(), NavigationScreen.Listener { fun updateLocation(location: Location) { if (routeModel.isNavigating()) { - val snapedLocation = snapLocation(location, routeModel.route.maneuverLocations()) - val distance = location.distanceTo(snapedLocation) + navigationScreen.updateTrip(location) + val wayPointLocation = routeModel.route.currentStep().wayPointLocation + val distance = location.distanceTo(wayPointLocation) if (distance > MAXIMAL_ROUTE_DEVIATION) { navigationScreen.calculateNewRoute(routeModel.routeState.destination) return } - navigationScreen.updateTrip(location) if (distance < MAXIMAL_SNAP_CORRECTION) { - surfaceRenderer.updateLocation(snapedLocation) + surfaceRenderer.updateLocation(wayPointLocation) } else { surfaceRenderer.updateLocation(location) } diff --git a/common/car/src/main/java/com/kouros/navigation/car/SurfaceRenderer.kt b/common/car/src/main/java/com/kouros/navigation/car/SurfaceRenderer.kt index df2453d..7813b3b 100644 --- a/common/car/src/main/java/com/kouros/navigation/car/SurfaceRenderer.kt +++ b/common/car/src/main/java/com/kouros/navigation/car/SurfaceRenderer.kt @@ -5,8 +5,6 @@ import android.graphics.Rect import android.hardware.display.DisplayManager import android.hardware.display.VirtualDisplay import android.location.Location -import android.os.CountDownTimer -import android.os.Handler import android.util.Log import androidx.car.app.AppManager import androidx.car.app.CarContext @@ -31,9 +29,12 @@ import com.kouros.navigation.car.map.cameraState import com.kouros.navigation.car.map.getPaddingValues import com.kouros.navigation.car.map.rememberBaseStyle import com.kouros.navigation.car.navigation.RouteCarModel +import com.kouros.navigation.data.Constants.ROUTING_ENGINE import com.kouros.navigation.data.Constants.homeLocation import com.kouros.navigation.data.ObjectBox +import com.kouros.navigation.data.RouteEngine import com.kouros.navigation.model.RouteModel +import com.kouros.navigation.utils.NavigationUtils.getIntKeyValue import com.kouros.navigation.utils.bearing import com.kouros.navigation.utils.calculateTilt import com.kouros.navigation.utils.calculateZoom @@ -161,7 +162,9 @@ class SurfaceRenderer( fun onConnectionStateUpdated(connectionState: Int) { when (connectionState) { - CarConnection.CONNECTION_TYPE_NATIVE -> ObjectBox.init(carContext) + CarConnection.CONNECTION_TYPE_NOT_CONNECTED -> "Not connected to a head unit" + CarConnection.CONNECTION_TYPE_PROJECTION -> "Connected to Android Auto" + CarConnection.CONNECTION_TYPE_NATIVE -> ObjectBox.init(carContext) // Automotive OS } } @@ -256,44 +259,22 @@ class SurfaceRenderer( ) lastBearing = cameraPosition.value!!.bearing lastLocation = location - //speed.value = location.speed - if (!countDownTimerActive) { - countDownTimerActive = true - val mainThreadHandler = Handler(carContext.mainLooper) - val lastLocationTimer = lastLocation - checkUpdate(mainThreadHandler, lastLocationTimer) - } } } } - private fun checkUpdate( - mainThreadHandler: Handler, - lastLocationTimer: Location - ) { - mainThreadHandler.post { - object : CountDownTimer(3000, 1000) { - override fun onTick(millisUntilFinished: Long) {} - override fun onFinish() { - countDownTimerActive = false - if (lastLocation.time - lastLocationTimer.time < 1500) { - speed.postValue(0F) - } - } - }.start() - } - } - private fun updateCameraPosition(bearing: Double, zoom: Double, target: Position) { - cameraPosition.postValue( - cameraPosition.value!!.copy( - bearing = bearing, - zoom = zoom, - tilt = tilt, - padding = getPaddingValues(height, viewStyle), - target = target + synchronized(this) { + cameraPosition.postValue( + cameraPosition.value!!.copy( + bearing = bearing, + zoom = zoom, + tilt = tilt, + padding = getPaddingValues(height, viewStyle), + target = target + ) ) - ) + } } fun setRouteData() { @@ -316,17 +297,22 @@ class SurfaceRenderer( } fun setCategories(location: Location, route: String) { - viewStyle = ViewStyle.AMENITY_VIEW - routeData.value = route - updateCameraPosition( - 0.0, - 12.0, - target = Position(location.longitude, location.latitude) - ) + synchronized(this) { + viewStyle = ViewStyle.AMENITY_VIEW + routeData.value = route + updateCameraPosition( + 0.0, + 12.0, + target = Position(location.longitude, location.latitude) + ) + } } fun updateCarLocation(location: Location) { - // updateLocation(location) + val routingEngine = getIntKeyValue(carContext, ROUTING_ENGINE) + if (routingEngine == RouteEngine.OSRM.ordinal) { + updateLocation(location) + } } fun updateCarSpeed(newSpeed: Float) { diff --git a/common/car/src/main/java/com/kouros/navigation/car/map/MapView.kt b/common/car/src/main/java/com/kouros/navigation/car/map/MapView.kt index 1a30125..5fd0206 100644 --- a/common/car/src/main/java/com/kouros/navigation/car/map/MapView.kt +++ b/common/car/src/main/java/com/kouros/navigation/car/map/MapView.kt @@ -177,12 +177,12 @@ fun AmenityLayer(routeData: String?) { @Composable fun SpeedCameraLayer(speedCameras: String?) { if (speedCameras != null && speedCameras.isNotEmpty()) { - val color = const(Color.DarkGray) + val color = const(Color.Red) val cameraSource = rememberGeoJsonSource(GeoJsonData.JsonString(speedCameras)) SymbolLayer( id = "speed-camera-layer", source = cameraSource, - iconImage = image(painterResource(R.drawable.speed_camera_48px), drawAsSdf = true), + iconImage = image(painterResource(R.drawable.speed_camera_24px), drawAsSdf = true), iconColor = color, iconSize = interpolate( diff --git a/common/car/src/main/java/com/kouros/navigation/car/navigation/RouteCarModel.kt b/common/car/src/main/java/com/kouros/navigation/car/navigation/RouteCarModel.kt index ce72655..2aadf31 100644 --- a/common/car/src/main/java/com/kouros/navigation/car/navigation/RouteCarModel.kt +++ b/common/car/src/main/java/com/kouros/navigation/car/navigation/RouteCarModel.kt @@ -48,13 +48,10 @@ class RouteCarModel() : RouteModel() { val stepData = currentStep() val currentStepCueWithImage: SpannableString = createString(stepData.instruction) - - val straightNormal = Lane.Builder() .addDirection(LaneDirection.create(LaneDirection.SHAPE_STRAIGHT, false)) .build() - val step = Step.Builder(currentStepCueWithImage) .setManeuver( @@ -65,7 +62,7 @@ class RouteCarModel() : RouteModel() { .setRoad(routeState.destination.street!!) stepData.lane.forEach { if (it.indications.isNotEmpty() ) { - step.setLanesImage(createCarIcon(carContext, R.drawable.lanes)) + step.setLanesImage(createCarIcon(createLaneIcon(carContext, stepData))) step.addLane(straightNormal) } } @@ -139,6 +136,10 @@ class RouteCarModel() : RouteModel() { return CarIcon.Builder(IconCompat.createWithResource(carContext, iconRes)).build() } + fun createCarIcon(iconCompat: IconCompat): CarIcon { + return CarIcon.Builder(iconCompat).build() + } + fun showSpeedCamera(carContext: CarContext, distance: Double, maxSpeed: String?) { carContext.getCarService(AppManager::class.java) .showAlert(createAlert(carContext, distance, maxSpeed)) diff --git a/common/car/src/main/java/com/kouros/navigation/car/screen/NavigationScreen.kt b/common/car/src/main/java/com/kouros/navigation/car/screen/NavigationScreen.kt index 48a0c43..561c9ac 100644 --- a/common/car/src/main/java/com/kouros/navigation/car/screen/NavigationScreen.kt +++ b/common/car/src/main/java/com/kouros/navigation/car/screen/NavigationScreen.kt @@ -15,8 +15,6 @@ import androidx.car.app.model.Distance import androidx.car.app.model.Header import androidx.car.app.model.MessageTemplate import androidx.car.app.model.Template -import androidx.car.app.navigation.model.Lane -import androidx.car.app.navigation.model.LaneDirection import androidx.car.app.navigation.model.Maneuver import androidx.car.app.navigation.model.MapWithContentTemplate import androidx.car.app.navigation.model.MessageInfo @@ -92,12 +90,8 @@ class NavigationScreen( var speedCameras = listOf() val speedObserver = Observer> { cameras -> speedCameras = cameras - val coordinates = mutableListOf>() - val loc = location(0.0, 0.0) cameras.forEach { - val loc = - location(longitude = it.lon!!, latitude = it.lat!!) coordinates.add(listOf(it.lon!!, it.lat!!)) } val speedData = GeoUtils.createPointCollection(coordinates, "radar") @@ -238,22 +232,13 @@ class NavigationScreen( Distance.UNIT_METERS } val nextStep = routeModel.nextStep(carContext = carContext) - if (nextStep != null) { - return RoutingInfo.Builder() - .setCurrentStep( - routeModel.currentStep(carContext = carContext), - Distance.create(currentDistance, displayUnit) - ) - .setNextStep(nextStep) - .build() - } else { - return RoutingInfo.Builder() - .setCurrentStep( - routeModel.currentStep(carContext = carContext), - Distance.create(currentDistance, displayUnit) - ) - .build() - } + return RoutingInfo.Builder() + .setCurrentStep( + routeModel.currentStep(carContext = carContext), + Distance.create(currentDistance, displayUnit) + ) + .setNextStep(nextStep) + .build() } private fun createActionStripBuilder(): ActionStrip.Builder { @@ -350,7 +335,7 @@ class NavigationScreen( return Action.Builder() .setIcon(routeModel.createCarIcon(carContext, R.drawable.settings_48px)) .setOnClickListener { - screenManager.push(SettingsScreen(carContext)) + screenManager.push(SettingsScreen(carContext, viewModel)) } .build() } @@ -466,7 +451,7 @@ class NavigationScreen( } fun updateTrip(location: Location) { - updateSpeedCamera(location) + updateSpeedCamera(surfaceRenderer.lastLocation) with(routeModel) { updateLocation(location, viewModel) if (routeState.maneuverType == Maneuver.TYPE_DESTINATION diff --git a/common/car/src/main/java/com/kouros/navigation/car/screen/NavigationSettings.kt b/common/car/src/main/java/com/kouros/navigation/car/screen/NavigationSettings.kt index 1e36110..042aca2 100644 --- a/common/car/src/main/java/com/kouros/navigation/car/screen/NavigationSettings.kt +++ b/common/car/src/main/java/com/kouros/navigation/car/screen/NavigationSettings.kt @@ -12,11 +12,12 @@ import androidx.car.app.model.Toggle import com.kouros.data.R import com.kouros.navigation.data.Constants.AVOID_MOTORWAY import com.kouros.navigation.data.Constants.AVOID_TOLLWAY +import com.kouros.navigation.model.ViewModel import com.kouros.navigation.utils.NavigationUtils.getBooleanKeyValue import com.kouros.navigation.utils.NavigationUtils.setBooleanKeyValue -class NavigationSettings(private val carContext: CarContext) : Screen(carContext) { +class NavigationSettings(private val carContext: CarContext, private var viewModel: ViewModel) : Screen(carContext) { private var motorWayToggleState = false @@ -52,7 +53,12 @@ class NavigationSettings(private val carContext: CarContext) : Screen(carContext tollWayToggleState = !tollWayToggleState }.setChecked(tollWayToggleState).build() listBuilder.addItem(buildRowForTemplate(R.string.avoid_tolls_row_title, tollwayToggle)) - + listBuilder.addItem( + buildRowForScreenTemplate( + RoutingSettings(carContext, viewModel), + R.string.routing_engine + ) + ) return ListTemplate.Builder() .setSingleList(listBuilder.build()) .setHeader( @@ -70,4 +76,12 @@ class NavigationSettings(private val carContext: CarContext) : Screen(carContext .setToggle(toggle) .build() } + + private fun buildRowForScreenTemplate(screen: Screen, title: Int): Row { + return Row.Builder() + .setTitle(carContext.getString(title)) + .setOnClickListener { screenManager.push(screen) } + .setBrowsable(true) + .build() + } } \ No newline at end of file diff --git a/common/car/src/main/java/com/kouros/navigation/car/screen/RoutePreviewScreen.kt b/common/car/src/main/java/com/kouros/navigation/car/screen/RoutePreviewScreen.kt index 7ca4558..7a2db84 100644 --- a/common/car/src/main/java/com/kouros/navigation/car/screen/RoutePreviewScreen.kt +++ b/common/car/src/main/java/com/kouros/navigation/car/screen/RoutePreviewScreen.kt @@ -80,7 +80,6 @@ class RoutePreviewScreen( val header = Header.Builder() .setStartHeaderAction(Action.BACK) .setTitle(carContext.getString(R.string.route_preview)) - //.addEndHeaderAction(navigateAction) .addEndHeaderAction( favoriteAction() ) diff --git a/common/car/src/main/java/com/kouros/navigation/car/screen/RoutingSettings.kt b/common/car/src/main/java/com/kouros/navigation/car/screen/RoutingSettings.kt new file mode 100644 index 0000000..90cdede --- /dev/null +++ b/common/car/src/main/java/com/kouros/navigation/car/screen/RoutingSettings.kt @@ -0,0 +1,81 @@ +package com.kouros.navigation.car.screen + +import androidx.car.app.CarContext +import androidx.car.app.CarToast +import androidx.car.app.Screen +import androidx.car.app.model.Action +import androidx.car.app.model.Header +import androidx.car.app.model.ItemList +import androidx.car.app.model.ListTemplate +import androidx.car.app.model.Row +import androidx.car.app.model.SectionedItemList +import androidx.car.app.model.Template +import com.kouros.data.R +import com.kouros.navigation.data.Constants.ROUTING_ENGINE +import com.kouros.navigation.data.RouteEngine +import com.kouros.navigation.model.ViewModel +import com.kouros.navigation.utils.NavigationUtils.getIntKeyValue +import com.kouros.navigation.utils.NavigationUtils.setIntKeyValue + +class RoutingSettings(private val carContext: CarContext, private var viewModel: ViewModel) : Screen(carContext) { + private var routingEngine = RouteEngine.VALHALLA.ordinal + + init { + routingEngine = getIntKeyValue(carContext, ROUTING_ENGINE) + } + + override fun onGetTemplate(): Template { + val templateBuilder = ListTemplate.Builder() + val radioList = + ItemList.Builder() + .addItem( + buildRowForTemplate( + R.string.valhalla, + ) + ) + .addItem( + buildRowForTemplate( + R.string.osrm, + ) + ) + .setOnSelectedListener { index: Int -> + this.onSelected(index) + } + .setSelectedIndex(routingEngine) + .build() + + return templateBuilder + .addSectionedList(SectionedItemList.create( + radioList, + carContext.getString(R.string.routing_engine) + )) + .setHeader( + Header.Builder() + .setTitle(carContext.getString(R.string.routing_engine)) + .setStartHeaderAction(Action.BACK) + .build() + ) + .build() + } + + + private fun onSelected(index: Int) { + setIntKeyValue(carContext, index, ROUTING_ENGINE) + viewModel.routingEngine.value = index + CarToast.makeText( + carContext, + (carContext + .getString(R.string.routing_engine) + + ":" + + " " + index), CarToast.LENGTH_LONG + ) + .show() + } + + private fun buildRowForTemplate(title: Int): Row { + return Row.Builder() + .setTitle(carContext.getString(title)) + .build() + } + +} \ No newline at end of file diff --git a/common/car/src/main/java/com/kouros/navigation/car/screen/SettingsScreen.kt b/common/car/src/main/java/com/kouros/navigation/car/screen/SettingsScreen.kt index 644dad8..7c2be97 100644 --- a/common/car/src/main/java/com/kouros/navigation/car/screen/SettingsScreen.kt +++ b/common/car/src/main/java/com/kouros/navigation/car/screen/SettingsScreen.kt @@ -24,10 +24,12 @@ import androidx.car.app.model.ListTemplate import androidx.car.app.model.Row import androidx.car.app.model.Template import com.kouros.data.R +import com.kouros.navigation.model.ViewModel /** A screen demonstrating selectable lists. */ class SettingsScreen( carContext: CarContext, + private var viewModel: ViewModel, ) : Screen(carContext) { override fun onGetTemplate(): Template { @@ -40,7 +42,7 @@ class SettingsScreen( ) listBuilder.addItem( buildRowForTemplate( - NavigationSettings(carContext), + NavigationSettings(carContext, viewModel), R.string.navigation_settings ) ) diff --git a/common/data/src/main/java/com/kouros/navigation/data/Data.kt b/common/data/src/main/java/com/kouros/navigation/data/Data.kt index 8f7c368..ea3ea24 100644 --- a/common/data/src/main/java/com/kouros/navigation/data/Data.kt +++ b/common/data/src/main/java/com/kouros/navigation/data/Data.kt @@ -174,6 +174,8 @@ object Constants { const val AVOID_TOLLWAY = "AvoidTollway" + const val ROUTING_ENGINE = "RoutingEngine" + const val NEXT_STEP_THRESHOLD = 100.0 const val MAXIMAL_SNAP_CORRECTION = 50.0 @@ -182,7 +184,6 @@ object Constants { const val DESTINATION_ARRIVAL_DISTANCE = 40.0 - val ROUTE_ENGINE = RouteEngine.VALHALLA.name } diff --git a/common/data/src/main/java/com/kouros/navigation/data/NavigationRepository.kt b/common/data/src/main/java/com/kouros/navigation/data/NavigationRepository.kt index e852219..9b5ac38 100644 --- a/common/data/src/main/java/com/kouros/navigation/data/NavigationRepository.kt +++ b/common/data/src/main/java/com/kouros/navigation/data/NavigationRepository.kt @@ -30,8 +30,6 @@ import kotlinx.serialization.json.Json abstract class NavigationRepository { - private val placesUrl = "https://kouros-online.de/maps/placespwd"; - private val nominatimUrl = "https://nominatim.openstreetmap.org/" @@ -58,27 +56,6 @@ abstract class NavigationRepository { return fetchUrl("${nominatimUrl}reverse?lat=${location.latitude}&lon=${location.longitude}&format=jsonv2&addressdetails=true&countrycodes=de", false) } - fun getPlaces(): List { - val places: MutableList = ArrayList() - val placesStr = fetchUrl(placesUrl, true) - val jArray = JSONArray(placesStr) - for (i in 0.. { newType = androidx.car.app.navigation.model.Maneuver.TYPE_STRAIGHT } - ManeuverType.turn.value -> { + ManeuverType.turn.value, + ManeuverType.endOfRoad.value -> { if (maneuver.modifier == "right") { newType = androidx.car.app.navigation.model.Maneuver.TYPE_TURN_NORMAL_RIGHT } } - ManeuverType.turn.value -> { + ManeuverType.turn.value, + ManeuverType.endOfRoad.value, + ManeuverType.onRamp.value + -> { if (maneuver.modifier == "left") { newType = androidx.car.app.navigation.model.Maneuver.TYPE_TURN_NORMAL_LEFT } } + ManeuverType.fork.value + -> { + if (maneuver.modifier == "slight left") { + newType = androidx.car.app.navigation.model.Maneuver.TYPE_TURN_SLIGHT_LEFT + } + } + ManeuverType.fork.value + -> { + if (maneuver.modifier == "slight right") { + newType = androidx.car.app.navigation.model.Maneuver.TYPE_TURN_SLIGHT_RIGHT + } + } } + return newType } } diff --git a/common/data/src/main/java/com/kouros/navigation/data/overpass/Overpass.kt b/common/data/src/main/java/com/kouros/navigation/data/overpass/Overpass.kt index fe1845b..5d797e3 100644 --- a/common/data/src/main/java/com/kouros/navigation/data/overpass/Overpass.kt +++ b/common/data/src/main/java/com/kouros/navigation/data/overpass/Overpass.kt @@ -64,18 +64,20 @@ class Overpass { } fun overpassApi(httpURLConnection: HttpURLConnection, searchQuery: String) : List { - val outputStreamWriter = OutputStreamWriter(httpURLConnection.outputStream) - outputStreamWriter.write(searchQuery) - outputStreamWriter.flush() - // Check if the connection is successful - val responseCode = httpURLConnection.responseCode - if (responseCode == HttpURLConnection.HTTP_OK) { - val response = httpURLConnection.inputStream.bufferedReader() - .use { it.readText() } // defaults to UTF-8 - val gson = GsonBuilder().serializeNulls().create() - val overpass = gson.fromJson(response, Amenity::class.java) - // println("Overpass: $response") - return overpass.elements + try { + val outputStreamWriter = OutputStreamWriter(httpURLConnection.outputStream) + outputStreamWriter.write(searchQuery) + outputStreamWriter.flush() + // Check if the connection is successful + val responseCode = httpURLConnection.responseCode + if (responseCode == HttpURLConnection.HTTP_OK) { + val response = httpURLConnection.inputStream.bufferedReader() + .use { it.readText() } // defaults to UTF-8 + val gson = GsonBuilder().serializeNulls().create() + val overpass = gson.fromJson(response, Amenity::class.java) + return overpass.elements + } + } catch (e: Exception) { } return emptyList() } diff --git a/common/data/src/main/java/com/kouros/navigation/data/route/Step.kt b/common/data/src/main/java/com/kouros/navigation/data/route/Step.kt index f54853d..709ff1d 100644 --- a/common/data/src/main/java/com/kouros/navigation/data/route/Step.kt +++ b/common/data/src/main/java/com/kouros/navigation/data/route/Step.kt @@ -1,8 +1,12 @@ package com.kouros.navigation.data.route +import android.location.Location +import com.kouros.navigation.utils.location + data class Step( var index : Int = 0, var waypointIndex : Int = 0, + var wayPointLocation : Location = location(0.0,0.0), val maneuver: Maneuver, val duration: Double = 0.0, val distance: Double = 0.0, diff --git a/common/data/src/main/java/com/kouros/navigation/data/valhalla/ValhallaRoute.kt b/common/data/src/main/java/com/kouros/navigation/data/valhalla/ValhallaRoute.kt index 438ffdd..2a6e18d 100644 --- a/common/data/src/main/java/com/kouros/navigation/data/valhalla/ValhallaRoute.kt +++ b/common/data/src/main/java/com/kouros/navigation/data/valhalla/ValhallaRoute.kt @@ -1,8 +1,10 @@ package com.kouros.navigation.data.valhalla +import androidx.car.app.navigation.model.Maneuver +import com.kouros.data.R import com.kouros.navigation.data.Route import com.kouros.navigation.data.route.Leg -import com.kouros.navigation.data.route.Maneuver +import com.kouros.navigation.data.route.Maneuver as RouteManeuver import com.kouros.navigation.data.route.Step import com.kouros.navigation.data.route.Summary import com.kouros.navigation.utils.GeoUtils.createLineStringCollection @@ -18,10 +20,11 @@ class ValhallaRoute { val steps = mutableListOf() var stepIndex = 0 routeJson.legs[0].maneuvers.forEach { - val maneuver = Maneuver( + val maneuver = RouteManeuver( bearingBefore = 0, bearingAfter = it.bearingAfter, - type = it.type, + //type = it.type, + type = convertType(it), waypoints =waypoints.subList(it.beginShapeIndex, it.endShapeIndex+1) ) var name = "" @@ -40,4 +43,56 @@ class ValhallaRoute { .legs(listOf(leg)) .waypoints(waypoints) } + + fun convertType(maneuver: Maneuvers): Int { + var newType = 0 + when (maneuver.type) { + ManeuverType.None.value -> { + newType = Maneuver.TYPE_STRAIGHT + } + ManeuverType.Destination.value, + ManeuverType.DestinationRight.value, + ManeuverType.DestinationLeft.value, + -> { + newType = Maneuver.TYPE_DESTINATION + } + + ManeuverType.Right.value -> { + newType = Maneuver.TYPE_TURN_NORMAL_RIGHT + } + + ManeuverType.Left.value -> { + newType = Maneuver.TYPE_TURN_NORMAL_LEFT + } + + ManeuverType.RampRight.value -> { + newType = Maneuver.TYPE_OFF_RAMP_SLIGHT_RIGHT + } + + ManeuverType.RampLeft.value -> { + newType = Maneuver.TYPE_OFF_RAMP_SLIGHT_LEFT + } + + ManeuverType.ExitRight.value -> { + newType = Maneuver.TYPE_TURN_SLIGHT_RIGHT + } + + ManeuverType.StayRight.value -> { + newType = Maneuver.TYPE_KEEP_RIGHT + } + + ManeuverType.StayLeft.value -> { + newType = Maneuver.TYPE_KEEP_LEFT + } + + ManeuverType.RoundaboutEnter.value -> { + newType = Maneuver.TYPE_ROUNDABOUT_ENTER_CCW + } + + ManeuverType.RoundaboutExit.value -> { + newType = Maneuver.TYPE_ROUNDABOUT_EXIT_CCW + } + } + return newType + } } \ No newline at end of file diff --git a/common/data/src/main/java/com/kouros/navigation/model/RouteModel.kt b/common/data/src/main/java/com/kouros/navigation/model/RouteModel.kt index 4667167..fa42b8e 100644 --- a/common/data/src/main/java/com/kouros/navigation/model/RouteModel.kt +++ b/common/data/src/main/java/com/kouros/navigation/model/RouteModel.kt @@ -1,28 +1,31 @@ package com.kouros.navigation.model import android.content.Context +import android.graphics.Bitmap +import android.graphics.BitmapFactory +import android.graphics.Canvas +import android.graphics.Matrix import android.location.Location import androidx.car.app.navigation.model.Maneuver import androidx.car.app.navigation.model.Step +import androidx.core.graphics.createBitmap +import androidx.core.graphics.drawable.IconCompat import com.kouros.data.R import com.kouros.navigation.data.Constants.NEXT_STEP_THRESHOLD -import com.kouros.navigation.data.Constants.ROUTE_ENGINE -import com.kouros.navigation.data.valhalla.ManeuverType +import com.kouros.navigation.data.Constants.ROUTING_ENGINE import com.kouros.navigation.data.Place import com.kouros.navigation.data.Route -import com.kouros.navigation.data.RouteEngine import com.kouros.navigation.data.StepData import com.kouros.navigation.data.route.Intersection import com.kouros.navigation.data.route.Lane import com.kouros.navigation.data.route.Leg +import com.kouros.navigation.data.valhalla.ManeuverType +import com.kouros.navigation.utils.GeoUtils.createCenterLocation import com.kouros.navigation.utils.NavigationUtils.getIntKeyValue import com.kouros.navigation.utils.location import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.GlobalScope -import kotlinx.coroutines.coroutineScope -import kotlinx.coroutines.invoke import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking import java.util.concurrent.TimeUnit @@ -40,6 +43,8 @@ open class RouteModel() { val lastSpeedIndex: Int = 0, val maxSpeed: Int = 0, val location: Location = location(0.0, 0.0), + val lastLocation: Location = location(0.0, 0.0), + val bearing : Float = 0F ) var routeState = RouteState() @@ -55,11 +60,14 @@ open class RouteModel() { get() = routeState.route!!.legs!!.first() fun startNavigation(routeString: String, context: Context) { - val routeEngine = getIntKeyValue(context = context, ROUTE_ENGINE) - val newRoute = Route.Builder() + val routeEngine = getIntKeyValue(context = context, ROUTING_ENGINE) + var newRoute = Route.Builder() .routeEngine(routeEngine) .route(routeString) .build() + // TODO: + newRoute = newRoute.copy(centerLocation = createCenterLocation(newRoute.routeGeoJson)) + println("Route ${newRoute.centerLocation}") this.routeState = routeState.copy( route = newRoute, isNavigating = true @@ -80,6 +88,7 @@ open class RouteModel() { routeState = routeState.copy(location = location) findStep(location) updateSpeedLimit(location, viewModel) + } private fun findStep(location: Location) { @@ -93,6 +102,9 @@ open class RouteModel() { nearestDistance = distance route.currentStep = step.index step.waypointIndex = wayIndex + step.wayPointLocation = location(waypoint[0], waypoint[1]) + val bearing = routeState.lastLocation.bearingTo(location) + this.routeState = routeState.copy(lastLocation = location, bearing = bearing) } } if (nearestDistance == 0F) { @@ -104,11 +116,9 @@ open class RouteModel() { break } } - //println("Current Index ${route.currentStep} WayPoint: ${route.currentStep().waypointIndex}") } private fun currentIntersection(location: Location): Intersection { - var inter = Intersection() var nearestDistance = 100000.0f route.currentStep().intersection.forEach { @@ -120,6 +130,7 @@ open class RouteModel() { } return inter } + fun updateSpeedLimit(location: Location, viewModel: ViewModel) = runBlocking { CoroutineScope(Dispatchers.IO).launch { // speed limit @@ -150,7 +161,7 @@ open class RouteModel() { var maneuverType = if (hasArrived(currentStep.maneuver.type)) { currentStep.maneuver.type } else { - ManeuverType.None.value + Maneuver.TYPE_STRAIGHT } // Get the single, correct maneuver for this state val relevantStep = if (shouldAdvance) { @@ -187,6 +198,7 @@ open class RouteModel() { when (distanceLeft) { in 0.0..NEXT_STEP_THRESHOLD -> { } + else -> { if (step.name.isNotEmpty()) { text = step.name @@ -262,68 +274,49 @@ open class RouteModel() { } fun maneuverIcon(routeManeuverType: Int): (Pair) { - var type = Maneuver.TYPE_DEPART var currentTurnIcon = R.drawable.ic_turn_name_change when (routeManeuverType) { - ManeuverType.None.value -> { - type = Maneuver.TYPE_STRAIGHT + Maneuver.TYPE_STRAIGHT -> { currentTurnIcon = R.drawable.ic_turn_name_change } - ManeuverType.Destination.value, - ManeuverType.DestinationRight.value, - ManeuverType.DestinationLeft.value, + Maneuver.TYPE_DESTINATION, -> { - type = Maneuver.TYPE_DESTINATION currentTurnIcon = R.drawable.ic_turn_destination } - ManeuverType.Right.value -> { - type = Maneuver.TYPE_TURN_NORMAL_RIGHT + Maneuver.TYPE_TURN_NORMAL_RIGHT -> { currentTurnIcon = R.drawable.ic_turn_normal_right } - ManeuverType.Left.value -> { - type = Maneuver.TYPE_TURN_NORMAL_LEFT + Maneuver.TYPE_TURN_NORMAL_LEFT -> { currentTurnIcon = R.drawable.ic_turn_normal_left } - ManeuverType.RampRight.value -> { - type = Maneuver.TYPE_OFF_RAMP_SLIGHT_RIGHT + Maneuver.TYPE_OFF_RAMP_SLIGHT_RIGHT -> { currentTurnIcon = R.drawable.ic_turn_slight_right } - ManeuverType.RampLeft.value -> { - type = Maneuver.TYPE_TURN_NORMAL_LEFT - currentTurnIcon = R.drawable.ic_turn_normal_left - } - - ManeuverType.ExitRight.value -> { - type = Maneuver.TYPE_TURN_SLIGHT_RIGHT + Maneuver.TYPE_TURN_SLIGHT_RIGHT -> { currentTurnIcon = R.drawable.ic_turn_slight_right } - ManeuverType.StayRight.value -> { - type = Maneuver.TYPE_KEEP_RIGHT + Maneuver.TYPE_KEEP_RIGHT -> { currentTurnIcon = R.drawable.ic_turn_name_change } - - ManeuverType.StayLeft.value -> { - type = Maneuver.TYPE_KEEP_LEFT + Maneuver.TYPE_KEEP_LEFT -> { currentTurnIcon = R.drawable.ic_turn_name_change } - - ManeuverType.RoundaboutEnter.value -> { - type = Maneuver.TYPE_ROUNDABOUT_ENTER_CCW + Maneuver.TYPE_ROUNDABOUT_ENTER_CCW -> { currentTurnIcon = R.drawable.ic_roundabout_ccw } - ManeuverType.RoundaboutExit.value -> { - type = Maneuver.TYPE_ROUNDABOUT_EXIT_CCW + Maneuver.TYPE_ROUNDABOUT_EXIT_CCW -> { + currentTurnIcon = R.drawable.ic_roundabout_ccw } } - return Pair(type, currentTurnIcon) + return Pair(routeManeuverType, currentTurnIcon) } fun isNavigating(): Boolean { @@ -336,4 +329,79 @@ open class RouteModel() { || type == ManeuverType.Destination.value || type == ManeuverType.DestinationLeft.value } + + fun createLaneIcon(context: Context, stepData: StepData): IconCompat { + val bitmaps = mutableListOf() + stepData.lane.forEach { + if (it.indications.isNotEmpty()) { + it.indications.forEach { it2 -> + val resource = laneToResource(it2, it, stepData) + if (it2 != "none") { + println("Direction $resource") + if (resource.isNotEmpty()) { + val id = resourceId( resource); + val bitMap = BitmapFactory.decodeResource(context.resources, id) + bitmaps.add(bitMap) + } + } + } + } + } + return IconCompat.createWithBitmap(overlay(bitmaps = bitmaps)) + } + + + fun overlay(bitmaps: List): Bitmap { + val matrix = Matrix() + if (bitmaps.size == 1) { + return bitmaps.first() + } + val bmOverlay = createBitmap( + bitmaps.first().getWidth() * bitmaps.size, + bitmaps.first().getHeight(), + bitmaps.first().getConfig()!! + ) + val canvas = Canvas(bmOverlay) + canvas.drawBitmap(bitmaps.first(), matrix, null) + var i = 0 + bitmaps.forEach { + if (i > 0) { + matrix.setTranslate(i * 40F, 0F) + canvas.drawBitmap(it, matrix, null) + } + i++ + } + return bmOverlay + } + + private fun laneToResource(direction: String, lane: Lane, stepData: StepData): String { + println("Maneuver ${stepData.maneuverType}") + return when (val direction = direction.replace(" ", "_")) { + "left" -> if (stepData.maneuverType == Maneuver.TYPE_TURN_NORMAL_LEFT) "${direction}_valid" else "${direction}_not_valid" + "right" -> if (stepData.maneuverType == Maneuver.TYPE_TURN_NORMAL_RIGHT) "${direction}_valid" else "${direction}_not_valid" + "straight" -> if (stepData.maneuverType == Maneuver.TYPE_STRAIGHT) "${direction}_valid" else "${direction}_not_valid" + "slight_right" -> if (stepData.maneuverType == Maneuver.TYPE_TURN_SLIGHT_RIGHT) "${direction}_valid" else "${direction}_not_valid" + "slight_left" -> if (stepData.maneuverType == Maneuver.TYPE_TURN_SLIGHT_LEFT) "${direction}_valid" else "${direction}_not_valid" + else -> {""} + } + } + + fun resourceId( + variableName: String, + ): Int { + return when(variableName) { + "left_not_valid" -> R.drawable.left_not_valid + "left_valid" -> R.drawable.left_valid + "left_valid_right_not_valid" -> R.drawable.left_valid_right_not_valid + "right_not_valid" -> R.drawable.right_not_valid + "right_valid" -> R.drawable.right_valid + "slight_right_not_valid" -> R.drawable.slight_right_not_valid + "slight_right_valid" -> R.drawable.slight_right_valid + "straight_not_valid" -> R.drawable.straight_not_valid + "straight_not_valid_right_valid" -> R.drawable.straight_not_valid_right_valid + "straight_valid" -> R.drawable.straight_valid + else -> {R.drawable.ic_close_white_24dp} + } + } + } \ No newline at end of file diff --git a/common/data/src/main/java/com/kouros/navigation/model/ViewModel.kt b/common/data/src/main/java/com/kouros/navigation/model/ViewModel.kt index 86d0ac4..9bd52d0 100644 --- a/common/data/src/main/java/com/kouros/navigation/model/ViewModel.kt +++ b/common/data/src/main/java/com/kouros/navigation/model/ViewModel.kt @@ -67,6 +67,11 @@ class ViewModel(private val repository: NavigationRepository) : ViewModel() { MutableLiveData() } + val routingEngine: MutableLiveData by lazy { + MutableLiveData() + } + + fun loadRecentPlace(location: Location, context: Context) { viewModelScope.launch(Dispatchers.IO) { try { diff --git a/common/data/src/main/java/com/kouros/navigation/utils/NavigationUtils.kt b/common/data/src/main/java/com/kouros/navigation/utils/NavigationUtils.kt index ffa9035..ddbaafb 100644 --- a/common/data/src/main/java/com/kouros/navigation/utils/NavigationUtils.kt +++ b/common/data/src/main/java/com/kouros/navigation/utils/NavigationUtils.kt @@ -4,7 +4,7 @@ import android.content.Context import android.location.Location import android.location.LocationManager import androidx.core.content.edit -import com.kouros.navigation.data.Constants.ROUTE_ENGINE +import com.kouros.navigation.data.Constants.ROUTING_ENGINE import com.kouros.navigation.data.Constants.SHARED_PREF_KEY import com.kouros.navigation.data.RouteEngine import com.kouros.navigation.data.osrm.OsrmRepository @@ -26,7 +26,7 @@ import kotlin.time.Duration.Companion.seconds object NavigationUtils { fun getRouteEngine(context: Context): ViewModel { - val routeEngine = getIntKeyValue(context = context, ROUTE_ENGINE) + val routeEngine = getIntKeyValue(context = context, ROUTING_ENGINE) return when (routeEngine) { RouteEngine.VALHALLA.ordinal -> ViewModel(ValhallaRepository()) else -> ViewModel(OsrmRepository()) diff --git a/common/data/src/main/res/drawable/lanes_leftleftssr.png b/common/data/src/main/res/drawable/lanes_leftleftssr.png new file mode 100644 index 0000000..3eb9921 Binary files /dev/null and b/common/data/src/main/res/drawable/lanes_leftleftssr.png differ diff --git a/common/data/src/main/res/drawable/lanes_ssr.png b/common/data/src/main/res/drawable/lanes_ssr.png new file mode 100644 index 0000000..f953351 Binary files /dev/null and b/common/data/src/main/res/drawable/lanes_ssr.png differ diff --git a/common/data/src/main/res/drawable/left_not_valid.png b/common/data/src/main/res/drawable/left_not_valid.png new file mode 100644 index 0000000..21d0752 Binary files /dev/null and b/common/data/src/main/res/drawable/left_not_valid.png differ diff --git a/common/data/src/main/res/drawable/left_valid.png b/common/data/src/main/res/drawable/left_valid.png new file mode 100644 index 0000000..1cfd533 Binary files /dev/null and b/common/data/src/main/res/drawable/left_valid.png differ diff --git a/common/data/src/main/res/drawable/left_valid_right_not_valid.png b/common/data/src/main/res/drawable/left_valid_right_not_valid.png new file mode 100644 index 0000000..3b5159a Binary files /dev/null and b/common/data/src/main/res/drawable/left_valid_right_not_valid.png differ diff --git a/common/data/src/main/res/drawable/right_not_valid.png b/common/data/src/main/res/drawable/right_not_valid.png new file mode 100644 index 0000000..158a6da Binary files /dev/null and b/common/data/src/main/res/drawable/right_not_valid.png differ diff --git a/common/data/src/main/res/drawable/right_valid.png b/common/data/src/main/res/drawable/right_valid.png new file mode 100644 index 0000000..7e7d420 Binary files /dev/null and b/common/data/src/main/res/drawable/right_valid.png differ diff --git a/common/data/src/main/res/drawable/slight_right_not_valid.png b/common/data/src/main/res/drawable/slight_right_not_valid.png new file mode 100644 index 0000000..158a6da Binary files /dev/null and b/common/data/src/main/res/drawable/slight_right_not_valid.png differ diff --git a/common/data/src/main/res/drawable/slight_right_valid.png b/common/data/src/main/res/drawable/slight_right_valid.png new file mode 100644 index 0000000..7e7d420 Binary files /dev/null and b/common/data/src/main/res/drawable/slight_right_valid.png differ diff --git a/common/data/src/main/res/drawable/speed_camera_24px.xml b/common/data/src/main/res/drawable/speed_camera_24px.xml new file mode 100644 index 0000000..1c3b8e8 --- /dev/null +++ b/common/data/src/main/res/drawable/speed_camera_24px.xml @@ -0,0 +1,10 @@ + + + diff --git a/common/data/src/main/res/drawable/straight_not_valid.png b/common/data/src/main/res/drawable/straight_not_valid.png new file mode 100644 index 0000000..f913be1 Binary files /dev/null and b/common/data/src/main/res/drawable/straight_not_valid.png differ diff --git a/common/data/src/main/res/drawable/straight_not_valid_right_valid.png b/common/data/src/main/res/drawable/straight_not_valid_right_valid.png new file mode 100644 index 0000000..70188f1 Binary files /dev/null and b/common/data/src/main/res/drawable/straight_not_valid_right_valid.png differ diff --git a/common/data/src/main/res/drawable/straight_valid.png b/common/data/src/main/res/drawable/straight_valid.png new file mode 100644 index 0000000..58d73fb Binary files /dev/null and b/common/data/src/main/res/drawable/straight_valid.png differ diff --git a/common/data/src/main/res/values/strings.xml b/common/data/src/main/res/values/strings.xml index 7bb0ec6..38bb54d 100644 --- a/common/data/src/main/res/values/strings.xml +++ b/common/data/src/main/res/values/strings.xml @@ -30,4 +30,7 @@ Reject OK Search + Valhalla + Osrm + Routing engine \ No newline at end of file