Initial commit

This commit is contained in:
Dimitris
2025-11-13 19:46:08 +01:00
commit d63747e811
119 changed files with 5833 additions and 0 deletions

1
common/car/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/build

View File

@@ -0,0 +1,53 @@
plugins {
alias(libs.plugins.android.library)
alias(libs.plugins.kotlin.android)
alias(libs.plugins.kotlin.compose)
}
android {
namespace = "com.kouros.android.cars.carappservice"
compileSdk = 36
defaultConfig {
minSdk = 34
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles("consumer-rules.pro")
}
buildTypes {
release {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
kotlinOptions {
jvmTarget = "11"
}
buildFeatures {
compose = true
}
}
dependencies {
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.car.app)
implementation(libs.ui)
implementation(libs.androidx.lifecycle.runtime.ktx)
implementation(libs.androidx.ui)
implementation(libs.maplibre.compose)
//implementation(libs.maplibre.composeMaterial3)
implementation(project(":common:data"))
implementation(libs.androidx.runtime.livedata)
implementation(libs.androidx.compose.foundation)
androidTestImplementation(libs.androidx.junit)
testImplementation(libs.junit)
}

View File

21
common/car/proguard-rules.pro vendored Normal file
View File

@@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

View File

@@ -0,0 +1,58 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2023 Google LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!--
This AndroidManifest.xml will contain all of the elements that should be shared across the
Android Auto and Automotive OS versions of the app, such as the CarAppService <service> element
-->
<!--
This permission is required to use the `PlaceListMapTemplate` and should only be declared
by apps declaring the `androidx.car.app.category.POI` category
-->
<uses-permission android:name="androidx.car.app.MAP_TEMPLATES" />
<uses-permission android:name="androidx.car.app.NAVIGATION_TEMPLATES" />
<uses-permission android:name="android.permission.INTERNET" />
<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_COARSE_LOCATION"/>
<uses-permission android:name="androidx.car.app.ACCESS_SURFACE" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<application android:requestLegacyExternalStorage="true">
<!--
Since this app does not use any features from beyond API level 1, it makes the most sense
to use that as the `minCarApiLevel`. Even if it did use features from higher API levels,
it could still use this value as long as those features are only used behind a runtime check
-->
<meta-data
android:name="androidx.car.app.minCarApiLevel"
android:value="1" />
<service
android:name="com.kouros.navigation.car.NavigationCarAppService"
android:exported="true">
<intent-filter>
<action android:name="androidx.car.app.CarAppService" />
<category android:name="androidx.car.app.category.WEATHER" />
<category android:name="androidx.car.app.category.POI"/>
<category android:name="androidx.car.app.category.NAVIGATION"/>
</intent-filter>
</service>
</application>
</manifest>

View File

@@ -0,0 +1,29 @@
package com.kouros.navigation.car
import android.os.Bundle
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleRegistry
import androidx.savedstate.SavedStateRegistryController
import androidx.savedstate.SavedStateRegistryOwner
// Taken and slightly modified from the original at
// https://gist.github.com/handstandsam/6ecff2f39da72c0b38c07aa80bbb5a2f
class CustomLifecycleOwner : SavedStateRegistryOwner {
private var lifecycleRegistry: LifecycleRegistry = LifecycleRegistry(this)
private var savedStateRegistryController: SavedStateRegistryController = SavedStateRegistryController.Companion.create(this)
override val lifecycle: Lifecycle = lifecycleRegistry
override val savedStateRegistry = savedStateRegistryController.savedStateRegistry
fun handleLifecycleEvent(event: Lifecycle.Event) {
if (lifecycleRegistry.currentState != Lifecycle.State.DESTROYED) {
lifecycleRegistry.handleLifecycleEvent(event)
}
}
fun performRestore(savedState: Bundle?) {
if (!savedStateRegistryController.savedStateRegistry.isRestored) {
savedStateRegistryController.performRestore(savedState)
}
}
}

View File

@@ -0,0 +1,46 @@
/*
* Copyright 2023 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.kouros.navigation.car
import android.annotation.SuppressLint
import android.location.Location
import androidx.car.app.CarAppService
import androidx.car.app.Session
import androidx.car.app.SessionInfo
import androidx.car.app.validation.HostValidator
class NavigationCarAppService : CarAppService() {
@SuppressLint("PrivateResource")
override fun createHostValidator(): HostValidator {
return HostValidator.ALLOW_ALL_HOSTS_VALIDATOR
}
override fun onCreateSession(sessionInfo: SessionInfo): Session {
return NavigationSession()
}
}
public interface LocationCallback {
fun onLocationChanged(location: Location) {
}
}

View File

@@ -0,0 +1,202 @@
package com.kouros.navigation.car
import android.Manifest
import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.location.Location
import android.location.LocationManager
import android.util.Log
import androidx.car.app.CarContext
import androidx.car.app.Screen
import androidx.car.app.ScreenManager
import androidx.car.app.Session
import androidx.car.app.navigation.model.Maneuver
import androidx.core.location.LocationListenerCompat
import androidx.core.net.toUri
import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.LifecycleOwner
import com.kouros.navigation.car.navigation.RouteCarModel
import com.kouros.navigation.car.screen.NavigationScreen
import com.kouros.navigation.car.screen.RequestPermissionScreen
import com.kouros.navigation.car.screen.SearchScreen
import com.kouros.navigation.data.Constants.TAG
import com.kouros.navigation.data.ObjectBox
import com.kouros.navigation.model.RouteModel
class NavigationSession : Session() {
val uriScheme = "samples";
val uriHost = "navigation";
lateinit var route: RouteCarModel;
lateinit var navigationScreen: NavigationScreen
lateinit var surfaceRenderer: SurfaceRenderer
var locationIndex = 0
val test = true
var mLocationListener: LocationListenerCompat = LocationListenerCompat { location: Location? ->
updateLocation(location)
}
private val mLifeCycleObserver: LifecycleObserver = object : DefaultLifecycleObserver {
override fun onCreate(owner: LifecycleOwner) {
Log.i(TAG, "In onCreate()")
}
override fun onResume(owner: LifecycleOwner) {
Log.i(TAG, "In onResume()")
}
override fun onPause(owner: LifecycleOwner) {
Log.i(TAG, "In onPause()")
}
override fun onStop(owner: LifecycleOwner) {
Log.i(TAG, "In onStop()")
}
override fun onDestroy(owner: LifecycleOwner) {
Log.i(TAG, "In onDestroy()")
val locationManager =
carContext.getSystemService(Context.LOCATION_SERVICE) as LocationManager
locationManager.removeUpdates(mLocationListener)
}
}
init {
val lifecycle: Lifecycle = lifecycle
lifecycle.addObserver(mLifeCycleObserver)
}
override fun onCreateScreen(intent: Intent): Screen {
route = RouteCarModel()
ObjectBox.init(carContext);
surfaceRenderer = SurfaceRenderer(carContext, lifecycle, route)
navigationScreen = NavigationScreen(carContext, surfaceRenderer, route)
if (carContext.checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED
&& carContext.checkSelfPermission(Manifest.permission.READ_CONTACTS)
== PackageManager.PERMISSION_GRANTED
) {
requestLocationUpdates()
} else {
// If we do not have the location permission, show the request permission screen.
val screenManager =
carContext.getCarService(ScreenManager::class.java)
screenManager
.push(navigationScreen)
return RequestPermissionScreen(
carContext,
mLocationPermissionCheckCallback = {
screenManager.pop()
},
mContactsPermissionCheckCallback = {
screenManager.pop()
}
)
}
return navigationScreen
}
override fun onNewIntent(intent: Intent) {
val screenManager = carContext.getCarService(ScreenManager::class.java)
if ((CarContext.ACTION_NAVIGATE == intent.action)) {
val uri = ("http://" + intent.dataString).toUri()
val location = Location(LocationManager.GPS_PROVIDER)
screenManager.popToRoot()
screenManager.pushForResult(
SearchScreen(
carContext,
surfaceRenderer,
location,
// TODO: Uri
)
) { obj: Any? ->
if (obj != null) {
}
}
return
}
val uri = intent.data
if (uri != null && uriScheme == uri.scheme
&& uriHost == uri.schemeSpecificPart
) {
val top = screenManager.getTop()
when (uri.fragment) {
"DEEP_LINK_ACTION" -> if (top !is NavigationScreen) {
screenManager.popToRoot()
}
else -> {}
}
}
}
@SuppressLint("MissingPermission")
fun requestLocationUpdates() {
val locationManager =
carContext.getSystemService(Context.LOCATION_SERVICE) as LocationManager
val location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER)
updateLocation(location)
locationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER,
/* minTimeMs= */ 100,
/* minDistanceM= */ 0f,
mLocationListener
)
}
fun updateLocation(location: Location?) {
if (location != null) {
if (test) {
test(location)
} else {
update(location)
}
}
}
fun test(location: Location?) {
if (route.isNavigating() && locationIndex < route.polylineLocations.size) {
val loc = route.polylineLocations[locationIndex]
val curLocation = Location(LocationManager.GPS_PROVIDER)
curLocation.longitude = loc[0]
curLocation.latitude = loc[1]
update(curLocation)
locationIndex += 1
if (locationIndex > route.polylineLocations.size) {
val locationManager =
carContext.getSystemService(Context.LOCATION_SERVICE) as LocationManager
locationManager.removeUpdates(mLocationListener)
}
} else {
update(location = location!!)
}
}
fun update(location: Location) {
surfaceRenderer.updateLocation(location)
if (route.isNavigating()) {
route.findManeuver(location)
// if (routingModel.distanceToRoute > 50) {
// routingModel.stopNavigating()
// locationIndex = 0
// surfaceRenderer.setGeoJson()
// navigationScreen.reRoute()
// }
navigationScreen.updateTrip()
}
}
}

View File

@@ -0,0 +1,340 @@
package com.kouros.navigation.car
import android.app.Presentation
import android.graphics.Rect
import android.hardware.display.DisplayManager
import android.hardware.display.VirtualDisplay
import android.location.Location
import android.location.LocationManager
import android.util.Log
import androidx.car.app.AppManager
import androidx.car.app.CarContext
import androidx.car.app.SurfaceCallback
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.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.unit.dp
import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.setViewTreeLifecycleOwner
import androidx.savedstate.setViewTreeSavedStateRegistryOwner
import com.kouros.navigation.car.navigation.RouteCarModel
import com.kouros.navigation.utils.NavigationUtils.Utils.createGeoJson
import org.maplibre.compose.camera.CameraPosition
import org.maplibre.compose.camera.rememberCameraState
import org.maplibre.compose.expressions.dsl.const
import org.maplibre.compose.layers.CircleLayer
import org.maplibre.compose.layers.FillLayer
import org.maplibre.compose.layers.LineLayer
import org.maplibre.compose.location.LocationPuck
import org.maplibre.compose.location.LocationPuckColors
import org.maplibre.compose.location.rememberDefaultLocationProvider
import org.maplibre.compose.location.rememberUserLocationState
import org.maplibre.compose.map.MaplibreMap
import org.maplibre.compose.sources.GeoJsonData
import org.maplibre.compose.sources.getBaseSource
import org.maplibre.compose.sources.rememberGeoJsonSource
import org.maplibre.compose.style.BaseStyle
import org.maplibre.spatialk.geojson.Position
import kotlin.time.Duration.Companion.seconds
import androidx.compose.runtime.collectAsState
class SurfaceRenderer(carContext: CarContext, lifecycle: Lifecycle,
private var routeModel: RouteCarModel) : DefaultLifecycleObserver {
var mVisibleArea: Rect? = null
var mStableArea: Rect? = null
private val mCarContext: CarContext = carContext
var lastLocation = Location(LocationManager.GPS_PROVIDER)
val cameraPosition = MutableLiveData(
CameraPosition(
zoom = 15.0,
target = Position(latitude = 48.1857475, longitude = 11.5793627)
)
)
val geojson = MutableLiveData("")
val previewGeojson = MutableLiveData("")
var preview = false
lateinit var mapView: ComposeView
val tilt = 60.0
val padding = PaddingValues(start = 150.dp, top = 250.dp)
val prePadding = PaddingValues(start = 150.dp, bottom = 300.dp)
val mSurfaceCallback: SurfaceCallback = object : SurfaceCallback {
lateinit var lifecycleOwner: CustomLifecycleOwner
lateinit var virtualDisplay: VirtualDisplay
lateinit var presentation: Presentation
override fun onSurfaceAvailable(surfaceContainer: SurfaceContainer) {
synchronized(this@SurfaceRenderer) {
Log.i(TAG, "Surface available $surfaceContainer")
lifecycleOwner = CustomLifecycleOwner()
lifecycleOwner.performRestore(null)
// technically, we only really need any one of these instead of all 3
// i add them to be consistent with the actual lifecycle.
lifecycleOwner.handleLifecycleEvent(Lifecycle.Event.ON_CREATE)
lifecycleOwner.handleLifecycleEvent(Lifecycle.Event.ON_START)
lifecycleOwner.handleLifecycleEvent(Lifecycle.Event.ON_RESUME)
virtualDisplay = carContext.getSystemService(DisplayManager::class.java)
.createVirtualDisplay(
"Maps",
surfaceContainer.width,
surfaceContainer.height,
surfaceContainer.dpi,
surfaceContainer.surface,
0
)
mapView = ComposeView(carContext).apply {
this.setViewTreeLifecycleOwner(lifecycleOwner)
this.setViewTreeSavedStateRegistryOwner(lifecycleOwner)
setContent {
Map()
}
}
presentation = Presentation(carContext, virtualDisplay.display)
presentation.setContentView(mapView)
presentation.show()
}
}
override fun onVisibleAreaChanged(visibleArea: Rect) {
synchronized(this@SurfaceRenderer) {
mVisibleArea = visibleArea
}
}
override fun onStableAreaChanged(stableArea: Rect) {
synchronized(this@SurfaceRenderer) {
mStableArea = stableArea
}
}
override fun onSurfaceDestroyed(surfaceContainer: SurfaceContainer) {
synchronized(this@SurfaceRenderer) {
Log.i(TAG, "SurfaceRenderer destroyed")
presentation.dismiss()
// This handles releasing the Surface provided when creating the VirtualDisplay
virtualDisplay.release()
lifecycleOwner.handleLifecycleEvent(Lifecycle.Event.ON_PAUSE)
lifecycleOwner.handleLifecycleEvent(Lifecycle.Event.ON_STOP)
lifecycleOwner.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY)
}
}
override fun onScroll(distanceX: Float, distanceY: Float) {
Log.i(TAG, "onScroll")
synchronized(this@SurfaceRenderer) {
}
}
override fun onScale(focusX: Float, focusY: Float, scaleFactor: Float) {
}
}
init {
lifecycle.addObserver(this)
}
@Composable
fun Map() {
val position: CameraPosition? by cameraPosition.observeAsState()
val geoJsonData: String? by geojson.observeAsState()
val previewGeoJsonData: String? by previewGeojson.observeAsState()
val cameraState =
rememberCameraState(
firstPosition =
CameraPosition(
target = Position(
latitude = position!!.target.latitude,
longitude = position!!.target.longitude
),
zoom = 15.0,
tilt = tilt,
padding = getPaddingValues()
)
)
val variant = if (isSystemInDarkTheme()) "dark" else "light"
val locationProvider = rememberDefaultLocationProvider()
val locationState = rememberUserLocationState(locationProvider)
MaplibreMap(
cameraState = cameraState,
//baseStyle = BaseStyle.Uri("https://tiles.openfreemap.org/styles/liberty"),
baseStyle = BaseStyle.Uri("https://kouros-online.de/liberty"),
) {
LocationPuck(
idPrefix = "user-location",
locationState = locationState,
cameraState = cameraState,
accuracyThreshold = 10f,
colors = LocationPuckColors(accuracyStrokeColor = Color.Green)
)
getBaseSource(id = "openmaptiles")?.let { tiles ->
FillLayer(id = "example", visible = false, source = tiles, sourceLayer = "building")
val coordinates = mutableListOf<List<Double>>()
coordinates.add(listOf(position!!.target.longitude, position!!.target.latitude))
coordinates.add(
listOf(
position!!.target.longitude + 0.00001,
position!!.target.latitude + 0.00001
)
)
RouteLayer(geoJsonData, previewGeoJsonData)
}
}
LaunchedEffect(position) {
cameraState.animateTo(
finalPosition = CameraPosition(
bearing = position!!.bearing,
zoom = position!!.zoom,
target = position!!.target,
tilt = tilt,
padding = getPaddingValues()
),
duration = 3.seconds
)
}
}
@Composable
fun RouteLayer(geoJsonData: String?, previewGeoJsonData: String?) {
if (geoJsonData!!.isNotEmpty()) {
val routes =
rememberGeoJsonSource(GeoJsonData.JsonString(geoJsonData!!))
LineLayer(
id = "routes-casing",
source = routes,
color = const(Color.White),
width = const(12.dp),
)
LineLayer(
id = "routes",
source = routes,
color = const(Color.Blue),
width = const(10.dp),
)
}
if (previewGeoJsonData!!.isNotEmpty()) {
val routes =
rememberGeoJsonSource(GeoJsonData.JsonString(previewGeoJsonData!!))
LineLayer(
id = "routes-casing-pre",
source = routes,
color = const(Color.White),
width = const(6.dp),
)
LineLayer(
id = "routes-pre",
source = routes,
color = const(Color.Cyan),
width = const(4.dp),
)
}
}
override fun onCreate(owner: LifecycleOwner) {
Log.i(TAG, "SurfaceRenderer created")
mCarContext.getCarService(AppManager::class.java)
.setSurfaceCallback(mSurfaceCallback)
}
/** Handles the map zoom-in and zoom-out events. */
fun handleScale(zoomSign: Int) {
synchronized(this) {
val newZoom = if (zoomSign < 0) {
cameraPosition.value!!.zoom - 1.0
} else {
cameraPosition.value!!.zoom + 1.0
}
cameraPosition.postValue(
cameraPosition.value!!.copy(
zoom = newZoom,
target = cameraPosition.value!!.target
)
)
}
}
fun updateLocation(location: Location) {
synchronized(this) {
var bearing = cameraPosition.value!!.bearing
if (lastLocation.latitude != location.latitude) {
if (lastLocation.distanceTo(location) > 10) {
bearing = lastLocation.bearingTo(location).toDouble()
}
}
if (preview) {
bearing = 0.0
}
val zoom = calculateZoom(location)
cameraPosition.postValue(
cameraPosition.value!!.copy(
bearing = bearing,
zoom = zoom,
padding = getPaddingValues(),
target = Position(location.longitude, location.latitude),
)
)
lastLocation = location
}
}
private fun calculateZoom(location: Location): Double {
if (preview) {
return 11.0
}
//var zoom = cameraPosition.value!!.zoom
val zoom = when (location.speed.toInt()) {
in 0..10 -> 17.0
in 11..20 -> 16.0
in 21..30 -> 15.0
in 31..40 -> 14.0
in 41..50 -> 13.0
in 51..60 -> 12.0
else -> 11
}
return zoom.toDouble()
}
fun setGeoJson() {
geojson.value = routeModel.geoJson
preview = false
}
fun setPreviewGeoJson(geoRoute: String) {
previewGeojson.value = geoRoute
preview = true
}
fun getPaddingValues(): PaddingValues {
return if (preview) {
prePadding
} else {
padding
}
}
companion
object {
private const val TAG = "MapRenderer"
}
}

View File

@@ -0,0 +1,83 @@
package com.kouros.navigation.car.navigation
import android.R
import android.app.Activity
import android.location.Location
import android.os.Bundle
import android.os.Environment
import android.view.Menu
import android.view.View
import android.widget.TextView
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
}
}

View File

@@ -0,0 +1,76 @@
package com.kouros.navigation.car.navigation
import androidx.annotation.DrawableRes
import androidx.annotation.StringRes
import androidx.car.app.CarContext
import androidx.car.app.CarToast
import androidx.car.app.model.Action
import androidx.car.app.model.Alert
import androidx.car.app.model.AlertCallback
import androidx.car.app.model.CarIcon
import androidx.car.app.model.CarText
import androidx.car.app.model.OnClickListener
import androidx.core.graphics.drawable.IconCompat
import com.kouros.android.cars.carappservice.R
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(
@StringRes titleRes: Int, @StringRes toastStringRes: Int,
flags: Int
): Action {
return Action.Builder()
.setOnClickListener { showToast(toastStringRes) }
.setTitle(createCarText(titleRes))
.setFlags(flags)
.build()
}
fun showToast(@StringRes toastStringRes: Int) {
CarToast.makeText(
carContext,
carContext.getString(toastStringRes),
CarToast.LENGTH_SHORT
)
.show()
}
fun createCarText(@StringRes stringRes: Int): CarText {
return CarText.create(carContext.getString(stringRes))
}
fun createCarIcon(@DrawableRes iconRes: Int): CarIcon {
return CarIcon.Builder(IconCompat.createWithResource(carContext, iconRes)).build()
}
}

View File

@@ -0,0 +1,223 @@
/*
* Copyright 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.kouros.navigation.car.navigation
import android.net.Uri
import android.text.SpannableString
import androidx.annotation.DrawableRes
import androidx.annotation.StringRes
import androidx.car.app.CarContext
import androidx.car.app.model.CarColor
import androidx.car.app.model.CarIcon
import androidx.car.app.model.CarText
import androidx.car.app.model.DateTimeWithZone
import androidx.car.app.model.Distance
import androidx.car.app.navigation.model.Maneuver
import androidx.car.app.navigation.model.Step
import androidx.car.app.navigation.model.TravelEstimate
import androidx.core.graphics.drawable.IconCompat
import com.kouros.android.cars.carappservice.R
import com.kouros.navigation.data.ManeuverType
import com.kouros.navigation.model.RouteModel
import org.json.JSONObject
import java.util.TimeZone
import java.util.concurrent.TimeUnit
/** A class that provides models for the routing demos. */
class RouteCarModel() : RouteModel() {
/** Returns the current [Step] with information such as the cue text and images. */
fun currentStep(carContext: CarContext): Step {
val maneuver = (maneuvers[maneuverIndex] as JSONObject)
val maneuverType = maneuver.getInt("type")
val distanceStepLeft = leftStepDistance() * 1000
var text = ""
var routing: (Pair<Int, CarIcon>)
routing = if (hasArrived(maneuverType)) {
routingData(maneuverType, carContext)
} else {
routingData(ManeuverType.None.value, carContext)
}
when (distanceStepLeft) {
in 0.0..100.0 -> {
if (maneuverIndex < maneuvers.length()) {
val maneuver = (maneuvers[maneuverIndex + 1] as JSONObject)
if (maneuver.optJSONArray("street_names") != null) {
text = maneuver.getJSONArray("street_names").get(0) as String
}
val maneuverType = maneuver.getInt("type")
routing = routingData(maneuverType, carContext)
}
}
else -> {
if (maneuver.optJSONArray("street_names") != null) {
text = maneuver.getJSONArray("street_names").get(0) as String
}
}
}
val currentStepCueWithImage: SpannableString =
createString(text)
val step =
Step.Builder(currentStepCueWithImage)
.setManeuver(
Maneuver.Builder(routing.first)
.setIcon(routing.second)
.build()
)
.setRoad(destination.street!!)
.build()
return step
}
/** Returns the next [Step] with information such as the cue text and images. */
fun nextStep(carContext: CarContext): Step {
val maneuver = (maneuvers[maneuverIndex + 1] as JSONObject)
val maneuverType = maneuver.getInt("type")
val routing = routingData(maneuverType, carContext)
val distanceLeft = leftStepDistance() * 1000
var text = ""
when (distanceLeft) {
in 0.0..100.0 -> {
if (maneuver.optJSONArray("street_names") != null) {
text = maneuver.getJSONArray("street_names").get(0) as String
}
}
else -> {
if (maneuver.optJSONArray("street_names") != null) {
text = maneuver.getJSONArray("street_names").get(0) as String
}
}
}
val currentStepCueWithImage: SpannableString =
createString(text)
val step =
Step.Builder(currentStepCueWithImage)
.setManeuver(
Maneuver.Builder(routing.first)
.setIcon(routing.second)
.build()
)
.build()
return step
}
fun routingData(routeManeuverType: Int, carContext: CarContext): (Pair<Int, CarIcon>) {
var type = Maneuver.TYPE_DEPART
var currentTurnIcon = createCarIcon(carContext, R.drawable.ic_turn_name_change)
when (routeManeuverType) {
ManeuverType.Destination.value,
ManeuverType.DestinationLeft.value,
ManeuverType.DestinationRight.value
-> {
type = Maneuver.TYPE_DESTINATION
currentTurnIcon = createCarIcon(carContext, R.drawable.ic_turn_destination)
}
ManeuverType.None.value -> {
type = Maneuver.TYPE_STRAIGHT
currentTurnIcon = createCarIcon(carContext, R.drawable.ic_turn_name_change)
}
ManeuverType.Right.value -> {
type = Maneuver.TYPE_TURN_NORMAL_RIGHT
// currentTurnIcon = createCarIcon(carContext, R.drawable.ic_turn_normal_right)
currentTurnIcon = createCarIcon(carContext, R.drawable.turn_right_48px1)
}
ManeuverType.Left.value -> {
type = Maneuver.TYPE_TURN_NORMAL_LEFT
currentTurnIcon = createCarIcon(carContext, R.drawable.ic_turn_slight_left)
}
ManeuverType.RampLeft.value -> {
type = Maneuver.TYPE_TURN_NORMAL_LEFT
currentTurnIcon = createCarIcon(carContext, R.drawable.ic_turn_normal_left)
}
ManeuverType.ExitRight.value -> {
type = Maneuver.TYPE_TURN_SLIGHT_RIGHT
currentTurnIcon = createCarIcon(carContext, R.drawable.ic_turn_slight_right)
}
ManeuverType.StayLeft.value -> {
type = Maneuver.TYPE_KEEP_LEFT
currentTurnIcon = createCarIcon(carContext, R.drawable.ic_turn_slight_left)
}
}
maneuverType = type
return Pair(type, currentTurnIcon)
}
fun hasArrived(type: Int): Boolean {
return type == ManeuverType.DestinationRight.value
|| maneuverType == ManeuverType.Destination.value
|| maneuverType == ManeuverType.DestinationLeft.value
}
fun travelEstimate(carContext: CarContext): TravelEstimate {
val timeLeft = travelLeftTime()
// Calculate the time to destination from the current time.
val nowUtcMillis = System.currentTimeMillis()
val timeToDestinationMillis =
TimeUnit.SECONDS.toMillis(timeLeft.toLong())
val leftDistance = travelLeftDistance()
val displayUnit = if (leftDistance > 1.0) {
Distance.UNIT_KILOMETERS
} else {
Distance.UNIT_METERS
}
return TravelEstimate.Builder( // The estimated distance to the destination.
Distance.create(
leftDistance,
displayUnit
), // Arrival time at the destination with the destination time zone.
DateTimeWithZone.create(
nowUtcMillis + timeToDestinationMillis,
TimeZone.getTimeZone("Europe/Berlin")
)
)
.setRemainingTimeSeconds(
TimeUnit.MILLISECONDS.toSeconds(
timeToDestinationMillis
)
)
.setRemainingTimeColor(CarColor.YELLOW)
.setRemainingDistanceColor(CarColor.RED)
//.setTripText(createCarText(carContext,R.string.travel_est_trip_text))
.setTripIcon(createCarIcon(carContext, R.drawable.ic_close_white_24dp))
.build()
}
private fun createString(
text: String
): SpannableString {
val spannableString = SpannableString(text)
return spannableString
}
fun createCarText(carContext: CarContext, @StringRes stringRes: Int): CarText {
return CarText.create(carContext.getString(stringRes))
}
fun createCarIcon(carContext: CarContext, @DrawableRes iconRes: Int): CarIcon {
return CarIcon.Builder(IconCompat.createWithResource(carContext, iconRes)).build()
}
}

View File

@@ -0,0 +1,248 @@
package com.kouros.navigation.car.screen
import android.content.ComponentName
import android.content.Intent
import android.location.Location
import android.location.LocationManager
import android.os.CountDownTimer
import androidx.car.app.CarContext
import androidx.car.app.Screen
import androidx.car.app.model.Action
import androidx.car.app.model.ActionStrip
import androidx.car.app.model.CarColor
import androidx.car.app.model.CarIcon
import androidx.car.app.model.Distance
import androidx.car.app.model.Template
import androidx.car.app.navigation.model.Maneuver
import androidx.car.app.navigation.model.MessageInfo
import androidx.car.app.navigation.model.NavigationTemplate
import androidx.car.app.navigation.model.RoutingInfo
import androidx.car.app.notification.CarPendingIntent
import androidx.car.app.suggestion.model.Suggestion
import androidx.core.graphics.drawable.IconCompat
import androidx.lifecycle.Observer
import com.kouros.android.cars.carappservice.R
import com.kouros.navigation.car.NavigationCarAppService
import com.kouros.navigation.car.SurfaceRenderer
import com.kouros.navigation.car.navigation.NavigationMessage
import com.kouros.navigation.car.navigation.RouteCarModel
import com.kouros.navigation.data.NavigationRepository
import com.kouros.navigation.data.Place
import com.kouros.navigation.model.ViewModel
class NavigationScreen(
carContext: CarContext,
private var surfaceRenderer: SurfaceRenderer,
private var routeModel: RouteCarModel
) :
Screen(carContext) {
var currentNavigationLocation = Location(LocationManager.GPS_PROVIDER)
val vieModel = ViewModel(NavigationRepository())
val observer = Observer<String> { route ->
if (route.isNotEmpty()) {
routeModel.createNavigationRoute(route)
surfaceRenderer.setGeoJson()
invalidate()
}
}
init {
vieModel.route.observe(this, observer)
}
override fun onGetTemplate(): Template {
// Log.i(TAG, "onGetTemplate NavigationScreen")
val actionStripBuilder: ActionStrip.Builder = ActionStrip.Builder()
actionStripBuilder.addAction(
Action.Builder()
.setIcon(routeModel.createCarIcon(carContext, R.drawable.ic_search_black36dp))
.setOnClickListener {
startSearchScreen()
}
//.setFlags(Action.FLAG_IS_PERSISTENT)
.build()
)
return if (routeModel.isNavigating()) {
getNavigationTemplate(actionStripBuilder)
} else {
getNavigationEndTemplate(actionStripBuilder)
}
}
private fun getNavigationTemplate(actionStripBuilder: ActionStrip.Builder): NavigationTemplate{
actionStripBuilder.addAction(
Action.Builder()
.setTitle(carContext.getString(R.string.stop_action_title))
.setIcon(
CarIcon.Builder(
IconCompat.createWithResource(
carContext,
R.drawable.ic_close_white_24dp
)
)
.build()
)
.setOnClickListener {
surfaceRenderer.geojson.postValue("")
routeModel.stopNavigating()
invalidate()
}
.build()
)
return NavigationTemplate.Builder()
.setNavigationInfo(
getRoutingInfo()
)
.setDestinationTravelEstimate(routeModel.travelEstimate(carContext))
.setActionStrip(actionStripBuilder.build())
.setMapActionStrip(mapActionStripBuilder().build())
.setBackgroundColor(CarColor.GREEN)
.build()
}
private fun getNavigationEndTemplate(actionStripBuilder: ActionStrip.Builder): NavigationTemplate{
if (routeModel.isArrived()) {
val timer = object: CountDownTimer(10000, 10000) {
override fun onTick(millisUntilFinished: Long) {}
override fun onFinish() {
routeModel.arrived = false
invalidate()
}
}
timer.start()
return NavigationTemplate.Builder()
.setNavigationInfo(
MessageInfo.Builder(
carContext.getString(R.string.arrived_exclamation_msg)
)
.setText(routeModel.destination.street!!)
.setImage(
CarIcon.Builder(
IconCompat.createWithResource(
carContext,
R.drawable.ic_place_white_24dp
)
)
.build()
)
.build()
)
.setBackgroundColor(CarColor.GREEN)
.setActionStrip(actionStripBuilder.build())
.setMapActionStrip(mapActionStripBuilder().build())
.build()
} else {
return NavigationTemplate.Builder()
.setBackgroundColor(CarColor.SECONDARY)
.setActionStrip(actionStripBuilder.build())
.setMapActionStrip(mapActionStripBuilder().build())
.build()
}
}
fun getRoutingInfo(): RoutingInfo {
var currentDistance = routeModel.currentDistance
val displayUnit = if (currentDistance > 1000.0) {
currentDistance /= 1000.0
Distance.UNIT_KILOMETERS
} else {
Distance.UNIT_METERS
}
return RoutingInfo.Builder()
.setCurrentStep(
routeModel.currentStep(carContext = carContext),
Distance.create(currentDistance, displayUnit)
)
.setNextStep(routeModel.nextStep(carContext = carContext))
.build()
}
private fun mapActionStripBuilder(): ActionStrip.Builder {
val actionStripBuilder = ActionStrip.Builder()
.addAction(
Action.Builder()
.setIcon(
CarIcon.Builder(
IconCompat.createWithResource(
carContext,
R.drawable.ic_zoom_in_24
)
)
.build()
).setOnClickListener {
surfaceRenderer.handleScale(1)
}
.build()
)
.addAction(
Action.Builder()
.setIcon(
CarIcon.Builder(
IconCompat.createWithResource(
carContext,
R.drawable.ic_zoom_out_24
)
)
.build()
).setOnClickListener {
surfaceRenderer.handleScale(-1)
}
.build())
return actionStripBuilder
}
private fun getSuggestion(title: Int, subtitle: Int, icon: CarIcon): Suggestion {
return Suggestion.Builder()
.setIdentifier("0")
.setTitle(carContext.getString(title))
.setSubtitle(carContext.getString(subtitle))
.setIcon(icon)
.setAction(
CarPendingIntent.getCarApp(
carContext, 0,
Intent().setComponent(
ComponentName(
carContext,
NavigationCarAppService::class.java
)
),
//.setAction(NavigationSession.EXECUTE_SCRIPT),
0
)
)
.build()
}
private fun startSearchScreen() {
screenManager
.pushForResult(
SearchScreen(carContext, surfaceRenderer, surfaceRenderer.lastLocation)
) { obj: Any? ->
if (obj != null) {
val place = obj as Place
val location = Location(LocationManager.GPS_PROVIDER)
location.latitude = place.latitude
location.longitude = place.longitude
vieModel.saveRecent(place)
vieModel.loadRoute(surfaceRenderer.lastLocation, location)
currentNavigationLocation = location
routeModel.destination = place
invalidate()
}
}
}
fun reRoute() {
//NavigationMessage(carContext).createAlert()
//vieModel.loadRoute(surfaceRenderer.lastLocation, currentNavigationLocation)
}
fun updateTrip() {
if (routeModel.maneuverType == Maneuver.TYPE_DESTINATION && routeModel.leftStepDistance() * 1000 < 25.0) {
routeModel.arrived = true
routeModel.stopNavigating()
}
invalidate()
}
}

View File

@@ -0,0 +1,153 @@
package com.kouros.navigation.car.screen
import android.location.Location
import android.net.Uri
import android.text.Spannable
import android.text.SpannableString
import androidx.car.app.CarContext
import androidx.car.app.CarToast
import androidx.car.app.Screen
import androidx.car.app.model.Action
import androidx.car.app.model.CarIcon
import androidx.car.app.model.Distance
import androidx.car.app.model.DistanceSpan
import androidx.car.app.model.Header
import androidx.car.app.model.ItemList
import androidx.car.app.model.ListTemplate
import androidx.car.app.model.Row
import androidx.car.app.model.Template
import androidx.core.graphics.drawable.IconCompat
import androidx.lifecycle.Observer
import com.kouros.android.cars.carappservice.R
import com.kouros.navigation.car.SurfaceRenderer
import com.kouros.navigation.car.navigation.RouteCarModel
import com.kouros.navigation.data.Constants
import com.kouros.navigation.data.NavigationRepository
import com.kouros.navigation.data.Place
import com.kouros.navigation.model.ViewModel
class PlaceListScreen(
private val carContext: CarContext,
private val surfaceRenderer: SurfaceRenderer,
location: Location,
private val category: String
) : Screen(carContext) {
val viewModel = ViewModel(NavigationRepository())
var places = listOf<Place>()
val observer = Observer<List<Place>> { newPlaces ->
places = newPlaces
invalidate()
}
val observerAddress = Observer<List<Place>> { newContacts ->
places = newContacts
invalidate()
}
init {
if (category == Constants.RECENT) {
viewModel.places.observe(this, observer)
viewModel.loadPlaces(location)
}
if (category == Constants.CONTACTS) {
viewModel.contactAddress.observe(this, observerAddress)
viewModel.loadContacts(carContext)
}
}
override fun onGetTemplate(): Template {
val itemListBuilder = ItemList.Builder()
.setNoItemsMessage("No places to show")
places.forEach {
itemListBuilder.addItem(
Row.Builder()
.addAction(
deleteAction(it)
)
.setImage(contactIcon(it.avatar, it.category))
.setTitle(it.name!!)
.addText(SpannableString(" ").apply {
setSpan(
DistanceSpan.create(
Distance.create(
it.distance.toDouble(),
Distance.UNIT_KILOMETERS
)
), 0, 1, Spannable.SPAN_INCLUSIVE_INCLUSIVE
)
})
.setOnClickListener {
val place = Place(
0,
it.name,
it.category,
it.latitude,
it.longitude,
it.postalCode,
it.city,
it.street,
avatar = null
)
screenManager
.pushForResult(
RoutePreviewScreen(
carContext,
surfaceRenderer,
place
)
) { obj: Any? ->
if (obj != null) {
setResult(obj)
finish()
}
}
}
.build()
)
}
val title = if (category == Constants.RECENT) {
carContext.getString(R.string.recent_destinations)
} else {
carContext.getString(R.string.contacts)
}
val header = Header.Builder()
.setStartHeaderAction(Action.BACK)
.setTitle(title)
.build()
return ListTemplate.Builder()
.setHeader(header)
.setSingleList(itemListBuilder.build())
.build()
}
private fun deleteAction(place: Place): Action = Action.Builder()
.setIcon(
RouteCarModel().createCarIcon(
carContext,
R.drawable.ic_close_white_24dp
)
)
.setOnClickListener {
viewModel.deleteRecent(place)
CarToast.makeText(
carContext,
R.string.recent_Item_deleted, CarToast.LENGTH_LONG
).show()
invalidate()
}
.build()
fun contactIcon(avatar: Uri?, category: String?): CarIcon {
if (category == Constants.RECENT || avatar == null) {
return CarIcon.Builder(
IconCompat.createWithResource(
carContext, R.drawable.ic_place_white_24dp
)
).build()
}
return CarIcon.Builder(IconCompat.createWithContentUri(avatar)).build()
}
}

View File

@@ -0,0 +1,60 @@
package com.kouros.navigation.car.screen
import android.Manifest.permission
import androidx.car.app.CarContext
import androidx.car.app.CarToast
import androidx.car.app.Screen
import androidx.car.app.model.Action
import androidx.car.app.model.CarColor
import androidx.car.app.model.MessageTemplate
import androidx.car.app.model.OnClickListener
import androidx.car.app.model.ParkedOnlyOnClickListener
import androidx.car.app.model.Template
/** Screen for asking the user to grant location permission. */
class RequestPermissionScreen(
carContext: CarContext,
var mLocationPermissionCheckCallback: LocationPermissionCheckCallback,
var mContactsPermissionCheckCallback: LocationPermissionCheckCallback,
) : Screen(carContext) {
/** Callback called when the location permission is granted. */
fun interface LocationPermissionCheckCallback {
/** Callback called when the location permission is granted. */
fun onPermissionGranted()
}
override fun onGetTemplate(): Template {
val permissions: MutableList<String?> = ArrayList()
permissions.add(permission.ACCESS_FINE_LOCATION)
permissions.add(permission.READ_CONTACTS)
val message = "This app needs access to location in order to show the map around you"
val listener: OnClickListener = ParkedOnlyOnClickListener.create {
carContext.requestPermissions(
permissions
) { approved: MutableList<String?>?, rejected: MutableList<String?>? ->
CarToast.makeText(
carContext,
String.format("Approved: %s Rejected: %s", approved, rejected),
CarToast.LENGTH_LONG
).show()
if (!approved!!.isEmpty()) {
mLocationPermissionCheckCallback.onPermissionGranted()
mContactsPermissionCheckCallback.onPermissionGranted()
finish()
}
}
}
val action = Action.Builder()
.setTitle("Grant Access")
.setBackgroundColor(CarColor.GREEN)
.setOnClickListener(listener)
.build()
return MessageTemplate.Builder(message)
.addAction(action)
.build()
}
}

View File

@@ -0,0 +1,243 @@
/*
* Copyright 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.kouros.navigation.car.screen
import android.location.Geocoder
import android.location.Location
import android.location.LocationManager
import android.os.CountDownTimer
import android.text.SpannableString
import androidx.annotation.DrawableRes
import androidx.annotation.StringRes
import androidx.car.app.CarContext
import androidx.car.app.CarToast
import androidx.car.app.Screen
import androidx.car.app.constraints.ConstraintManager
import androidx.car.app.model.Action
import androidx.car.app.model.ActionStrip
import androidx.car.app.model.CarIcon
import androidx.car.app.model.CarText
import androidx.car.app.model.DurationSpan
import androidx.car.app.model.Header
import androidx.car.app.model.ItemList
import androidx.car.app.model.ListTemplate
import androidx.car.app.model.Row
import androidx.car.app.model.Template
import androidx.car.app.navigation.model.MapController
import androidx.car.app.navigation.model.MapWithContentTemplate
import androidx.core.graphics.drawable.IconCompat
import androidx.lifecycle.Observer
import com.kouros.android.cars.carappservice.R
import com.kouros.navigation.car.SurfaceRenderer
import com.kouros.navigation.car.navigation.NavigationMessage
import com.kouros.navigation.car.navigation.RouteCarModel
import com.kouros.navigation.data.NavigationRepository
import com.kouros.navigation.data.Place
import com.kouros.navigation.model.ViewModel
/** Creates a screen using the new [androidx.car.app.navigation.model.MapWithContentTemplate] */
class RoutePreviewScreen(
carContext: CarContext,
private var surfaceRenderer: SurfaceRenderer,
private var destination: Place
) :
Screen(carContext) {
private var mIsFavorite = false
private var mItemLimit = 0
private var street = ""
val vieModel = ViewModel(NavigationRepository())
val routeModel = RouteCarModel()
val navigationMessage = NavigationMessage(carContext)
val observer = Observer<String> { route ->
if (route.isNotEmpty()) {
routeModel.createNavigationRoute(route)
surfaceRenderer.setPreviewGeoJson(routeModel.geoJson)
val geocoder = Geocoder(carContext)
geocoder.getFromLocation(destination.latitude, destination.longitude, 1) {
for (address in it) {
street = address.getAddressLine(0)
}
invalidate()
}
}
}
init {
vieModel.previewRoute.observe(this, observer)
val location = Location(LocationManager.GPS_PROVIDER)
location.latitude = destination.latitude
location.longitude = destination.longitude
vieModel.loadPreviewRoute(surfaceRenderer.lastLocation, location)
}
override fun onGetTemplate(): Template {
// Adjust the item limit according to the car constrains.
mItemLimit =
carContext.getCarService(ConstraintManager::class.java)
.getContentLimit(
ConstraintManager.CONTENT_LIMIT_TYPE_ROUTE_LIST
)
val navigateActionIcon: CarIcon = CarIcon.Builder(
IconCompat.createWithResource(
carContext, R.drawable.baseline_assistant_navigation_24
)
).build()
val navigateAction = Action.Builder()
.setIcon(navigateActionIcon)
.setOnClickListener { this.onNavigate() }
.build()
val itemListBuilder = ItemList.Builder()
if (routeModel.polylineLocations.isNotEmpty()) {
itemListBuilder.addItem(createRow(0, navigateAction))
}
val header = Header.Builder()
.setStartHeaderAction(Action.BACK)
.setTitle(carContext.getString(R.string.route_preview))
.addEndHeaderAction(
Action.Builder()
.setIcon(
CarIcon.Builder(
IconCompat.createWithResource(
carContext,
if (mIsFavorite)
R.drawable.ic_favorite_filled_white_24dp
else
R.drawable.ic_favorite_white_24dp
)
)
.build()
)
.setOnClickListener {
mIsFavorite = !mIsFavorite
CarToast.makeText(
carContext,
if (mIsFavorite)
carContext
.getString(R.string.favorite_toast_msg)
else
carContext.getString(
R.string.not_favorite_toast_msg
),
CarToast.LENGTH_SHORT
)
.show()
invalidate()
}
.build()
)
.addEndHeaderAction(
Action.Builder()
.setOnClickListener { finish() }
.setIcon(
CarIcon.Builder(
IconCompat.createWithResource(
carContext,
R.drawable.ic_close_white_24dp
)
)
.build()
)
.build()
)
.build()
val timer = object: CountDownTimer(10000, 10000) {
override fun onTick(millisUntilFinished: Long) {}
override fun onFinish() {
onNavigate()
}
}
timer.start()
return MapWithContentTemplate.Builder()
.setContentTemplate(
ListTemplate.Builder()
.setHeader(header)
.setSingleList(itemListBuilder.build())
.build()
)
.setMapController(
MapController.Builder().setMapActionStrip(
getMapActionStrip()
).build()
)
.build()
}
private fun createRow(index: Int, action: Action): Row {
val route: CarText = createRouteText(index)
return Row.Builder()
.setTitle(route)
.setOnClickListener { onRouteSelected(index) }
.addText(street)
.addAction(action)
.build()
}
private fun createRouteText(index: Int): CarText {
val time = routeModel.summary.getInt("time")
val length = routeModel.summary.getInt("length")
val firstRoute = SpannableString(" \u00b7 $length km")
firstRoute.setSpan(
DurationSpan.create(time.toLong()), 0, 1,0
)
return CarText.Builder(firstRoute)
.build()
}
private fun onNavigate() {
setResult(destination)
finish()
}
private fun onRouteSelected(index: Int) {
setResult(destination)
finish()
}
fun getMapActionStrip(): ActionStrip {
return ActionStrip.Builder()
.addAction(
createToastAction(R.drawable.ic_zoom_in_24, R.string.zoomed_in_toast_msg)
)
.addAction(
createToastAction(R.drawable.ic_zoom_out_24, R.string.zoomed_out_toast_msg)
)
.addAction(Action.PAN)
.build()
}
private fun createToastAction(
@DrawableRes iconRes: Int,
@StringRes toastStringRes: Int
): Action {
return Action.Builder()
.setOnClickListener { surfaceRenderer.handleScale(-1) }
.setIcon(navigationMessage.createCarIcon(iconRes))
.build()
}
}

View File

@@ -0,0 +1,151 @@
package com.kouros.navigation.car.screen
import android.annotation.SuppressLint
import android.location.Geocoder
import android.location.Location
import android.location.LocationManager
import androidx.car.app.CarContext
import androidx.car.app.Screen
import androidx.car.app.model.Action
import androidx.car.app.model.ItemList
import androidx.car.app.model.Row
import androidx.car.app.model.SearchTemplate
import androidx.car.app.model.SearchTemplate.SearchCallback
import androidx.car.app.model.Template
import com.kouros.android.cars.carappservice.R
import com.kouros.navigation.car.SurfaceRenderer
import com.kouros.navigation.data.Category
import com.kouros.navigation.data.Constants
import com.kouros.navigation.data.Place
import com.kouros.navigation.utils.NavigationUtils.Utils.getBoundingBox
class SearchScreen(
carContext: CarContext,
private var surfaceRenderer: SurfaceRenderer,
private var location: Location
) : Screen(carContext) {
var isSearchComplete: Boolean = false
var isSearching: Boolean = false
var categories: List<Category> = listOf(
Category(id = Constants.RECENT, name = carContext.getString(R.string.recent_destinations)),
Category(id = Constants.CONTACTS, name = carContext.getString(R.string.contacts))
)
override fun onGetTemplate(): Template {
val itemListBuilder = ItemList.Builder()
.setNoItemsMessage("No categories to show")
val searchItemListBuilder = ItemList.Builder()
.setNoItemsMessage("No search results to show")
println("OnGetTemplate SearchScreen ${categories.size}")
if (!isSearching) {
categories.forEach {
it.name
itemListBuilder.addItem(
Row.Builder()
.setTitle(it.name)
.setOnClickListener {
screenManager
.pushForResult(
PlaceListScreen(
carContext,
surfaceRenderer,
location,
it.id
)
) { obj: Any? ->
if (obj != null) {
setResult(obj)
finish()
}
}
}
.setBrowsable(true)
.build()
)
}
}
val itemList = if (!isSearching) {
itemListBuilder.build()
} else {
searchItemListBuilder.build()
}
return SearchTemplate.Builder(
object : SearchCallback {
override fun onSearchTextChanged(searchText: String) {
doSearch(searchText, searchItemListBuilder)
}
override fun onSearchSubmitted(searchTerm: String) {
isSearchComplete = true
doSearch(searchTerm, searchItemListBuilder)
}
})
.setHeaderAction(Action.BACK)
.setShowKeyboardByDefault(false)
.setItemList(itemList)
.build()
}
@SuppressLint("DefaultLocale")
fun doSearch(searchText: String, searchItemListBuilder: ItemList.Builder) {
isSearching = true
val geocoder = Geocoder(carContext)
val box = getBoundingBox(location.latitude, location.longitude, 100.0)
val lowerLeft = box["sw"]
val lowerLeftLat = lowerLeft!!["lat"]!!
val lowerLeftLon = lowerLeft["lon"]!!
val upperRight = box["ne"]
val upperRightLat = upperRight!!["lat"]!!
val upperRightLon = upperRight["lon"]!!
val addressLocation = Location(LocationManager.GPS_PROVIDER)
geocoder.getFromLocationName(
searchText, 5,
lowerLeftLat, lowerLeftLon, upperRightLat, upperRightLon
) {
for (address in it) {
val name: String = address.getAddressLine(0)
addressLocation.latitude = address.latitude
addressLocation.longitude = address.longitude
val distance = location.distanceTo(addressLocation)
val dist = String.format("%.1f", (distance / 1000))
searchItemListBuilder.addItem(
Row.Builder()
.setTitle("$name $dist km")
.setOnClickListener {
val place = Place(
0,
name,
name,
address.latitude,
address.longitude,
"0",
"city",
name
)
setResult(place)
finish()
}
.setBrowsable(false)
.build()
)
}
}
if (searchText.isEmpty()) {
isSearching = false
}
val itemList = searchItemListBuilder.build()
println("Searching ${itemList.items.size}")
invalidate()
}
}

View File

@@ -0,0 +1,30 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
<aapt:attr name="android:fillColor">
<gradient
android:endX="85.84757"
android:endY="92.4963"
android:startX="42.9492"
android:startY="49.59793"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
android:strokeWidth="1"
android:strokeColor="#00000000" />
</vector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 660 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 345 B

View File

@@ -0,0 +1,21 @@
<!--
Copyright 2024 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#FFFFFF" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
<path android:fillColor="@android:color/white" android:pathData="M12,1C5.93,1 1,5.93 1,12s4.93,11 11,11 11,-4.93 11,-11S18.07,1 12,1zM15.57,17L12,15.42 8.43,17l-0.37,-0.37L12,7l3.95,9.63 -0.38,0.37z"/>
</vector>

View File

@@ -0,0 +1,21 @@
<!--
Copyright 2023 Google LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<vector android:height="24dp" android:tint="#000000"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M12,2L4.5,20.29l0.71,0.71L12,18l6.79,3 0.71,-0.71z"/>
</vector>

View File

@@ -0,0 +1,26 @@
<!--
Copyright 2022 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M6.4,19 L5,17.6 10.6,12 5,6.4 6.4,5 12,10.6 17.6,5 19,6.4 13.4,12 19,17.6 17.6,19 12,13.4Z"/>
</vector>

View File

@@ -0,0 +1,26 @@
<!--
Copyright 2022 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M12,21 L10.55,19.7Q6.625,16.2 4.312,13.612Q2,11.025 2,8.15Q2,5.8 3.575,4.225Q5.15,2.65 7.5,2.65Q8.825,2.65 10,3.212Q11.175,3.775 12,4.75Q12.825,3.775 14,3.212Q15.175,2.65 16.5,2.65Q18.85,2.65 20.425,4.225Q22,5.8 22,8.15Q22,11.025 19.688,13.612Q17.375,16.2 13.45,19.7ZM12,18.3Q8.425,15.05 6.213,12.7Q4,10.35 4,8.15Q4,6.65 5,5.65Q6,4.65 7.5,4.65Q8.675,4.65 9.675,5.312Q10.675,5.975 11.05,7H12.95Q13.325,5.975 14.325,5.312Q15.325,4.65 16.5,4.65Q18,4.65 19,5.65Q20,6.65 20,8.15Q20,10.35 17.788,12.7Q15.575,15.05 12,18.3ZM12,18.3Q15.575,15.05 17.788,12.7Q20,10.35 20,8.15Q20,6.65 19,5.65Q18,4.65 16.5,4.65Q15.325,4.65 14.325,5.312Q13.325,5.975 12.95,7H11.05Q10.675,5.975 9.675,5.312Q8.675,4.65 7.5,4.65Q6,4.65 5,5.65Q4,6.65 4,8.15Q4,10.35 6.213,12.7Q8.425,15.05 12,18.3Z"/>
</vector>

View File

@@ -0,0 +1,26 @@
<!--
Copyright 2022 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M12,21 L10.55,19.7Q6.625,16.2 4.312,13.612Q2,11.025 2,8.15Q2,5.8 3.575,4.225Q5.15,2.65 7.5,2.65Q8.825,2.65 10,3.212Q11.175,3.775 12,4.75Q12.825,3.775 14,3.212Q15.175,2.65 16.5,2.65Q18.85,2.65 20.425,4.225Q22,5.8 22,8.15Q22,11.025 19.688,13.612Q17.375,16.2 13.45,19.7ZM12,11.475Q12,11.475 12,11.475Q12,11.475 12,11.475Q12,11.475 12,11.475Q12,11.475 12,11.475Q12,11.475 12,11.475Q12,11.475 12,11.475Q12,11.475 12,11.475Q12,11.475 12,11.475Q12,11.475 12,11.475Q12,11.475 12,11.475Q12,11.475 12,11.475Q12,11.475 12,11.475ZM12,18.3Q15.575,15.05 17.788,12.7Q20,10.35 20,8.15Q20,6.65 19,5.65Q18,4.65 16.5,4.65Q15.325,4.65 14.325,5.312Q13.325,5.975 12.95,7H11.05Q10.675,5.975 9.675,5.312Q8.675,4.65 7.5,4.65Q6,4.65 5,5.65Q4,6.65 4,8.15Q4,10.35 6.213,12.7Q8.425,15.05 12,18.3Z"/>
</vector>

View File

@@ -0,0 +1,58 @@
<!--
Copyright (C) 2021 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="512dp"
android:height="512dp"
android:viewportWidth="512"
android:viewportHeight="512">
<group>
<clip-path android:pathData="M256,256m-256,0a256,256 0,1 1,512 0a256,256 0,1 1,-512 0 M 0,0"/>
<path
android:pathData="M0.3,-1h512v512h-512z"
android:fillColor="#9334E6"/>
<path
android:pathData="M668,-2.1v-4.8h-73.2v-69.8h73v-4.8h-73.2v-73.7h-4.8v73.7h-70v-73.7H515v73.7h-70v-73.7h-4.8v73.7h-70v-73.7h-4.8v73.7h-70v-73.7h-4.8v73.7h-69.8v-73.7H216v73.7h-70v-73.7h-4.8v73.7h-70v-73.7h-4.8v73.7h-70v-73.7h-4.8v73.7h-70v-73.7h-4.8v73.7h-73.2v4.8h73.2v69.8h-73.2v4.8h73.2v69.7h-73.2v4.8h73.2v69.8h-73.2v4.8h73.2v69.7h-73.2v4.8h73.2v69.8h-73.2v4.8h73.2v69.7h-73.2v4.8h73.2v69.8h-73.2v4.8h73.2V515h-73.2v4.8h73.2v69.8h-73.2v4.8h73.2v73.8h4.8v-73.7h70v73.7h4.8v-73.7h70v73.7h4.8v-73.7h70v73.7h4.8v-73.7h70v73.7h4.8v-73.7h70v73.7h4.8v-73.7h70v73.7h4.8v-73.7h70v73.7h4.8v-73.7h70v73.7h4.8v-73.7h70v73.7h4.8v-73.7H668v-4.8h-73.2v-69.8H668v-4.8h-73.2v-69.7H668v-4.8h-73.2v-69.8H668V366h-73.2v-69.7H668v-4.8h-73.2v-69.8H668v-4.8h-73.2v-69.7H668v-4.8h-73.2V72.5H668v-4.8h-73.2V-2.1H668zM440.3,519.9v69.8h-70v-69.8H440.3zM440.3,445.4v69.7h-70v-69.7L440.3,445.4L440.3,445.4zM440.3,370.8v69.8h-70v-69.8H440.3zM440.3,296.3V366h-70v-69.7H440.3zM440.3,221.7v69.8h-70v-69.8H440.3zM440.3,147v69.7h-70V147H440.3zM440.3,72.4v69.8h-70V72.4H440.3zM440.3,-2.1v69.7h-70V-2.1H440.3zM440.3,-76.8V-7h-70v-69.8H440.3zM365.4,519.9v69.8h-70v-69.8H365.4zM365.4,445.4v69.7h-70v-69.7L365.4,445.4L365.4,445.4zM365.4,370.8v69.8h-70v-69.8H365.4zM365.4,296.3V366h-70v-69.7H365.4zM365.4,221.7v69.8h-70v-69.8H365.4zM365.4,147v69.7h-70V147H365.4zM365.4,72.4v69.8h-70V72.4H365.4zM365.4,-2.1v69.7h-70V-2.1H365.4zM295.5,-6.9v-69.8h70v69.8C365.5,-6.9 295.5,-6.9 295.5,-6.9zM290.8,519.9v69.8h-70v-69.8H290.8zM290.8,445.4v69.7h-70v-69.7L290.8,445.4L290.8,445.4zM290.8,370.8v69.8h-70v-69.8H290.8zM220.8,291.3v-69.8h69.8v69.8H220.8zM290.8,296.3V366h-70v-69.7H290.8zM220.8,67.6V-2.1h70v69.7H220.8zM290.8,142.2h-70V72.4h70V142.2zM290.8,147v69.7h-70V147H290.8zM220.8,-6.9v-69.8h69.8v69.8C290.6,-6.9 220.8,-6.9 220.8,-6.9zM589.9,519.9v69.8h-70v-69.8H589.9zM589.9,445.4v69.7h-70v-69.7L589.9,445.4L589.9,445.4zM589.9,370.8v69.8h-70v-69.8H589.9zM589.9,296.3V366h-70v-69.7H589.9zM589.9,221.7v69.8h-70v-69.8H589.9zM589.9,147v69.7h-70V147H589.9zM589.9,72.4v69.8h-70V72.4H589.9zM589.9,-2.1v69.7h-70V-2.1H589.9zM589.9,-76.8V-7h-70v-69.8H589.9zM515.1,519.9v69.8h-70v-69.8H515.1zM515.1,445.4v69.7h-70v-69.7L515.1,445.4L515.1,445.4zM515.1,370.8v69.8h-70v-69.8H515.1zM515.1,296.3V366h-70v-69.7H515.1zM515.1,221.7v69.8h-70v-69.8H515.1zM515.1,147v69.7h-70V147H515.1zM515.1,72.4v69.8h-70V72.4H515.1zM445.1,67.6V-2.1h70v69.7H445.1zM445.1,-6.9v-69.8h70v69.8C515.1,-6.9 445.1,-6.9 445.1,-6.9zM216,519.9v69.8h-70v-69.8H216zM216,445.4v69.7h-70v-69.7L216,445.4L216,445.4zM216,370.8v69.8h-70v-69.8H216zM216,296.3V366h-70v-69.7H216zM216,221.5v69.8h-70v-69.8L216,221.5L216,221.5zM216,147v69.7h-70V147H216zM216,72.4v69.8h-70V72.4H216zM216,-2.1v69.7h-70V-2.1H216zM216,-76.8V-7h-70v-69.8H216zM141.2,519.9v69.8h-70v-69.8H141.2zM141.2,445.4v69.7h-70v-69.7L141.2,445.4L141.2,445.4zM141.2,370.8v69.8h-70v-69.8H141.2zM141.2,296.3V366h-70v-69.7H141.2zM141.2,221.5v69.8h-70v-69.8L141.2,221.5L141.2,221.5zM141.2,147v69.7h-70V147H141.2zM141.2,72.4v69.8h-70V72.4H141.2zM141.2,-2.1v69.7h-70V-2.1H141.2zM141.2,-76.8V-7h-70v-69.8H141.2zM66.4,519.9v69.8h-70v-69.8H66.4zM66.4,445.4v69.7h-70v-69.7L66.4,445.4L66.4,445.4zM66.4,370.8v69.8h-70v-69.8H66.4zM66.4,296.3V366h-70v-69.7H66.4zM66.4,221.5v69.8h-70v-69.8L66.4,221.5L66.4,221.5zM66.4,147v69.7h-70V147H66.4zM66.4,72.4v69.8h-70V72.4H66.4zM66.4,-2.1v69.7h-70V-2.1H66.4zM66.4,-76.8V-7h-70v-69.8H66.4zM-8.4,519.9v69.8h-70v-69.8H-8.4zM-8.4,445.4v69.7h-70v-69.7L-8.4,445.4L-8.4,445.4zM-8.4,370.8v69.8h-70v-69.8H-8.4zM-8.4,296.3V366h-70v-69.7H-8.4zM-8.4,221.5v69.8h-70v-69.8L-8.4,221.5L-8.4,221.5zM-8.4,147v69.7h-70V147H-8.4zM-8.4,72.4v69.8h-70V72.4H-8.4zM-8.4,-2.1v69.7h-70V-2.1H-8.4zM-8.4,-76.8V-7h-70v-69.8H-8.4z"
android:strokeAlpha="0.7"
android:fillColor="#C58AF9"
android:fillAlpha="0.7"/>
<path
android:pathData="M95.9,333.5l151.6,-250.3l18.7,3.8l164,272l-108,30l-70.5,-29.5l-89.4,39.5l-18,-10l25,-33l-63,-1.5z"
android:fillColor="#9334E6"/>
<path
android:pathData="M415.5,321.6L279.2,90.3C274.4,82 265.6,77 256.1,77s-18.4,5 -23.2,13.3L95,322.9c-4.9,7.9 -4.9,17.9 0,25.8c4.9,8.2 13.7,13.2 23.2,13.3h41.2l-15.1,27.4l16.8,16.8l94.9,-38.1l94.8,38.5l16.8,-16.8l-15.1,-27.2h39.9c14.3,0.9 26.6,-10 27.5,-24.3c0.4,-5.8 -1.2,-11.5 -4.5,-16.3L415.5,321.6zM347.5,389.5l-91.4,-37.1l-91.5,37.1l-2.6,-2.6l94.1,-168.6L350,386.9L347.5,389.5zM392.5,348h-46.8l-28.5,-48l-61.1,-111l-60.4,107.8l-29.4,51H119c-4.5,-0.1 -8.7,-2.5 -11,-6.4c-2.2,-3.5 -2.2,-7.9 0,-11.4L245,97.2c4,-6 12.2,-7.6 18.2,-3.6c1.4,1 2.7,2.2 3.6,3.6l136.4,231.5l0,0c1.4,2.1 2.2,4.5 2.1,7c-0.2,6.9 -6,12.3 -12.8,12.1L392.5,348z"
android:fillColor="#FFFFFF"/>
<path
android:pathData="M362.8,354m-86.3,0a86.3,86.3 0,1 1,172.6 0a86.3,86.3 0,1 1,-172.6 0"
android:fillColor="#9334E6"
android:fillType="evenOdd"/>
<group>
<clip-path android:pathData="M362.8,351.9c-5.7,0 -10.3,-4.6 -10.3,-10.3c0,-5.7 4.6,-10.3 10.3,-10.3s10.3,4.6 10.3,10.3C373.2,347.3 368.5,351.9 362.8,351.9zM362.8,315.9c-14.8,0 -26.6,11.9 -26.6,26.6c0,19.9 26.6,49.4 26.6,49.4s26.6,-29.4 26.6,-49.4C389.4,327.9 377.5,315.9 362.8,315.9zM293.9,353.9c0,-35.7 27,-65.1 61.8,-68.7v14c-27,3.6 -48,26.8 -48,54.8s20.9,51.2 48,54.8v14C321,419 293.9,389.6 293.9,353.9zM406.6,300.5c-10.4,-8.6 -23.3,-13.9 -36.7,-15.3v14c10.1,1.3 19.3,5.3 26.9,11.2L406.6,300.5zM417.8,347h14c-1.4,-13.9 -6.9,-26.5 -15.3,-36.7l-9.9,9.9C412.5,327.8 416.5,336.9 417.8,347zM406.6,387.8l9.9,9.8c8.6,-10.4 13.9,-23.3 15.3,-36.7h-14C416.5,370.7 412.6,380 406.6,387.8zM369.8,408.8v14c13.9,-1.4 26.5,-6.9 36.7,-15.3l-9.8,-9.9C389,403.6 379.6,407.5 369.8,408.8z M 0,0"/>
<group>
<clip-path android:pathData="M279.9,271.1h165.8v165.8h-165.8z M 0,0"/>
<group>
<clip-path android:pathData="M279.9,271.1h165.8v165.8h-165.8z M 0,0"/>
<group>
<clip-path android:pathData="M279.9,271.1h165.8v165.8h-165.8z M 0,0"/>
<path
android:pathData="M245.3,236.5h235v235h-235z"
android:fillColor="#FFFFFF"/>
</group>
</group>
</group>
</group>
</group>
</vector>

View File

@@ -0,0 +1,170 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path
android:fillColor="#3DDC84"
android:pathData="M0,0h108v108h-108z" />
<path
android:fillColor="#00000000"
android:pathData="M9,0L9,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,0L19,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,0L29,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,0L39,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,0L49,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,0L59,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,0L69,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,0L79,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M89,0L89,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M99,0L99,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,9L108,9"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,19L108,19"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,29L108,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,39L108,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,49L108,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,59L108,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,69L108,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,79L108,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,89L108,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,99L108,99"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,29L89,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,39L89,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,49L89,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,59L89,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,69L89,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,79L89,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,19L29,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,19L39,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,19L49,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,19L59,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,19L69,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,19L79,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
</vector>

View File

@@ -0,0 +1,28 @@
<!--
Copyright 2021 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M15.54,5.54L13.77,7.3 12,5.54 10.23,7.3 8.46,5.54 12,2zM18.46,15.54l-1.76,-1.77L18.46,12l-1.76,-1.77 1.76,-1.77L22,12zM8.46,18.46l1.77,-1.76L12,18.46l1.77,-1.76 1.77,1.76L12,22zM5.54,8.46l1.76,1.77L5.54,12l1.76,1.77 -1.76,1.77L2,12z"/>
<path
android:fillColor="@android:color/white"
android:pathData="M12,12m-3,0a3,3 0,1 1,6 0a3,3 0,1 1,-6 0"/>
</vector>

View File

@@ -0,0 +1,25 @@
<!--
Copyright 2021 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M12,12c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2 2,0.9 2,2 -0.9,2 -2,2zM18,10.2C18,6.57 15.35,4 12,4s-6,2.57 -6,6.2c0,2.34 1.95,5.44 6,9.14 4.05,-3.7 6,-6.8 6,-9.14zM12,2c4.2,0 8,3.22 8,8.2 0,3.32 -2.67,7.25 -8,11.8 -5.33,-4.55 -8,-8.48 -8,-11.8C4,5.22 7.8,2 12,2z"
android:fillColor="#FFFFFF"/>
</vector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 678 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 461 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 631 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 631 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 832 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 396 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 650 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 651 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 593 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 593 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 463 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 464 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 829 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 835 B

View File

@@ -0,0 +1,25 @@
<!--
Copyright 2021 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
</vector>

View File

@@ -0,0 +1,25 @@
<!--
Copyright 2021 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M19,13H5v-2h14v2z"/>
</vector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@@ -0,0 +1,5 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="960" android:viewportWidth="960" android:width="24dp">
<path android:fillColor="@android:color/white" android:pathData="M200,840L200,200Q200,167 223.5,143.5Q247,120 280,120L520,120Q520,143 520,160Q520,177 520,200L280,200Q280,200 280,200Q280,200 280,200L280,718L480,632L680,718L680,440Q703,440 720,440Q737,440 760,440L760,840L480,720L200,840ZM280,200L280,200Q280,200 280,200Q280,200 280,200L520,200Q520,200 520,200Q520,200 520,200Q520,200 520,200Q520,200 520,200L520,200L480,200L280,200ZM680,360L680,280L600,280L600,200L680,200L680,120L760,120L760,200L840,200L840,280L760,280L760,360L680,360Z"/>
</vector>

View File

@@ -0,0 +1,5 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="960" android:viewportWidth="960" android:width="24dp">
<path android:fillColor="@android:color/white" android:pathData="M713,360L600,247L656,190L713,247L854,105L911,162L713,360ZM200,840L200,200Q200,167 223.5,143.5Q247,120 280,120L520,120Q520,143 520,160Q520,177 520,200L280,200Q280,200 280,200Q280,200 280,200L280,718L480,632L680,718L680,440Q703,440 720,440Q737,440 760,440L760,840L480,720L200,840ZM280,200L280,200Q280,200 280,200Q280,200 280,200L520,200Q520,200 520,200Q520,200 520,200Q520,200 520,200Q520,200 520,200L520,200L480,200L280,200Z"/>
</vector>

View File

@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="48dp"
android:height="48dp"
android:viewportWidth="960"
android:viewportHeight="960"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M280,800L280,432Q280,407.25 297.63,389.62Q315.25,372 340,372L726,372L636,282L678,240L840,402L678,564L636,522L726,432L340,432Q340,432 340,432Q340,432 340,432L340,800L280,800Z"/>
</vector>

View File

@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="48dp"
android:height="48dp"
android:viewportWidth="960"
android:viewportHeight="960"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M280,800L280,432Q280,407.25 297.63,389.62Q315.25,372 340,372L726,372L636,282L678,240L840,402L678,564L636,522L726,432L340,432Q340,432 340,432Q340,432 340,432L340,800L280,800Z"/>
</vector>

View File

@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?><!--
Copyright 2021 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#1E1D1D">
<ImageView
android:id="@+id/imageView"
android:layout_width="158dp"
android:layout_height="123dp"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="32dp"
android:src="@drawable/ic_launcher" />
</RelativeLayout>

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 982 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

View File

@@ -0,0 +1,380 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (C) 2021 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="back_caps_action_title" msgid="6392829425035919422">"ZURÜCK"</string>
<string name="home_caps_action_title" msgid="4853167242566949502">"STARTSEITE"</string>
<string name="exit_action_title" msgid="9086586388884500731">"Beenden"</string>
<string name="refresh_action_title" msgid="3674260822403151377">"Aktualisieren"</string>
<string name="close_action_title" msgid="2661907510124308560">"Schließen"</string>
<string name="grant_access_action_title" msgid="4033140828804350723">"Zugriff gewähren"</string>
<string name="enable_location_action_title" msgid="8181862247222797044">"Standortermittlung aktivieren"</string>
<string name="cancel_action_title" msgid="1149738685397349236">"Ignorieren"</string>
<string name="stop_action_title" msgid="1187619482795416314">"Stopp"</string>
<string name="more_action_title" msgid="1039516575011403837">"Mehr"</string>
<string name="call_action_title" msgid="6218977436905001611">"Anrufen"</string>
<string name="primary_action_title" msgid="7042003552215710683">"Primär"</string>
<string name="options_action_title" msgid="1168121856107932984">"Optionen"</string>
<string name="search_action_title" msgid="3483459674263446335">"Suchen"</string>
<string name="checked_action_title" msgid="906023941445896399">"Aktiviert"</string>
<string name="unchecked_action_title" msgid="802503415474307811">"Deaktiviert"</string>
<string name="on_action_title" msgid="4129601573763429611">"An"</string>
<string name="off_action_title" msgid="8669201170189204848">"Aus"</string>
<string name="settings_action_title" msgid="8616900063253887861">"Einstellungen"</string>
<string name="accept_action_title" msgid="4899660585470647578">"Annehmen"</string>
<string name="reject_action_title" msgid="6730366705938402668">"Ablehnen"</string>
<string name="ok_action_title" msgid="7128494973966098611">"OK"</string>
<string name="throw_action_title" msgid="7163710562670220163">"Auslösen"</string>
<string name="commute_action_title" msgid="2585755255290185096">"Arbeitsweg"</string>
<string name="sign_out_action_title" msgid="1653943000866713010">"Abmelden"</string>
<string name="try_anyway_action_title" msgid="7384500054249311718">"Trotzdem versuchen"</string>
<string name="yes_action_title" msgid="5507096013762092189">"Ja"</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="bug_reported_toast_msg" msgid="2487119172744644317">"Fehler wurde gemeldet!"</string>
<string name="zoomed_in_toast_msg" msgid="8915301497303842649">"Herangezoomt"</string>
<string name="zoomed_out_toast_msg" msgid="6260981223227212493">"Herausgezoomt"</string>
<string name="triggered_toast_msg" msgid="3396166539208366382">"Ausgelöst"</string>
<string name="primary_toast_msg" msgid="7153771322662005447">"Primäre Schaltfläche gedrückt"</string>
<string name="search_toast_msg" msgid="7826530065407699347">"Schaltfläche „Suchen“ gedrückt"</string>
<string name="options_toast_msg" msgid="2146223786877557730">"Optionsschaltfläche gedrückt"</string>
<string name="favorite_toast_msg" msgid="522064494016370117">"Favorit!"</string>
<string name="not_favorite_toast_msg" msgid="6831181108681007428">"Kein Favorit!"</string>
<string name="nav_requested_toast_msg" msgid="6696525973145493908">"Navigation angefragt"</string>
<string name="selected_route_toast_msg" msgid="3149189677200086656">"Ausgewählte Route"</string>
<string name="visible_routes_toast_msg" msgid="7065558153736024203">"Sichtbare Routen"</string>
<string name="second_item_toast_msg" msgid="7210054709419608215">"Zweiter Eintrag angeklickt"</string>
<string name="third_item_checked_toast_msg" msgid="3022450599567347361">"Dritter Eintrag aktiviert"</string>
<string name="fifth_item_checked_toast_msg" msgid="1627599668504718594">"Fünfter Eintrag aktiviert"</string>
<string name="sixth_item_toast_msg" msgid="6117028866385793707">"Sechster Eintrag angeklickt"</string>
<string name="settings_toast_msg" msgid="7697794473002342727">"Einstellungen angeklickt"</string>
<string name="parked_toast_msg" msgid="2532422265890824446">"Aktion „Geparkt“"</string>
<string name="more_toast_msg" msgid="5938288138225509885">"„Mehr“ angeklickt"</string>
<string name="commute_toast_msg" msgid="4112684360647638688">"Schaltfläche für Arbeitsweg gedrückt"</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="dial" msgid="3145707439707628311">"Wählen"</string>
<string name="address" msgid="9010635942573581302">"Adresse"</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_dialer" msgid="1471602619507306261">"Fehler beim Starten des Telefons"</string>
<string name="car_hardware_demo_title" msgid="3679106197233262689">"Demo der Auto-Hardware"</string>
<string name="car_hardware_info" msgid="1244783247616395012">"Informationen zur Auto-Hardware"</string>
<string name="model_info" msgid="494224423025683030">"Modellinformationen"</string>
<string name="no_model_permission" msgid="5333629877014978947">"Keine Berechtigung für Modell"</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="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="phone_screen_permission_msg" msgid="3599815596923367256">"Berechtigungen über das Smartphone-Display erteilen"</string>
<string name="enable_location_permission_on_device_msg" msgid="472752487966156897">"Berechtigungen zur Standortermittlung auf Gerät aktivieren"</string>
<string name="enable_location_permission_on_phone_msg" msgid="5082615523959139121">"Standortermittlung auf dem Smartphone-Bildschirm aktivieren"</string>
<string name="required_permissions_title" msgid="5351791879153568211">"Erforderliche Berechtigungen"</string>
<string name="request_permissions_title" msgid="7456426341142412300">"Demo der Berechtigungsanfrage"</string>
<string name="cancel_reservation_title" msgid="1374986823057959608">"Bildschirm zum Stornieren der Reservierung"</string>
<string name="reservation_cancelled_msg" msgid="6334213670275547875">"Reservierung wurde storniert"</string>
<string name="result_demo_title" msgid="3900525190662148290">"Ergebnisdemo"</string>
<string name="not_started_for_result_msg" msgid="7498800528148447270">"Diese App wurde nicht für ein Ergebnis gestartet"</string>
<string name="started_for_result_msg" msgid="4225260243713833974">"Diese App wurde aufgerufen, um Ergebnisse aus %s zu erhalten. Wähle das Ergebnis aus, das an den Anrufer zurückgesendet werden soll."</string>
<string name="arrived_exclamation_msg" msgid="9132265698563096988">"Angekommen!"</string>
<string name="send_notification_title" msgid="4731688444696028193">"Benachrichtigung senden"</string>
<string name="start_notifications_title" msgid="8699668027543530460">"Benachrichtigungen starten"</string>
<string name="stop_notifications_title" msgid="3703892710275206239">"Benachrichtigungen deaktivieren"</string>
<string name="notification_title" msgid="5507590705935298176">"Benachrichtigung"</string>
<string name="importance_title" msgid="9034862997821839831">"Wichtigkeit"</string>
<string name="category_title" msgid="4783851267093259949">"Kategorie"</string>
<string name="ongoing_title" msgid="4957996003270280496">"Aktiv"</string>
<string name="default_importance" msgid="6347996298832939989">"Standard"</string>
<string name="high_importance" msgid="5009120714837304882">"Hoch"</string>
<string name="low_importance" msgid="4721161314404294033">"Gering"</string>
<string name="unknown_importance" msgid="909001735933359216">"Unbekannt"</string>
<string name="notification_demo" msgid="1819496937832036387">"Benachrichtigungsdemo"</string>
<string name="misc_demo_title" msgid="7399959062407349380">"Verschiedene Demos"</string>
<string name="navigating_demo_title" msgid="7454579665387386476">"Navigationsdemo"</string>
<string name="arrived_demo_title" msgid="6708013121387053838">"Demo für „Angekommen“"</string>
<string name="junction_image_demo_title" msgid="3302979708776502314">"Demo des Kreuzungsbildes"</string>
<string name="nav_template_demos_title" msgid="8215835368932160866">"Demos der Navigationsvorlage"</string>
<string name="map_template_pane_demo_title" msgid="4849450903277412004">"Demo der Kartenvorlage mit Bereich"</string>
<string name="map_template_list_demo_title" msgid="1473810899303903185">"Demo der Kartenvorlage mit Liste"</string>
<string name="start_notification_title" msgid="2208831088632818681">"Benachrichtigung beginnen"</string>
<string name="stop_notification_title" msgid="3709643750540881176">"Benachrichtigung deaktivieren"</string>
<string name="nav_notification_demo_title" msgid="4448683262984308442">"Demo der Navigationsbenachrichtigung"</string>
<string name="go_straight" msgid="2301747728609198718">"Geradeaus fahren"</string>
<string name="turn_right" msgid="4710562732720109969">"Rechts abbiegen"</string>
<string name="take_520" msgid="3804796387195842741">"Die 520 nehmen"</string>
<string name="gas_station" msgid="1203313937444666161">"Tankstelle"</string>
<string name="short_route" msgid="4831864276538141265">"Kurze Route"</string>
<string name="less_busy" msgid="310625272281710983">"Weniger Verkehr"</string>
<string name="hov_friendly" msgid="6956152104754594971">"Carpool-Spur-fähig"</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_route" msgid="5172258139245088080">"Weiter zur Route"</string>
<string name="routes_title" msgid="7799772149932075357">"Routen"</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="notification_template_demo_title" msgid="5076051497316030274">"Demo der Benachrichtigungsvorlage"</string>
<string name="nav_map_template_demo_title" msgid="344985380763975398">"Demo der Navigationsvorlage nur mit Karte"</string>
<string name="nav_demos_title" msgid="72781206086461004">"Navigationsdemos"</string>
<string name="navigation_alert_title" msgid="8306554249264200848">"Blitzer noch da?"</string>
<string name="navigation_alert_subtitle" msgid="3331130131492672264">"Vor 10 Minuten gemeldet"</string>
<string name="no_toll_card_permission" msgid="6789073114449712090">"Keine Berechtigung für Mautkarte."</string>
<string name="no_energy_level_permission" msgid="1684773185095107825">"Keine Berechtigung für Akkustand."</string>
<string name="no_speed_permission" msgid="5812532480922675390">"Keine Berechtigung für Geschwindigkeit."</string>
<string name="no_mileage_permission" msgid="4074779840599589847">"Keine Berechtigung für Kilometerstand."</string>
<string name="no_ev_status_permission" msgid="933075402821938973">"Keine Berechtigung für Status des Elektrofahrzeugs."</string>
<string name="no_accelerometer_permission" msgid="896914448469117234">"Keine Berechtigung für Beschleunigungsmesser."</string>
<string name="no_gyroscope_permission" msgid="665293140266771569">"Keine Berechtigung für Gyroskop."</string>
<string name="no_compass_permission" msgid="5162304489577567125">"Keine Berechtigung für Kompass."</string>
<string name="no_car_hardware_location" msgid="3505517472938045093">"Keine Berechtigung für Auto-Hardware-Standort."</string>
<string name="fetch_toll_info" msgid="6864627977128179834">"Mautinformationen werden abgerufen."</string>
<string name="fetch_energy_level" msgid="1773415471137542832">"Akkustand wird abgerufen."</string>
<string name="fetch_speed" msgid="7333830984597189627">"Geschwindigkeit wird abgerufen."</string>
<string name="fetch_mileage" msgid="7490131687788025123">"Kilometerstand wird abgerufen."</string>
<string name="fetch_ev_status" msgid="2798910410830567052">"Status des Elektrofahrzeugs wird abgerufen."</string>
<string name="fetch_accelerometer" msgid="697750041126810911">"Beschleunigungsmesser wird abgerufen."</string>
<string name="fetch_gyroscope" msgid="7153155318827188539">"Gyroskop wird abgerufen."</string>
<string name="fetch_compass" msgid="7316188117590056717">"Kompass wird abgerufen."</string>
<string name="fetch_location" msgid="5015066922035852615">"Standort wird abgerufen."</string>
<string name="toll_card_state" msgid="4430544885695162226">"Status der Mautkarte"</string>
<string name="low_energy" msgid="3462774027012877028">"Niedriger Akkustand"</string>
<string name="range" msgid="8744960568263400641">"Bereich"</string>
<string name="fuel" msgid="4253578650127250651">"Kraftstoff"</string>
<string name="battery" msgid="2183623637331546820">"Akku"</string>
<string name="display_speed" msgid="9161318805331348165">"Geschwindigkeit anzeigen"</string>
<string name="raw_speed" msgid="7295910214088983967">"Rohgeschwindigkeit"</string>
<string name="unit" msgid="7697521583928135171">"Einheit"</string>
<string name="odometer" msgid="3925174645651546591">"Kilometerzähler"</string>
<string name="ev_connected" msgid="2277845607662494696">"Ladeanschluss des Elektrofahrzeugs verbunden"</string>
<string name="ev_open" msgid="4916704450914519643">"Ladeanschluss des Elektrofahrzeugs ist offen"</string>
<string name="accelerometer" msgid="2084026313768299185">"Beschleunigungsmesser"</string>
<string name="gyroscope" msgid="3428075828014504651">"Gyroskop"</string>
<string name="compass" msgid="7037367764762441245">"Kompass"</string>
<string name="car_hardware_location" msgid="5826128477363068617">"Standort der Auto-Hardware"</string>
<string name="non_actionable" msgid="8999757911111188784">"Keine Aktion möglich"</string>
<string name="second_item" msgid="5245792503030812493">"Zweiter Eintrag"</string>
<string name="third_item" msgid="334088179008716411">"Dritter Eintrag"</string>
<string name="fourth_item" msgid="1153409687260543158">"Vierter Eintrag"</string>
<string name="fifth_item" msgid="295284272719956932">"Der fünfte Eintrag hat einen langen Titel"</string>
<string name="sixth_item" msgid="3880321601391343607">"Der sechste Eintrag hat einen langen Titel"</string>
<string name="grid_template_demo_title" msgid="6159115661928982245">"Demo der Rastervorlage"</string>
<string name="parked_only_title" msgid="3190603222397552672">"Titel für „Nur geparkt“"</string>
<string name="parked_only_text" msgid="8720610556452272916">"Mehr Text für „Nur geparkt“."</string>
<string name="clicked_row_prefix" msgid="9068303427922069941">"Angeklickte Zeile"</string>
<string name="first_line_text" msgid="6648055806656590336">"Erste Textzeile"</string>
<string name="second_line_text" msgid="38664490158836864">"Zweite Textzeile"</string>
<string name="long_line_text" msgid="8082962600953333087">"Dieser Subtext kann im uneingeschränkten Modus (z. B. Parkmodus, eingeschränkter Modus für niedrige Geschwindigkeit) vollständig angezeigt werden. Im eingeschränkten Modus (z. B. Fahrmodus) wird er jedoch nach zwei Zeilen abgeschnitten. Zu Testzwecken ist dieser Subtext extrem lang."</string>
<string name="title_prefix" msgid="3991742709199357049">"Titel"</string>
<string name="list_template_demo_title" msgid="1740208242737246151">"Demo für Listenvorlage"</string>
<string name="long_msg_template_demo_title" msgid="1793748562161438131">"Demo der langen Nachrichtenvorlage"</string>
<string name="long_msg_template_not_supported_text" msgid="3641559637317672505">"Dein Host unterstützt keine lange Nachrichtenvorlage"</string>
<string name="long_msg_template_not_supported_title" msgid="8600719470226274925">"Inkompatibler Host"</string>
<string name="msg_template_demo_title" msgid="3895210951340409473">"Demo der Nachrichtenvorlage"</string>
<string name="msg_template_demo_text" msgid="2275291617716161409">"Nachricht wird hier angezeigt.\nMehr Text in der zweiten Zeile."</string>
<string name="short_msg_template_demo_title" msgid="6798738013668580714">"Demo der kurzen Nachrichtenvorlage"</string>
<string name="sectioned_item_template_demo_title" msgid="8377594346379786774">"Demo für Elementvorlage mit Abschnitten"</string>
<string name="sectioned_item_template_radio_button_section_title" msgid="1014325865070733609">"Abschnitt „Optionsfeld“"</string>
<string name="sectioned_item_template_toggle_section_title" msgid="3197227971733559949">"Abschnitt wechseln"</string>
<string name="sectioned_item_template_lots_of_rows_section_title" msgid="1501401956386938735">"Abschnitt „Viele Zeilen“"</string>
<string name="sectioned_item_template_grid_item_section_title" msgid="565528119467142741">"Bereich für Rasterelement"</string>
<string name="pane_template_demo_title" msgid="7804292600060341608">"Demo der Bereichsvorlage"</string>
<string name="place_list_template_demo_title" msgid="2054022985455460469">"Demo der Ortslistenvorlage"</string>
<string name="browse_places_title" msgid="7246005909846715898">"Orte durchsuchen"</string>
<string name="search_template_demo_title" msgid="1770474418958318114">"Suchvorlagendemo"</string>
<string name="search_hint" msgid="978495498991026792">"Hier suchen"</string>
<string name="additional_text" msgid="5755100726890686184">"Bitte lies unsere "<annotation link="terms_of_service">"Nutzungsbedingungen"</annotation></string>
<string name="google_sign_in" msgid="6556259799319701727">"Google Log-in"</string>
<string name="use_pin" msgid="7850893299484337431">"PIN nutzen"</string>
<string name="qr_code" msgid="5487041647280777397">"QR-Code"</string>
<string name="sign_in_template_not_supported_text" msgid="7184733753948837646">"Dein Host unterstützt keine Anmeldevorlage"</string>
<string name="sign_in_template_not_supported_title" msgid="4892883228898541764">"Inkompatibler Host"</string>
<string name="email_hint" msgid="7205549445477319606">"E-Mail"</string>
<string name="sign_in_title" msgid="4551967308262681703">"Anmelden"</string>
<string name="sign_in_instructions" msgid="9044850228284294762">"Anmeldedaten eingeben"</string>
<string name="invalid_email_error_msg" msgid="5261362663718987167">"Der Nutzername muss eine gültige E-Mail-Adresse sein"</string>
<string name="invalid_length_error_msg" msgid="8238905276326976425">"Der Nutzername muss mindestens %s Zeichen enthalten"</string>
<string name="invalid_password_error_msg" msgid="1090359893902674610">"Ungültiges Passwort"</string>
<string name="password_hint" msgid="2869107073860012864">"Passwort"</string>
<string name="password_sign_in_instruction_prefix" msgid="9105788349198243508">"Nutzername"</string>
<string name="pin_sign_in_instruction" msgid="2288691296234360441">"Gib diese PIN auf deinem Telefon ein"</string>
<string name="qr_code_sign_in_title" msgid="8137070561006464518">"Zum Anmelden QR-Code scannen"</string>
<string name="sign_in_with_google_title" msgid="8043752000786977249">"Über Google anmelden"</string>
<string name="provider_sign_in_instruction" msgid="7586815688292506743">"Schließe mit dieser Schaltfläche dein Google Log-in ab"</string>
<string name="sign_in_complete_text" msgid="8423984266325680606">"Du bist angemeldet!"</string>
<string name="sign_in_complete_title" msgid="8919868148773983428">"Anmeldung abgeschlossen"</string>
<string name="sign_in_template_demo_title" msgid="6052035424941410249">"Anmeldungsvorlagendemo"</string>
<string name="tab_template_layouts_demo_title" msgid="6529681462424538165">"Tab-Vorlage  Demos"</string>
<string name="tab_template_demo_title" msgid="7587839101813629975">"Tab-Vorlage  Demo"</string>
<string name="tab_title_message" msgid="5266710951630087246">"Tab „Nachrichten“"</string>
<string name="tab_title_pane" msgid="2520606145526537263">"Tab „Bereich“"</string>
<string name="tab_title_list" msgid="5104962518489668123">"Tab „Liste“"</string>
<string name="tab_title_grid" msgid="5268168907976325154">"Tab „Raster“ mit langem Tab-Titel"</string>
<string name="tab_title_search" msgid="1892925693146631173">"Tab „Suche“"</string>
<string name="tab_title_loading" msgid="5385807479734490989">"Tab wird geladen"</string>
<string name="tab_template_loading_demo_title" msgid="4638051615030345574">"Tab-Vorlage  Demo wird geladen"</string>
<string name="tab_template_no_tabs_demo_title" msgid="6907466201298082309">"Tab-Vorlage  Demo „Keine Tabs“"</string>
<string name="images_unknown_host_error" msgid="3180661817432720076">"Für einen unbekannten Host können keine Bilder angezeigt werden"</string>
<string name="icon_title_prefix" msgid="8487026131229541244">"Symbol"</string>
<string name="content_provider_icons_demo_title" msgid="5708602618664311097">"Demo der Contentanbietersymbole"</string>
<string name="icons_demo_title" msgid="4082976685262307357">"Symboldemo"</string>
<string name="app_icon_title" msgid="7534936683349723423">"Das App-Symbol"</string>
<string name="vector_no_tint_title" msgid="874591632279039146">"Ein Vektor-Drawable ohne Färbung"</string>
<string name="vector_with_tint_title" msgid="1022346419829696827">"Ein Vektor-Drawable mit einer Färbung"</string>
<string name="vector_with_app_theme_attr_title" msgid="4890094482708376219">"Ein Vektor-Drawable mit einem App-Designattribut für die Farbe"</string>
<string name="png_res_title" msgid="7437083018336747544">"Eine PNG wurde als Ressource gesendet"</string>
<string name="png_bitmap_title" msgid="3385912074130977032">"Eine PNG-Datei, als Bitmap gesendet"</string>
<string name="just_row_title" msgid="965700021568970725">"Nur ein Titel"</string>
<string name="title_with_app_icon_row_title" msgid="6294250714820740520">"Titel mit App-Symbol"</string>
<string name="title_with_res_id_image_row_title" msgid="3813134904602875778">"Titel mit Bild für Ressourcen-ID"</string>
<string name="title_with_svg_image_row_title" msgid="6109092343637263755">"Titel mit SVG-Bild"</string>
<string name="colored_secondary_row_title" msgid="5173288934252528929">"Farbiger Sekundärtext"</string>
<string name="title_with_secondary_lines_row_title" msgid="7769408881272549837">"Titel mit mehreren Zeilen Sekundärtext"</string>
<string name="title_with_secondary_lines_row_text_1" msgid="8945114692653524102">"Du darfst irren, und irren, und irren aber immer weniger, und weniger, und weniger."</string>
<string name="title_with_secondary_lines_row_text_2" msgid="1017734603405251531">" Piet Hein"</string>
<string name="rows_demo_title" msgid="3198566660454251007">"Demo der Zeilen"</string>
<string name="text_icons_demo_title" msgid="8732943920672143201">"Demos für Text und Symbole"</string>
<string name="row_text_icons_demo_title" msgid="135167694047524905">"Demo der Zeilen mit Text und Symbolen"</string>
<string name="radio_button_list_demo_title" msgid="9082264324855338774">"Demo der Optionsfeldlisten"</string>
<string name="selectable_lists_demo_title" msgid="5492658731113129386">"Demo der auswählbaren Listen"</string>
<string name="option_1_title" msgid="7221252541651471199">"Option 1"</string>
<string name="option_2_title" msgid="1905146448697963818">"Option 2"</string>
<string name="option_3_title" msgid="6319268250436119258">"Option 3"</string>
<string name="option_row_radio_title" msgid="5978617101267398181">"Zeile mit Optionsfeld"</string>
<string name="option_row_radio_icon_title" msgid="3304229002524317977">"Zeile mit Optionsfeld und Symbol"</string>
<string name="option_row_radio_icon_colored_text_title" msgid="947641896184637026">"Zeile mit Optionsfeld, Symbol und farbigem Text"</string>
<string name="some_additional_text" msgid="4009872495806318260">"Zusätzlicher Text"</string>
<string name="sample_additional_list" msgid="5085372891301576306">"Beispiel für auswählbare Liste"</string>
<string name="task_restriction_demo_title" msgid="2212084350718766941">"Demo der Aufgabenbeschränkung"</string>
<string name="task_limit_reached_msg" msgid="7162842196382260992">"Hierdurch wird die maximale Anzahl an Schritten überschritten und du gelangst zu einem neuen Bildschirm."</string>
<string name="task_step_of_title" msgid="2791717962535723839">"Aufgabe: Schritt %1$d von %2$d"</string>
<string name="task_step_of_text" msgid="4646729781462227219">"Klicken, um fortzufahren"</string>
<string name="task_content_allowed" msgid="545061986612431190">"Bitte rufe die verschiedenen Vorlagen auf und achte darauf, dass sich das Auto im Fahrmodus befindet"</string>
<string name="toggle_button_demo_title" msgid="3179103600967398928">"Demo der Ein-/Aus-Schaltfläche"</string>
<string name="toggle_test_title" msgid="924485265152862631">"Test der Ein-/Aus-Schaltfläche"</string>
<string name="toggle_test_text" msgid="8107217216013312857">"Zustandsorientierte Änderungen sind erlaubt"</string>
<string name="toggle_test_first_toggle_title" msgid="3635022201072117680">"Test der Ein-/Aus-Schaltfläche aktivieren"</string>
<string name="toggle_test_first_toggle_text" msgid="5914741538328669668">"Klicke diese Option an, um den Test der Ein-/Aus-Schaltfläche zu aktivieren"</string>
<string name="toggle_test_second_toggle_title" msgid="1083594617400613969">"Test der Ein-/Aus-Schaltfläche"</string>
<string name="toggle_test_second_toggle_text" msgid="1813071017415876745">"Zustandsorientierte Änderungen sind erlaubt"</string>
<string name="image_test_title" msgid="8273863429801477547">"Bildtest"</string>
<string name="image_test_text" msgid="6264812093895530445">"Bildänderungen sind erlaubt"</string>
<string name="additional_data_title" msgid="3546689652240300617">"Zusätzliche Daten"</string>
<string name="additional_data_text" msgid="2846223398214158872">"Updates beim Zurückgehen erlaubt."</string>
<string name="toggle_test_enabled" msgid="982370904182034076">"Test der Ein-/Aus-Schaltfläche aktiviert"</string>
<string name="toggle_test_disabled" msgid="8366040658408451664">"Test der Ein-/Aus-Schaltfläche deaktiviert"</string>
<string name="secondary_actions_decoration_button_demo_title" msgid="3710817648501132309">"Demo der sekundären Aktion und der Dekoration"</string>
<string name="secondary_actions_test_title" msgid="3664453747553733613">"Test für sekundäre Aktion"</string>
<string name="secondary_actions_test_subtitle" msgid="6985282813402073703">"Nur die sekundäre Aktion kann ausgewählt werden"</string>
<string name="decoration_test_title" msgid="8450127046762442244">"Dekorationstest"</string>
<string name="secondary_actions_decoration_test_title" msgid="6282873404859209490">"Sekundäre Aktionen und Dekoration"</string>
<string name="secondary_actions_decoration_test_title_long" msgid="3700606949229899169">"Zeile mit sekundären Aktionen und Dekoration mit einem sehr langen Titel"</string>
<string name="secondary_actions_decoration_test_subtitle" msgid="155884606592724532">"Auch diese Zeile kann ausgewählt werden"</string>
<string name="recent_Item_deleted" msgid="5076434693504006565">Eintrag gelöscht</string>
<string name="row_primary_action_toast" msgid="756516694751965204">"Zeile mit der primären Aktion ist ausgewählt"</string>
<string name="sectioned_item_list_demo_title" msgid="1236735461225007729">"Demo für Elementliste mit Abschnitten"</string>
<string name="sectioned_item_list_one_title" msgid="6594204350307263338">"Liste 1"</string>
<string name="sectioned_item_list_two_title" msgid="4941545381743022833">"Liste 2"</string>
<string name="sectioned_item_list_subtext" msgid="2963927693547537519">"Subtext unter jeder Liste"</string>
<string name="empty_list_demo_title" msgid="5989013634820902455">"Leere Liste  Demo"</string>
<string name="empty_list_message" msgid="5331395517560728138">"Die Liste ist leer"</string>
<string name="misc_templates_demos_title" msgid="6077169010255928114">"Demos der verschiedenen Vorlagen"</string>
<string name="showcase_demos_title" msgid="1542092687878113304">"Demos anzeigen"</string>
<string name="template_layouts_demo_title" msgid="788249269446087847">"Demo der Layoutvorlagen"</string>
<string name="grid_template_menu_demo_title" msgid="7096285873490705119">"Demo der Rastervorlagen"</string>
<string name="voice_access_demo_title" msgid="3825223890895361496">"Bildschirm für Voice Access-Demo"</string>
<string name="user_interactions_demo_title" msgid="1356952319161314986">"Nutzerinteraktionen"</string>
<string name="request_permission_menu_demo_title" msgid="4796486779527427017">"Demos zur Berechtigungsanfrage"</string>
<string name="application_overflow_title" msgid="396427940886169325">"Anwendungs-Overflow-Validator"</string>
<string name="application_overflow_subtitle1" msgid="7429415605726615529">"Bitte teste die folgenden Vorlagen, wenn du"</string>
<string name="application_overflow_subtitle2" msgid="4385123036846369714">"das Fahrzeug vom Park- in den Fahrmodus umschaltest"</string>
<string name="perm_group" msgid="3834918337351876270">"Berechtigungsgruppe"</string>
<string name="perm_group_description" msgid="7348847631139139024">"Berechtigungsgruppe für die Showcase App"</string>
<string name="perm_fine_location" msgid="5438874642600304118">"Zugriff auf genauen Standort"</string>
<string name="perm_fine_location_desc" msgid="3549183883787912516">"Berechtigung für Zugriff auf den genauen Standort"</string>
<string name="perm_coarse_location" msgid="6140337431619481015">"Zugriff auf ungefähren Standort"</string>
<string name="perm_coarse_location_desc" msgid="6074759942301565943">"Berechtigung für Zugriff auf den ungefähren Standort"</string>
<string name="perm_record_audio" msgid="2758340693260523493">"Zugriff für Audioaufnahmen"</string>
<string name="perm_record_audio_desc" msgid="8038648467605928912">"Berechtigung für Zugriff für Audioaufnahmen"</string>
<string name="location_1_description" msgid="4801052291684791371">"Gefärbter Ressourcenvektor"</string>
<string name="location_2_description" msgid="3331356135359047166">"Bitmap-Infobild"</string>
<string name="location_3_description" msgid="3982142774088944850">"Farbige Textmarkierung"</string>
<string name="location_4_description" msgid="6560365445044381911">"Bitmap-Bild"</string>
<string name="location_description_text_label" msgid="2779911545316756419">"Textlabel"</string>
<string name="parking_vs_driving_demo_title" msgid="3367862800135053111">"Demo: Parken im Vergleich zu Fahren"</string>
<string name="latest_feature_details" msgid="6843008350392721502">"Displays in Autos."</string>
<string name="latest_feature_title" msgid="7929405790070777460">"Neueste Funktionen"</string>
<string name="loading_toggle_enabled" msgid="8828072732804454994">"Laden aktiviert"</string>
<string name="loading_toggle_disabled" msgid="7689738885077382673">"Laden deaktiviert"</string>
<string name="loading_screen" msgid="4771507490730308794">"Ladebildschirm"</string>
<string name="vector_toggle_details" msgid="1301305340033556819">"Schieberegler zum Hinzufügen/Entfernen von Farben"</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="route_options_demo_title" msgid="4599699012716426514">"Routenoptionen"</string>
<string name="avoid_highways_row_title" msgid="4711913426200490304">"Autobahnen 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_with_content_demo_title" msgid="1032610482145018739">"Demos von Karten mit Inhalten"</string>
<string name="map_with_message_demo_title" msgid="7007078234918054436">"Karte mit Demo der Nachrichtenvorlage"</string>
<string name="map_with_grid_demo_title" msgid="688667167861193192">"Demo einer Karte mit Rastervorlage"</string>
<string name="route_preview">Routen</string>
<string name="recent_destinations">Letzte Ziele</string>
<string name="contacts">Kontakte</string>
</resources>

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2021 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<declare-styleable name="ShowcaseTheme">
<attr name="themedIconColor" format="color"/>
<attr name="markerIconTintColor" format="color"/>
<attr name="markerIconTintColorDark" format="color"/>
</declare-styleable>
</resources>

View File

@@ -0,0 +1,508 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2021 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="app_name" translatable="false">Showcase</string>
<!-- Action Titles -->
<string name="back_caps_action_title">BACK</string>
<string name="home_caps_action_title">HOME</string>
<string name="exit_action_title">Exit</string>
<string name="refresh_action_title">Refresh</string>
<string name="close_action_title">Close</string>
<string name="grant_access_action_title">Grant Access</string>
<string name="enable_location_action_title">Enable Location</string>
<string name="cancel_action_title">Cancel</string>
<string name="stop_action_title">Stop</string>
<string name="more_action_title">More</string>
<string name="call_action_title">Call</string>
<string name="primary_action_title">Primary</string>
<string name="options_action_title">Options</string>
<string name="search_action_title">Search</string>
<string name="checked_action_title">Checked</string>
<string name="unchecked_action_title">Unchecked</string>
<string name="on_action_title">On</string>
<string name="off_action_title">Off</string>
<string name="settings_action_title">Settings</string>
<string name="accept_action_title">Accept</string>
<string name="reject_action_title">Reject</string>
<string name="ok_action_title">OK</string>
<string name="throw_action_title">Throw</string>
<string name="commute_action_title">Commute</string>
<string name="sign_out_action_title">Sign out</string>
<string name="try_anyway_action_title">Try Anyway</string>
<string name="yes_action_title">Yes</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 -->
<string name="bug_reported_toast_msg">Bug reported!</string>
<string name="zoomed_in_toast_msg">Zoomed in</string>
<string name="zoomed_out_toast_msg">Zoomed out</string>
<string name="triggered_toast_msg">Triggered</string>
<string name="primary_toast_msg">Primary button pressed</string>
<string name="search_toast_msg">Search button pressed</string>
<string name="options_toast_msg">Options button pressed</string>
<string name="favorite_toast_msg">Favorite!</string>
<string name="not_favorite_toast_msg">Not a favorite!</string>
<string name="nav_requested_toast_msg">Navigation Requested</string>
<string name="selected_route_toast_msg">Selected route</string>
<string name="visible_routes_toast_msg">Visible routes</string>
<string name="second_item_toast_msg">Clicked second item</string>
<string name="third_item_checked_toast_msg">Third item checked</string>
<string name="fifth_item_checked_toast_msg">Fifth item checked</string>
<string name="sixth_item_toast_msg">Clicked sixth item</string>
<string name="settings_toast_msg">Clicked Settings</string>
<string name="parked_toast_msg">Parked action</string>
<string name="more_toast_msg">Clicked More</string>
<string name="commute_toast_msg">Commute button pressed</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="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 -->
<string name="navigate">Navigate</string>
<string name="dial">Dial</string>
<string name="address">Address</string>
<string name="phone">Phone</string>
<!-- CarHardwareDemoScreen -->
<string name="fail_start_nav">Failure starting navigation</string>
<string name="fail_start_dialer">Failure starting dialer</string>
<string name="car_hardware_demo_title">Car Hardware Demo</string>
<!-- CarHardwareInfoScreen -->
<string name="car_hardware_info">Car Hardware Information</string>
<string name="model_info">Model Information</string>
<string name="no_model_permission">No Model Permission</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 -->
<string name="package_not_found_error_msg">Package Not found.</string>
<string name="permissions_granted_msg">All permissions have been granted. Please revoke permissions from Settings.</string>
<string name="needs_access_msg_prefix">The app needs access to the following permissions:\n</string>
<string name="phone_screen_permission_msg">Grant Permission on the phone screen</string>
<string name="enable_location_permission_on_device_msg">Enable Location Permissions on device</string>
<string name="enable_location_permission_on_phone_msg">Enable location on the phone screen</string>
<string name="required_permissions_title">Required Permissions</string>
<string name="request_permissions_title">Request Permission Demo</string>
<!-- ReservationCancelledScreen -->
<string name="cancel_reservation_title">Cancel Reservation Screen</string>
<string name="reservation_cancelled_msg">Reservation canceled</string>
<!-- ResultDemoScreen -->
<string name="result_demo_title">Result demo</string>
<string name="not_started_for_result_msg">This app was not started for result</string>
<string name="started_for_result_msg">This app was called for result from %s. Please select the result to send back to the caller</string>
<!-- ArrivedDemoScreen -->
<string name="arrived_exclamation_msg">Arrived!</string>
<!-- RoutingDemoModels -->
<string name="current_step_cue" translatable="false">Roy st 520</string>
<string name="next_step_cue" translatable="false">I5 Aurora Ave N</string>
<!-- NotificationDemoScreen -->
<string name="send_notification_title">Send a notification</string>
<string name="start_notifications_title">Start notifications</string>
<string name="stop_notifications_title">Stop notifications</string>
<string name="notification_title">Notification</string>
<string name="importance_title">Importance</string>
<string name="category_title">Category</string>
<string name="ongoing_title">Ongoing</string>
<string name="default_importance">Default</string>
<string name="high_importance">High</string>
<string name="low_importance">Low</string>
<string name="unknown_importance">Unknown</string>
<string name="notification_demo">Notification Demo</string>
<!-- MiscDemoScreen -->
<string name="misc_demo_title">Misc Demos</string>
<!-- NavigationTemplateDemoScreen -->
<string name="navigating_demo_title">Navigating Demo</string>
<string name="arrived_demo_title">Arrived Demo</string>
<string name="junction_image_demo_title">Junction Image Demo</string>
<string name="nav_template_demos_title">Navigation Template Demos</string>
<!-- MapTemplateDemoScreen -->
<string name="map_template_pane_demo_title">Map Template with Pane Demo</string>
<string name="map_template_list_demo_title">Map Template with List Demo</string>
<!-- NavigationNotificationsDemoScreen -->
<string name="start_notification_title">Start Notification</string>
<string name="stop_notification_title">Stop Notification</string>
<string name="nav_notification_demo_title">Navigation Notification Demo</string>
<!-- NavigationNotificationService -->
<string name="go_straight">Go Straight</string>
<string name="turn_right">Turn Right</string>
<string name="take_520">Take 520</string>
<string name="gas_station">Gas Station</string>
<!-- RoutePreviewDemoScreen -->
<string name="short_route">Short route</string>
<string name="less_busy">Less busy</string>
<string name="hov_friendly">HOV friendly</string>
<string name="long_route">Long route</string>
<string name="continue_start_nav">Continue to start navigation</string>
<string name="continue_route">Continue to route</string>
<string name="routes_title">Routes</string>
<!-- NavigationDemosScreen -->
<string name="place_list_nav_template_demo_title">Place List Navigation Template Demo</string>
<string name="route_preview_template_demo_title">Route Preview Template Demo</string>
<string name="notification_template_demo_title">Notification Template Demo</string>
<string name="nav_map_template_demo_title">Navigation Template with map only Demo</string>
<string name="nav_demos_title">Navigation Demos</string>
<string name="navigation_alert_title">Still a speed trap?</string>
<string name="navigation_alert_subtitle">Reported 10m ago</string>
<!-- CarHardwareRenderer -->
<string name="no_toll_card_permission">No TollCard Permission.</string>
<string name="no_energy_level_permission">No EnergyLevel Permission.</string>
<string name="no_speed_permission">No Speed Permission.</string>
<string name="no_mileage_permission">No Mileage Permission.</string>
<string name="no_ev_status_permission">No EV status Permission.</string>
<string name="no_accelerometer_permission">No Accelerometer Permission.</string>
<string name="no_gyroscope_permission">No Gyroscope Permission.</string>
<string name="no_compass_permission">No Compass Permission.</string>
<string name="no_car_hardware_location">No CarHardwareLocation Permission.</string>
<string name="fetch_toll_info">Fetching Toll information.</string>
<string name="fetch_energy_level">Fetching Energy Level.</string>
<string name="fetch_speed">Fetching Speed.</string>
<string name="fetch_mileage">Fetching Mileage.</string>
<string name="fetch_ev_status">Fetching EV status.</string>
<string name="fetch_accelerometer">Fetching Accelerometer.</string>
<string name="fetch_gyroscope">Fetching Gyroscope.</string>
<string name="fetch_compass">Fetching Compass.</string>
<string name="fetch_location">Fetching Location.</string>
<string name="toll_card_state">Toll card state</string>
<string name="low_energy">Low energy</string>
<string name="range">Range</string>
<string name="fuel">Fuel</string>
<string name="battery">Battery</string>
<string name="display_speed">Display Speed</string>
<string name="raw_speed">Raw Speed</string>
<string name="unit">Unit</string>
<string name="odometer">Odometer</string>
<string name="ev_connected">Ev Charge Port Connected</string>
<string name="ev_open">Ev Charge Port Open</string>
<string name="accelerometer">Accelerometer</string>
<string name="gyroscope">Gyroscope</string>
<string name="compass">Compass</string>
<string name="car_hardware_location">Car Hardware Location</string>
<!-- GridTemplateDemoScreen -->
<string name="non_actionable">Non-actionable</string>
<string name="second_item">Second Item</string>
<string name="third_item">Third Item</string>
<string name="fourth_item">Fourth Item</string>
<string name="fifth_item">Fifth Item has a long title set</string>
<string name="sixth_item">Sixth Item has a long title set</string>
<string name="grid_template_demo_title">Grid Template Demo</string>
<!-- ListTemplateDemoScreen -->
<string name="parked_only_title">Parked Only Title</string>
<string name="parked_only_text">More Parked only text.</string>
<string name="clicked_row_prefix">Clicked row</string>
<string name="first_line_text">First line of text</string>
<string name="second_line_text">Second line of text</string>
<string name="long_line_text">This subtext can fully display in unrestricted mode (ex. parking mode, restricted low speed mode). But this will truncate to only two lines while in restricted mode (ex. driving mode). For testing purposes, this subtext is super super super super super long</string>
<string name="title_prefix">Title</string>
<string name="list_template_demo_title">List Template Demo</string>
<!-- LongMessageTemplateDemoScreen -->
<string name="long_msg_template_demo_title">Long Message Template Demo</string>
<string name="long_msg_template_text" translatable="false">Lorem ipsum dolor sit amet, consectetur adipiscing elit. \nAliquam laoreet ac metus eu commodo. Sed a congue diam, sed dictum lectus. Nam nec\ntristique dolor, quis sodales arcu. Etiam at metus eu nulla auctor varius. \nInteger dolor lorem, placerat sit amet lacus in, imperdiet semper dui. Vestibulum \nante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; \nQuisque gravida fermentum egestas.\n\n\n\nUt ut sodales mi. Aenean porta vel ipsum sed lacinia. Morbi odio ipsum, hendrerit \neu est et, sollicitudin finibus diam. Nunc sit amet felis elit. Orci varius \nnatoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Sed \nvestibulum, tellus a rutrum auctor, diam arcu vestibulum purus, nec mollis ligula \nnisi in nisi. Donec sem tortor, pharetra sed fermentum sit amet, ullamcorper nec \nsapien. Aliquam risus arcu, porttitor eu dui nec, vulputate tempus libero. \nCurabitur sit amet tristique orci. Suspendisse et odio tempus, tempus turpis quis,\n euismod est.\n\n\n\nVestibulum mauris ante, luctus viverra nisi eget, blandit facilisis nulla. \nPhasellus ex lorem, semper in vestibulum nec, aliquet vel elit. Aliquam vitae \nligula nec enim dictum lobortis. Sed varius turpis quis nisi tempus varius. Sed \nnon sollicitudin magna, at mattis tortor. Curabitur quis ligula eget lorem mattis \ntincidunt et in sapien. Curabitur a elit nisi. Aliquam ex arcu, hendrerit eget \nturpis vitae, bibendum vulputate nibh. Fusce vitae ex aliquet, tristique magna eu,\n vulputate dui. Aenean tempor viverra tortor non pharetra. Pellentesque convallis \nnec risus a auctor. Praesent non sem non eros tincidunt ullamcorper efficitur non \nlacus.\n\n\n\nSuspendisse accumsan ultricies egestas. Aenean leo ligula, congue ac erat eu, \nlobortis ultricies lorem. Nulla finibus, arcu sed tincidunt lobortis, magna justo \nrutrum ligula, et mattis felis turpis vel ex. Morbi ac auctor ex, at bibendum sem.\n Vestibulum a tortor iaculis, viverra felis vitae, lobortis est. Duis sit amet \ncondimentum sem. Ut molestie, dolor pretium imperdiet maximus, enim orci porta \nquam, id gravida enim nunc vitae lacus. Pellentesque habitant morbi tristique \nsenectus et netus et malesuada fames ac turpis egestas. Nullam vel justo eu risus \nlobortis dignissim sit amet ullamcorper nulla. Donec finibus cursus purus \nporttitor pellentesque.\n\n\n\nDonec at vehicula ante. Suspendisse rutrum nisl quis metus faucibus lacinia. \nVestibulum eros sapien, eleifend nec accumsan a, interdum sed nisi. Aenean posuere\n ultrices lorem non pharetra. Nulla non porta ligula. Maecenas at elit diam. \nNullam gravida augue et semper eleifend. Fusce venenatis ac arcu et luctus. Mauris\n ultricies urna non dui interdum, vel hendrerit est aliquam. Fusce id dictum leo, \nfringilla egestas ipsum.</string>
<string name="long_msg_template_not_supported_text">Your host doesn\'t support Long Message template</string>
<string name="long_msg_template_not_supported_title">Incompatible host</string>
<!-- MessageTemplateDemoScreen -->
<string name="msg_template_demo_title">Message Template Demo</string>
<string name="msg_template_demo_text">Message goes here.\nMore text on second line.</string>
<string name="short_msg_template_demo_title">Short Message Template Demo</string>
<!-- SectionedItemTemplateDemo -->
<string name="sectioned_item_template_demo_title">Sectioned Item Template Demo</string>
<string name="sectioned_item_template_radio_button_section_title">Radio Button Section</string>
<string name="sectioned_item_template_toggle_section_title">Toggle Section</string>
<string name="sectioned_item_template_lots_of_rows_section_title">Lots of Rows Section</string>
<string name="sectioned_item_template_grid_item_section_title">Grid Item Section</string>
<!-- PaneTemplateDemoScreen -->
<string name="pane_template_demo_title">Pane Template Demo</string>
<!-- PlaceListTemplateBrowseDemoScreen -->
<string name="place_list_template_demo_title">Place List Template Demo</string>
<string name="browse_places_title">Browse Places</string>
<!-- SearchTemplateDemoScreen -->
<string name="search_template_demo_title">Search Template Demo</string>
<string name="search_hint">Search here</string>
<!-- SignInTemplateDemoScreen -->
<string name="additional_text">Please review our <annotation link="terms_of_service">terms of service</annotation></string>
<string name="google_sign_in">Google sign-in</string>
<string name="use_pin">Use PIN</string>
<string name="qr_code">QR Code</string>
<string name="sign_in_template_not_supported_text">Your host doesn\'t support Sign In template</string>
<string name="sign_in_template_not_supported_title">Incompatible host</string>
<string name="email_hint">Email</string>
<string name="sign_in_title">Sign in</string>
<string name="sign_in_instructions">Enter your credentials</string>
<string name="invalid_email_error_msg">User name must be a valid email address</string>
<string name="invalid_length_error_msg">User name must be at least %s characters long</string>
<string name="invalid_password_error_msg">Invalid password</string>
<string name="password_hint">password</string>
<string name="password_sign_in_instruction_prefix">Username</string>
<string name="pin_sign_in_instruction">Type this PIN in your phone</string>
<string name="qr_code_sign_in_title">Scan QR Code to sign in</string>
<string name="sign_in_with_google_title">Sign in with Google</string>
<string name="provider_sign_in_instruction">Use this button to complete your Google sign-in</string>
<string name="sign_in_complete_text">You are signed in!</string>
<string name="sign_in_complete_title">Sign in completed</string>
<string name="sign_in_template_demo_title">Sign In Template Demo</string>
<!-- TabTemplateScreen -->
<string name="tab_template_layouts_demo_title">Tab Template Demos</string>
<string name="tab_template_demo_title">Tab Template Demo</string>
<string name="tab_title_message">Message Tab</string>
<string name="tab_title_pane">Pane Tab</string>
<string name="tab_title_list">List Tab</string>
<string name="tab_title_grid">Grid Tab with Long Tab Title</string>
<string name="tab_title_search">Search Tab</string>
<string name="tab_title_loading">Loading Tab</string>
<string name="tab_template_loading_demo_title">Tab Template Loading Demo</string>
<string name="tab_template_no_tabs_demo_title">Tab Template No Tabs Demo</string>
<!-- ContentProviderIconsDemoScreen -->
<string name="images_unknown_host_error">Images cannot be displayed for an unknown host</string>
<string name="icon_title_prefix">Icon</string>
<string name="content_provider_icons_demo_title">Content Provider Icons Demo</string>
<!-- IconsDemoScreen -->
<string name="icons_demo_title">Icons Demo</string>
<string name="app_icon_title">The app icon</string>
<string name="vector_no_tint_title">A vector drawable, without a tint</string>
<string name="vector_with_tint_title">A vector drawable, with a tint</string>
<string name="vector_with_app_theme_attr_title">A vector drawable, with an app\'s theme attribute for its color</string>
<string name="png_res_title">A PNG, sent as a resource</string>
<string name="png_bitmap_title">A PNG, sent as a bitmap</string>
<!-- RowDemoScreen -->
<string name="just_row_title">Just a title</string>
<string name="title_with_app_icon_row_title">Title with app icon</string>
<string name="title_with_res_id_image_row_title">Title with resource ID image</string>
<string name="title_with_svg_image_row_title">Title with SVG image</string>
<string name="colored_secondary_row_title">Colored secondary text</string>
<string name="title_with_secondary_lines_row_title">Title with multiple secondary text lines</string>
<string name="title_with_secondary_lines_row_text_1">Err and err and err again, but less and less and less.</string>
<string name="title_with_secondary_lines_row_text_2">- Piet Hein</string>
<string name="rows_demo_title">Rows Demo</string>
<!-- TextAndIconsDemosScreen -->
<string name="text_icons_demo_title">Text and Icons Demos</string>
<string name="row_text_icons_demo_title">Rows with Text and Icons Demo</string>
<!-- SelectableListsDemoScreen -->
<string name="radio_button_list_demo_title">Radio Button Lists Demo</string>
<string name="selectable_lists_demo_title">Selectable Lists Demo</string>
<string name="option_1_title">Option 1</string>
<string name="option_2_title">Option 2</string>
<string name="option_3_title">Option 3</string>
<string name="option_row_radio_title">Row with Radio Button</string>
<string name="option_row_radio_icon_title">Row with Radio Button and Icon</string>
<string name="option_row_radio_icon_colored_text_title">Row with Radio Button and Icon and Colored Text</string>
<string name="some_additional_text">Some additional text</string>
<string name="sample_additional_list">Sample selectable list</string>
<!-- TaskRestrictionDemoScreen -->
<string name="task_restriction_demo_title">Task Restriction Demo</string>
<string name="task_limit_reached_msg">This will overflow the step count, and lead you to a new screen. </string>
<string name="task_step_of_title">Task step %1$d of %2$d</string>
<string name="task_step_of_text">Click to go forward</string>
<string name="task_content_allowed">Please visit the different templates and ensure the car is in driving mode</string>
<!-- ToggleButtonDemoScreen -->
<string name="toggle_button_demo_title">Toggle Button Demo</string>
<string name="toggle_test_title">Toggle test</string>
<string name="toggle_test_text">Stateful changes are allowed</string>
<string name="toggle_test_first_toggle_title">Enable Toggle Test</string>
<string name="toggle_test_first_toggle_text">Check this one to enable the toggle test</string>
<string name="toggle_test_second_toggle_title">Toggle test</string>
<string name="toggle_test_second_toggle_text">Stateful changes are allowed</string>
<string name="image_test_title">Image test</string>
<string name="image_test_text">Image changes are allowed</string>
<string name="additional_data_title">Additional Data</string>
<string name="additional_data_text">Updates allowed on back operations.</string>
<string name="toggle_test_enabled">Toggle Test Enabled</string>
<string name="toggle_test_disabled">Toggle Test Disabled</string>
<!--SecondaryActionsAndDecorationDemoScreen -->
<string name="secondary_actions_decoration_button_demo_title">Secondary Action and Decoration Demo</string>
<string name="secondary_actions_test_title">Secondary Action Test</string>
<string name="secondary_actions_test_subtitle">Only the secondary action can be selected</string>
<string name="decoration_test_title">Decoration Test</string>
<string name="secondary_actions_decoration_test_title">Secondary Actions and Decoration</string>
<string name="secondary_actions_decoration_test_title_long">Row with Secondary Actions and Decoration with a really long title</string>
<string name="secondary_actions_decoration_test_subtitle">The row can also be selected</string>
<string name="recent_Item_deleted">Place deleted</string>
<string name="row_primary_action_toast">Row primary action is selected</string>
<!--SectionedItemListDemoScreen -->
<string name="sectioned_item_list_demo_title">Sectioned Item List Demo</string>
<string name="sectioned_item_list_one_title">List 1</string>
<string name="sectioned_item_list_two_title">List 2</string>
<string name="sectioned_item_list_subtext">Subtext under each list</string>
<!-- EmptyListDemoScreen -->
<string name="empty_list_demo_title">Empty List Demo</string>
<string name="empty_list_message">The list is empty</string>
<!-- StartScreen -->
<string name="misc_templates_demos_title">Misc Templates Demos</string>
<string name="cal_api_level_prefix" translatable="false">CAL API Level: %d</string>
<string name="showcase_demos_title">Showcase Demos</string>
<string name="template_layouts_demo_title">Template Layout Demos</string>
<string name="grid_template_menu_demo_title">Grid Template Demos</string>
<!-- User Interactions Screen -->
<string name="voice_access_demo_title">Voice Access Demo Screen</string>
<string name="user_interactions_demo_title">User Interactions</string>
<string name="request_permission_menu_demo_title">Request Permissions Demos</string>
<!-- Task Overflow Demo Screen -->
<string name="application_overflow_title">Application Overflow Validator</string>
<string name="application_overflow_subtitle1">Please test the following templates while changing</string>
<string name="application_overflow_subtitle2">the vehicle from parked to driving state</string>
<!-- Manifest file permissions -->
<string name="perm_group">Permission Group</string>
<string name="perm_group_description">Permission Group for Showcase App</string>
<string name="perm_fine_location">Access to Fine Location</string>
<string name="perm_fine_location_desc">Permission for Access to Fine Location</string>
<string name="perm_coarse_location">Access to Coarse Location</string>
<string name="perm_coarse_location_desc">Permission for Access to Coarse Location</string>
<string name="perm_record_audio">Access to Record Audio</string>
<string name="perm_record_audio_desc">Permission for Access to Record Audio</string>
<!-- Location Strings -->
<string name="location_1_title" translatable="false">Google Kirkland</string>
<string name="location_1_address" translatable="false">747 6th St South, Kirkland, WA 98033</string>
<string name="location_1_description">Tinted resource vector</string>
<string name="location_1_phone" translatable="false">+14257395600</string>
<string name="location_2_title" translatable="false">Google Bellevue</string>
<string name="location_2_address" translatable="false">1120 112th Ave NE, Bellevue, WA 98004</string>
<string name="location_2_description">Image resource bitmap</string>
<string name="location_2_phone" translatable="false">+14252301301</string>
<string name="location_3_title" translatable="false">Google South Lake Union</string>
<string name="location_3_address" translatable="false">1021 Valley St, Seattle, WA 98109</string>
<string name="location_3_description">Colored text marker</string>
<string name="location_3_phone" translatable="false">+12065311800</string>
<string name="location_4_title" translatable="false">Google Seattle</string>
<string name="location_4_address" translatable="false">601 N 34th St, Seattle, WA 98103</string>
<string name="location_4_description">Image bitmap</string>
<string name="location_4_phone" translatable="false">+12068761800</string>
<string name="location_5_address" translatable="false">1600 Amphitheatre Pkwy, Mountain View, CA 94043</string>
<string name="location_5_phone" translatable="false">+16502530000</string>
<string name="location_6_title" translatable="false">Google Bothell</string>
<string name="location_6_address" translatable="false">11831 North Creek Pkwy, Bothell, WA 98011</string>
<string name="location_7_title" translatable="false">Seward Park</string>
<string name="location_7_address" translatable="false">5900 Lake Washington Blvd S, Seattle, WA 98118</string>
<string name="location_8_title" translatable="false">Luther Burbank Park</string>
<string name="location_8_address" translatable="false">2040 84th Ave SE, Mercer Island, WA 98040</string>
<string name="location_9_title" translatable="false">Heritage Park</string>
<string name="location_9_address" translatable="false">111 Waverly Way, Kirkland, WA 98033</string>
<string name="location_description_text_label">Text label</string>
<string name="location_phone_not_available" translatable="false">n/a</string>
<string name="parking_vs_driving_demo_title">Parking Vs Driving Demo</string>
<string name="latest_feature_details">Cluster Displays in cars!</string>
<string name="latest_feature_title">Latest Features</string>
<string name="loading_toggle_enabled">Loading enabled</string>
<string name="loading_toggle_disabled">Loading disabled</string>
<string name="loading_screen">Loading screen</string>
<string name="vector_toggle_details">Toggle to add/remove color</string>
<string name="map_template_toggle_demo_title">Map Template with Toggles</string>
<string name="avoid_tolls_row_title">Avoid tolls</string>
<string name="route_options_demo_title">Route options</string>
<string name="avoid_highways_row_title">Avoid highways</string>
<string name="avoid_ferries_row_title">Avoid ferry</string>
<string name="map_demos_title">Map Demos</string>
<string name="map_with_content_demo_title">Map With Content Demos</string>
<string name="map_with_message_demo_title">Map With Message Template Demo</string>
<string name="map_with_grid_demo_title">Map With Grid Template Demo</string>
<string name="route_preview">Routes</string>
<string name="recent_destinations">Recent</string>
<string name="contacts">Contacts</string>
</resources>

View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2021 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<style name="CarAppTheme">
<item name="themedIconColor">#FFFF0000</item>
<item name="carColorPrimary">#ff7f39fb</item>
<item name="carColorPrimaryDark">#5904DF</item>
<item name="carColorSecondary">#328E10</item>
<item name="carColorSecondaryDark">#1A6004</item>
<item name="carPermissionActivityLayout">@layout/permission_request</item>
<item name="markerIconTintColor">#FF7F39FB</item>
<item name="markerIconTintColorDark">#FF5904DF</item>
</style>
</resources>

View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2023 Google LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<automotiveApp>
<uses name="template"/>
</automotiveApp>

View File

@@ -0,0 +1,18 @@
package com.kouros.navigation.car
import com.kouros.navigation.car.navigation.RoutingModel
import org.junit.Assert.assertEquals
import org.junit.Test
/**
* Example local unit test, which will execute on the development machine (host).
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
class ExampleUnitTest {
@Test
fun addition_isCorrect() {
assertEquals(4, 2 + 2)
}
}