Reroute
This commit is contained in:
@@ -12,25 +12,25 @@ android {
|
|||||||
applicationId = "com.kouros.navigation"
|
applicationId = "com.kouros.navigation"
|
||||||
minSdk = 33
|
minSdk = 33
|
||||||
targetSdk = 36
|
targetSdk = 36
|
||||||
versionCode = 1
|
versionCode = 2
|
||||||
versionName = "0.1.3"
|
versionName = "0.1.3.1"
|
||||||
setProperty("archivesBaseName", "navi-$versionName")
|
setProperty("archivesBaseName", "navi-$versionName")
|
||||||
|
|
||||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||||
}
|
}
|
||||||
|
|
||||||
signingConfigs {
|
signingConfigs {
|
||||||
// getByName("debug") {
|
getByName("debug") {
|
||||||
// keyAlias = "alias"
|
keyAlias = "release"
|
||||||
// keyPassword = "alpha2000"
|
keyPassword = "zeta67#gAe3aN3"
|
||||||
// storeFile = file("/home/kouros/work/keystore/keystoreRelease")
|
storeFile = file("/home/kouros/work/keystore/keystoreRelease")
|
||||||
// storePassword = "alpha2000"
|
storePassword = "zeta67#gAe3aN3"
|
||||||
// }
|
}
|
||||||
create("release") {
|
create("release") {
|
||||||
keyAlias = "release"
|
keyAlias = "release"
|
||||||
keyPassword = "zeta67#g"
|
keyPassword = "zeta67#gAe3aN3"
|
||||||
storeFile = file("/home/kouros/work/keystore/keystoreRelease")
|
storeFile = file("/home/kouros/work/keystore/keystoreRelease")
|
||||||
storePassword = "zeta67#g"
|
storePassword = "zeta67#gAe3aN3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,11 +46,11 @@ android {
|
|||||||
// Specifies one flavor dimension.
|
// Specifies one flavor dimension.
|
||||||
flavorDimensions += "version"
|
flavorDimensions += "version"
|
||||||
productFlavors {
|
productFlavors {
|
||||||
// create("demo") {
|
create("demo") {
|
||||||
// dimension = "version"
|
dimension = "version"
|
||||||
// applicationIdSuffix = ".demo"
|
applicationIdSuffix = ".demo"
|
||||||
// versionNameSuffix = "-demo"
|
versionNameSuffix = "-demo"
|
||||||
// }
|
}
|
||||||
create("full") {
|
create("full") {
|
||||||
dimension = "version"
|
dimension = "version"
|
||||||
applicationIdSuffix = ".full"
|
applicationIdSuffix = ".full"
|
||||||
@@ -87,11 +87,15 @@ dependencies {
|
|||||||
implementation(project(":common:car"))
|
implementation(project(":common:car"))
|
||||||
implementation(libs.play.services.location)
|
implementation(libs.play.services.location)
|
||||||
implementation(libs.androidx.compose.runtime)
|
implementation(libs.androidx.compose.runtime)
|
||||||
|
implementation(libs.androidx.navigation.compose)
|
||||||
|
implementation(libs.androidx.compose.ui.tooling.preview)
|
||||||
|
implementation(libs.androidx.compose.material3.window.size.class1)
|
||||||
|
|
||||||
testImplementation(libs.junit)
|
testImplementation(libs.junit)
|
||||||
androidTestImplementation(libs.androidx.junit)
|
androidTestImplementation(libs.androidx.junit)
|
||||||
androidTestImplementation(libs.androidx.espresso.core)
|
androidTestImplementation(libs.androidx.espresso.core)
|
||||||
androidTestImplementation(platform(libs.androidx.compose.bom))
|
androidTestImplementation(platform(libs.androidx.compose.bom))
|
||||||
|
debugImplementation(libs.androidx.compose.ui.tooling)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,9 @@
|
|||||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
||||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
|
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
|
||||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
|
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
|
||||||
|
<uses-permission android:name="android.permission.READ_CONTACTS"/>
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION"
|
||||||
|
tools:ignore="MockLocation" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:name="com.kouros.navigation.MainApplication"
|
android:name="com.kouros.navigation.MainApplication"
|
||||||
@@ -23,7 +26,7 @@
|
|||||||
android:resource="@xml/automotive_app_desc" />
|
android:resource="@xml/automotive_app_desc" />
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name="com.kouros.navigation.MainActivity"
|
android:name="com.kouros.navigation.ui.MainActivity"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
android:theme="@style/Theme.Navigation">
|
android:theme="@style/Theme.Navigation">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
|
|||||||
@@ -24,5 +24,7 @@ class MainApplication : Application() {
|
|||||||
companion object {
|
companion object {
|
||||||
var appContext: Context? = null
|
var appContext: Context? = null
|
||||||
private set
|
private set
|
||||||
|
|
||||||
|
var useContacts = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
package com.kouros.navigation.model
|
||||||
|
|
||||||
|
import android.location.Location
|
||||||
|
import android.location.LocationManager
|
||||||
|
import android.os.SystemClock
|
||||||
|
|
||||||
|
class MockLocation (private var locationManager: LocationManager) {
|
||||||
|
|
||||||
|
fun setMockLocation(latitude: Double, longitude: Double) {
|
||||||
|
try {
|
||||||
|
// Set mock location for all providers
|
||||||
|
setMockLocationForProvider(LocationManager.GPS_PROVIDER, latitude, longitude)
|
||||||
|
setMockLocationForProvider(LocationManager.NETWORK_PROVIDER, latitude, longitude)
|
||||||
|
} catch (e: NumberFormatException) {
|
||||||
|
} catch (e: SecurityException) {
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setMockLocationForProvider(provider: String, latitude: Double, longitude: Double) {
|
||||||
|
try {
|
||||||
|
// Check if provider exists
|
||||||
|
if (!locationManager.allProviders.contains(provider)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enable test provider
|
||||||
|
// For API 31+
|
||||||
|
locationManager.addTestProvider(
|
||||||
|
provider,
|
||||||
|
false, // requiresNetwork
|
||||||
|
false, // requiresSatellite
|
||||||
|
false, // requiresCell
|
||||||
|
false, // hasMonetaryCost
|
||||||
|
true, // supportsAltitude
|
||||||
|
true, // supportsSpeed
|
||||||
|
true, // supportsBearing
|
||||||
|
android.location.provider.ProviderProperties.POWER_USAGE_LOW,
|
||||||
|
android.location.provider.ProviderProperties.ACCURACY_FINE
|
||||||
|
)
|
||||||
|
|
||||||
|
locationManager.setTestProviderEnabled(provider, true)
|
||||||
|
|
||||||
|
// Create mock location
|
||||||
|
val mockLocation = Location(provider).apply {
|
||||||
|
this.latitude = latitude
|
||||||
|
this.longitude = longitude
|
||||||
|
this.altitude = 0.0
|
||||||
|
this.accuracy = 1.0f
|
||||||
|
this.speed = 15F
|
||||||
|
this.time = System.currentTimeMillis()
|
||||||
|
this.elapsedRealtimeNanos = SystemClock.elapsedRealtimeNanos()
|
||||||
|
|
||||||
|
this.bearingAccuracyDegrees = 0.0f
|
||||||
|
this.verticalAccuracyMeters = 0.0f
|
||||||
|
this.speedAccuracyMetersPerSecond = 0.0f
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the mock location
|
||||||
|
locationManager.setTestProviderLocation(provider, mockLocation)
|
||||||
|
|
||||||
|
} catch (e: SecurityException) {
|
||||||
|
throw e
|
||||||
|
} catch (e: IllegalArgumentException) {
|
||||||
|
// Provider already exists, just update location
|
||||||
|
try {
|
||||||
|
locationManager.setTestProviderEnabled(provider, true)
|
||||||
|
|
||||||
|
val mockLocation = Location(provider).apply {
|
||||||
|
this.latitude = latitude
|
||||||
|
this.longitude = longitude
|
||||||
|
this.altitude = 0.0
|
||||||
|
this.accuracy = 1.0f
|
||||||
|
this.time = System.currentTimeMillis()
|
||||||
|
this.elapsedRealtimeNanos = SystemClock.elapsedRealtimeNanos()
|
||||||
|
|
||||||
|
this.bearingAccuracyDegrees = 0.0f
|
||||||
|
this.verticalAccuracyMeters = 0.0f
|
||||||
|
this.speedAccuracyMetersPerSecond = 0.0f
|
||||||
|
}
|
||||||
|
|
||||||
|
locationManager.setTestProviderLocation(provider, mockLocation)
|
||||||
|
} catch (ex: Exception) {
|
||||||
|
ex.printStackTrace()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,31 +1,30 @@
|
|||||||
package com.kouros.navigation
|
package com.kouros.navigation.ui
|
||||||
|
|
||||||
import android.Manifest
|
import android.Manifest
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
|
import android.app.AppOpsManager
|
||||||
|
import android.content.pm.PackageManager
|
||||||
import android.location.Location
|
import android.location.Location
|
||||||
import android.location.LocationManager
|
import android.location.LocationManager
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.os.Process
|
||||||
|
import android.widget.Toast
|
||||||
import androidx.activity.ComponentActivity
|
import androidx.activity.ComponentActivity
|
||||||
import androidx.activity.compose.setContent
|
import androidx.activity.compose.setContent
|
||||||
import androidx.activity.enableEdgeToEdge
|
import androidx.activity.enableEdgeToEdge
|
||||||
import androidx.compose.foundation.border
|
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
|
||||||
import androidx.compose.material3.Card
|
import androidx.compose.material3.Card
|
||||||
import androidx.compose.material3.ExtendedFloatingActionButton
|
import androidx.compose.material3.ExtendedFloatingActionButton
|
||||||
import androidx.compose.material3.HorizontalDivider
|
import androidx.compose.material3.HorizontalDivider
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.MaterialTheme
|
|
||||||
import androidx.compose.material3.ModalDrawerSheet
|
import androidx.compose.material3.ModalDrawerSheet
|
||||||
import androidx.compose.material3.ModalNavigationDrawer
|
import androidx.compose.material3.ModalNavigationDrawer
|
||||||
import androidx.compose.material3.NavigationDrawerItem
|
import androidx.compose.material3.NavigationDrawerItem
|
||||||
import androidx.compose.material3.Scaffold
|
import androidx.compose.material3.Scaffold
|
||||||
import androidx.compose.material3.SegmentedButtonDefaults.Icon
|
import androidx.compose.material3.SegmentedButtonDefaults
|
||||||
import androidx.compose.material3.SnackbarHost
|
import androidx.compose.material3.SnackbarHost
|
||||||
import androidx.compose.material3.SnackbarHostState
|
import androidx.compose.material3.SnackbarHostState
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
@@ -38,46 +37,40 @@ import androidx.compose.runtime.remember
|
|||||||
import androidx.compose.runtime.rememberCoroutineScope
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
|
||||||
import androidx.compose.ui.graphics.Color
|
|
||||||
import androidx.compose.ui.platform.LocalContext
|
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
|
import androidx.core.app.ActivityCompat
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import androidx.lifecycle.Observer
|
import androidx.lifecycle.Observer
|
||||||
import com.kouros.navigation.ui.theme.NavigationTheme
|
|
||||||
import com.google.accompanist.permissions.ExperimentalPermissionsApi
|
import com.google.accompanist.permissions.ExperimentalPermissionsApi
|
||||||
import com.google.accompanist.permissions.rememberMultiplePermissionsState
|
import com.google.accompanist.permissions.rememberMultiplePermissionsState
|
||||||
|
import com.google.android.gms.location.FusedLocationProviderClient
|
||||||
|
import com.google.android.gms.location.LocationServices
|
||||||
import com.kouros.android.cars.carappservice.R
|
import com.kouros.android.cars.carappservice.R
|
||||||
|
import com.kouros.navigation.MainApplication
|
||||||
import com.kouros.navigation.car.BuildingLayer
|
import com.kouros.navigation.car.BuildingLayer
|
||||||
import com.kouros.navigation.car.Puck
|
|
||||||
import com.kouros.navigation.car.PuckState
|
import com.kouros.navigation.car.PuckState
|
||||||
import com.kouros.navigation.car.RouteLayer
|
import com.kouros.navigation.car.RouteLayer
|
||||||
|
|
||||||
import com.kouros.navigation.data.Category
|
|
||||||
import com.kouros.navigation.data.Constants
|
import com.kouros.navigation.data.Constants
|
||||||
import com.kouros.navigation.data.Constants.SHOW_THREED_BUILDING
|
|
||||||
import com.kouros.navigation.data.NavigationRepository
|
import com.kouros.navigation.data.NavigationRepository
|
||||||
import com.kouros.navigation.data.StepData
|
import com.kouros.navigation.data.StepData
|
||||||
|
import com.kouros.navigation.model.MockLocation
|
||||||
import com.kouros.navigation.model.RouteModel
|
import com.kouros.navigation.model.RouteModel
|
||||||
import com.kouros.navigation.model.ViewModel
|
import com.kouros.navigation.model.ViewModel
|
||||||
import com.kouros.navigation.utils.NavigationUtils.getBooleanKeyValue
|
import com.kouros.navigation.ui.theme.NavigationTheme
|
||||||
import com.kouros.navigation.utils.NavigationUtils.snapLocation
|
import com.kouros.navigation.utils.NavigationUtils
|
||||||
import com.kouros.navigation.utils.calculateZoom
|
import com.kouros.navigation.utils.calculateZoom
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.GlobalScope
|
||||||
|
import kotlinx.coroutines.async
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.koin.androidx.compose.koinViewModel
|
|
||||||
import org.maplibre.compose.camera.CameraPosition
|
import org.maplibre.compose.camera.CameraPosition
|
||||||
import org.maplibre.compose.camera.rememberCameraState
|
import org.maplibre.compose.camera.rememberCameraState
|
||||||
import org.maplibre.compose.location.DesiredAccuracy
|
import org.maplibre.compose.location.DesiredAccuracy
|
||||||
import org.maplibre.compose.location.LocationPuck
|
|
||||||
import org.maplibre.compose.location.LocationPuckColors
|
|
||||||
import org.maplibre.compose.location.LocationPuckSizes
|
|
||||||
import org.maplibre.compose.location.LocationTrackingEffect
|
import org.maplibre.compose.location.LocationTrackingEffect
|
||||||
import org.maplibre.compose.location.rememberDefaultLocationProvider
|
import org.maplibre.compose.location.rememberDefaultLocationProvider
|
||||||
import org.maplibre.compose.location.rememberUserLocationState
|
import org.maplibre.compose.location.rememberUserLocationState
|
||||||
@@ -87,10 +80,12 @@ import org.maplibre.compose.style.BaseStyle
|
|||||||
import org.maplibre.spatialk.geojson.Position
|
import org.maplibre.spatialk.geojson.Position
|
||||||
import kotlin.time.Duration.Companion.seconds
|
import kotlin.time.Duration.Companion.seconds
|
||||||
|
|
||||||
|
|
||||||
class MainActivity : ComponentActivity() {
|
class MainActivity : ComponentActivity() {
|
||||||
|
|
||||||
private val coroutineScope: CoroutineScope = CoroutineScope(Dispatchers.IO)
|
private val LOCATION_PERMISSION_REQUEST_CODE = 1001
|
||||||
|
|
||||||
|
private val CONTACTS_PERMISSION_REQUEST_CODE = 1002
|
||||||
|
|
||||||
val routeData = MutableLiveData("")
|
val routeData = MutableLiveData("")
|
||||||
|
|
||||||
val vieModel = ViewModel(NavigationRepository())
|
val vieModel = ViewModel(NavigationRepository())
|
||||||
@@ -107,6 +102,8 @@ class MainActivity : ComponentActivity() {
|
|||||||
val observer = Observer<String> { newRoute ->
|
val observer = Observer<String> { newRoute ->
|
||||||
routeModel.startNavigation(newRoute)
|
routeModel.startNavigation(newRoute)
|
||||||
routeData.value = routeModel.route.routeGeoJson
|
routeData.value = routeModel.route.routeGeoJson
|
||||||
|
println("Start simulating $newRoute")
|
||||||
|
simulate()
|
||||||
}
|
}
|
||||||
|
|
||||||
val cameraPosition = MutableLiveData(
|
val cameraPosition = MutableLiveData(
|
||||||
@@ -116,33 +113,57 @@ class MainActivity : ComponentActivity() {
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
var locationIndex = 0
|
|
||||||
|
|
||||||
var simulate = false
|
private lateinit var locationManager: LocationManager
|
||||||
|
private lateinit var fusedLocationClient: FusedLocationProviderClient
|
||||||
|
|
||||||
|
private lateinit var mock: MockLocation
|
||||||
|
|
||||||
init {
|
init {
|
||||||
vieModel.route.observe(this, observer)
|
vieModel.route.observe(this, observer)
|
||||||
if (simulate) {
|
|
||||||
vieModel.loadRoute(
|
|
||||||
Constants.homeLocation,
|
|
||||||
Constants.home2Location
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
checkLocationPermissions()
|
||||||
|
|
||||||
|
if (MainApplication.useContacts) {
|
||||||
|
checkContactsPermissions()
|
||||||
|
}
|
||||||
|
|
||||||
|
checkMockLocationEnabled()
|
||||||
|
|
||||||
enableEdgeToEdge()
|
enableEdgeToEdge()
|
||||||
setContent {
|
setContent {
|
||||||
|
if ((checkPermissionForLocation() && !MainApplication.useContacts)
|
||||||
|
|| (checkPermissionForLocation() && MainApplication.useContacts && checkPermissionForContact())) {
|
||||||
|
Content()
|
||||||
|
} else {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun Content() {
|
||||||
|
locationManager = getSystemService(LOCATION_SERVICE) as LocationManager
|
||||||
|
fusedLocationClient = LocationServices.getFusedLocationProviderClient(this)
|
||||||
|
mock = MockLocation(locationManager)
|
||||||
|
mock.setMockLocation(
|
||||||
|
Constants.homeLocation.latitude,
|
||||||
|
Constants.homeLocation.longitude
|
||||||
|
)
|
||||||
|
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
val snackbarHostState = remember { SnackbarHostState() }
|
val snackbarHostState = remember { SnackbarHostState() }
|
||||||
|
var simulationText by remember { mutableStateOf("Start Simulation") }
|
||||||
|
|
||||||
NavigationTheme {
|
NavigationTheme {
|
||||||
ModalNavigationDrawer(
|
ModalNavigationDrawer(
|
||||||
drawerContent = {
|
drawerContent = {
|
||||||
ModalDrawerSheet {
|
ModalDrawerSheet {
|
||||||
Text("Drawer title", modifier = Modifier.padding(16.dp))
|
Text("Drawer title", modifier = Modifier.Companion.padding(16.dp))
|
||||||
HorizontalDivider()
|
HorizontalDivider()
|
||||||
NavigationDrawerItem(
|
NavigationDrawerItem(
|
||||||
label = { Text(text = "Drawer Item") },
|
label = { Text(text = "Drawer Item") },
|
||||||
@@ -161,32 +182,35 @@ class MainActivity : ComponentActivity() {
|
|||||||
floatingActionButton = {
|
floatingActionButton = {
|
||||||
ExtendedFloatingActionButton(
|
ExtendedFloatingActionButton(
|
||||||
text = {
|
text = {
|
||||||
Text("Navigate")
|
Text(simulationText)
|
||||||
},
|
},
|
||||||
icon = { Icon(true) },
|
icon = { SegmentedButtonDefaults.Icon(true) },
|
||||||
onClick = {
|
onClick = {
|
||||||
scope.launch {
|
scope.launch {
|
||||||
snackbarHostState.showSnackbar("Starte Navigation")
|
snackbarHostState.showSnackbar("Starte Navigation")
|
||||||
}
|
}
|
||||||
if (!routeModel.isNavigating() && lastLocation.latitude != 0.0) {
|
if (!routeModel.isNavigating()) {
|
||||||
tilt = 60.0
|
tilt = 60.0
|
||||||
vieModel.loadRoute(
|
vieModel.loadRoute(
|
||||||
|
applicationContext,
|
||||||
lastLocation,
|
lastLocation,
|
||||||
Constants.home2Location
|
Constants.home2Location
|
||||||
)
|
)
|
||||||
|
simulationText = "Stop Simulation"
|
||||||
} else {
|
} else {
|
||||||
tilt = 0.0
|
tilt = 0.0
|
||||||
routeModel.stopNavigation()
|
routeModel.stopNavigation()
|
||||||
routeData.value = ""
|
routeData.value = ""
|
||||||
|
println("stopNavigation")
|
||||||
|
simulationText = "Start Simulation"
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
) { innerPadding ->
|
) { innerPadding ->
|
||||||
Column(modifier = Modifier.padding(innerPadding)) {
|
Column(modifier = Modifier.Companion.padding(innerPadding)) {
|
||||||
CheckPermission()
|
//CheckPermission()
|
||||||
}
|
Map()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -206,7 +230,7 @@ class MainActivity : ComponentActivity() {
|
|||||||
listOf(
|
listOf(
|
||||||
Manifest.permission.ACCESS_COARSE_LOCATION,
|
Manifest.permission.ACCESS_COARSE_LOCATION,
|
||||||
Manifest.permission.ACCESS_FINE_LOCATION,
|
Manifest.permission.ACCESS_FINE_LOCATION,
|
||||||
Manifest.permission.READ_CONTACTS,
|
//Manifest.permission.READ_CONTACTS,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -272,11 +296,7 @@ class MainActivity : ComponentActivity() {
|
|||||||
)
|
)
|
||||||
val userLocationState = rememberUserLocationState(locationProvider)
|
val userLocationState = rememberUserLocationState(locationProvider)
|
||||||
val locationState = locationProvider.location.collectAsState()
|
val locationState = locationProvider.location.collectAsState()
|
||||||
if (!simulate) {
|
|
||||||
updateLocation(locationState.value)
|
updateLocation(locationState.value)
|
||||||
} else {
|
|
||||||
simulate()
|
|
||||||
}
|
|
||||||
if (locationState.value != null && lastLocation.latitude == 0.0) {
|
if (locationState.value != null && lastLocation.latitude == 0.0) {
|
||||||
lastLocation.latitude = locationState.value?.position!!.latitude
|
lastLocation.latitude = locationState.value?.position!!.latitude
|
||||||
lastLocation.longitude = locationState.value?.position!!.longitude
|
lastLocation.longitude = locationState.value?.position!!.longitude
|
||||||
@@ -300,29 +320,33 @@ class MainActivity : ComponentActivity() {
|
|||||||
baseStyle = BaseStyle.Uri(Constants.STYLE),
|
baseStyle = BaseStyle.Uri(Constants.STYLE),
|
||||||
) {
|
) {
|
||||||
getBaseSource(id = "openmaptiles")?.let { tiles ->
|
getBaseSource(id = "openmaptiles")?.let { tiles ->
|
||||||
if (!getBooleanKeyValue(context = applicationContext, SHOW_THREED_BUILDING)) {
|
if (!NavigationUtils.getBooleanKeyValue(
|
||||||
|
context = applicationContext,
|
||||||
|
Constants.SHOW_THREED_BUILDING
|
||||||
|
)
|
||||||
|
) {
|
||||||
BuildingLayer(tiles)
|
BuildingLayer(tiles)
|
||||||
}
|
}
|
||||||
RouteLayer(route, "")
|
RouteLayer(route, "")
|
||||||
}
|
}
|
||||||
if (userLocationState.location != null) {
|
|
||||||
val location = Location(LocationManager.GPS_PROVIDER)
|
val location = Location(LocationManager.GPS_PROVIDER)
|
||||||
|
if (userLocationState.location != null) {
|
||||||
location.longitude = userLocationState.location!!.position.longitude
|
location.longitude = userLocationState.location!!.position.longitude
|
||||||
location.latitude = userLocationState.location!!.position.latitude
|
location.latitude = userLocationState.location!!.position.latitude
|
||||||
PuckState(cameraState, userLocationState,)
|
PuckState(cameraState, userLocationState)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LocationTrackingEffect(
|
LocationTrackingEffect(
|
||||||
locationState = userLocationState,
|
locationState = userLocationState,
|
||||||
) {
|
) {
|
||||||
//cameraState.updateFromLocation()
|
|
||||||
cameraState.animateTo(
|
cameraState.animateTo(
|
||||||
finalPosition = CameraPosition(
|
finalPosition = CameraPosition(
|
||||||
bearing = position!!.bearing,
|
bearing = position!!.bearing,
|
||||||
zoom = position!!.zoom,
|
zoom = position!!.zoom,
|
||||||
target = position!!.target,
|
target = position!!.target,
|
||||||
tilt = tilt
|
tilt = tilt,
|
||||||
|
padding = PaddingValues(start = 0.dp, top = 350.dp)
|
||||||
),
|
),
|
||||||
duration = 1.seconds
|
duration = 1.seconds
|
||||||
)
|
)
|
||||||
@@ -345,86 +369,107 @@ class MainActivity : ComponentActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun checkLocationPermissions() {
|
||||||
|
val permissions = mutableListOf(
|
||||||
|
Manifest.permission.ACCESS_FINE_LOCATION,
|
||||||
|
Manifest.permission.ACCESS_COARSE_LOCATION,
|
||||||
|
)
|
||||||
|
if (MainApplication.useContacts) {
|
||||||
|
permissions.add(Manifest.permission.READ_CONTACTS)
|
||||||
|
}
|
||||||
|
|
||||||
fun updateTestLocation(location: Location) {
|
val permissionsToRequest = permissions.filter {
|
||||||
var snapedLocation = location
|
ContextCompat.checkSelfPermission(this, it) != PackageManager.PERMISSION_GRANTED
|
||||||
var bearing: Double
|
}
|
||||||
|
|
||||||
|
if (permissionsToRequest.isNotEmpty()) {
|
||||||
|
ActivityCompat.requestPermissions(
|
||||||
|
this,
|
||||||
|
permissionsToRequest.toTypedArray(),
|
||||||
|
LOCATION_PERMISSION_REQUEST_CODE
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun checkPermissionForLocation(): Boolean {
|
||||||
|
val permissions = mutableListOf(
|
||||||
|
Manifest.permission.ACCESS_FINE_LOCATION,
|
||||||
|
Manifest.permission.ACCESS_COARSE_LOCATION,
|
||||||
|
)
|
||||||
|
|
||||||
|
if (MainApplication.useContacts) {
|
||||||
|
permissions.add(Manifest.permission.READ_CONTACTS)
|
||||||
|
}
|
||||||
|
val permissionsToRequest = permissions.filter {
|
||||||
|
ContextCompat.checkSelfPermission(this, it) != PackageManager.PERMISSION_GRANTED
|
||||||
|
}
|
||||||
|
return permissionsToRequest.isEmpty()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun checkPermissionForContact(): Boolean {
|
||||||
|
val permissions = arrayOf(
|
||||||
|
Manifest.permission.READ_CONTACTS,
|
||||||
|
)
|
||||||
|
val permissionsToRequest = permissions.filter {
|
||||||
|
ContextCompat.checkSelfPermission(this, it) != PackageManager.PERMISSION_GRANTED
|
||||||
|
}
|
||||||
|
return permissionsToRequest.isEmpty()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun checkContactsPermissions() {
|
||||||
|
val permissions = arrayOf(
|
||||||
|
Manifest.permission.READ_CONTACTS,
|
||||||
|
)
|
||||||
|
|
||||||
|
val permissionsToRequest = permissions.filter {
|
||||||
|
ContextCompat.checkSelfPermission(this, it) != PackageManager.PERMISSION_GRANTED
|
||||||
|
}
|
||||||
|
|
||||||
|
if (permissionsToRequest.isNotEmpty()) {
|
||||||
|
ActivityCompat.requestPermissions(
|
||||||
|
this,
|
||||||
|
permissionsToRequest.toTypedArray(),
|
||||||
|
CONTACTS_PERMISSION_REQUEST_CODE
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun checkMockLocationEnabled() {
|
||||||
|
try {
|
||||||
|
// Check if mock location is enabled for this app
|
||||||
|
val appOpsManager =
|
||||||
|
getSystemService(APP_OPS_SERVICE) as AppOpsManager
|
||||||
|
val mode =
|
||||||
|
appOpsManager.unsafeCheckOp(
|
||||||
|
AppOpsManager.OPSTR_MOCK_LOCATION,
|
||||||
|
Process.myUid(),
|
||||||
|
packageName
|
||||||
|
)
|
||||||
|
|
||||||
|
if (mode != AppOpsManager.MODE_ALLOWED) {
|
||||||
|
Toast.makeText(
|
||||||
|
this,
|
||||||
|
"Please select this app as mock location app in Developer Options",
|
||||||
|
Toast.LENGTH_LONG
|
||||||
|
).show()
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@OptIn(DelicateCoroutinesApi::class)
|
||||||
|
fun simulate() = GlobalScope.async {
|
||||||
|
for ((i, loc) in routeModel.route.waypoints.withIndex()) {
|
||||||
if (routeModel.isNavigating()) {
|
if (routeModel.isNavigating()) {
|
||||||
snapedLocation = snapLocation(location, routeModel.route.maneuverLocations())
|
|
||||||
routeModel.updateLocation(location)
|
|
||||||
bearing = routeModel.currentStep().bearing
|
|
||||||
instruction.postValue(routeModel.currentStep())
|
|
||||||
} else {
|
|
||||||
bearing = cameraPosition.value!!.bearing
|
|
||||||
}
|
|
||||||
val zoom = calculateZoom(snapedLocation.speed.toDouble())
|
|
||||||
cameraPosition.postValue(
|
|
||||||
cameraPosition.value!!.copy(
|
|
||||||
bearing = bearing,
|
|
||||||
zoom = zoom,
|
|
||||||
target = Position(snapedLocation.longitude, snapedLocation.latitude)
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun simulate() {
|
|
||||||
if (routeModel.isNavigating() && locationIndex < routeModel.route.waypoints.size) {
|
|
||||||
coroutineScope.launch {
|
|
||||||
delay(
|
|
||||||
100
|
|
||||||
)
|
|
||||||
val loc = routeModel.route.waypoints[locationIndex]
|
|
||||||
lastLocation.longitude = loc[0]
|
lastLocation.longitude = loc[0]
|
||||||
lastLocation.latitude = loc[1]
|
lastLocation.latitude = loc[1]
|
||||||
updateTestLocation(lastLocation)
|
if (i == 20) {
|
||||||
Thread.sleep(1_000)
|
mock.setMockLocation(loc[1] + 0.03, loc[0])
|
||||||
locationIndex++
|
} else {
|
||||||
}
|
mock.setMockLocation(loc[1], loc[0])
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun PlaceList(viewModel: ViewModel = koinViewModel()) {
|
|
||||||
var categories: List<Category>
|
|
||||||
val places = viewModel.places.observeAsState().value ?: return
|
|
||||||
|
|
||||||
val countries = places.groupBy { it.category }.map {
|
|
||||||
Category(id = Constants.RECENT, name = it.key!!)
|
|
||||||
}
|
|
||||||
categories = countries
|
|
||||||
val context = LocalContext.current
|
|
||||||
LazyColumn {
|
|
||||||
items(categories.size) {
|
|
||||||
val place = categories[it]
|
|
||||||
Row(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(8.dp)
|
|
||||||
.border(
|
|
||||||
2.dp,
|
|
||||||
color = MaterialTheme.colorScheme.outline,
|
|
||||||
shape = RoundedCornerShape(8.dp)
|
|
||||||
)
|
|
||||||
.clip(RoundedCornerShape(8.dp))
|
|
||||||
//.clickable {
|
|
||||||
//context.startActivity(place.toIntent(Intent.ACTION_VIEW))
|
|
||||||
//}
|
|
||||||
.padding(8.dp)
|
|
||||||
) {
|
|
||||||
Column {
|
|
||||||
Text(
|
|
||||||
text = place.name,
|
|
||||||
style = MaterialTheme.typography.labelLarge
|
|
||||||
)
|
|
||||||
Text(
|
|
||||||
text = place.name,
|
|
||||||
style = MaterialTheme.typography.bodyMedium,
|
|
||||||
overflow = TextOverflow.Ellipsis,
|
|
||||||
maxLines = 1
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
delay(1000L) //
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.kouros.navigation
|
package com.kouros.navigation.ui
|
||||||
|
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
@@ -26,6 +26,7 @@ import com.google.accompanist.permissions.MultiplePermissionsState
|
|||||||
import com.google.accompanist.permissions.PermissionState
|
import com.google.accompanist.permissions.PermissionState
|
||||||
import com.google.accompanist.permissions.rememberMultiplePermissionsState
|
import com.google.accompanist.permissions.rememberMultiplePermissionsState
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simple screen that manages the location permission state
|
* Simple screen that manages the location permission state
|
||||||
*/
|
*/
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.kouros.navigation
|
package com.kouros.navigation.ui
|
||||||
|
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
@@ -51,6 +51,7 @@ dependencies {
|
|||||||
implementation(libs.androidx.compose.ui)
|
implementation(libs.androidx.compose.ui)
|
||||||
implementation(libs.androidx.material3)
|
implementation(libs.androidx.material3)
|
||||||
implementation(libs.androidx.compose.ui.text)
|
implementation(libs.androidx.compose.ui.text)
|
||||||
|
implementation(libs.play.services.location)
|
||||||
androidTestImplementation(libs.androidx.junit)
|
androidTestImplementation(libs.androidx.junit)
|
||||||
testImplementation(libs.junit)
|
testImplementation(libs.junit)
|
||||||
}
|
}
|
||||||
@@ -32,7 +32,7 @@
|
|||||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
|
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
|
||||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
|
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
|
||||||
<uses-permission android:name="androidx.car.app.ACCESS_SURFACE" />
|
<uses-permission android:name="androidx.car.app.ACCESS_SURFACE" />
|
||||||
<uses-permission android:name="android.permission.READ_CONTACTS" />
|
<uses-permission android:name="android.permission.READ_CONTACTS"/>
|
||||||
|
|
||||||
<application android:requestLegacyExternalStorage="true">
|
<application android:requestLegacyExternalStorage="true">
|
||||||
<!--
|
<!--
|
||||||
|
|||||||
@@ -47,13 +47,10 @@ import org.maplibre.spatialk.geojson.Position
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun cameraState(
|
fun cameraState(
|
||||||
width: Int,
|
padding : PaddingValues,
|
||||||
height: Int,
|
|
||||||
position: CameraPosition?,
|
position: CameraPosition?,
|
||||||
tilt: Double,
|
tilt: Double,
|
||||||
preview: Boolean
|
|
||||||
): CameraState {
|
): CameraState {
|
||||||
val padding = getPaddingValues(height, preview)
|
|
||||||
return rememberCameraState(
|
return rememberCameraState(
|
||||||
firstPosition =
|
firstPosition =
|
||||||
CameraPosition(
|
CameraPosition(
|
||||||
@@ -117,20 +114,18 @@ fun BuildingLayer(tiles: Source) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun DrawImage(width: Int, height: Int, location: Location, street: String) {
|
fun DrawImage(padding: PaddingValues, location: Location, width: Int, height: Int, street: String) {
|
||||||
NavigationImage(height, street)
|
NavigationImage(padding, street)
|
||||||
Speed(width, height, location)
|
Speed(width, height, location)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun NavigationImage(height: Int, street: String) {
|
fun NavigationImage(padding: PaddingValues, street: String) {
|
||||||
val vector = ImageVector.vectorResource(id = R.drawable.assistant_navigation_48px)
|
val vector = ImageVector.vectorResource(id = R.drawable.assistant_navigation_48px)
|
||||||
val color = remember { NavigationColor }
|
val color = remember { NavigationColor }
|
||||||
BadgedBox(
|
BadgedBox(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(
|
.padding(padding),
|
||||||
start = 0.dp, top = distanceFromTop(height).dp
|
|
||||||
),
|
|
||||||
badge = {
|
badge = {
|
||||||
Badge()
|
Badge()
|
||||||
}
|
}
|
||||||
@@ -156,7 +151,7 @@ private fun Speed(
|
|||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(
|
.padding(
|
||||||
start = width.dp- 300.dp,
|
start = width.dp- 250.dp,
|
||||||
top = height.dp- 80.dp
|
top = height.dp- 80.dp
|
||||||
),
|
),
|
||||||
contentAlignment = Alignment.Center
|
contentAlignment = Alignment.Center
|
||||||
@@ -210,18 +205,17 @@ private fun Speed(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getPaddingValues(height: Int, preView: Boolean): PaddingValues {
|
fun getPaddingValues(width: Int, height: Int, preView: Boolean): PaddingValues {
|
||||||
val padding = PaddingValues(start = 0.dp, top = distanceFromTop(height).dp)
|
|
||||||
val prePadding = PaddingValues(start = 150.dp, bottom = 0.dp)
|
|
||||||
return if (preView) {
|
return if (preView) {
|
||||||
prePadding
|
PaddingValues(start = 150.dp, bottom = 0.dp)
|
||||||
} else {
|
} else {
|
||||||
padding
|
// PaddingValues(start = width.dp, top = distanceFromTop(height).dp)
|
||||||
|
PaddingValues(start = 0.dp, top = distanceFromTop(height).dp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun distanceFromTop(height: Int): Int {
|
fun distanceFromTop(height: Int): Int {
|
||||||
return height - percent(height, 20)
|
return height - percent(height, 25)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun percent(maxValue: Int, value: Int): Int {
|
fun percent(maxValue: Int, value: Int): Int {
|
||||||
|
|||||||
@@ -7,9 +7,7 @@ import android.content.Intent
|
|||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
import android.location.Location
|
import android.location.Location
|
||||||
import android.location.LocationManager
|
import android.location.LocationManager
|
||||||
import android.os.Build
|
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.annotation.RequiresApi
|
|
||||||
import androidx.car.app.CarContext
|
import androidx.car.app.CarContext
|
||||||
import androidx.car.app.Screen
|
import androidx.car.app.Screen
|
||||||
import androidx.car.app.ScreenManager
|
import androidx.car.app.ScreenManager
|
||||||
@@ -27,13 +25,7 @@ import com.kouros.navigation.car.screen.SearchScreen
|
|||||||
import com.kouros.navigation.data.Constants.MAXIMAL_ROUTE_DEVIATION
|
import com.kouros.navigation.data.Constants.MAXIMAL_ROUTE_DEVIATION
|
||||||
import com.kouros.navigation.data.Constants.MAXIMAL_SNAP_CORRECTION
|
import com.kouros.navigation.data.Constants.MAXIMAL_SNAP_CORRECTION
|
||||||
import com.kouros.navigation.data.Constants.TAG
|
import com.kouros.navigation.data.Constants.TAG
|
||||||
import com.kouros.navigation.data.ObjectBox
|
|
||||||
import com.kouros.navigation.utils.NavigationUtils.snapLocation
|
import com.kouros.navigation.utils.NavigationUtils.snapLocation
|
||||||
import com.kouros.navigation.utils.location
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.delay
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
|
|
||||||
class NavigationSession : Session(), NavigationScreen.Listener {
|
class NavigationSession : Session(), NavigationScreen.Listener {
|
||||||
val uriScheme = "samples";
|
val uriScheme = "samples";
|
||||||
@@ -46,16 +38,10 @@ class NavigationSession : Session(), NavigationScreen.Listener {
|
|||||||
|
|
||||||
lateinit var surfaceRenderer: SurfaceRenderer
|
lateinit var surfaceRenderer: SurfaceRenderer
|
||||||
|
|
||||||
var locationIndex = 0
|
|
||||||
|
|
||||||
val simulate = false
|
|
||||||
|
|
||||||
var mLocationListener: LocationListenerCompat = LocationListenerCompat { location: Location? ->
|
var mLocationListener: LocationListenerCompat = LocationListenerCompat { location: Location? ->
|
||||||
updateLocation(location)
|
updateLocation(location!!)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val coroutineScope: CoroutineScope = CoroutineScope(Dispatchers.IO)
|
|
||||||
|
|
||||||
private val mLifeCycleObserver: LifecycleObserver = object : DefaultLifecycleObserver {
|
private val mLifeCycleObserver: LifecycleObserver = object : DefaultLifecycleObserver {
|
||||||
override fun onCreate(owner: LifecycleOwner) {
|
override fun onCreate(owner: LifecycleOwner) {
|
||||||
Log.i(TAG, "In onCreate()")
|
Log.i(TAG, "In onCreate()")
|
||||||
@@ -161,6 +147,7 @@ class NavigationSession : Session(), NavigationScreen.Listener {
|
|||||||
val locationManager =
|
val locationManager =
|
||||||
carContext.getSystemService(Context.LOCATION_SERVICE) as LocationManager
|
carContext.getSystemService(Context.LOCATION_SERVICE) as LocationManager
|
||||||
val location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER)
|
val location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER)
|
||||||
|
if (location != null) {
|
||||||
updateLocation(location)
|
updateLocation(location)
|
||||||
locationManager.requestLocationUpdates(
|
locationManager.requestLocationUpdates(
|
||||||
LocationManager.GPS_PROVIDER,
|
LocationManager.GPS_PROVIDER,
|
||||||
@@ -169,48 +156,15 @@ class NavigationSession : Session(), NavigationScreen.Listener {
|
|||||||
mLocationListener
|
mLocationListener
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateLocation(location: Location?) {
|
|
||||||
if (location != null) {
|
|
||||||
if (simulate) {
|
|
||||||
simulate(location)
|
|
||||||
} else {
|
|
||||||
update(location)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun simulate(location: Location?) {
|
fun updateLocation(location: Location) {
|
||||||
if (routeModel.isNavigating() && locationIndex < routeModel.route.waypoints.size) {
|
|
||||||
coroutineScope.launch {
|
|
||||||
if (locationIndex >= routeModel.route.waypoints.size) {
|
|
||||||
return@launch
|
|
||||||
}
|
|
||||||
val loc = routeModel.route.waypoints[locationIndex]
|
|
||||||
val curLocation = Location(LocationManager.GPS_PROVIDER)
|
|
||||||
curLocation.longitude = loc[0]// + 0.00001 * locationIndex
|
|
||||||
curLocation.latitude = loc[1] //+ 0.00001 * locationIndex
|
|
||||||
curLocation.speed = 15F
|
|
||||||
update(curLocation)
|
|
||||||
locationIndex += 1
|
|
||||||
if (locationIndex > routeModel.route.waypoints.size) {
|
|
||||||
val locationManager =
|
|
||||||
carContext.getSystemService(Context.LOCATION_SERVICE) as LocationManager
|
|
||||||
locationManager.removeUpdates(mLocationListener)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
update(location = location!!)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun update(location: Location) {
|
|
||||||
if (routeModel.isNavigating()) {
|
if (routeModel.isNavigating()) {
|
||||||
val snapedLocation = snapLocation(location, routeModel.route.maneuverLocations())
|
val snapedLocation = snapLocation(location, routeModel.route.maneuverLocations())
|
||||||
val distance = location.distanceTo(snapedLocation)
|
val distance = location.distanceTo(snapedLocation)
|
||||||
if (distance > MAXIMAL_ROUTE_DEVIATION) {
|
if (distance > MAXIMAL_ROUTE_DEVIATION) {
|
||||||
// navigationScreen.calculateNewRoute()
|
navigationScreen.calculateNewRoute(routeModel.destination)
|
||||||
//return
|
return
|
||||||
}
|
}
|
||||||
routeModel.updateLocation(location)
|
routeModel.updateLocation(location)
|
||||||
navigationScreen.updateTrip()
|
navigationScreen.updateTrip()
|
||||||
|
|||||||
@@ -6,13 +6,13 @@ import android.hardware.display.DisplayManager
|
|||||||
import android.hardware.display.VirtualDisplay
|
import android.hardware.display.VirtualDisplay
|
||||||
import android.location.Location
|
import android.location.Location
|
||||||
import android.location.LocationManager
|
import android.location.LocationManager
|
||||||
import android.os.Build
|
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.annotation.RequiresApi
|
|
||||||
import androidx.car.app.AppManager
|
import androidx.car.app.AppManager
|
||||||
import androidx.car.app.CarContext
|
import androidx.car.app.CarContext
|
||||||
import androidx.car.app.SurfaceCallback
|
import androidx.car.app.SurfaceCallback
|
||||||
import androidx.car.app.SurfaceContainer
|
import androidx.car.app.SurfaceContainer
|
||||||
|
import androidx.compose.foundation.isSystemInDarkTheme
|
||||||
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
@@ -54,7 +54,7 @@ class SurfaceRenderer(
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
var visibleArea = MutableLiveData(
|
var visibleArea = MutableLiveData(
|
||||||
Rect(0,0,0,0)
|
Rect(0, 0, 0, 0)
|
||||||
)
|
)
|
||||||
|
|
||||||
var stableArea = Rect()
|
var stableArea = Rect()
|
||||||
@@ -162,16 +162,17 @@ class SurfaceRenderer(
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun MapView() {
|
fun MapView() {
|
||||||
|
val stateWidth = visibleArea.observeAsState()
|
||||||
val position: CameraPosition? by cameraPosition.observeAsState()
|
val position: CameraPosition? by cameraPosition.observeAsState()
|
||||||
val route: String? by routeData.observeAsState()
|
val route: String? by routeData.observeAsState()
|
||||||
val previewRoute: String? by previewRouteData.observeAsState()
|
val previewRoute: String? by previewRouteData.observeAsState()
|
||||||
val cameraState = cameraState(width, height, position, tilt, preview)
|
val paddingValues = getPaddingValues( width - stateWidth.value!!.width(), height, preview)
|
||||||
|
val cameraState = cameraState(paddingValues, position, tilt)
|
||||||
|
|
||||||
val baseStyle = BaseStyle.Uri(Constants.STYLE)
|
val baseStyle = BaseStyle.Uri(Constants.STYLE)
|
||||||
// if (isSystemInDarkTheme()) BaseStyle.Uri(Constants.STYLE_DARK) else BaseStyle.Uri(
|
if (isSystemInDarkTheme()) BaseStyle.Uri(Constants.STYLE_DARK) else BaseStyle.Uri(
|
||||||
// Constants.STYLE
|
Constants.STYLE
|
||||||
// )
|
)
|
||||||
|
|
||||||
MaplibreMap(
|
MaplibreMap(
|
||||||
cameraState = cameraState,
|
cameraState = cameraState,
|
||||||
baseStyle = baseStyle,
|
baseStyle = baseStyle,
|
||||||
@@ -184,11 +185,11 @@ class SurfaceRenderer(
|
|||||||
}
|
}
|
||||||
//Puck(cameraState, lastLocation)
|
//Puck(cameraState, lastLocation)
|
||||||
}
|
}
|
||||||
ShowPosition(cameraState, position)
|
ShowPosition(cameraState, position, paddingValues)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ShowPosition(cameraState: CameraState, position: CameraPosition?) {
|
fun ShowPosition(cameraState: CameraState, position: CameraPosition?, paddingValues: PaddingValues) {
|
||||||
val cameraDuration = duration(position)
|
val cameraDuration = duration(position)
|
||||||
var bearing = position!!.bearing
|
var bearing = position!!.bearing
|
||||||
var zoom = position.zoom
|
var zoom = position.zoom
|
||||||
@@ -196,9 +197,9 @@ class SurfaceRenderer(
|
|||||||
var localTilt = tilt
|
var localTilt = tilt
|
||||||
if (!preview) {
|
if (!preview) {
|
||||||
if (routeModel.isNavigating()) {
|
if (routeModel.isNavigating()) {
|
||||||
DrawImage(width, height, lastLocation, "")
|
DrawImage(paddingValues, lastLocation, width, height,"")
|
||||||
} else {
|
} else {
|
||||||
DrawImage(width, height, lastLocation, "")
|
DrawImage(paddingValues, lastLocation,width, height, "")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
bearing = 0.0
|
bearing = 0.0
|
||||||
@@ -213,7 +214,7 @@ class SurfaceRenderer(
|
|||||||
zoom = zoom,
|
zoom = zoom,
|
||||||
target = target,
|
target = target,
|
||||||
tilt = localTilt,
|
tilt = localTilt,
|
||||||
padding = getPaddingValues(height, preview)
|
padding = paddingValues
|
||||||
),
|
),
|
||||||
duration = cameraDuration
|
duration = cameraDuration
|
||||||
)
|
)
|
||||||
@@ -259,16 +260,21 @@ class SurfaceRenderer(
|
|||||||
fun updateLocation(location: Location) {
|
fun updateLocation(location: Location) {
|
||||||
synchronized(this) {
|
synchronized(this) {
|
||||||
if (!preview) {
|
if (!preview) {
|
||||||
var bearing = cameraPosition.value!!.bearing
|
val bearing = if (routeModel.isNavigating()) {
|
||||||
if (routeModel.isNavigating()) {
|
routeModel.currentStep().bearing
|
||||||
bearing = routeModel.currentStep().bearing
|
} else {
|
||||||
|
lastLocation.bearingTo(location).toInt().toDouble().absoluteValue
|
||||||
}
|
}
|
||||||
val zoom = if (!panView) {
|
val zoom = if (!panView) {
|
||||||
calculateZoom(location.speed.toDouble())
|
calculateZoom(location.speed.toDouble())
|
||||||
} else {
|
} else {
|
||||||
cameraPosition.value!!.zoom
|
cameraPosition.value!!.zoom
|
||||||
}
|
}
|
||||||
updateCameraPosition(bearing, zoom, Position(location.longitude, location.latitude))
|
updateCameraPosition(
|
||||||
|
bearing,
|
||||||
|
zoom,
|
||||||
|
Position(location.longitude, location.latitude)
|
||||||
|
)
|
||||||
lastBearing = cameraPosition.value!!.bearing
|
lastBearing = cameraPosition.value!!.bearing
|
||||||
lastLocation = location
|
lastLocation = location
|
||||||
} else {
|
} else {
|
||||||
@@ -289,7 +295,7 @@ class SurfaceRenderer(
|
|||||||
bearing = bearing,
|
bearing = bearing,
|
||||||
zoom = zoom,
|
zoom = zoom,
|
||||||
tilt = 0.0,
|
tilt = 0.0,
|
||||||
padding = getPaddingValues(height, preview),
|
padding = getPaddingValues(width-visibleArea.value!!.width(), height, preview),
|
||||||
target = target
|
target = target
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -315,9 +321,11 @@ class SurfaceRenderer(
|
|||||||
in 0.0..10.0 -> {
|
in 0.0..10.0 -> {
|
||||||
return 13.0
|
return 13.0
|
||||||
}
|
}
|
||||||
|
|
||||||
in 10.0..20.0 -> {
|
in 10.0..20.0 -> {
|
||||||
return 11.0
|
return 11.0
|
||||||
}
|
}
|
||||||
|
|
||||||
in 20.0..30.0 -> {
|
in 20.0..30.0 -> {
|
||||||
return 10.0
|
return 10.0
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,77 +0,0 @@
|
|||||||
package com.kouros.navigation.car.navigation
|
|
||||||
|
|
||||||
import android.location.Location
|
|
||||||
import android.os.Environment
|
|
||||||
import org.xml.sax.SAXException
|
|
||||||
import java.io.File
|
|
||||||
import java.io.FileInputStream
|
|
||||||
import java.io.FileNotFoundException
|
|
||||||
import java.io.IOException
|
|
||||||
import javax.xml.parsers.DocumentBuilderFactory
|
|
||||||
import javax.xml.parsers.ParserConfigurationException
|
|
||||||
|
|
||||||
|
|
||||||
class Gpx {
|
|
||||||
|
|
||||||
fun loadGPX() {
|
|
||||||
val path = Environment.getExternalStorageDirectory()
|
|
||||||
.toString() + "/Download/VogelHohen.gpx"
|
|
||||||
var info = ""
|
|
||||||
val gpxFile = File(path)
|
|
||||||
|
|
||||||
info = info + gpxFile.path + "\n\n"
|
|
||||||
|
|
||||||
val gpxList = decodeGPX(gpxFile)
|
|
||||||
print(gpxList)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private fun decodeGPX(file: File): MutableList<Location?> {
|
|
||||||
val list: MutableList<Location?> = ArrayList()
|
|
||||||
|
|
||||||
val documentBuilderFactory = DocumentBuilderFactory.newInstance()
|
|
||||||
try {
|
|
||||||
val documentBuilder = documentBuilderFactory.newDocumentBuilder()
|
|
||||||
val fileInputStream = FileInputStream(file)
|
|
||||||
val document = documentBuilder.parse(fileInputStream)
|
|
||||||
val elementRoot = document.documentElement
|
|
||||||
|
|
||||||
val nodelist_trkpt = elementRoot.getElementsByTagName("trkpt")
|
|
||||||
|
|
||||||
for (i in 0..<nodelist_trkpt.getLength()) {
|
|
||||||
val node = nodelist_trkpt.item(i)
|
|
||||||
val attributes = node.getAttributes()
|
|
||||||
|
|
||||||
val newLatitude = attributes.getNamedItem("lat").getTextContent()
|
|
||||||
val newLatitude_double = newLatitude.toDouble()
|
|
||||||
|
|
||||||
val newLongitude = attributes.getNamedItem("lon").getTextContent()
|
|
||||||
val newLongitude_double = newLongitude.toDouble()
|
|
||||||
|
|
||||||
val newLocationName = newLatitude + ":" + newLongitude
|
|
||||||
val newLocation = Location(newLocationName)
|
|
||||||
newLocation.setLatitude(newLatitude_double)
|
|
||||||
newLocation.setLongitude(newLongitude_double)
|
|
||||||
|
|
||||||
list.add(newLocation)
|
|
||||||
}
|
|
||||||
|
|
||||||
fileInputStream.close()
|
|
||||||
} catch (e: ParserConfigurationException) {
|
|
||||||
// TODO Auto-generated catch block
|
|
||||||
e.printStackTrace()
|
|
||||||
} catch (e: FileNotFoundException) {
|
|
||||||
// TODO Auto-generated catch block
|
|
||||||
e.printStackTrace()
|
|
||||||
} catch (e: SAXException) {
|
|
||||||
// TODO Auto-generated catch block
|
|
||||||
e.printStackTrace()
|
|
||||||
} catch (e: IOException) {
|
|
||||||
// TODO Auto-generated catch block
|
|
||||||
e.printStackTrace()
|
|
||||||
}
|
|
||||||
|
|
||||||
return list
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -15,37 +15,6 @@ import com.kouros.android.cars.carappservice.R
|
|||||||
|
|
||||||
class NavigationMessage (private var carContext: CarContext) {
|
class NavigationMessage (private var carContext: CarContext) {
|
||||||
|
|
||||||
/** Returns a sample [Alert]. */
|
|
||||||
fun createAlert(): Alert {
|
|
||||||
val title: CarText = createCarText(R.string.navigation_alert_title)
|
|
||||||
val subtitle: CarText = createCarText(R.string.navigation_alert_subtitle)
|
|
||||||
val icon = CarIcon.ALERT
|
|
||||||
|
|
||||||
val yesAction: Action = createToastAction(
|
|
||||||
R.string.yes_action_title,
|
|
||||||
R.string.yes_action_toast_msg, Action.FLAG_PRIMARY
|
|
||||||
)
|
|
||||||
val noAction: Action = createToastAction(
|
|
||||||
R.string.no_action_title, R.string.no_action_toast_msg,
|
|
||||||
Action.FLAG_DEFAULT
|
|
||||||
)
|
|
||||||
|
|
||||||
return Alert.Builder( /* alertId: */0, title, /* durationMillis: */10000)
|
|
||||||
.setSubtitle(subtitle)
|
|
||||||
.setIcon(icon)
|
|
||||||
.addAction(yesAction)
|
|
||||||
.addAction(noAction).setCallback(object : AlertCallback {
|
|
||||||
override fun onCancel(reason: Int) {
|
|
||||||
if (reason == AlertCallback.REASON_TIMEOUT) {
|
|
||||||
showToast(R.string.alert_timeout_toast_msg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDismiss() {
|
|
||||||
}
|
|
||||||
}).build()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createToastAction(
|
private fun createToastAction(
|
||||||
@StringRes titleRes: Int, @StringRes toastStringRes: Int,
|
@StringRes titleRes: Int, @StringRes toastStringRes: Int,
|
||||||
flags: Int
|
flags: Int
|
||||||
|
|||||||
@@ -214,7 +214,7 @@ class RouteCarModel() : RouteModel() {
|
|||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createString(
|
fun createString(
|
||||||
text: String
|
text: String
|
||||||
): SpannableString {
|
): SpannableString {
|
||||||
val spannableString = SpannableString(text)
|
val spannableString = SpannableString(text)
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ class DisplaySettings(private val carContext: CarContext) : Screen(carContext) {
|
|||||||
.setSingleList(listBuilder.build())
|
.setSingleList(listBuilder.build())
|
||||||
.setHeader(
|
.setHeader(
|
||||||
Header.Builder()
|
Header.Builder()
|
||||||
.setTitle(carContext.getString(R.string.content_limits))
|
.setTitle(carContext.getString(R.string.display_settings))
|
||||||
.setStartHeaderAction(Action.BACK)
|
.setStartHeaderAction(Action.BACK)
|
||||||
.build()
|
.build()
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ import androidx.car.app.model.Header
|
|||||||
import androidx.car.app.model.MessageTemplate
|
import androidx.car.app.model.MessageTemplate
|
||||||
import androidx.car.app.model.Template
|
import androidx.car.app.model.Template
|
||||||
import androidx.car.app.navigation.model.Maneuver
|
import androidx.car.app.navigation.model.Maneuver
|
||||||
import androidx.car.app.navigation.model.MapController
|
|
||||||
import androidx.car.app.navigation.model.MapWithContentTemplate
|
import androidx.car.app.navigation.model.MapWithContentTemplate
|
||||||
import androidx.car.app.navigation.model.MessageInfo
|
import androidx.car.app.navigation.model.MessageInfo
|
||||||
import androidx.car.app.navigation.model.NavigationTemplate
|
import androidx.car.app.navigation.model.NavigationTemplate
|
||||||
@@ -86,18 +85,17 @@ class NavigationScreen(
|
|||||||
|
|
||||||
override fun onGetTemplate(): Template {
|
override fun onGetTemplate(): Template {
|
||||||
val actionStripBuilder = createActionStripBuilder()
|
val actionStripBuilder = createActionStripBuilder()
|
||||||
return if (routeModel.isNavigating()) {
|
|
||||||
if (calculateNewRoute) {
|
if (calculateNewRoute) {
|
||||||
getNavigationLoadingTemplate(actionStripBuilder)
|
return navigationRerouteTemplate(actionStripBuilder)
|
||||||
} else {
|
|
||||||
getNavigationTemplate(actionStripBuilder)
|
|
||||||
}
|
}
|
||||||
|
return if (routeModel.isNavigating()) {
|
||||||
|
navigationTemplate(actionStripBuilder)
|
||||||
} else {
|
} else {
|
||||||
getNavigationEndTemplate(actionStripBuilder)
|
navigationEndTemplate(actionStripBuilder)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getNavigationTemplate(actionStripBuilder: ActionStrip.Builder): NavigationTemplate {
|
private fun navigationTemplate(actionStripBuilder: ActionStrip.Builder): NavigationTemplate {
|
||||||
actionStripBuilder.addAction(
|
actionStripBuilder.addAction(
|
||||||
stopAction()
|
stopAction()
|
||||||
)
|
)
|
||||||
@@ -112,7 +110,7 @@ class NavigationScreen(
|
|||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getNavigationEndTemplate(actionStripBuilder: ActionStrip.Builder): Template {
|
private fun navigationEndTemplate(actionStripBuilder: ActionStrip.Builder): Template {
|
||||||
if (routeModel.isArrived()) {
|
if (routeModel.isArrived()) {
|
||||||
val timer = object : CountDownTimer(10000, 10000) {
|
val timer = object : CountDownTimer(10000, 10000) {
|
||||||
override fun onTick(millisUntilFinished: Long) {}
|
override fun onTick(millisUntilFinished: Long) {}
|
||||||
@@ -122,6 +120,21 @@ class NavigationScreen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
timer.start()
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun navigationArrivedTemplate(actionStripBuilder: ActionStrip.Builder): NavigationTemplate {
|
||||||
return NavigationTemplate.Builder()
|
return NavigationTemplate.Builder()
|
||||||
.setNavigationInfo(
|
.setNavigationInfo(
|
||||||
MessageInfo.Builder(
|
MessageInfo.Builder(
|
||||||
@@ -143,20 +156,9 @@ class NavigationScreen(
|
|||||||
.setActionStrip(actionStripBuilder.build())
|
.setActionStrip(actionStripBuilder.build())
|
||||||
.setMapActionStrip(mapActionStripBuilder().build())
|
.setMapActionStrip(mapActionStripBuilder().build())
|
||||||
.build()
|
.build()
|
||||||
} else {
|
|
||||||
return if (recentPlaceFound && recentPlaceActive) {
|
|
||||||
return getRecentPlaceTemplate()
|
|
||||||
} else {
|
|
||||||
NavigationTemplate.Builder()
|
|
||||||
.setBackgroundColor(CarColor.SECONDARY)
|
|
||||||
.setActionStrip(actionStripBuilder.build())
|
|
||||||
.setMapActionStrip(mapActionStripBuilder().build())
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getRecentPlaceTemplate(): Template {
|
fun recentPlaceTemplate(): Template {
|
||||||
val messageTemplate = MessageTemplate.Builder(
|
val messageTemplate = MessageTemplate.Builder(
|
||||||
recentPlace.name + "\n"
|
recentPlace.name + "\n"
|
||||||
+ recentPlace.city
|
+ recentPlace.city
|
||||||
@@ -181,11 +183,27 @@ class NavigationScreen(
|
|||||||
return builder.build()
|
return builder.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getNavigationLoadingTemplate(actionStripBuilder: ActionStrip.Builder): NavigationTemplate {
|
fun navigationRerouteTemplate(actionStripBuilder: ActionStrip.Builder): NavigationTemplate {
|
||||||
return NavigationTemplate.Builder()
|
return NavigationTemplate.Builder()
|
||||||
.setNavigationInfo(RoutingInfo.Builder().setLoading(true).build())
|
.setNavigationInfo(
|
||||||
.setActionStrip(actionStripBuilder.build())
|
MessageInfo.Builder(
|
||||||
|
carContext.getString(R.string.new_route)
|
||||||
|
)
|
||||||
|
.setText(routeModel.destination.street.toString())
|
||||||
|
.setImage(
|
||||||
|
CarIcon.Builder(
|
||||||
|
IconCompat.createWithResource(
|
||||||
|
carContext,
|
||||||
|
R.drawable.navigation_48px
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
.build()
|
||||||
|
)
|
||||||
.setBackgroundColor(CarColor.SECONDARY)
|
.setBackgroundColor(CarColor.SECONDARY)
|
||||||
|
.setActionStrip(actionStripBuilder.build())
|
||||||
|
.setMapActionStrip(mapActionStripBuilder().build())
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -271,7 +289,7 @@ class NavigationScreen(
|
|||||||
)
|
)
|
||||||
.setOnClickListener {
|
.setOnClickListener {
|
||||||
val navigateTo = location(recentPlace.latitude, recentPlace.longitude)
|
val navigateTo = location(recentPlace.latitude, recentPlace.longitude)
|
||||||
viewModel.loadRoute(surfaceRenderer.lastLocation, navigateTo)
|
viewModel.loadRoute(carContext, surfaceRenderer.lastLocation, navigateTo)
|
||||||
routeModel.destination = recentPlace
|
routeModel.destination = recentPlace
|
||||||
}
|
}
|
||||||
.build()
|
.build()
|
||||||
@@ -394,7 +412,7 @@ class NavigationScreen(
|
|||||||
location.latitude = place.latitude
|
location.latitude = place.latitude
|
||||||
location.longitude = place.longitude
|
location.longitude = place.longitude
|
||||||
viewModel.saveRecent(place)
|
viewModel.saveRecent(place)
|
||||||
viewModel.loadRoute(surfaceRenderer.lastLocation, location)
|
viewModel.loadRoute(carContext, surfaceRenderer.lastLocation, location)
|
||||||
currentNavigationLocation = location
|
currentNavigationLocation = location
|
||||||
routeModel.destination = place
|
routeModel.destination = place
|
||||||
invalidate()
|
invalidate()
|
||||||
@@ -408,24 +426,25 @@ class NavigationScreen(
|
|||||||
invalidate()
|
invalidate()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun calculateNewRoute() {
|
fun calculateNewRoute(destination: Place) {
|
||||||
calculateNewRoute = true
|
calculateNewRoute = true
|
||||||
|
stopNavigation()
|
||||||
invalidate()
|
invalidate()
|
||||||
val mainThreadhandler = Handler(carContext.mainLooper)
|
val mainThreadHandler = Handler(carContext.mainLooper)
|
||||||
mainThreadhandler.post {
|
mainThreadHandler.post {
|
||||||
object : CountDownTimer(5000, 1000) {
|
object : CountDownTimer(5000, 1000) {
|
||||||
override fun onTick(millisUntilFinished: Long) {}
|
override fun onTick(millisUntilFinished: Long) {}
|
||||||
override fun onFinish() {
|
override fun onFinish() {
|
||||||
calculateNewRoute = false
|
calculateNewRoute = false
|
||||||
stopNavigation()
|
reRoute(destination)
|
||||||
}
|
}
|
||||||
}.start()
|
}.start()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun reRoute() {
|
fun reRoute(destination: Place) {
|
||||||
NavigationMessage(carContext).createAlert()
|
val dest = location(destination.latitude, destination.longitude)
|
||||||
viewModel.loadRoute(surfaceRenderer.lastLocation, currentNavigationLocation)
|
viewModel.loadRoute(carContext, surfaceRenderer.lastLocation, dest)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateTrip() {
|
fun updateTrip() {
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
package com.kouros.navigation.car.screen
|
package com.kouros.navigation.car.screen
|
||||||
|
|
||||||
import androidx.car.app.CarContext
|
import androidx.car.app.CarContext
|
||||||
import androidx.car.app.CarToast
|
|
||||||
import androidx.car.app.Screen
|
import androidx.car.app.Screen
|
||||||
import androidx.car.app.constraints.ConstraintManager
|
|
||||||
import androidx.car.app.model.Action
|
import androidx.car.app.model.Action
|
||||||
import androidx.car.app.model.Header
|
import androidx.car.app.model.Header
|
||||||
import androidx.car.app.model.ItemList
|
import androidx.car.app.model.ItemList
|
||||||
@@ -11,48 +9,65 @@ import androidx.car.app.model.ListTemplate
|
|||||||
import androidx.car.app.model.Row
|
import androidx.car.app.model.Row
|
||||||
import androidx.car.app.model.Template
|
import androidx.car.app.model.Template
|
||||||
import androidx.car.app.model.Toggle
|
import androidx.car.app.model.Toggle
|
||||||
import androidx.lifecycle.DefaultLifecycleObserver
|
|
||||||
import com.kouros.android.cars.carappservice.R
|
import com.kouros.android.cars.carappservice.R
|
||||||
import com.kouros.navigation.data.Constants.SHOW_THREED_BUILDING
|
import com.kouros.navigation.data.Constants.AVOID_MOTORWAY
|
||||||
|
import com.kouros.navigation.data.Constants.AVOID_TOLLWAY
|
||||||
import com.kouros.navigation.utils.NavigationUtils.getBooleanKeyValue
|
import com.kouros.navigation.utils.NavigationUtils.getBooleanKeyValue
|
||||||
import com.kouros.navigation.utils.NavigationUtils.setBooleanKeyValue
|
import com.kouros.navigation.utils.NavigationUtils.setBooleanKeyValue
|
||||||
|
|
||||||
|
|
||||||
class NavigationSettings(private val carContext: CarContext) : Screen(carContext) {
|
class NavigationSettings(private val carContext: CarContext) : Screen(carContext) {
|
||||||
|
|
||||||
|
private var motorWayToggleState = false
|
||||||
|
|
||||||
|
private var tollWayToggleState = false
|
||||||
|
|
||||||
|
init {
|
||||||
|
motorWayToggleState = getBooleanKeyValue(carContext, AVOID_MOTORWAY)
|
||||||
|
|
||||||
|
tollWayToggleState = getBooleanKeyValue(carContext, AVOID_MOTORWAY)
|
||||||
|
}
|
||||||
|
|
||||||
override fun onGetTemplate(): Template {
|
override fun onGetTemplate(): Template {
|
||||||
val listBuilder = ItemList.Builder()
|
val listBuilder = ItemList.Builder()
|
||||||
|
val highwayToggle: Toggle =
|
||||||
|
Toggle.Builder { checked: Boolean ->
|
||||||
|
if (checked) {
|
||||||
|
setBooleanKeyValue(carContext, true, AVOID_MOTORWAY)
|
||||||
|
} else {
|
||||||
|
setBooleanKeyValue(carContext, false, AVOID_MOTORWAY)
|
||||||
|
}
|
||||||
|
motorWayToggleState = !motorWayToggleState
|
||||||
|
}.setChecked(motorWayToggleState).build()
|
||||||
|
listBuilder.addItem(buildRowForTemplate(R.string.avoid_highways_row_title, highwayToggle))
|
||||||
|
|
||||||
|
// Tollway
|
||||||
listBuilder.addItem(
|
val tollwayToggle: Toggle =
|
||||||
buildRowForTemplate(
|
Toggle.Builder { checked: Boolean ->
|
||||||
R.string.list_limit,
|
if (checked) {
|
||||||
ConstraintManager.CONTENT_LIMIT_TYPE_LIST
|
setBooleanKeyValue(carContext, true, AVOID_TOLLWAY)
|
||||||
)
|
} else {
|
||||||
)
|
setBooleanKeyValue(carContext, false, AVOID_TOLLWAY)
|
||||||
|
}
|
||||||
|
tollWayToggleState = !tollWayToggleState
|
||||||
|
}.setChecked(tollWayToggleState).build()
|
||||||
|
listBuilder.addItem(buildRowForTemplate(R.string.avoid_tolls_row_title, tollwayToggle))
|
||||||
|
|
||||||
return ListTemplate.Builder()
|
return ListTemplate.Builder()
|
||||||
.setSingleList(listBuilder.build())
|
.setSingleList(listBuilder.build())
|
||||||
.setHeader(
|
.setHeader(
|
||||||
Header.Builder()
|
Header.Builder()
|
||||||
.setTitle(carContext.getString(R.string.content_limits))
|
.setTitle(carContext.getString(R.string.display_settings))
|
||||||
.setStartHeaderAction(Action.BACK)
|
.setStartHeaderAction(Action.BACK)
|
||||||
.build()
|
.build()
|
||||||
)
|
)
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun buildRowForTemplate(title: Int, contentLimitType: Int): Row {
|
private fun buildRowForTemplate(title: Int, toggle: Toggle): Row {
|
||||||
return Row.Builder()
|
return Row.Builder()
|
||||||
.setTitle(carContext.getString(title))
|
.setTitle(carContext.getString(title))
|
||||||
.addText(
|
.setToggle(toggle)
|
||||||
carContext
|
|
||||||
.getCarService(ConstraintManager::class.java)
|
|
||||||
.getContentLimit(contentLimitType).toString()
|
|
||||||
)
|
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -53,7 +53,7 @@ class PlaceListScreen(
|
|||||||
init {
|
init {
|
||||||
if (category == Constants.RECENT) {
|
if (category == Constants.RECENT) {
|
||||||
viewModel.places.observe(this, observer)
|
viewModel.places.observe(this, observer)
|
||||||
viewModel.loadPlaces(location)
|
viewModel.loadPlaces(carContext, location)
|
||||||
}
|
}
|
||||||
if (category == Constants.CONTACTS) {
|
if (category == Constants.CONTACTS) {
|
||||||
viewModel.contactAddress.observe(this, observerAddress)
|
viewModel.contactAddress.observe(this, observerAddress)
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ class RequestPermissionScreen(
|
|||||||
override fun onGetTemplate(): Template {
|
override fun onGetTemplate(): Template {
|
||||||
val permissions: MutableList<String?> = ArrayList()
|
val permissions: MutableList<String?> = ArrayList()
|
||||||
permissions.add(permission.ACCESS_FINE_LOCATION)
|
permissions.add(permission.ACCESS_FINE_LOCATION)
|
||||||
permissions.add(permission.READ_CONTACTS)
|
//permissions.add(permission.READ_CONTACTS)
|
||||||
|
|
||||||
val message = "This app needs access to location in order to show the map around you"
|
val message = "This app needs access to location in order to show the map around you"
|
||||||
|
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ class RoutePreviewScreen(
|
|||||||
val location = Location(LocationManager.GPS_PROVIDER)
|
val location = Location(LocationManager.GPS_PROVIDER)
|
||||||
location.latitude = destination.latitude
|
location.latitude = destination.latitude
|
||||||
location.longitude = destination.longitude
|
location.longitude = destination.longitude
|
||||||
vieModel.loadPreviewRoute(surfaceRenderer.lastLocation, location)
|
vieModel.loadPreviewRoute(carContext,surfaceRenderer.lastLocation, location)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onGetTemplate(): Template {
|
override fun onGetTemplate(): Template {
|
||||||
|
|||||||
@@ -41,8 +41,6 @@
|
|||||||
<string name="sign_out_action_title" msgid="1653943000866713010">"Abmelden"</string>
|
<string name="sign_out_action_title" msgid="1653943000866713010">"Abmelden"</string>
|
||||||
<string name="yes_action_title" msgid="5507096013762092189">"Ja"</string>
|
<string name="yes_action_title" msgid="5507096013762092189">"Ja"</string>
|
||||||
<string name="no_action_title" msgid="1452124604210014010">"Nein"</string>
|
<string name="no_action_title" msgid="1452124604210014010">"Nein"</string>
|
||||||
<string name="disable_all_rows" msgid="3003225080532928046">"Alle Zeilen deaktivieren"</string>
|
|
||||||
<string name="enable_all_rows" msgid="7274285275711872091">"Alle Zeilen aktivieren"</string>
|
|
||||||
<string name="zoomed_in_toast_msg" msgid="8915301497303842649">"Herangezoomt"</string>
|
<string name="zoomed_in_toast_msg" msgid="8915301497303842649">"Herangezoomt"</string>
|
||||||
<string name="zoomed_out_toast_msg" msgid="6260981223227212493">"Herausgezoomt"</string>
|
<string name="zoomed_out_toast_msg" msgid="6260981223227212493">"Herausgezoomt"</string>
|
||||||
<string name="triggered_toast_msg" msgid="3396166539208366382">"Ausgelöst"</string>
|
<string name="triggered_toast_msg" msgid="3396166539208366382">"Ausgelöst"</string>
|
||||||
@@ -55,59 +53,13 @@
|
|||||||
<string name="parked_toast_msg" msgid="2532422265890824446">"Aktion „Geparkt“"</string>
|
<string name="parked_toast_msg" msgid="2532422265890824446">"Aktion „Geparkt“"</string>
|
||||||
<string name="more_toast_msg" msgid="5938288138225509885">"„Mehr“ angeklickt"</string>
|
<string name="more_toast_msg" msgid="5938288138225509885">"„Mehr“ angeklickt"</string>
|
||||||
<string name="grant_location_permission_toast_msg" msgid="268046297444808010">"Standortermittlung erlauben, um aktuellen Standort anzuzeigen"</string>
|
<string name="grant_location_permission_toast_msg" msgid="268046297444808010">"Standortermittlung erlauben, um aktuellen Standort anzuzeigen"</string>
|
||||||
<string name="sign_in_with_google_toast_msg" msgid="5720947549233124775">"Über Google anmelden beginnt hier"</string>
|
|
||||||
<string name="changes_selection_to_index_toast_msg_prefix" msgid="957766225794389167">"Auswahl auf Index geändert"</string>
|
|
||||||
<string name="yes_action_toast_msg" msgid="6216215197177241247">"Schaltfläche „Ja“ gedrückt."</string>
|
|
||||||
<string name="no_action_toast_msg" msgid="6165492423831023809">"Schaltfläche „Nein“ gedrückt."</string>
|
|
||||||
<string name="alert_timeout_toast_msg" msgid="5568380708832805374">"Zeitüberschreitung bei Benachrichtigung."</string>
|
|
||||||
<string name="first_row_title" msgid="219428344573165351">"Zeile mit großem Bild und langem Text langem Text langem Text langem Text langem Text"</string>
|
|
||||||
<string name="first_row_text" msgid="3887390298628338716">"Text Text Text"</string>
|
|
||||||
<string name="other_row_title_prefix" msgid="4702355788835253197">"Zeilentitel"</string>
|
|
||||||
<string name="other_row_text" msgid="7510279447493169945">"Zeilentext"</string>
|
|
||||||
<string name="navigate" msgid="2713090390373996139">"Navigieren"</string>
|
<string name="navigate" msgid="2713090390373996139">"Navigieren"</string>
|
||||||
<string name="dial" msgid="3145707439707628311">"Wählen"</string>
|
<string name="dial" msgid="3145707439707628311">"Wählen"</string>
|
||||||
<string name="address" msgid="9010635942573581302">"Adresse"</string>
|
<string name="address" msgid="9010635942573581302">"Adresse"</string>
|
||||||
<string name="phone" msgid="2504766809811627577">"Smartphone"</string>
|
<string name="phone" msgid="2504766809811627577">"Smartphone"</string>
|
||||||
<string name="fail_start_nav" msgid="6921321606009212189">"Fehler beim Starten der Navigation"</string>
|
<string name="fail_start_nav" msgid="6921321606009212189">"Fehler beim Starten der Navigation"</string>
|
||||||
<string name="fail_start_dialer" msgid="1471602619507306261">"Fehler beim Starten des Telefons"</string>
|
<string name="fail_start_dialer" msgid="1471602619507306261">"Fehler beim Starten des Telefons"</string>
|
||||||
<string name="car_hardware_demo_title" msgid="3679106197233262689">"Demo der Auto-Hardware"</string>
|
<string name="display_settings" msgid="5726880972110281095">"Einstellungen für die Anzeige"</string>
|
||||||
<string name="car_hardware_info" msgid="1244783247616395012">"Informationen zur Auto-Hardware"</string>
|
|
||||||
<string name="model_info" msgid="494224423025683030">"Modellinformationen"</string>
|
|
||||||
<string name="manufacturer_unavailable" msgid="4978995415869838056">"Hersteller nicht verfügbar"</string>
|
|
||||||
<string name="model_unavailable" msgid="4075463010215406573">"Modell nicht verfügbar"</string>
|
|
||||||
<string name="year_unavailable" msgid="994338773299644607">"Jahr nicht verfügbar"</string>
|
|
||||||
<string name="energy_profile" msgid="81415433590192158">"Energieprofil"</string>
|
|
||||||
<string name="no_energy_profile_permission" msgid="4662285713731308888">"Keine Berechtigung für Energieprofil"</string>
|
|
||||||
<string name="fuel_types" msgid="6811375173343218212">"Kraftstofftypen"</string>
|
|
||||||
<string name="unavailable" msgid="3636401138255192934">"Nicht verfügbar"</string>
|
|
||||||
<string name="ev_connector_types" msgid="735458637011996125">"Elektrofahrzeug-Anschlusssteckertypen"</string>
|
|
||||||
<string name="example_title" msgid="530257630320010494">"Beispiel: %d"</string>
|
|
||||||
<string name="example_1_text" msgid="8631503055894800688">"Dieser Text ist "<annotation color="red">"rot"</annotation></string>
|
|
||||||
<string name="example_2_text" msgid="1359373957397219102">"Dieser Text ist "<annotation color="green">"grün"</annotation></string>
|
|
||||||
<string name="example_3_text" msgid="2409207170762049673">"Dieser Text ist "<annotation color="blue">"blau"</annotation></string>
|
|
||||||
<string name="example_4_text" msgid="9055989886645433000">"Dieser Text ist "<annotation color="yellow">"gelb"</annotation></string>
|
|
||||||
<string name="example_5_text" msgid="8828804968749423500">"Für diesen Text wird die Primärfarbe verwendet"</string>
|
|
||||||
<string name="example_6_text" msgid="7991523168517599600">"Dieser Text verwendet die Sekundärfarbe"</string>
|
|
||||||
<string name="color_demo" msgid="1822427636476178993">"Farbdemo"</string>
|
|
||||||
<string name="list_limit" msgid="3023536401535417286">"Listenbeschränkung"</string>
|
|
||||||
<string name="grid_limit" msgid="1350116012893549206">"Rasterbegrenzung"</string>
|
|
||||||
<string name="pane_limit" msgid="981518409516855230">"Bereichsbegrenzung"</string>
|
|
||||||
<string name="place_list_limit" msgid="6785181191763056582">"Limit für Ortsliste"</string>
|
|
||||||
<string name="route_list_limit" msgid="505793441615134116">"Limit für Routenliste"</string>
|
|
||||||
<string name="content_limits" msgid="5726880972110281095">"Beschränkungen für Inhalte"</string>
|
|
||||||
<string name="content_limits_demo_title" msgid="3207211638386727610">"Demo für „Beschränkungen für Inhalte“"</string>
|
|
||||||
<string name="finish_app_msg" msgid="8354334557053141891">"Dadurch wird die App geschlossen und beim nächsten Ausführen eine Berechtigungsanfrage eingeblendet"</string>
|
|
||||||
<string name="finish_app_title" msgid="9013328479438745074">"App-Demo beenden"</string>
|
|
||||||
<string name="finish_app_demo_title" msgid="8223819062053448384">"Beim nächsten Ausführen der Demo Berechtigungsbildschirm voranstellen"</string>
|
|
||||||
<string name="preseed_permission_app_title" msgid="182847662545676962">"Beim nächsten Ausführen Demo zu App-Berechtigungen voranstellen"</string>
|
|
||||||
<string name="preseed_permission_demo_title" msgid="5476541421753978071">"Beim nächsten Ausführen der Demo Berechtigungsbildschirm voranstellen"</string>
|
|
||||||
<string name="loading_demo_title" msgid="1086529475809143517">"Demo wird geladen"</string>
|
|
||||||
<string name="loading_demo_row_title" msgid="8933049915126088142">"Ladevorgang abgeschlossen!"</string>
|
|
||||||
<string name="pop_to_root" msgid="2078277386355064198">"Zu Stammverzeichnis wechseln"</string>
|
|
||||||
<string name="pop_to_marker" msgid="5007078308762725207">"Zur Markierung für verschiedene Demos wechseln"</string>
|
|
||||||
<string name="push_stack" msgid="2433062141810168976">"Weiter in Stack verschieben"</string>
|
|
||||||
<string name="pop_to_prefix" msgid="4288884615669751608">"Wechseln zu"</string>
|
|
||||||
<string name="pop_to_title" msgid="3924696281273379455">"Demo für „Wechseln zu“"</string>
|
|
||||||
<string name="package_not_found_error_msg" msgid="7525619456883627939">"Paket wurde nicht gefunden."</string>
|
<string name="package_not_found_error_msg" msgid="7525619456883627939">"Paket wurde nicht gefunden."</string>
|
||||||
<string name="permissions_granted_msg" msgid="2348556088141992714">"Alle Berechtigungen wurden erteilt. Du kannst sie in den Einstellungen deaktivieren."</string>
|
<string name="permissions_granted_msg" msgid="2348556088141992714">"Alle Berechtigungen wurden erteilt. Du kannst sie in den Einstellungen deaktivieren."</string>
|
||||||
<string name="needs_access_msg_prefix" msgid="2204136858798832382">"Die App benötigt Zugriff auf die folgenden Berechtigungen:\n"</string>
|
<string name="needs_access_msg_prefix" msgid="2204136858798832382">"Die App benötigt Zugriff auf die folgenden Berechtigungen:\n"</string>
|
||||||
@@ -154,7 +106,8 @@
|
|||||||
<string name="long_route" msgid="4737969235741057506">"Lange Route"</string>
|
<string name="long_route" msgid="4737969235741057506">"Lange Route"</string>
|
||||||
<string name="continue_start_nav" msgid="6231797535084469163">"Weiter, um die Navigation zu starten"</string>
|
<string name="continue_start_nav" msgid="6231797535084469163">"Weiter, um die Navigation zu starten"</string>
|
||||||
<string name="continue_route" msgid="5172258139245088080">"Weiter zur Route"</string>
|
<string name="continue_route" msgid="5172258139245088080">"Weiter zur Route"</string>
|
||||||
<string name="routes_title" msgid="7799772149932075357">"Routen"</string>
|
<string name="routes_title" msgid="7799772149932075357">"Route"</string>
|
||||||
|
<string name="new_route">Neue Route Berechnung</string>
|
||||||
<string name="place_list_nav_template_demo_title" msgid="8019588508812955290">"Demo der Navigationsvorlage für Ortslisten"</string>
|
<string name="place_list_nav_template_demo_title" msgid="8019588508812955290">"Demo der Navigationsvorlage für Ortslisten"</string>
|
||||||
<string name="route_preview_template_demo_title" msgid="7878704357953167555">"Demo der Routenvorschauvorlage"</string>
|
<string name="route_preview_template_demo_title" msgid="7878704357953167555">"Demo der Routenvorschauvorlage"</string>
|
||||||
<string name="notification_template_demo_title" msgid="5076051497316030274">"Demo der Benachrichtigungsvorlage"</string>
|
<string name="notification_template_demo_title" msgid="5076051497316030274">"Demo der Benachrichtigungsvorlage"</string>
|
||||||
@@ -355,7 +308,7 @@
|
|||||||
<string name="map_template_toggle_demo_title" msgid="6510798293640092611">"Kartenvorlage mit Ein-/Aus-Schaltflächen"</string>
|
<string name="map_template_toggle_demo_title" msgid="6510798293640092611">"Kartenvorlage mit Ein-/Aus-Schaltflächen"</string>
|
||||||
<string name="avoid_tolls_row_title" msgid="5194057244144831024">"Mautstraßen vermeiden"</string>
|
<string name="avoid_tolls_row_title" msgid="5194057244144831024">"Mautstraßen vermeiden"</string>
|
||||||
<string name="route_options_demo_title" msgid="4599699012716426514">"Routenoptionen"</string>
|
<string name="route_options_demo_title" msgid="4599699012716426514">"Routenoptionen"</string>
|
||||||
<string name="avoid_highways_row_title" msgid="4711913426200490304">"Autobahnen vermeiden"</string>
|
<string name="avoid_highways_row_title" msgid="4711913426200490304">"Autobahnen meiden"</string>
|
||||||
<string name="avoid_ferries_row_title" msgid="8232883866013711974">"Fähren vermeiden"</string>
|
<string name="avoid_ferries_row_title" msgid="8232883866013711974">"Fähren vermeiden"</string>
|
||||||
<string name="map_demos_title" msgid="2169766615521476592">"Kartenbezogene Demos"</string>
|
<string name="map_demos_title" msgid="2169766615521476592">"Kartenbezogene Demos"</string>
|
||||||
<string name="map_with_content_demo_title" msgid="1032610482145018739">"Demos von Karten mit Inhalten"</string>
|
<string name="map_with_content_demo_title" msgid="1032610482145018739">"Demos von Karten mit Inhalten"</string>
|
||||||
|
|||||||
@@ -41,8 +41,6 @@
|
|||||||
<string name="sign_out_action_title">Sign out</string>
|
<string name="sign_out_action_title">Sign out</string>
|
||||||
<string name="yes_action_title">Yes</string>
|
<string name="yes_action_title">Yes</string>
|
||||||
<string name="no_action_title">No</string>
|
<string name="no_action_title">No</string>
|
||||||
<string name="disable_all_rows">Disable All Rows</string>
|
|
||||||
<string name="enable_all_rows">Enable All Rows</string>
|
|
||||||
|
|
||||||
<!-- Toast Messages -->
|
<!-- Toast Messages -->
|
||||||
<string name="zoomed_in_toast_msg">Zoomed in</string>
|
<string name="zoomed_in_toast_msg">Zoomed in</string>
|
||||||
@@ -57,17 +55,8 @@
|
|||||||
<string name="parked_toast_msg">Parked action</string>
|
<string name="parked_toast_msg">Parked action</string>
|
||||||
<string name="more_toast_msg">Clicked More</string>
|
<string name="more_toast_msg">Clicked More</string>
|
||||||
<string name="grant_location_permission_toast_msg">Grant location Permission to see current location</string>
|
<string name="grant_location_permission_toast_msg">Grant location Permission to see current location</string>
|
||||||
<string name="sign_in_with_google_toast_msg">Sign-in with Google starts here</string>
|
|
||||||
<string name="changes_selection_to_index_toast_msg_prefix">Changed selection to index</string>
|
<string name="changes_selection_to_index_toast_msg_prefix">Changed selection to index</string>
|
||||||
<string name="yes_action_toast_msg">Yes button pressed!</string>
|
|
||||||
<string name="no_action_toast_msg">No button pressed!</string>
|
|
||||||
<string name="alert_timeout_toast_msg">Alert is timed out!</string>
|
|
||||||
|
|
||||||
<!-- Row text -->
|
|
||||||
<string name="first_row_title">Row with a large image and long text long text long text long text long text</string>
|
|
||||||
<string name="first_row_text">Text text text</string>
|
|
||||||
<string name="other_row_title_prefix">Row title </string>
|
|
||||||
<string name="other_row_text">Row text</string>
|
|
||||||
|
|
||||||
<!-- Place Details Screen -->
|
<!-- Place Details Screen -->
|
||||||
<string name="navigate">Navigate</string>
|
<string name="navigate">Navigate</string>
|
||||||
@@ -78,56 +67,8 @@
|
|||||||
<!-- CarHardwareDemoScreen -->
|
<!-- CarHardwareDemoScreen -->
|
||||||
<string name="fail_start_nav">Failure starting navigation</string>
|
<string name="fail_start_nav">Failure starting navigation</string>
|
||||||
<string name="fail_start_dialer">Failure starting dialer</string>
|
<string name="fail_start_dialer">Failure starting dialer</string>
|
||||||
<string name="car_hardware_demo_title">Car Hardware Demo</string>
|
|
||||||
|
|
||||||
<!-- CarHardwareInfoScreen -->
|
<string name="display_settings">Display settings</string>
|
||||||
<string name="car_hardware_info">Car Hardware Information</string>
|
|
||||||
<string name="model_info">Model Information</string>
|
|
||||||
<string name="manufacturer_unavailable">Manufacturer unavailable</string>
|
|
||||||
<string name="model_unavailable">Model unavailable</string>
|
|
||||||
<string name="year_unavailable">Year unavailable</string>
|
|
||||||
<string name="energy_profile">Energy Profile</string>
|
|
||||||
<string name="no_energy_profile_permission">No Energy Profile Permission</string>
|
|
||||||
<string name="fuel_types">Fuel Types</string>
|
|
||||||
<string name="unavailable">Unavailable</string>
|
|
||||||
<string name="ev_connector_types">EV Connector Types</string>
|
|
||||||
|
|
||||||
<!-- ColorDemoScreen -->
|
|
||||||
<string name="example_title">Example %d</string>
|
|
||||||
<string name="example_1_text">This text has a <annotation color="red">red</annotation> color</string>
|
|
||||||
<string name="example_2_text">This text has a <annotation color="green">green</annotation> color</string>
|
|
||||||
<string name="example_3_text">This text has a <annotation color="blue">blue</annotation> color</string>
|
|
||||||
<string name="example_4_text">This text has a <annotation color="yellow">yellow</annotation> color</string>
|
|
||||||
<string name="example_5_text">This text uses the primary color</string>
|
|
||||||
<string name="example_6_text">This text uses the secondary color</string>
|
|
||||||
<string name="color_demo">Color Demo</string>
|
|
||||||
|
|
||||||
<!-- ContentLimitsDemoScreen -->
|
|
||||||
<string name="list_limit">List Limit</string>
|
|
||||||
<string name="grid_limit">Grid Limit</string>
|
|
||||||
<string name="pane_limit">Pane Limit</string>
|
|
||||||
<string name="place_list_limit">Place List Limit</string>
|
|
||||||
<string name="route_list_limit">Route List Limit</string>
|
|
||||||
<string name="content_limits">Content Limits</string>
|
|
||||||
<string name="content_limits_demo_title">Content Limits Demo</string>
|
|
||||||
|
|
||||||
<!-- FinishAppScreen -->
|
|
||||||
<string name="finish_app_msg">This will finish the app, and when you return it will pre-seed a permission screen</string>
|
|
||||||
<string name="finish_app_title">Finish App Demo</string>
|
|
||||||
<string name="finish_app_demo_title">Pre-seed the Permission Screen on next run Demo</string>
|
|
||||||
<string name="preseed_permission_app_title">Pre-seed permission App Demo</string>
|
|
||||||
<string name="preseed_permission_demo_title">Pre-seed the Permission Screen on next run Demo</string>
|
|
||||||
|
|
||||||
<!-- LoadingDemoScreen -->
|
|
||||||
<string name="loading_demo_title">Loading Demo</string>
|
|
||||||
<string name="loading_demo_row_title">Loading Complete!</string>
|
|
||||||
|
|
||||||
<!-- PopToDemoScreen -->
|
|
||||||
<string name="pop_to_root">Pop to root</string>
|
|
||||||
<string name="pop_to_marker">Pop to Misc Demo Marker</string>
|
|
||||||
<string name="push_stack">Push further in stack</string>
|
|
||||||
<string name="pop_to_prefix">Pop To </string>
|
|
||||||
<string name="pop_to_title">PopTo Demo</string>
|
|
||||||
|
|
||||||
<!-- RequestPermissionScreen -->
|
<!-- RequestPermissionScreen -->
|
||||||
<string name="package_not_found_error_msg">Package Not found.</string>
|
<string name="package_not_found_error_msg">Package Not found.</string>
|
||||||
@@ -193,7 +134,6 @@
|
|||||||
<string name="take_520">Take 520</string>
|
<string name="take_520">Take 520</string>
|
||||||
<string name="gas_station">Gas Station</string>
|
<string name="gas_station">Gas Station</string>
|
||||||
|
|
||||||
<!-- RoutePreviewDemoScreen -->
|
|
||||||
<string name="short_route">Short route</string>
|
<string name="short_route">Short route</string>
|
||||||
<string name="less_busy">Less busy</string>
|
<string name="less_busy">Less busy</string>
|
||||||
<string name="hov_friendly">HOV friendly</string>
|
<string name="hov_friendly">HOV friendly</string>
|
||||||
@@ -201,6 +141,7 @@
|
|||||||
<string name="continue_start_nav">Continue to start navigation</string>
|
<string name="continue_start_nav">Continue to start navigation</string>
|
||||||
<string name="continue_route">Continue to route</string>
|
<string name="continue_route">Continue to route</string>
|
||||||
<string name="routes_title">Routes</string>
|
<string name="routes_title">Routes</string>
|
||||||
|
<string name="new_route">New Route calculation</string>
|
||||||
|
|
||||||
<!-- NavigationDemosScreen -->
|
<!-- NavigationDemosScreen -->
|
||||||
<string name="place_list_nav_template_demo_title">Place List Navigation Template Demo</string>
|
<string name="place_list_nav_template_demo_title">Place List Navigation Template Demo</string>
|
||||||
|
|||||||
@@ -5,9 +5,9 @@ import android.location.LocationManager
|
|||||||
import com.kouros.navigation.data.Constants.home2Location
|
import com.kouros.navigation.data.Constants.home2Location
|
||||||
import com.kouros.navigation.data.Constants.homeLocation
|
import com.kouros.navigation.data.Constants.homeLocation
|
||||||
import com.kouros.navigation.data.NavigationRepository
|
import com.kouros.navigation.data.NavigationRepository
|
||||||
|
import com.kouros.navigation.data.SearchFilter
|
||||||
import com.kouros.navigation.model.RouteModel
|
import com.kouros.navigation.model.RouteModel
|
||||||
import com.kouros.navigation.model.ViewModel
|
import com.kouros.navigation.model.ViewModel
|
||||||
import org.junit.Assert.assertEquals
|
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -30,7 +30,7 @@ class ViewModelTest {
|
|||||||
toLocation.latitude = home2Location.latitude
|
toLocation.latitude = home2Location.latitude
|
||||||
toLocation.longitude = home2Location.longitude
|
toLocation.longitude = home2Location.longitude
|
||||||
|
|
||||||
val route = repo.getRoute(fromLocation, toLocation)
|
val route = repo.getRoute(fromLocation, toLocation, SearchFilter())
|
||||||
model.startNavigation(route)
|
model.startNavigation(route)
|
||||||
println(route)
|
println(route)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,14 +16,19 @@
|
|||||||
|
|
||||||
package com.kouros.navigation.data
|
package com.kouros.navigation.data
|
||||||
|
|
||||||
|
import android.R
|
||||||
import android.location.Location
|
import android.location.Location
|
||||||
import android.location.LocationManager
|
import android.location.LocationManager
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
|
import com.google.gson.GsonBuilder
|
||||||
|
import com.kouros.navigation.data.valhalla.Maneuvers
|
||||||
|
import com.kouros.navigation.data.valhalla.ValhallaJson
|
||||||
|
import com.kouros.navigation.utils.NavigationUtils.createGeoJson
|
||||||
|
import com.kouros.navigation.utils.NavigationUtils.decodePolyline
|
||||||
import io.objectbox.annotation.Entity
|
import io.objectbox.annotation.Entity
|
||||||
import io.objectbox.annotation.Id
|
import io.objectbox.annotation.Id
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import java.time.LocalDate
|
import org.maplibre.geojson.Point
|
||||||
import java.util.Date
|
|
||||||
|
|
||||||
data class Category(
|
data class Category(
|
||||||
val id: String,
|
val id: String,
|
||||||
@@ -60,29 +65,6 @@ data class StepData (
|
|||||||
var bearing: Double
|
var bearing: Double
|
||||||
)
|
)
|
||||||
|
|
||||||
val dataPlaces = listOf(
|
|
||||||
Place(
|
|
||||||
id = 0,
|
|
||||||
name = "Vogelhartstr. 17",
|
|
||||||
category = "Favorites",
|
|
||||||
latitude = 48.1857475,
|
|
||||||
longitude = 11.5793627,
|
|
||||||
postalCode = "80807",
|
|
||||||
city = "München",
|
|
||||||
street = "Vogelhartstr. 17"
|
|
||||||
|
|
||||||
),
|
|
||||||
Place(
|
|
||||||
id = 0,
|
|
||||||
name = "Hohenwaldeckstr. 27",
|
|
||||||
category = "Recent",
|
|
||||||
latitude = 48.1165005,
|
|
||||||
longitude = 11.594349,
|
|
||||||
postalCode = "81541",
|
|
||||||
city = "München",
|
|
||||||
street = "Hohenwaldeckstr. 27",
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
// GeoJSON data classes
|
// GeoJSON data classes
|
||||||
@Serializable
|
@Serializable
|
||||||
@@ -107,9 +89,41 @@ data class GeoJsonFeatureCollection(
|
|||||||
data class Locations (
|
data class Locations (
|
||||||
var lat : Double,
|
var lat : Double,
|
||||||
var lon : Double,
|
var lon : Double,
|
||||||
var street : String = ""
|
var street : String = "",
|
||||||
|
val search_filter: SearchFilter,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class SearchFilter(
|
||||||
|
var max_road_class: String = "",
|
||||||
|
var exclude_toll : Boolean = false
|
||||||
|
) {
|
||||||
|
|
||||||
|
class Builder {
|
||||||
|
private var avoidMotorway = false
|
||||||
|
private var avoidTollway = false
|
||||||
|
|
||||||
|
fun avoidMotorway (value: Boolean ) = apply {
|
||||||
|
avoidMotorway = value
|
||||||
|
}
|
||||||
|
|
||||||
|
fun avoidTollway (value: Boolean ) = apply {
|
||||||
|
avoidTollway = value
|
||||||
|
}
|
||||||
|
|
||||||
|
fun build(): SearchFilter {
|
||||||
|
val filter = SearchFilter()
|
||||||
|
if (avoidMotorway) {
|
||||||
|
filter.max_road_class = "trunk"
|
||||||
|
}
|
||||||
|
if (avoidTollway) {
|
||||||
|
filter.exclude_toll = true
|
||||||
|
}
|
||||||
|
return filter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class ValhallaLocation (
|
data class ValhallaLocation (
|
||||||
var locations: List<Locations>,
|
var locations: List<Locations>,
|
||||||
@@ -149,6 +163,10 @@ object Constants {
|
|||||||
|
|
||||||
const val SHOW_THREED_BUILDING = "Show3D"
|
const val SHOW_THREED_BUILDING = "Show3D"
|
||||||
|
|
||||||
|
const val AVOID_MOTORWAY = "AvoidMotorway"
|
||||||
|
|
||||||
|
const val AVOID_TOLLWAY = "AvoidTollway"
|
||||||
|
|
||||||
const val NEXT_STEP_THRESHOLD = 100.0
|
const val NEXT_STEP_THRESHOLD = 100.0
|
||||||
|
|
||||||
const val MAXIMAL_SNAP_CORRECTION = 50.0
|
const val MAXIMAL_SNAP_CORRECTION = 50.0
|
||||||
|
|||||||
@@ -34,10 +34,15 @@ class NavigationRepository {
|
|||||||
|
|
||||||
private val nominatimUrl = "https://nominatim.openstreetmap.org/"
|
private val nominatimUrl = "https://nominatim.openstreetmap.org/"
|
||||||
|
|
||||||
fun getRoute(currentLocation : Location, location: Location): String {
|
// Road classes from highest to lowest are:
|
||||||
|
// motorway, trunk, primary, secondary, tertiary, unclassified, residential, service_other.
|
||||||
|
|
||||||
|
// exclude_toll
|
||||||
|
fun getRoute(currentLocation: Location, location: Location, SearchFilter: SearchFilter): String {
|
||||||
|
SearchFilter
|
||||||
val vLocation = listOf(
|
val vLocation = listOf(
|
||||||
Locations(lat = currentLocation.latitude, lon = currentLocation.longitude),
|
Locations(lat = currentLocation.latitude, lon = currentLocation.longitude, search_filter = SearchFilter),
|
||||||
Locations(lat = location.latitude, lon = location.longitude)
|
Locations(lat = location.latitude, lon = location.longitude, search_filter = SearchFilter)
|
||||||
)
|
)
|
||||||
val valhallaLocation = ValhallaLocation(
|
val valhallaLocation = ValhallaLocation(
|
||||||
locations = vLocation,
|
locations = vLocation,
|
||||||
@@ -50,8 +55,8 @@ class NavigationRepository {
|
|||||||
return fetchUrl(routeUrl + routeLocation, true)
|
return fetchUrl(routeUrl + routeLocation, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getRouteDistance(currentLocation : Location, location: Location): Double {
|
fun getRouteDistance(currentLocation: Location, location: Location, searchFilter: SearchFilter): Double {
|
||||||
val route = getRoute(currentLocation, location)
|
val route = getRoute(currentLocation, location, searchFilter)
|
||||||
val routeModel = RouteModel()
|
val routeModel = RouteModel()
|
||||||
routeModel.startNavigation(route)
|
routeModel.startNavigation(route)
|
||||||
return routeModel.route.distance
|
return routeModel.route.distance
|
||||||
@@ -108,7 +113,6 @@ class NavigationRepository {
|
|||||||
httpURLConnection.setRequestProperty("User-Agent", "email=nominatim@kouros-online.de");
|
httpURLConnection.setRequestProperty("User-Agent", "email=nominatim@kouros-online.de");
|
||||||
httpURLConnection.requestMethod = "GET"
|
httpURLConnection.requestMethod = "GET"
|
||||||
val responseCode = httpURLConnection.responseCode
|
val responseCode = httpURLConnection.responseCode
|
||||||
println(responseCode)
|
|
||||||
if (responseCode == HttpURLConnection.HTTP_OK) {
|
if (responseCode == HttpURLConnection.HTTP_OK) {
|
||||||
val response = httpURLConnection.inputStream.bufferedReader()
|
val response = httpURLConnection.inputStream.bufferedReader()
|
||||||
.use { it.readText() } // defaults to UTF-8
|
.use { it.readText() } // defaults to UTF-8
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import com.kouros.navigation.utils.location
|
|||||||
import org.maplibre.geojson.FeatureCollection
|
import org.maplibre.geojson.FeatureCollection
|
||||||
import org.maplibre.geojson.Point
|
import org.maplibre.geojson.Point
|
||||||
import org.maplibre.turf.TurfMeasurement
|
import org.maplibre.turf.TurfMeasurement
|
||||||
|
import org.maplibre.turf.TurfMisc
|
||||||
import kotlin.math.absoluteValue
|
import kotlin.math.absoluteValue
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
@@ -72,7 +73,7 @@ open class RouteModel() {
|
|||||||
if (distance < nearestDistance) {
|
if (distance < nearestDistance) {
|
||||||
nearestDistance = distance
|
nearestDistance = distance
|
||||||
route.currentManeuverIndex = i
|
route.currentManeuverIndex = i
|
||||||
calculateCurrentIndex(beginShapeIndex, endShapeIndex, location)
|
calculateCurrentShapeIndex(beginShapeIndex, endShapeIndex, location)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -83,16 +84,17 @@ open class RouteModel() {
|
|||||||
if (maneuver.streetNames != null && maneuver.streetNames.isNotEmpty()) {
|
if (maneuver.streetNames != null && maneuver.streetNames.isNotEmpty()) {
|
||||||
text = maneuver.streetNames[0]
|
text = maneuver.streetNames[0]
|
||||||
}
|
}
|
||||||
// TODO: +1 check
|
|
||||||
val curLocation = location(
|
val curLocation = location(
|
||||||
route.pointLocations[currentShapeIndex].latitude(),
|
route.pointLocations[currentShapeIndex].latitude(),
|
||||||
route.pointLocations[currentShapeIndex].longitude()
|
route.pointLocations[currentShapeIndex].longitude()
|
||||||
)
|
)
|
||||||
|
if (currentShapeIndex < route.pointLocations.size) {
|
||||||
val nextLocation = location(
|
val nextLocation = location(
|
||||||
route.pointLocations[currentShapeIndex + 1].latitude(),
|
route.pointLocations[currentShapeIndex + 1].latitude(),
|
||||||
route.pointLocations[currentShapeIndex + 1].longitude()
|
route.pointLocations[currentShapeIndex + 1].longitude()
|
||||||
)
|
)
|
||||||
bearing = curLocation.bearingTo(nextLocation)
|
bearing = curLocation.bearingTo(nextLocation).absoluteValue
|
||||||
|
}
|
||||||
val distanceStepLeft = leftStepDistance() * 1000
|
val distanceStepLeft = leftStepDistance() * 1000
|
||||||
when (distanceStepLeft) {
|
when (distanceStepLeft) {
|
||||||
in 0.0..NEXT_STEP_THRESHOLD -> {
|
in 0.0..NEXT_STEP_THRESHOLD -> {
|
||||||
@@ -108,7 +110,7 @@ open class RouteModel() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Calculates the index in a maneuver. */
|
/** Calculates the index in a maneuver. */
|
||||||
private fun calculateCurrentIndex(
|
private fun calculateCurrentShapeIndex(
|
||||||
beginShapeIndex: Int,
|
beginShapeIndex: Int,
|
||||||
endShapeIndex: Int,
|
endShapeIndex: Int,
|
||||||
location: Location
|
location: Location
|
||||||
|
|||||||
@@ -3,8 +3,6 @@ package com.kouros.navigation.model
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.location.Geocoder
|
import android.location.Geocoder
|
||||||
import android.location.Location
|
import android.location.Location
|
||||||
import android.os.Build
|
|
||||||
import androidx.annotation.RequiresApi
|
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
@@ -14,13 +12,14 @@ import com.kouros.navigation.data.NavigationRepository
|
|||||||
import com.kouros.navigation.data.ObjectBox.boxStore
|
import com.kouros.navigation.data.ObjectBox.boxStore
|
||||||
import com.kouros.navigation.data.Place
|
import com.kouros.navigation.data.Place
|
||||||
import com.kouros.navigation.data.Place_
|
import com.kouros.navigation.data.Place_
|
||||||
|
import com.kouros.navigation.data.SearchFilter
|
||||||
import com.kouros.navigation.data.nominatim.Search
|
import com.kouros.navigation.data.nominatim.Search
|
||||||
import com.kouros.navigation.data.nominatim.SearchResult
|
import com.kouros.navigation.data.nominatim.SearchResult
|
||||||
|
import com.kouros.navigation.utils.NavigationUtils
|
||||||
import com.kouros.navigation.utils.location
|
import com.kouros.navigation.utils.location
|
||||||
import io.objectbox.kotlin.boxFor
|
import io.objectbox.kotlin.boxFor
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import java.time.LocalDate
|
|
||||||
import java.time.LocalDateTime
|
import java.time.LocalDateTime
|
||||||
import java.time.ZoneOffset
|
import java.time.ZoneOffset
|
||||||
|
|
||||||
@@ -66,7 +65,6 @@ class ViewModel(private val repository: NavigationRepository) : ViewModel() {
|
|||||||
//place.distance = distance.toFloat()
|
//place.distance = distance.toFloat()
|
||||||
if (place.distance == 0F) {
|
if (place.distance == 0F) {
|
||||||
recentPlace.postValue(place)
|
recentPlace.postValue(place)
|
||||||
println("RecentPlace $recentPlace")
|
|
||||||
return@launch
|
return@launch
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -75,7 +73,7 @@ class ViewModel(private val repository: NavigationRepository) : ViewModel() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fun loadPlaces(location: Location) {
|
fun loadPlaces(context: Context, location: Location) {
|
||||||
viewModelScope.launch(Dispatchers.IO) {
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
try {
|
try {
|
||||||
val placeBox = boxStore.boxFor(Place::class)
|
val placeBox = boxStore.boxFor(Place::class)
|
||||||
@@ -87,7 +85,7 @@ class ViewModel(private val repository: NavigationRepository) : ViewModel() {
|
|||||||
query.close()
|
query.close()
|
||||||
for (place in results) {
|
for (place in results) {
|
||||||
val plLocation = location(place.latitude, place.longitude)
|
val plLocation = location(place.latitude, place.longitude)
|
||||||
val distance = repository.getRouteDistance(location, plLocation)
|
val distance = repository.getRouteDistance(location, plLocation, getSearchFilter(context))
|
||||||
place.distance = distance.toFloat()
|
place.distance = distance.toFloat()
|
||||||
}
|
}
|
||||||
places.postValue(results)
|
places.postValue(results)
|
||||||
@@ -97,20 +95,20 @@ class ViewModel(private val repository: NavigationRepository) : ViewModel() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun loadRoute(currentLocation: Location, location: Location) {
|
fun loadRoute(context: Context, currentLocation: Location, location: Location) {
|
||||||
viewModelScope.launch(Dispatchers.IO) {
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
try {
|
try {
|
||||||
route.postValue(repository.getRoute(currentLocation, location))
|
route.postValue(repository.getRoute(currentLocation, location, getSearchFilter(context)))
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun loadPreviewRoute(currentLocation: Location, location: Location) {
|
fun loadPreviewRoute(context: Context, currentLocation: Location, location: Location) {
|
||||||
viewModelScope.launch(Dispatchers.IO) {
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
try {
|
try {
|
||||||
previewRoute.postValue(repository.getRoute(currentLocation, location))
|
previewRoute.postValue(repository.getRoute(currentLocation, location, getSearchFilter(context)))
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
}
|
}
|
||||||
@@ -133,7 +131,7 @@ class ViewModel(private val repository: NavigationRepository) : ViewModel() {
|
|||||||
if (addressLines.size > 1) {
|
if (addressLines.size > 1) {
|
||||||
val plLocation = location(adr.latitude, adr.longitude)
|
val plLocation = location(adr.latitude, adr.longitude)
|
||||||
val distance =
|
val distance =
|
||||||
repository.getRouteDistance(currentLocation, plLocation)
|
repository.getRouteDistance(currentLocation, plLocation, getSearchFilter(context))
|
||||||
contactList.add(
|
contactList.add(
|
||||||
Place(
|
Place(
|
||||||
id = address.contactId,
|
id = address.contactId,
|
||||||
@@ -179,7 +177,6 @@ class ViewModel(private val repository: NavigationRepository) : ViewModel() {
|
|||||||
|
|
||||||
fun reverseAddress(location: Location ): String {
|
fun reverseAddress(location: Location ): String {
|
||||||
val address = repository.reverseAddress(location)
|
val address = repository.reverseAddress(location)
|
||||||
println(address)
|
|
||||||
val gson = GsonBuilder().serializeNulls().create()
|
val gson = GsonBuilder().serializeNulls().create()
|
||||||
val place = gson.fromJson(address, SearchResult::class.java)
|
val place = gson.fromJson(address, SearchResult::class.java)
|
||||||
println(place.address.road)
|
println(place.address.road)
|
||||||
@@ -226,5 +223,21 @@ class ViewModel(private val repository: NavigationRepository) : ViewModel() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getSearchFilter(context: Context): SearchFilter {
|
||||||
|
|
||||||
|
val avoidMotorway = NavigationUtils.getBooleanKeyValue(
|
||||||
|
context = context,
|
||||||
|
Constants.AVOID_MOTORWAY
|
||||||
|
)
|
||||||
|
val avoidTollway = NavigationUtils.getBooleanKeyValue(
|
||||||
|
context = context,
|
||||||
|
Constants.AVOID_TOLLWAY
|
||||||
|
)
|
||||||
|
return SearchFilter.Builder()
|
||||||
|
.avoidMotorway(avoidMotorway)
|
||||||
|
.avoidTollway(avoidTollway)
|
||||||
|
.build()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,6 +30,10 @@ runtime = "1.9.5"
|
|||||||
accompanist = "0.37.3"
|
accompanist = "0.37.3"
|
||||||
uiVersion = "1.9.5"
|
uiVersion = "1.9.5"
|
||||||
uiText = "1.9.5"
|
uiText = "1.9.5"
|
||||||
|
navigationCompose = "2.9.6"
|
||||||
|
uiToolingPreview = "1.9.5"
|
||||||
|
uiTooling = "1.9.5"
|
||||||
|
material3WindowSizeClass = "1.4.0"
|
||||||
|
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
@@ -63,6 +67,10 @@ androidx-compose-runtime = { group = "androidx.compose.runtime", name = "runtime
|
|||||||
accompanist-permissions = { module = "com.google.accompanist:accompanist-permissions", version.ref = "accompanist" }
|
accompanist-permissions = { module = "com.google.accompanist:accompanist-permissions", version.ref = "accompanist" }
|
||||||
androidx-compose-ui = { group = "androidx.compose.ui", name = "ui", version.ref = "uiVersion" }
|
androidx-compose-ui = { group = "androidx.compose.ui", name = "ui", version.ref = "uiVersion" }
|
||||||
androidx-compose-ui-text = { group = "androidx.compose.ui", name = "ui-text", version.ref = "uiText" }
|
androidx-compose-ui-text = { group = "androidx.compose.ui", name = "ui-text", version.ref = "uiText" }
|
||||||
|
androidx-navigation-compose = { group = "androidx.navigation", name = "navigation-compose", version.ref = "navigationCompose" }
|
||||||
|
androidx-compose-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview", version.ref = "uiToolingPreview" }
|
||||||
|
androidx-compose-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling", version.ref = "uiTooling" }
|
||||||
|
androidx-compose-material3-window-size-class1 = { group = "androidx.compose.material3", name = "material3-window-size-class", version.ref = "material3WindowSizeClass" }
|
||||||
|
|
||||||
[plugins]
|
[plugins]
|
||||||
android-application = { id = "com.android.application", version.ref = "agp" }
|
android-application = { id = "com.android.application", version.ref = "agp" }
|
||||||
|
|||||||
Reference in New Issue
Block a user