SheetContent Simulation
This commit is contained in:
@@ -1,19 +1,3 @@
|
||||
/*
|
||||
* Copyright 2023 Google LLC
|
||||
*
|
||||
* 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
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
|
||||
@@ -52,16 +52,30 @@ import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import android.Manifest.permission
|
||||
|
||||
/**
|
||||
* Main session for Android Auto/Automotive OS navigation.
|
||||
* Manages the lifecycle of the navigation session, including location updates,
|
||||
* car hardware sensors, routing engine selection, and screen navigation.
|
||||
* Implements NavigationScreen.Listener for handling navigation events.
|
||||
*/
|
||||
class NavigationSession : Session(), NavigationScreen.Listener {
|
||||
|
||||
// Flag to enable/disable contact access feature
|
||||
val useContacts = false
|
||||
|
||||
// Model for managing route state and navigation logic for Android Auto
|
||||
lateinit var routeModel: RouteCarModel;
|
||||
|
||||
// Main navigation screen displayed to the user
|
||||
lateinit var navigationScreen: NavigationScreen
|
||||
|
||||
// Handles map surface rendering on the car display
|
||||
lateinit var surfaceRenderer: SurfaceRenderer
|
||||
|
||||
/**
|
||||
* Location listener that receives GPS updates from the device.
|
||||
* Only processes location if car location hardware is not being used.
|
||||
*/
|
||||
var mLocationListener: LocationListenerCompat = LocationListenerCompat { location: Location? ->
|
||||
val repository = getSettingsRepository(carContext)
|
||||
val useCarLocation = runBlocking { repository.carLocationFlow.first() }
|
||||
@@ -70,6 +84,10 @@ class NavigationSession : Session(), NavigationScreen.Listener {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Lifecycle observer for managing session lifecycle events.
|
||||
* Cleans up resources when the session is destroyed.
|
||||
*/
|
||||
private val mLifeCycleObserver: LifecycleObserver = object : DefaultLifecycleObserver {
|
||||
override fun onCreate(owner: LifecycleOwner) {
|
||||
}
|
||||
@@ -92,9 +110,16 @@ class NavigationSession : Session(), NavigationScreen.Listener {
|
||||
}
|
||||
}
|
||||
|
||||
// ViewModel for navigation data and business logic
|
||||
lateinit var navigationViewModel: NavigationViewModel
|
||||
|
||||
// Store for ViewModels to survive configuration changes
|
||||
lateinit var viewModelStoreOwner : ViewModelStoreOwner
|
||||
|
||||
/**
|
||||
* Listener for car hardware location updates.
|
||||
* Receives location data from the car's GPS system.
|
||||
*/
|
||||
val carLocationListener: OnCarDataAvailableListener<CarHardwareLocation?> =
|
||||
OnCarDataAvailableListener { data ->
|
||||
if (data.location.status == CarValue.STATUS_SUCCESS) {
|
||||
@@ -105,6 +130,10 @@ class NavigationSession : Session(), NavigationScreen.Listener {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Listener for car compass/orientation sensor.
|
||||
* Updates the surface renderer with car orientation for map rotation.
|
||||
*/
|
||||
val carCompassListener: OnCarDataAvailableListener<Compass?> =
|
||||
OnCarDataAvailableListener { data ->
|
||||
if (data.orientations.status == CarValue.STATUS_SUCCESS) {
|
||||
@@ -115,17 +144,26 @@ class NavigationSession : Session(), NavigationScreen.Listener {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Listener for car speed sensor updates.
|
||||
* Receives speed in meters per second from car hardware.
|
||||
*/
|
||||
val carSpeedListener = OnCarDataAvailableListener<Speed> { data ->
|
||||
if (data.displaySpeedMetersPerSecond.status == CarValue.STATUS_SUCCESS) {
|
||||
val speed = data.displaySpeedMetersPerSecond.value
|
||||
surfaceRenderer.updateCarSpeed(speed!!)
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
val lifecycle: Lifecycle = lifecycle
|
||||
lifecycle.addObserver(mLifeCycleObserver)
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when routing engine preference changes.
|
||||
* Creates appropriate repository based on user selection.
|
||||
*/
|
||||
fun onRoutingEngineStateUpdated(routeEngine : Int) {
|
||||
navigationViewModel = when (routeEngine) {
|
||||
RouteEngine.VALHALLA.ordinal -> NavigationViewModel(ValhallaRepository())
|
||||
@@ -134,10 +172,19 @@ class NavigationSession : Session(), NavigationScreen.Listener {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when location permission is granted.
|
||||
* Initializes car hardware sensors if available.
|
||||
*/
|
||||
fun onPermissionGranted(permission : Boolean) {
|
||||
addSensors(routeModel.navState.carConnection)
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when car connection state changes.
|
||||
* Handles different connection types: Not Connected, Automotive OS Native, Android Auto Projection.
|
||||
* Requests appropriate car speed permissions based on connection type.
|
||||
*/
|
||||
fun onConnectionStateUpdated(connectionState: Int) {
|
||||
routeModel.navState = routeModel.navState.copy(carConnection = connectionState)
|
||||
when (connectionState) {
|
||||
@@ -153,8 +200,14 @@ class NavigationSession : Session(), NavigationScreen.Listener {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the initial screen for the session.
|
||||
* Sets up ViewModel store, initializes components, checks permissions,
|
||||
* and returns appropriate starting screen.
|
||||
*/
|
||||
override fun onCreateScreen(intent: Intent): Screen {
|
||||
|
||||
// Create ViewModelStoreOwner to manage ViewModels across lifecycle
|
||||
viewModelStoreOwner = object : ViewModelStoreOwner {
|
||||
override val viewModelStore = ViewModelStore()
|
||||
}
|
||||
@@ -166,6 +219,7 @@ class NavigationSession : Session(), NavigationScreen.Listener {
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize ViewModel with saved routing engine preference
|
||||
navigationViewModel = getViewModel(carContext)
|
||||
|
||||
navigationViewModel.routingEngine.observe(this, ::onRoutingEngineStateUpdated)
|
||||
@@ -174,13 +228,17 @@ class NavigationSession : Session(), NavigationScreen.Listener {
|
||||
|
||||
routeModel = RouteCarModel()
|
||||
|
||||
// Monitor car connection state
|
||||
CarConnection(carContext).type.observe(this, ::onConnectionStateUpdated)
|
||||
|
||||
// Initialize surface renderer for map display
|
||||
surfaceRenderer = SurfaceRenderer(carContext, lifecycle, routeModel, viewModelStoreOwner)
|
||||
|
||||
// Create main navigation screen
|
||||
navigationScreen =
|
||||
NavigationScreen(carContext, surfaceRenderer, routeModel, this, navigationViewModel)
|
||||
|
||||
// Check for required permissions before starting
|
||||
if ( carContext.checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION)
|
||||
== PackageManager.PERMISSION_GRANTED
|
||||
&& !useContacts
|
||||
@@ -207,6 +265,11 @@ class NavigationSession : Session(), NavigationScreen.Listener {
|
||||
return navigationScreen
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers listeners for car hardware sensors.
|
||||
* Only adds location and compass sensors if useCarLocation setting is enabled.
|
||||
* Speed sensor is added for both native and projection connections.
|
||||
*/
|
||||
fun addSensors(connectionState: Int) {
|
||||
val carInfo = carContext.getCarService(CarHardwareManager::class.java).carInfo
|
||||
val repository = getSettingsRepository(carContext)
|
||||
@@ -228,6 +291,10 @@ class NavigationSession : Session(), NavigationScreen.Listener {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters all car hardware sensor listeners.
|
||||
* Called when session is being destroyed to prevent memory leaks.
|
||||
*/
|
||||
fun removeSensors() {
|
||||
val carInfo = carContext.getCarService(CarHardwareManager::class.java).carInfo
|
||||
val repository = getSettingsRepository(carContext)
|
||||
@@ -242,6 +309,10 @@ class NavigationSession : Session(), NavigationScreen.Listener {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles new intents, primarily for navigation deep links from other apps.
|
||||
* Supports ACTION_NAVIGATE for starting navigation to a specific location.
|
||||
*/
|
||||
override fun onNewIntent(intent: Intent) {
|
||||
val screenManager = carContext.getCarService(ScreenManager::class.java)
|
||||
if ((CarContext.ACTION_NAVIGATE == intent.action)) {
|
||||
@@ -278,11 +349,18 @@ class NavigationSession : Session(), NavigationScreen.Listener {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when car configuration changes (e.g., day/night mode).
|
||||
*/
|
||||
override fun onCarConfigurationChanged(newConfiguration: Configuration) {
|
||||
println("Configuration: ${newConfiguration.isNightModeActive}")
|
||||
super.onCarConfigurationChanged(newConfiguration)
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests GPS location updates from the device.
|
||||
* Updates with last known location and starts listening for updates every 500ms or 5 meters.
|
||||
*/
|
||||
@SuppressLint("MissingPermission")
|
||||
fun requestLocationUpdates() {
|
||||
val locationManager =
|
||||
@@ -300,6 +378,12 @@ class NavigationSession : Session(), NavigationScreen.Listener {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates navigation state with new location.
|
||||
* Handles route snapping, deviation detection for rerouting, and map updates.
|
||||
* Snaps location to nearest point on route if within threshold.
|
||||
* Triggers reroute calculation if deviated too far from route.
|
||||
*/
|
||||
fun updateLocation(location: Location) {
|
||||
if (location.hasBearing()) {
|
||||
routeModel.navState = routeModel.navState.copy(routeBearing = location.bearing)
|
||||
@@ -309,10 +393,12 @@ class NavigationSession : Session(), NavigationScreen.Listener {
|
||||
if (!routeModel.navState.arrived) {
|
||||
val snapedLocation = snapLocation(location, routeModel.route.maneuverLocations())
|
||||
val distance = location.distanceTo(snapedLocation)
|
||||
// Check if user has deviated too far from route
|
||||
if (distance > MAXIMAL_ROUTE_DEVIATION) {
|
||||
navigationScreen.calculateNewRoute(routeModel.navState.destination)
|
||||
return
|
||||
}
|
||||
// Snap to route if close enough, otherwise use raw location
|
||||
if (distance < MAXIMAL_SNAP_CORRECTION) {
|
||||
surfaceRenderer.updateLocation(snapedLocation)
|
||||
} else {
|
||||
@@ -324,14 +410,20 @@ class NavigationSession : Session(), NavigationScreen.Listener {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops active navigation and clears route state.
|
||||
* Called when user exits navigation or arrives at destination.
|
||||
*/
|
||||
override fun stopNavigation(context: CarContext) {
|
||||
routeModel.stopNavigation(context)
|
||||
}
|
||||
|
||||
|
||||
companion object {
|
||||
// URI host for deep linking
|
||||
var uriHost: String = "navigation"
|
||||
|
||||
// URI scheme for deep linking
|
||||
var uriScheme: String = "samples"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,53 +51,100 @@ import org.maplibre.compose.style.BaseStyle
|
||||
import org.maplibre.spatialk.geojson.Position
|
||||
|
||||
|
||||
/**
|
||||
* Handles map rendering for Android Auto using a virtual display.
|
||||
* Creates a VirtualDisplay to render Compose UI onto the car's surface.
|
||||
* Manages camera position, zoom, tilt, and navigation state for the map view.
|
||||
*/
|
||||
class SurfaceRenderer(
|
||||
private var carContext: CarContext, lifecycle: Lifecycle,
|
||||
private var routeModel: RouteCarModel,
|
||||
private var viewModelStoreOwner: ViewModelStoreOwner
|
||||
) : DefaultLifecycleObserver {
|
||||
|
||||
// Last known location for bearing calculations
|
||||
var lastLocation = location(0.0, 0.0)
|
||||
|
||||
// Car orientation sensor value (999F means no valid orientation)
|
||||
var carOrientation = 999F
|
||||
|
||||
// Current camera position state for the map
|
||||
private val cameraPosition = MutableLiveData(
|
||||
CameraPosition(
|
||||
zoom = 15.0,
|
||||
target = Position(latitude = homeVogelhart.latitude, longitude = homeVogelhart.longitude)
|
||||
)
|
||||
)
|
||||
|
||||
// Visible area of the map surface (can change based on UI elements)
|
||||
private var visibleArea = MutableLiveData(
|
||||
Rect(0, 0, 0, 0)
|
||||
)
|
||||
|
||||
// Stable area that won't change during scrolling
|
||||
var stableArea = Rect()
|
||||
|
||||
// Surface dimensions
|
||||
var width = 0
|
||||
var height = 0
|
||||
|
||||
// Last bearing for smooth transitions
|
||||
var lastBearing = 0.0
|
||||
|
||||
// LiveData for route GeoJSON data
|
||||
val routeData = MutableLiveData("")
|
||||
|
||||
// Traffic incident data (incident ID to GeoJSON mapping)
|
||||
val trafficData = MutableLiveData(emptyMap<String, String>())
|
||||
|
||||
// Speed camera locations as GeoJSON
|
||||
val speedCamerasData = MutableLiveData("")
|
||||
|
||||
// Current speed in km/h
|
||||
val speed = MutableLiveData(0F)
|
||||
|
||||
// Speed limit for current road
|
||||
val maxSpeed = MutableLiveData(0)
|
||||
|
||||
// Current view mode (navigation, preview, etc.)
|
||||
var viewStyle = ViewStyle.VIEW
|
||||
|
||||
// Center location for route preview
|
||||
lateinit var centerLocation: Location
|
||||
|
||||
// Route distance for calculating preview zoom
|
||||
var previewDistance = 0.0
|
||||
|
||||
// Compose view for rendering the map
|
||||
lateinit var mapView: ComposeView
|
||||
|
||||
// Camera tilt angle (default 55 degrees for navigation)
|
||||
var tilt = 55.0
|
||||
|
||||
// Map base style (day/night)
|
||||
val style: MutableLiveData<BaseStyle> by lazy {
|
||||
MutableLiveData()
|
||||
}
|
||||
|
||||
/**
|
||||
* SurfaceCallback implementation for handling the Android Auto surface lifecycle.
|
||||
* Creates and manages the VirtualDisplay and Presentation for rendering Compose content.
|
||||
*/
|
||||
val mSurfaceCallback: SurfaceCallback = object : SurfaceCallback {
|
||||
|
||||
// Custom lifecycle owner for the virtual display
|
||||
lateinit var lifecycleOwner: CustomLifecycleOwner
|
||||
|
||||
// Virtual display for rendering the map
|
||||
lateinit var virtualDisplay: VirtualDisplay
|
||||
|
||||
// Presentation that hosts the Compose view
|
||||
lateinit var presentation: Presentation
|
||||
|
||||
/**
|
||||
* Called when the surface becomes available.
|
||||
* Creates VirtualDisplay, initializes lifecycle, and sets up Compose rendering.
|
||||
*/
|
||||
override fun onSurfaceAvailable(surfaceContainer: SurfaceContainer) {
|
||||
synchronized(this@SurfaceRenderer) {
|
||||
Log.i(TAG, "Surface available $surfaceContainer")
|
||||
@@ -135,18 +182,29 @@ class SurfaceRenderer(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the visible area changes (e.g., due to UI elements appearing).
|
||||
*/
|
||||
override fun onVisibleAreaChanged(newVisibleArea: Rect) {
|
||||
synchronized(this@SurfaceRenderer) {
|
||||
visibleArea.value = newVisibleArea
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the stable area changes.
|
||||
* Stable area is guaranteed not to change during scroll events.
|
||||
*/
|
||||
override fun onStableAreaChanged(newStableArea: Rect) {
|
||||
synchronized(this@SurfaceRenderer) {
|
||||
stableArea = newStableArea
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the surface is being destroyed.
|
||||
* Cleans up resources and notifies lifecycle owner.
|
||||
*/
|
||||
override fun onSurfaceDestroyed(surfaceContainer: SurfaceContainer) {
|
||||
synchronized(this@SurfaceRenderer) {
|
||||
Log.i(TAG, "SurfaceRenderer destroyed")
|
||||
@@ -159,11 +217,17 @@ class SurfaceRenderer(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when user scrolls the map (not currently implemented).
|
||||
*/
|
||||
override fun onScroll(distanceX: Float, distanceY: Float) {
|
||||
synchronized(this@SurfaceRenderer) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when user scales (zooms) the map (not currently implemented).
|
||||
*/
|
||||
override fun onScale(focusX: Float, focusY: Float, scaleFactor: Float) {
|
||||
|
||||
}
|
||||
@@ -179,6 +243,10 @@ class SurfaceRenderer(
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Composable function that renders the map and navigation UI.
|
||||
* Observes various LiveData sources and updates the map accordingly.
|
||||
*/
|
||||
@Composable
|
||||
fun MapView() {
|
||||
|
||||
@@ -204,6 +272,10 @@ class SurfaceRenderer(
|
||||
ShowPosition(cameraState, position, paddingValues)
|
||||
}
|
||||
|
||||
/**
|
||||
* Composable that handles camera animations and navigation overlays.
|
||||
* Displays speed indicator and navigation images during active navigation.
|
||||
*/
|
||||
@Composable
|
||||
fun ShowPosition(
|
||||
cameraState: CameraState,
|
||||
@@ -244,7 +316,10 @@ class SurfaceRenderer(
|
||||
.setSurfaceCallback(mSurfaceCallback)
|
||||
}
|
||||
|
||||
/** Handles the map zoom-in and zoom-out events. */
|
||||
/**
|
||||
* Handles the map zoom-in and zoom-out events.
|
||||
* Switches to PAN_VIEW mode and updates camera zoom level.
|
||||
*/
|
||||
fun handleScale(zoomSign: Int) {
|
||||
synchronized(this) {
|
||||
if (viewStyle == ViewStyle.VIEW) {
|
||||
@@ -264,6 +339,11 @@ class SurfaceRenderer(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the camera position based on current location.
|
||||
* Calculates appropriate bearing, zoom, and maintains view style.
|
||||
* Uses car orientation sensor if available, otherwise falls back to location bearing.
|
||||
*/
|
||||
fun updateLocation(location: Location) {
|
||||
synchronized(this) {
|
||||
if (viewStyle == ViewStyle.VIEW || viewStyle == ViewStyle.PAN_VIEW) {
|
||||
@@ -296,6 +376,10 @@ class SurfaceRenderer(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates camera position with new bearing, zoom, and target.
|
||||
* Posts update to LiveData for UI observation.
|
||||
*/
|
||||
private fun updateCameraPosition(bearing: Double, zoom: Double, target: Position) {
|
||||
synchronized(this) {
|
||||
cameraPosition.postValue(
|
||||
@@ -310,15 +394,25 @@ class SurfaceRenderer(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets route data for active navigation and switches to VIEW mode.
|
||||
*/
|
||||
fun setRouteData() {
|
||||
routeData.value = routeModel.curRoute.routeGeoJson
|
||||
viewStyle = ViewStyle.VIEW
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates traffic incident data on the map.
|
||||
*/
|
||||
fun setTrafficData(traffic: Map<String, String> ) {
|
||||
trafficData.value = traffic as MutableMap<String, String>?
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up route preview mode with overview camera position.
|
||||
* Calculates appropriate zoom based on route distance.
|
||||
*/
|
||||
fun setPreviewRouteData(routeModel: RouteModel) {
|
||||
viewStyle = ViewStyle.PREVIEW
|
||||
with(routeModel) {
|
||||
@@ -333,6 +427,9 @@ class SurfaceRenderer(
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays a specific location (e.g., amenity/POI) on the map.
|
||||
*/
|
||||
fun setCategories(location: Location, route: String) {
|
||||
synchronized(this) {
|
||||
viewStyle = ViewStyle.AMENITY_VIEW
|
||||
@@ -345,6 +442,10 @@ class SurfaceRenderer(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates car location from the connected car system.
|
||||
* Only updates location when using OSRM routing engine.
|
||||
*/
|
||||
fun updateCarLocation(location: Location) {
|
||||
val repository = getSettingsRepository(carContext)
|
||||
val routingEngine = runBlocking { repository.routingEngineFlow.first() }
|
||||
@@ -353,10 +454,16 @@ class SurfaceRenderer(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates current speed for display.
|
||||
*/
|
||||
fun updateCarSpeed(newSpeed: Float) {
|
||||
speed.value = newSpeed
|
||||
}
|
||||
|
||||
/**
|
||||
* Centers the map on a specific category/POI location.
|
||||
*/
|
||||
fun setCategoryLocation(location: Location, category: String) {
|
||||
viewStyle = ViewStyle.AMENITY_VIEW
|
||||
cameraPosition.postValue(
|
||||
@@ -373,7 +480,14 @@ class SurfaceRenderer(
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Enum representing different map view modes.
|
||||
* - VIEW: Active navigation mode with follow-car camera
|
||||
* - PREVIEW: Route overview before starting navigation
|
||||
* - PAN_VIEW: User-controlled map panning
|
||||
* - AMENITY_VIEW: Displaying POI/amenity locations
|
||||
*/
|
||||
enum class ViewStyle {
|
||||
VIEW, PREVIEW, PAN_VIEW, AMENITY_VIEW
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,7 +57,6 @@ class SearchScreen(
|
||||
.setNoItemsMessage("No search results to show")
|
||||
if (!isSearchComplete) {
|
||||
categories.forEach {
|
||||
it.name
|
||||
itemListBuilder.addItem(
|
||||
Row.Builder()
|
||||
.setTitle(it.name)
|
||||
|
||||
@@ -34,6 +34,6 @@ class OsrmRepository : NavigationRepository() {
|
||||
location: Location,
|
||||
carOrientation: Float
|
||||
): String {
|
||||
TODO("Not yet implemented")
|
||||
return ""
|
||||
}
|
||||
}
|
||||
@@ -53,6 +53,6 @@ class ValhallaRepository : NavigationRepository() {
|
||||
location: Location,
|
||||
carOrientation: Float
|
||||
): String {
|
||||
TODO("Not yet implemented")
|
||||
return ""
|
||||
}
|
||||
}
|
||||
@@ -250,10 +250,12 @@ class NavigationViewModel(private val repository: NavigationRepository) : ViewMo
|
||||
currentLocation,
|
||||
carOrientation
|
||||
)
|
||||
val trafficData = rebuildTraffic(data)
|
||||
traffic.postValue(
|
||||
trafficData
|
||||
)
|
||||
if (data.isNotEmpty()) {
|
||||
val trafficData = rebuildTraffic(data)
|
||||
traffic.postValue(
|
||||
trafficData
|
||||
)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user