Speed radar
This commit is contained in:
@@ -180,6 +180,7 @@ class NavigationSession : Session(), NavigationScreen.Listener {
|
||||
routeModel.stopNavigation()
|
||||
}
|
||||
|
||||
|
||||
companion object {
|
||||
var uriHost: String = "navigation"
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ import com.kouros.navigation.data.Constants
|
||||
import com.kouros.navigation.data.ObjectBox
|
||||
import com.kouros.navigation.model.RouteModel
|
||||
import com.kouros.navigation.utils.bearing
|
||||
import com.kouros.navigation.utils.calcTilt
|
||||
import com.kouros.navigation.utils.calculateTilt
|
||||
import com.kouros.navigation.utils.calculateZoom
|
||||
import com.kouros.navigation.utils.duration
|
||||
import com.kouros.navigation.utils.location
|
||||
@@ -225,7 +225,7 @@ class SurfaceRenderer(
|
||||
} else {
|
||||
cameraPosition.value!!.zoom + 1.0
|
||||
}
|
||||
tilt = calcTilt(newZoom, tilt)
|
||||
tilt = calculateTilt(newZoom, tilt)
|
||||
updateCameraPosition(
|
||||
cameraPosition.value!!.bearing,
|
||||
newZoom,
|
||||
@@ -310,7 +310,7 @@ class SurfaceRenderer(
|
||||
}
|
||||
|
||||
fun setCategories(location: Location, route: String) {
|
||||
viewStyle = ViewStyle.SEARCH_VIEW
|
||||
viewStyle = ViewStyle.AMENITY_VIEW
|
||||
routeData.value = route
|
||||
updateCameraPosition(
|
||||
0.0,
|
||||
@@ -319,14 +319,13 @@ class SurfaceRenderer(
|
||||
)
|
||||
}
|
||||
|
||||
fun setCategoryLocation(location: Location) {
|
||||
viewStyle = ViewStyle.SEARCH_VIEW
|
||||
fun setCategoryLocation(location: Location, category: String) {
|
||||
viewStyle = ViewStyle.AMENITY_VIEW
|
||||
cameraPosition.postValue(
|
||||
cameraPosition.value!!.copy(
|
||||
target = Position(location.longitude, location.latitude)
|
||||
)
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
companion
|
||||
@@ -337,6 +336,6 @@ class SurfaceRenderer(
|
||||
|
||||
|
||||
enum class ViewStyle {
|
||||
VIEW, PREVIEW, PAN_VIEW, SEARCH_VIEW
|
||||
VIEW, PREVIEW, PAN_VIEW, AMENITY_VIEW
|
||||
|
||||
}
|
||||
@@ -33,16 +33,18 @@ import com.kouros.navigation.data.RouteColor
|
||||
import com.kouros.navigation.data.SpeedColor
|
||||
import com.kouros.navigation.utils.NavigationUtils.getBooleanKeyValue
|
||||
import com.kouros.navigation.utils.NavigationUtils.getIntKeyValue
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.json.JsonObject
|
||||
import org.maplibre.compose.camera.CameraPosition
|
||||
import org.maplibre.compose.camera.CameraState
|
||||
import org.maplibre.compose.camera.rememberCameraState
|
||||
import org.maplibre.compose.expressions.dsl.const
|
||||
import org.maplibre.compose.expressions.dsl.contains
|
||||
import org.maplibre.compose.expressions.dsl.exponential
|
||||
import org.maplibre.compose.expressions.dsl.image
|
||||
import org.maplibre.compose.expressions.dsl.interpolate
|
||||
import org.maplibre.compose.expressions.dsl.zoom
|
||||
import org.maplibre.compose.layers.Anchor
|
||||
import org.maplibre.compose.layers.CircleLayer
|
||||
import org.maplibre.compose.layers.FillLayer
|
||||
import org.maplibre.compose.layers.LineLayer
|
||||
import org.maplibre.compose.layers.SymbolLayer
|
||||
@@ -58,9 +60,15 @@ import org.maplibre.compose.sources.Source
|
||||
import org.maplibre.compose.sources.getBaseSource
|
||||
import org.maplibre.compose.sources.rememberGeoJsonSource
|
||||
import org.maplibre.compose.style.BaseStyle
|
||||
import org.maplibre.geojson.FeatureCollection
|
||||
import org.maplibre.spatialk.geojson.BoundingBox.Companion.serializer
|
||||
import org.maplibre.spatialk.geojson.Feature
|
||||
import org.maplibre.spatialk.geojson.FeatureCollection
|
||||
import org.maplibre.spatialk.geojson.GeoJson
|
||||
import org.maplibre.spatialk.geojson.Geometry
|
||||
import org.maplibre.spatialk.geojson.Position
|
||||
import org.maplibre.spatialk.geojson.dsl.FeatureBuilder
|
||||
import org.maplibre.spatialk.geojson.dsl.FeatureCollectionBuilder
|
||||
import org.maplibre.spatialk.geojson.dsl.buildFeatureCollection
|
||||
|
||||
|
||||
@Composable
|
||||
@@ -103,19 +111,22 @@ fun MapLibre(
|
||||
if (!getBooleanKeyValue(context = context, SHOW_THREED_BUILDING)) {
|
||||
BuildingLayer(tiles)
|
||||
}
|
||||
RouteLayer(route, viewStyle)
|
||||
if (viewStyle == ViewStyle.AMENITY_VIEW) {
|
||||
AmenityLayer(route)
|
||||
} else {
|
||||
RouteLayer(route)
|
||||
}
|
||||
}
|
||||
//Puck(cameraState, lastLocation)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun RouteLayer(routeData: String?, viewStyle: ViewStyle) {
|
||||
fun RouteLayer(routeData: String?) {
|
||||
if (routeData != null && routeData.isNotEmpty()) {
|
||||
val routes = rememberGeoJsonSource(GeoJsonData.JsonString(routeData))
|
||||
if (viewStyle == ViewStyle.VIEW) {
|
||||
LineLayer(
|
||||
id = "routes-casing$viewStyle",
|
||||
id = "routes-casing",
|
||||
source = routes,
|
||||
color = const(Color.White),
|
||||
width =
|
||||
@@ -129,7 +140,7 @@ fun RouteLayer(routeData: String?, viewStyle: ViewStyle) {
|
||||
),
|
||||
)
|
||||
LineLayer(
|
||||
id = "routes$viewStyle",
|
||||
id = "routes",
|
||||
source = routes,
|
||||
color = const(RouteColor),
|
||||
width =
|
||||
@@ -142,21 +153,27 @@ fun RouteLayer(routeData: String?, viewStyle: ViewStyle) {
|
||||
20 to const(22.dp),
|
||||
),
|
||||
)
|
||||
} else {
|
||||
SymbolLayer(
|
||||
id = "my-symbol-layer",
|
||||
source = routes,
|
||||
// Convert a drawable resource to a MapLibre image
|
||||
// drawAsSdf = true allows us to tint the image programmatically
|
||||
iconImage = image(painterResource(com.kouros.android.cars.carappservice.R.drawable.ev_station_24px), drawAsSdf = true),
|
||||
// Now we can apply any color we want!
|
||||
iconColor = const(Color.Red),
|
||||
iconSize = const(5.0f)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun AmenityLayer(routeData: String?) {
|
||||
if (routeData != null && routeData.isNotEmpty()) {
|
||||
val color = if (routeData.contains(Constants.PHARMACY)) {
|
||||
const(Color.Red)
|
||||
} else {
|
||||
const(Color.Green)
|
||||
}
|
||||
val routes = rememberGeoJsonSource(GeoJsonData.JsonString(routeData))
|
||||
SymbolLayer(
|
||||
id = "amenity-layer",
|
||||
source = routes,
|
||||
iconImage = image(painterResource(R.drawable.ev_station_48px), drawAsSdf = true),
|
||||
iconColor = color,
|
||||
iconSize = const(3.0f),
|
||||
)
|
||||
}
|
||||
}
|
||||
@Composable
|
||||
fun BuildingLayer(tiles: Source) {
|
||||
Anchor.Replace("building-3d") {
|
||||
|
||||
@@ -18,7 +18,12 @@ package com.kouros.navigation.car.navigation
|
||||
import android.text.SpannableString
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.car.app.AppManager
|
||||
import androidx.car.app.CarContext
|
||||
import androidx.car.app.model.Action
|
||||
import androidx.car.app.model.Action.FLAG_DEFAULT
|
||||
import androidx.car.app.model.Alert
|
||||
import androidx.car.app.model.AlertCallback
|
||||
import androidx.car.app.model.CarColor
|
||||
import androidx.car.app.model.CarIcon
|
||||
import androidx.car.app.model.CarText
|
||||
@@ -28,8 +33,7 @@ import androidx.car.app.navigation.model.Maneuver
|
||||
import androidx.car.app.navigation.model.Step
|
||||
import androidx.car.app.navigation.model.TravelEstimate
|
||||
import androidx.core.graphics.drawable.IconCompat
|
||||
import com.kouros.navigation.data.Constants.NEXT_STEP_THRESHOLD
|
||||
import com.kouros.navigation.data.ManeuverType
|
||||
import com.kouros.data.R
|
||||
import com.kouros.navigation.model.RouteModel
|
||||
import java.util.TimeZone
|
||||
import java.util.concurrent.TimeUnit
|
||||
@@ -117,4 +121,43 @@ class RouteCarModel() : RouteModel() {
|
||||
fun createCarIcon(carContext: CarContext, @DrawableRes iconRes: Int): CarIcon {
|
||||
return CarIcon.Builder(IconCompat.createWithResource(carContext, iconRes)).build()
|
||||
}
|
||||
|
||||
fun showSpeedCamera(carContext: CarContext, distance: Double, maxSpeed: String?) {
|
||||
carContext.getCarService<AppManager?>(AppManager::class.java)
|
||||
.showAlert(createAlert(carContext, distance, maxSpeed))
|
||||
}
|
||||
|
||||
fun createAlert(carContext: CarContext, distance: Double, maxSpeed: String?): Alert {
|
||||
val title = createCarText(carContext,R.string.speed_camera)
|
||||
val subtitle = CarText.create(maxSpeed!!)
|
||||
val icon = CarIcon.ALERT
|
||||
|
||||
val dismissAction: Action = createToastAction(
|
||||
carContext,
|
||||
R.string.speed_camera, R.string.exit_action_title,
|
||||
FLAG_DEFAULT
|
||||
)
|
||||
|
||||
return Alert.Builder( /* alertId: */0, title, /* durationMillis: */10000)
|
||||
.setSubtitle(subtitle)
|
||||
.setIcon(icon)
|
||||
.addAction(dismissAction).setCallback(object : AlertCallback {
|
||||
override fun onCancel(reason: Int) {
|
||||
}
|
||||
override fun onDismiss() {
|
||||
}
|
||||
}).build()
|
||||
}
|
||||
|
||||
private fun createToastAction(
|
||||
carContext: CarContext,
|
||||
@StringRes titleRes: Int, @StringRes toastStringRes: Int,
|
||||
flags: Int
|
||||
): Action {
|
||||
return Action.Builder()
|
||||
.setOnClickListener { }
|
||||
.setTitle(createCarText(carContext,titleRes))
|
||||
.setFlags(flags)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,9 @@ import com.kouros.data.R
|
||||
import com.kouros.navigation.car.SurfaceRenderer
|
||||
import com.kouros.navigation.car.ViewStyle
|
||||
import com.kouros.navigation.data.Category
|
||||
import com.kouros.navigation.data.Constants
|
||||
import com.kouros.navigation.data.Constants.CHARGING_STATION
|
||||
import com.kouros.navigation.data.Constants.FUEL_STATION
|
||||
import com.kouros.navigation.data.Constants.PHARMACY
|
||||
|
||||
class CategoriesScreen(
|
||||
private val carContext: CarContext,
|
||||
@@ -24,9 +26,9 @@ class CategoriesScreen(
|
||||
) : Screen(carContext) {
|
||||
|
||||
var categories: List<Category> = listOf(
|
||||
Category(id = Constants.FUEL_STATION, name = carContext.getString(R.string.fuel_station)),
|
||||
Category(id = Constants.PHARMACY, name = carContext.getString(R.string.pharmacy)),
|
||||
Category(id = Constants.CHARGING_STATION, name = carContext.getString(R.string.charging_station))
|
||||
Category(id = FUEL_STATION, name = carContext.getString(R.string.fuel_station)),
|
||||
Category(id = PHARMACY, name = carContext.getString(R.string.pharmacy)),
|
||||
Category(id = CHARGING_STATION, name = carContext.getString(R.string.charging_station))
|
||||
)
|
||||
|
||||
override fun onGetTemplate(): Template {
|
||||
@@ -36,13 +38,7 @@ class CategoriesScreen(
|
||||
itemListBuilder.addItem(
|
||||
Row.Builder()
|
||||
.setTitle(it.name)
|
||||
.setImage(CarIcon.Builder(
|
||||
IconCompat.createWithResource(
|
||||
carContext,
|
||||
com.kouros.android.cars.carappservice.R.drawable.ev_station_24px
|
||||
)
|
||||
)
|
||||
.build())
|
||||
.setImage(carIcon(carContext,it.id))
|
||||
.setOnClickListener {
|
||||
screenManager
|
||||
.pushForResult(
|
||||
@@ -64,7 +60,7 @@ class CategoriesScreen(
|
||||
)
|
||||
}
|
||||
|
||||
surfaceRenderer.viewStyle = ViewStyle.SEARCH_VIEW
|
||||
surfaceRenderer.viewStyle = ViewStyle.AMENITY_VIEW
|
||||
|
||||
val header = Header.Builder()
|
||||
.setStartHeaderAction(Action.BACK)
|
||||
@@ -76,4 +72,20 @@ class CategoriesScreen(
|
||||
.setSingleList(itemListBuilder.build())
|
||||
.build()
|
||||
}
|
||||
}
|
||||
|
||||
fun carIcon(context: CarContext, id: String): CarIcon {
|
||||
val resId = when (id) {
|
||||
FUEL_STATION -> R.drawable.local_gas_station_48px
|
||||
PHARMACY -> R.drawable.local_pharmacy_48px
|
||||
CHARGING_STATION -> R.drawable.ev_station_48px
|
||||
else -> {}
|
||||
}
|
||||
return CarIcon.Builder(
|
||||
IconCompat.createWithResource(
|
||||
context,
|
||||
resId as Int
|
||||
)
|
||||
)
|
||||
.build()
|
||||
}
|
||||
@@ -3,12 +3,10 @@ package com.kouros.navigation.car.screen
|
||||
import android.location.Location
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.car.app.CarContext
|
||||
import androidx.car.app.CarToast
|
||||
import androidx.car.app.Screen
|
||||
import androidx.car.app.constraints.ConstraintManager
|
||||
import androidx.car.app.model.Action
|
||||
import androidx.car.app.model.ActionStrip
|
||||
import androidx.car.app.model.CarIcon
|
||||
import androidx.car.app.model.CarText
|
||||
import androidx.car.app.model.Header
|
||||
import androidx.car.app.model.ItemList
|
||||
@@ -17,24 +15,24 @@ import androidx.car.app.model.Row
|
||||
import androidx.car.app.model.Template
|
||||
import androidx.car.app.navigation.model.MapController
|
||||
import androidx.car.app.navigation.model.MapWithContentTemplate
|
||||
import androidx.car.app.versioning.CarAppApiLevels
|
||||
import androidx.core.graphics.drawable.IconCompat
|
||||
import androidx.lifecycle.Observer
|
||||
import com.kouros.data.R
|
||||
import com.kouros.navigation.car.SurfaceRenderer
|
||||
import com.kouros.navigation.car.navigation.NavigationMessage
|
||||
import com.kouros.navigation.data.Constants
|
||||
import com.kouros.navigation.data.NavigationRepository
|
||||
import com.kouros.navigation.data.overpass.Elements
|
||||
import com.kouros.navigation.model.ViewModel
|
||||
import com.kouros.navigation.utils.GeoUtils.createPointCollection
|
||||
import com.kouros.navigation.utils.location
|
||||
import com.kouros.navigation.utils.round
|
||||
import kotlin.math.min
|
||||
|
||||
class CategoryScreen(
|
||||
private val carContext: CarContext,
|
||||
private val surfaceRenderer: SurfaceRenderer,
|
||||
location: Location,
|
||||
category: String,
|
||||
private val category: String,
|
||||
) : Screen(carContext) {
|
||||
|
||||
val viewModel = ViewModel(NavigationRepository())
|
||||
@@ -52,7 +50,7 @@ class CategoryScreen(
|
||||
coordinates.add(listOf(it.lon!!, it.lat!!))
|
||||
}
|
||||
if (elements.isNotEmpty()) {
|
||||
val route = createPointCollection(coordinates)
|
||||
val route = createPointCollection(coordinates, category)
|
||||
surfaceRenderer.setCategories(loc, route)
|
||||
invalidate()
|
||||
}
|
||||
@@ -65,41 +63,25 @@ class CategoryScreen(
|
||||
|
||||
|
||||
override fun onGetTemplate(): Template {
|
||||
|
||||
val listBuilder = ItemList.Builder()
|
||||
if (carContext.getCarAppApiLevel() > CarAppApiLevels.LEVEL_1) {
|
||||
var index = 0
|
||||
val listLimit = min(
|
||||
100,
|
||||
carContext.getCarService(ConstraintManager::class.java)
|
||||
.getContentLimit(
|
||||
ConstraintManager.CONTENT_LIMIT_TYPE_LIST
|
||||
)
|
||||
)
|
||||
elements.forEach {
|
||||
if (index++ < listLimit) {
|
||||
var index = 0
|
||||
val listLimit = min(
|
||||
50,
|
||||
carContext.getCarService(ConstraintManager::class.java)
|
||||
.getContentLimit(
|
||||
ConstraintManager.CONTENT_LIMIT_TYPE_LIST
|
||||
)
|
||||
)
|
||||
elements.forEach {
|
||||
if (index++ < listLimit) {
|
||||
if (it.tags.operator != null) {
|
||||
listBuilder.addItem(
|
||||
Row.Builder()
|
||||
.setOnClickListener {
|
||||
val location = location(it.lon!!, it.lat!!)
|
||||
surfaceRenderer.setCategoryLocation(location)
|
||||
}
|
||||
.setTitle(it.tags.operator.toString())
|
||||
.setImage(
|
||||
CarIcon.Builder(
|
||||
IconCompat.createWithResource(
|
||||
carContext,
|
||||
com.kouros.android.cars.carappservice.R.drawable.ev_station_24px
|
||||
)
|
||||
)
|
||||
.build()
|
||||
)
|
||||
.addText(it.tags.network.toString())
|
||||
.build()
|
||||
createItem(it, category)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val header = Header.Builder()
|
||||
.setStartHeaderAction(Action.BACK)
|
||||
.setTitle(carContext.getString(R.string.charging_station))
|
||||
@@ -116,11 +98,39 @@ class CategoryScreen(
|
||||
getMapActionStrip()
|
||||
).build()
|
||||
)
|
||||
|
||||
return builder.build()
|
||||
}
|
||||
|
||||
private fun secondText(sText: String): CarText {
|
||||
private fun createItem(it: Elements, category: String): Row {
|
||||
var name = ""
|
||||
if (it.tags.name != null) {
|
||||
name = it.tags.name.toString()
|
||||
}
|
||||
if (name.isEmpty()) {
|
||||
name = it.tags.operator.toString()
|
||||
}
|
||||
val row = Row.Builder()
|
||||
.setOnClickListener {
|
||||
val location = location(it.lon!!, it.lat!!)
|
||||
surfaceRenderer.setCategoryLocation(location, category)
|
||||
println(it)
|
||||
}
|
||||
.setTitle(name)
|
||||
.setImage(carIcon(carContext, category))
|
||||
if (it.distance < 1000) {
|
||||
row.addText("${(it.distance).toInt()} m")
|
||||
} else {
|
||||
row.addText("${(it.distance / 1000).round(1)} km")
|
||||
}
|
||||
if (category == Constants.CHARGING_STATION) {
|
||||
row.addText("${it.tags.socketType2} X Typ 2 ${it.tags.socketType2Output}")
|
||||
} else {
|
||||
row.addText(carText("${it.tags.openingHours}"))
|
||||
}
|
||||
return row.build()
|
||||
}
|
||||
|
||||
private fun carText(sText: String): CarText {
|
||||
val secondText =
|
||||
CarText.Builder(
|
||||
"================= " + sText + " ================"
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package com.kouros.navigation.car.screen
|
||||
|
||||
import android.content.ComponentName
|
||||
import android.content.Intent
|
||||
import android.location.Location
|
||||
import android.location.LocationManager
|
||||
import android.os.CountDownTimer
|
||||
@@ -9,6 +7,7 @@ import android.os.Handler
|
||||
import androidx.car.app.CarContext
|
||||
import androidx.car.app.Screen
|
||||
import androidx.car.app.model.Action
|
||||
import androidx.car.app.model.Action.FLAG_DEFAULT
|
||||
import androidx.car.app.model.ActionStrip
|
||||
import androidx.car.app.model.CarColor
|
||||
import androidx.car.app.model.CarIcon
|
||||
@@ -21,18 +20,18 @@ import androidx.car.app.navigation.model.MapWithContentTemplate
|
||||
import androidx.car.app.navigation.model.MessageInfo
|
||||
import androidx.car.app.navigation.model.NavigationTemplate
|
||||
import androidx.car.app.navigation.model.RoutingInfo
|
||||
import androidx.car.app.notification.CarPendingIntent
|
||||
import androidx.car.app.suggestion.model.Suggestion
|
||||
import androidx.core.graphics.drawable.IconCompat
|
||||
import androidx.lifecycle.Observer
|
||||
import com.kouros.data.R
|
||||
import com.kouros.navigation.car.NavigationCarAppService
|
||||
import com.kouros.navigation.car.SurfaceRenderer
|
||||
import com.kouros.navigation.car.ViewStyle
|
||||
import com.kouros.navigation.car.navigation.RouteCarModel
|
||||
import com.kouros.navigation.data.Constants
|
||||
import com.kouros.navigation.data.Constants.DESTINATION_ARRIVAL_DISTANCE
|
||||
import com.kouros.navigation.data.NavigationRepository
|
||||
import com.kouros.navigation.data.Place
|
||||
import com.kouros.navigation.data.nominatim.SearchResult
|
||||
import com.kouros.navigation.data.overpass.Elements
|
||||
import com.kouros.navigation.model.ViewModel
|
||||
import com.kouros.navigation.utils.location
|
||||
|
||||
@@ -41,7 +40,6 @@ class NavigationScreen(
|
||||
private var surfaceRenderer: SurfaceRenderer,
|
||||
private var routeModel: RouteCarModel,
|
||||
private var listener: Listener
|
||||
|
||||
) :
|
||||
Screen(carContext) {
|
||||
|
||||
@@ -52,20 +50,14 @@ class NavigationScreen(
|
||||
}
|
||||
|
||||
var currentNavigationLocation = Location(LocationManager.GPS_PROVIDER)
|
||||
|
||||
lateinit var recentPlace: Place
|
||||
|
||||
var recentPlaceFound = false
|
||||
|
||||
var recentPlaceActive = true
|
||||
|
||||
var calculateNewRoute = false
|
||||
var recentPlace = Place()
|
||||
var navigationType = NavigationType.VIEW
|
||||
val viewModel = ViewModel(NavigationRepository())
|
||||
val observer = Observer<String> { route ->
|
||||
if (route.isNotEmpty()) {
|
||||
navigationType = NavigationType.NAVIGATION
|
||||
routeModel.startNavigation(route)
|
||||
surfaceRenderer.setRouteData()
|
||||
recentPlaceActive = false
|
||||
invalidate()
|
||||
}
|
||||
}
|
||||
@@ -73,26 +65,48 @@ class NavigationScreen(
|
||||
val recentObserver = Observer<Place> { lastPlace ->
|
||||
if (!routeModel.isNavigating()) {
|
||||
recentPlace = lastPlace
|
||||
recentPlaceFound = true
|
||||
navigationType = NavigationType.RECENT
|
||||
invalidate()
|
||||
}
|
||||
}
|
||||
|
||||
val placeObserver = Observer<SearchResult> { searchResult ->
|
||||
val place = Place(
|
||||
name = searchResult.displayName,
|
||||
street = searchResult.address.road,
|
||||
city = searchResult.address.city,
|
||||
latitude = searchResult.lat.toDouble(),
|
||||
longitude = searchResult.lon.toDouble(),
|
||||
category = Constants.CONTACTS,
|
||||
postalCode = searchResult.address.postcode
|
||||
)
|
||||
navigateToPlace(place)
|
||||
}
|
||||
|
||||
var lastCameraSearch = 0
|
||||
|
||||
var speedCameras = listOf<Elements>()
|
||||
val speedObserver = Observer<List<Elements>> { cameras ->
|
||||
speedCameras = cameras
|
||||
println("Speed cameras ${speedCameras.size}")
|
||||
}
|
||||
|
||||
init {
|
||||
viewModel.route.observe(this, observer)
|
||||
viewModel.recentPlace.observe(this, recentObserver)
|
||||
viewModel.loadRecentPlace(location = surfaceRenderer.lastLocation)
|
||||
viewModel.placeLocation.observe(this, placeObserver)
|
||||
viewModel.speedCameras.observe(this, speedObserver)
|
||||
}
|
||||
|
||||
override fun onGetTemplate(): Template {
|
||||
val actionStripBuilder = createActionStripBuilder()
|
||||
if (calculateNewRoute) {
|
||||
return navigationRerouteTemplate(actionStripBuilder)
|
||||
}
|
||||
return if (routeModel.isNavigating()) {
|
||||
navigationTemplate(actionStripBuilder)
|
||||
} else {
|
||||
navigationEndTemplate(actionStripBuilder)
|
||||
return when (navigationType) {
|
||||
NavigationType.NAVIGATION -> navigationTemplate(actionStripBuilder)
|
||||
NavigationType.RECENT -> navigationRecentPlaceTemplate()
|
||||
NavigationType.REROUTE -> navigationRerouteTemplate(actionStripBuilder)
|
||||
NavigationType.ARRIVAL -> navigationEndTemplate(actionStripBuilder)
|
||||
else -> navigationViewTemplate(actionStripBuilder)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,30 +125,37 @@ class NavigationScreen(
|
||||
.build()
|
||||
}
|
||||
|
||||
private fun navigationViewTemplate(actionStripBuilder: ActionStrip.Builder): Template {
|
||||
return NavigationTemplate.Builder()
|
||||
.setBackgroundColor(CarColor.SECONDARY)
|
||||
.setActionStrip(actionStripBuilder.build())
|
||||
.setMapActionStrip(mapActionStripBuilder().build())
|
||||
.build()
|
||||
|
||||
}
|
||||
|
||||
private fun navigationEndTemplate(actionStripBuilder: ActionStrip.Builder): Template {
|
||||
if (routeModel.routeState.arrived) {
|
||||
val timer = object : CountDownTimer(10000, 10000) {
|
||||
val timer = object : CountDownTimer(8000, 1000) {
|
||||
override fun onTick(millisUntilFinished: Long) {}
|
||||
override fun onFinish() {
|
||||
routeModel.routeState = routeModel.routeState.copy(arrived = false)
|
||||
navigationType = NavigationType.VIEW
|
||||
invalidate()
|
||||
}
|
||||
}
|
||||
timer.start()
|
||||
return navigationArrivedTemplate(actionStripBuilder)
|
||||
} else {
|
||||
return if (recentPlaceFound && recentPlaceActive) {
|
||||
return recentPlaceTemplate()
|
||||
} else {
|
||||
NavigationTemplate.Builder()
|
||||
.setBackgroundColor(CarColor.SECONDARY)
|
||||
.setActionStrip(actionStripBuilder.build())
|
||||
.setMapActionStrip(mapActionStripBuilder().build())
|
||||
.build()
|
||||
}
|
||||
return NavigationTemplate.Builder()
|
||||
.setBackgroundColor(CarColor.SECONDARY)
|
||||
.setActionStrip(actionStripBuilder.build())
|
||||
.setMapActionStrip(mapActionStripBuilder().build())
|
||||
.build()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun navigationArrivedTemplate(actionStripBuilder: ActionStrip.Builder): NavigationTemplate {
|
||||
var street = ""
|
||||
if (routeModel.routeState.destination.street != null) {
|
||||
@@ -163,7 +184,7 @@ class NavigationScreen(
|
||||
.build()
|
||||
}
|
||||
|
||||
fun recentPlaceTemplate(): Template {
|
||||
fun navigationRecentPlaceTemplate(): Template {
|
||||
val messageTemplate = MessageTemplate.Builder(
|
||||
recentPlace.name + "\n"
|
||||
+ recentPlace.city
|
||||
@@ -266,6 +287,7 @@ class NavigationScreen(
|
||||
}
|
||||
|
||||
private fun navigateAction(): Action {
|
||||
navigationType = NavigationType.NAVIGATION
|
||||
return Action.Builder()
|
||||
.setIcon(
|
||||
CarIcon.Builder(
|
||||
@@ -296,9 +318,10 @@ class NavigationScreen(
|
||||
.build()
|
||||
)
|
||||
.setOnClickListener {
|
||||
recentPlaceActive = false
|
||||
navigationType = NavigationType.VIEW
|
||||
invalidate()
|
||||
}
|
||||
.setFlags(FLAG_DEFAULT)
|
||||
.build()
|
||||
}
|
||||
|
||||
@@ -368,28 +391,6 @@ class NavigationScreen(
|
||||
.build()
|
||||
}
|
||||
|
||||
private fun getSuggestion(title: Int, subtitle: Int, icon: CarIcon): Suggestion {
|
||||
return Suggestion.Builder()
|
||||
.setIdentifier("0")
|
||||
.setTitle(carContext.getString(title))
|
||||
.setSubtitle(carContext.getString(subtitle))
|
||||
.setIcon(icon)
|
||||
.setAction(
|
||||
CarPendingIntent.getCarApp(
|
||||
carContext, 0,
|
||||
Intent().setComponent(
|
||||
ComponentName(
|
||||
carContext,
|
||||
NavigationCarAppService::class.java
|
||||
)
|
||||
),
|
||||
//.setAction(NavigationSession.EXECUTE_SCRIPT),
|
||||
0
|
||||
)
|
||||
)
|
||||
.build()
|
||||
}
|
||||
|
||||
private fun startSearchScreen() {
|
||||
screenManager
|
||||
.pushForResult(
|
||||
@@ -397,26 +398,39 @@ class NavigationScreen(
|
||||
) { obj: Any? ->
|
||||
if (obj != null) {
|
||||
val place = obj as Place
|
||||
val location = Location(LocationManager.GPS_PROVIDER)
|
||||
location.latitude = place.latitude
|
||||
location.longitude = place.longitude
|
||||
viewModel.saveRecent(place)
|
||||
viewModel.loadRoute(carContext, surfaceRenderer.lastLocation, location)
|
||||
currentNavigationLocation = location
|
||||
routeModel.routeState.destination = place
|
||||
invalidate()
|
||||
if (place.longitude == 0.0) {
|
||||
viewModel.findAddress(
|
||||
"${obj.city} ${obj.street}},",
|
||||
currentNavigationLocation
|
||||
)
|
||||
// result see observer
|
||||
} else {
|
||||
navigateToPlace(place)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun navigateToPlace(place: Place) {
|
||||
navigationType = NavigationType.VIEW
|
||||
val location = location(place.longitude, place.latitude)
|
||||
viewModel.saveRecent(place)
|
||||
currentNavigationLocation = location
|
||||
viewModel.loadRoute(carContext, surfaceRenderer.lastLocation, location)
|
||||
routeModel.routeState.destination = place
|
||||
invalidate()
|
||||
}
|
||||
|
||||
fun stopNavigation() {
|
||||
navigationType = NavigationType.VIEW
|
||||
listener.stopNavigation()
|
||||
surfaceRenderer.routeData.value = ""
|
||||
lastCameraSearch = 0
|
||||
invalidate()
|
||||
}
|
||||
|
||||
fun calculateNewRoute(destination: Place) {
|
||||
calculateNewRoute = true
|
||||
navigationType = NavigationType.REROUTE
|
||||
stopNavigation()
|
||||
invalidate()
|
||||
val mainThreadHandler = Handler(carContext.mainLooper)
|
||||
@@ -424,7 +438,7 @@ class NavigationScreen(
|
||||
object : CountDownTimer(3000, 1000) {
|
||||
override fun onTick(millisUntilFinished: Long) {}
|
||||
override fun onFinish() {
|
||||
calculateNewRoute = false
|
||||
navigationType = NavigationType.NAVIGATION
|
||||
reRoute(destination)
|
||||
}
|
||||
}.start()
|
||||
@@ -437,6 +451,12 @@ class NavigationScreen(
|
||||
}
|
||||
|
||||
fun updateTrip(location: Location) {
|
||||
if (lastCameraSearch++ % 100 == 0) {
|
||||
viewModel.getSpeedCameras(location)
|
||||
}
|
||||
if (speedCameras.isNotEmpty()) {
|
||||
updateDistance(location)
|
||||
}
|
||||
with(routeModel) {
|
||||
updateLocation(location)
|
||||
if (routeState.maneuverType == Maneuver.TYPE_DESTINATION
|
||||
@@ -445,8 +465,33 @@ class NavigationScreen(
|
||||
stopNavigation()
|
||||
routeState = routeState.copy(arrived = true)
|
||||
surfaceRenderer.routeData.value = ""
|
||||
navigationType = NavigationType.ARRIVAL
|
||||
invalidate()
|
||||
}
|
||||
}
|
||||
invalidate()
|
||||
}
|
||||
|
||||
private fun updateDistance(
|
||||
location: Location,
|
||||
) {
|
||||
val updatedCameras = mutableListOf<Elements>()
|
||||
speedCameras.forEach {
|
||||
val plLocation =
|
||||
location(longitude = it.lon!!, latitude = it.lat!!)
|
||||
val distance = plLocation.distanceTo(location)
|
||||
it.distance = distance.toDouble()
|
||||
updatedCameras.add(it)
|
||||
}
|
||||
val sortedList = updatedCameras.sortedWith(compareBy { it.distance })
|
||||
val camera = sortedList.first()
|
||||
if (camera.distance < 100) {
|
||||
routeModel.showSpeedCamera(carContext, camera.distance, camera.tags.maxspeed)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
enum class NavigationType {
|
||||
VIEW, NAVIGATION, REROUTE, RECENT, ARRIVAL
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import android.text.SpannableString
|
||||
import androidx.car.app.CarContext
|
||||
import androidx.car.app.CarToast
|
||||
import androidx.car.app.Screen
|
||||
import androidx.car.app.constraints.ConstraintManager
|
||||
import androidx.car.app.model.Action
|
||||
import androidx.car.app.model.CarIcon
|
||||
import androidx.car.app.model.Distance
|
||||
@@ -22,10 +23,14 @@ import com.kouros.data.R
|
||||
import com.kouros.navigation.car.SurfaceRenderer
|
||||
import com.kouros.navigation.car.navigation.RouteCarModel
|
||||
import com.kouros.navigation.data.Constants
|
||||
import com.kouros.navigation.data.Constants.CONTACTS
|
||||
import com.kouros.navigation.data.Constants.FAVORITES
|
||||
import com.kouros.navigation.data.Constants.RECENT
|
||||
import com.kouros.navigation.data.Constants.categories
|
||||
import com.kouros.navigation.data.NavigationRepository
|
||||
import com.kouros.navigation.data.Place
|
||||
import com.kouros.navigation.model.ViewModel
|
||||
import kotlin.math.min
|
||||
|
||||
|
||||
class PlaceListScreen(
|
||||
@@ -62,73 +67,74 @@ class PlaceListScreen(
|
||||
}
|
||||
|
||||
fun loadPlaces() {
|
||||
if (category == Constants.RECENT) {
|
||||
if (category == RECENT) {
|
||||
viewModel.loadRecentPlaces(carContext, location)
|
||||
}
|
||||
if (category == Constants.CONTACTS) {
|
||||
viewModel.loadContacts(carContext, location)
|
||||
if (category == CONTACTS) {
|
||||
viewModel.loadContacts(carContext)
|
||||
}
|
||||
if (category == Constants.FAVORITES) {
|
||||
if (category == FAVORITES) {
|
||||
viewModel.loadFavorites(carContext, location)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onGetTemplate(): Template {
|
||||
val itemListBuilder = ItemList.Builder()
|
||||
.setNoItemsMessage(carContext.getString(R.string.no_places))
|
||||
places.forEach {
|
||||
itemListBuilder.addItem(
|
||||
Row.Builder()
|
||||
.addAction(
|
||||
deleteAction(it)
|
||||
val row = Row.Builder()
|
||||
.setImage(contactIcon(it.avatar, it.category))
|
||||
.setTitle(it.name!!)
|
||||
.setOnClickListener {
|
||||
val place = Place(
|
||||
0,
|
||||
it.name,
|
||||
it.category,
|
||||
it.latitude,
|
||||
it.longitude,
|
||||
it.postalCode,
|
||||
it.city,
|
||||
it.street,
|
||||
avatar = null
|
||||
)
|
||||
.setImage(contactIcon(it.avatar, it.category))
|
||||
.setTitle(it.name!!)
|
||||
.addText(SpannableString(" ").apply {
|
||||
setSpan(
|
||||
DistanceSpan.create(
|
||||
Distance.create(
|
||||
it.distance.toDouble(),
|
||||
Distance.UNIT_KILOMETERS
|
||||
)
|
||||
), 0, 1, Spannable.SPAN_INCLUSIVE_INCLUSIVE
|
||||
)
|
||||
})
|
||||
.setOnClickListener {
|
||||
val place = Place(
|
||||
0,
|
||||
it.name,
|
||||
it.category,
|
||||
it.latitude,
|
||||
it.longitude,
|
||||
it.postalCode,
|
||||
it.city,
|
||||
it.street,
|
||||
avatar = null
|
||||
)
|
||||
setResult(place)
|
||||
finish()
|
||||
// screenManager
|
||||
// .pushForResult(
|
||||
// RoutePreviewScreen(
|
||||
// carContext,
|
||||
// surfaceRenderer,
|
||||
// place
|
||||
// )
|
||||
// ) { obj: Any? ->
|
||||
// if (obj != null) {
|
||||
// setResult(obj)
|
||||
// finish()
|
||||
// }
|
||||
// }
|
||||
}
|
||||
.build()
|
||||
screenManager
|
||||
.pushForResult(
|
||||
RoutePreviewScreen(
|
||||
carContext,
|
||||
surfaceRenderer,
|
||||
place
|
||||
)
|
||||
) { obj: Any? ->
|
||||
if (obj != null) {
|
||||
setResult(obj)
|
||||
finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
if (category != CONTACTS) {
|
||||
row.addText(SpannableString(" ").apply {
|
||||
setSpan(
|
||||
DistanceSpan.create(
|
||||
Distance.create(
|
||||
it.distance.toDouble(),
|
||||
Distance.UNIT_KILOMETERS
|
||||
)
|
||||
), 0, 1, Spannable.SPAN_INCLUSIVE_INCLUSIVE
|
||||
)
|
||||
})
|
||||
row.addAction(
|
||||
deleteAction(it)
|
||||
)
|
||||
}
|
||||
itemListBuilder.addItem(
|
||||
row.build()
|
||||
)
|
||||
}
|
||||
var title = ""
|
||||
when(category) {
|
||||
Constants.RECENT -> title = carContext.getString(R.string.recent_destinations)
|
||||
Constants.CONTACTS -> title = carContext.getString(R.string.contacts)
|
||||
Constants.FAVORITES -> title = carContext.getString(R.string.favorites)
|
||||
when (category) {
|
||||
RECENT -> title = carContext.getString(R.string.recent_destinations)
|
||||
CONTACTS -> title = carContext.getString(R.string.contacts)
|
||||
FAVORITES -> title = carContext.getString(R.string.favorites)
|
||||
}
|
||||
val header = Header.Builder()
|
||||
.setStartHeaderAction(Action.BACK)
|
||||
|
||||
@@ -1,18 +1,3 @@
|
||||
/*
|
||||
* Copyright 2024 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.kouros.navigation.car.screen
|
||||
|
||||
import android.os.CountDownTimer
|
||||
@@ -22,18 +7,23 @@ 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.Action.FLAG_DEFAULT
|
||||
import androidx.car.app.model.Action.FLAG_PRIMARY
|
||||
import androidx.car.app.model.ActionStrip
|
||||
import androidx.car.app.model.CarColor
|
||||
import androidx.car.app.model.CarIcon
|
||||
import androidx.car.app.model.CarText
|
||||
import androidx.car.app.model.DurationSpan
|
||||
import androidx.car.app.model.Header
|
||||
import androidx.car.app.model.ItemList
|
||||
import androidx.car.app.model.ListTemplate
|
||||
import androidx.car.app.model.MessageTemplate
|
||||
import androidx.car.app.model.Row
|
||||
import androidx.car.app.model.Template
|
||||
import androidx.car.app.navigation.model.MapController
|
||||
import androidx.car.app.navigation.model.MapWithContentTemplate
|
||||
import androidx.car.app.navigation.model.NavigationTemplate
|
||||
import androidx.car.app.navigation.model.RoutingInfo
|
||||
import androidx.core.graphics.drawable.IconCompat
|
||||
import androidx.lifecycle.Observer
|
||||
import com.kouros.data.R
|
||||
@@ -78,24 +68,20 @@ class RoutePreviewScreen(
|
||||
override fun onGetTemplate(): Template {
|
||||
val navigateActionIcon: CarIcon = CarIcon.Builder(
|
||||
IconCompat.createWithResource(
|
||||
carContext, R.drawable.baseline_assistant_navigation_24
|
||||
carContext, R.drawable.navigation_48px
|
||||
)
|
||||
).build()
|
||||
val navigateAction = Action.Builder()
|
||||
.setFlags(FLAG_PRIMARY)
|
||||
.setFlags(FLAG_DEFAULT)
|
||||
.setIcon(navigateActionIcon)
|
||||
.setOnClickListener { this.onNavigate() }
|
||||
|
||||
.build()
|
||||
|
||||
val itemListBuilder = ItemList.Builder()
|
||||
|
||||
if (routeModel.isNavigating() && routeModel.route.waypoints.isNotEmpty()) {
|
||||
itemListBuilder.addItem(createRow(0, navigateAction))
|
||||
}
|
||||
|
||||
val header = Header.Builder()
|
||||
.setStartHeaderAction(Action.BACK)
|
||||
.setTitle(carContext.getString(R.string.route_preview))
|
||||
//.addEndHeaderAction(navigateAction)
|
||||
.addEndHeaderAction(
|
||||
favoriteAction()
|
||||
)
|
||||
@@ -104,21 +90,30 @@ class RoutePreviewScreen(
|
||||
)
|
||||
.build()
|
||||
|
||||
val timer = object : CountDownTimer(10000, 15000) {
|
||||
val message = if (routeModel.isNavigating() && routeModel.route.waypoints.isNotEmpty()) {
|
||||
createRouteText()
|
||||
} else {
|
||||
CarText.Builder("Wait")
|
||||
.build()
|
||||
}
|
||||
val messageTemplate = MessageTemplate.Builder(
|
||||
message
|
||||
)
|
||||
.setHeader(header)
|
||||
.addAction(navigateAction)
|
||||
.setLoading(message.toString() == "Wait")
|
||||
.build()
|
||||
|
||||
val timer = object : CountDownTimer(5000, 1000) {
|
||||
override fun onTick(millisUntilFinished: Long) {}
|
||||
override fun onFinish() {
|
||||
onNavigate()
|
||||
//onNavigate()
|
||||
}
|
||||
}
|
||||
timer.start()
|
||||
|
||||
return MapWithContentTemplate.Builder()
|
||||
.setContentTemplate(
|
||||
ListTemplate.Builder()
|
||||
.setHeader(header)
|
||||
.setSingleList(itemListBuilder.build())
|
||||
.build()
|
||||
)
|
||||
.setContentTemplate(messageTemplate)
|
||||
.setMapController(
|
||||
MapController.Builder().setMapActionStrip(
|
||||
getMapActionStrip()
|
||||
@@ -177,18 +172,8 @@ class RoutePreviewScreen(
|
||||
.build()
|
||||
)
|
||||
.build()
|
||||
private fun createRow(index: Int, action: Action): Row {
|
||||
val route: CarText = createRouteText(index)
|
||||
return Row.Builder()
|
||||
.setTitle(route)
|
||||
.setOnClickListener { onRouteSelected(index) }
|
||||
.addText("${destination.street!!} ${destination.postalCode} ${destination.city}")
|
||||
.addAction(action)
|
||||
.build()
|
||||
}
|
||||
|
||||
|
||||
private fun createRouteText(index: Int): CarText {
|
||||
private fun createRouteText(): CarText {
|
||||
val time = routeModel.route.summary.time
|
||||
val length = BigDecimal(routeModel.route.distance).setScale(1, RoundingMode.HALF_EVEN)
|
||||
val firstRoute = SpannableString(" \u00b7 $length km")
|
||||
|
||||
@@ -35,7 +35,7 @@ class SearchScreen(
|
||||
|
||||
var categories: List<Category> = listOf(
|
||||
Category(id = Constants.RECENT, name = carContext.getString(R.string.recent_destinations)),
|
||||
//Category(id = Constants.CONTACTS, name = carContext.getString(R.string.contacts)),
|
||||
Category(id = Constants.CONTACTS, name = carContext.getString(R.string.contacts)),
|
||||
Category(id = Constants.CATEGORIES, name = carContext.getString(R.string.category_title)),
|
||||
Category(id = Constants.FAVORITES, name = carContext.getString(R.string.favorites))
|
||||
)
|
||||
|
||||
@@ -31,7 +31,6 @@ class SettingsScreen(
|
||||
) : Screen(carContext) {
|
||||
|
||||
override fun onGetTemplate(): Template {
|
||||
|
||||
val listBuilder = ItemList.Builder()
|
||||
listBuilder.addItem(
|
||||
buildRowForTemplate(
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M340,760L440,600L380,600L380,480L280,640L340,640L340,760ZM240,400L480,400L480,200Q480,200 480,200Q480,200 480,200L240,200Q240,200 240,200Q240,200 240,200L240,400ZM240,760L480,760L480,480L240,480L240,760ZM160,840L160,200Q160,167 183.5,143.5Q207,120 240,120L480,120Q513,120 536.5,143.5Q560,167 560,200L560,480L610,480Q639,480 659.5,500.5Q680,521 680,550L680,735Q680,752 694,766Q708,780 725,780Q743,780 756.5,766Q770,752 770,735L770,360L760,360Q743,360 731.5,348.5Q720,337 720,320L720,240L740,240L740,180L780,180L780,240L820,240L820,180L860,180L860,240L880,240L880,320Q880,337 868.5,348.5Q857,360 840,360L830,360L830,735Q830,777 799.5,808.5Q769,840 725,840Q682,840 651,808.5Q620,777 620,735L620,550Q620,545 617.5,542.5Q615,540 610,540L560,540L560,840L160,840ZM480,760L240,760L240,760L480,760Z"/>
|
||||
</vector>
|
||||
@@ -24,9 +24,11 @@ class ViewModelTest {
|
||||
fun routeViewModelTest() {
|
||||
|
||||
val fromLocation = Location(LocationManager.GPS_PROVIDER)
|
||||
fromLocation.isMock = true
|
||||
fromLocation.latitude = homeLocation.latitude
|
||||
fromLocation.longitude = homeLocation.longitude
|
||||
val toLocation = Location(LocationManager.GPS_PROVIDER)
|
||||
toLocation.isMock = true
|
||||
toLocation.latitude = home2Location.latitude
|
||||
toLocation.longitude = home2Location.longitude
|
||||
|
||||
|
||||
Reference in New Issue
Block a user