diff --git a/app/src/google/java/net/vonforst/evmap/auto/VehicleDataScreen.kt b/app/src/google/java/net/vonforst/evmap/auto/VehicleDataScreen.kt
index 1d25907a..d6559cea 100644
--- a/app/src/google/java/net/vonforst/evmap/auto/VehicleDataScreen.kt
+++ b/app/src/google/java/net/vonforst/evmap/auto/VehicleDataScreen.kt
@@ -6,9 +6,7 @@ import android.os.Looper
import androidx.car.app.CarContext
import androidx.car.app.Screen
import androidx.car.app.hardware.CarHardwareManager
-import androidx.car.app.hardware.info.EnergyLevel
-import androidx.car.app.hardware.info.Model
-import androidx.car.app.hardware.info.Speed
+import androidx.car.app.hardware.info.*
import androidx.car.app.model.*
import androidx.core.content.ContextCompat
import androidx.core.graphics.drawable.IconCompat
@@ -17,6 +15,7 @@ import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.OnLifecycleEvent
import net.vonforst.evmap.BuildConfig
import net.vonforst.evmap.R
+import net.vonforst.evmap.ui.CompassNeedle
import net.vonforst.evmap.ui.Gauge
import kotlin.math.min
import kotlin.math.roundToInt
@@ -26,7 +25,10 @@ class VehicleDataScreen(ctx: CarContext) : Screen(ctx), LifecycleObserver {
private var model: Model? = null
private var energyLevel: EnergyLevel? = null
private var speed: Speed? = null
+ private var heading: Compass? = null
private var gauge = Gauge((ctx.resources.displayMetrics.density * 128).roundToInt(), ctx)
+ private var compass =
+ CompassNeedle((ctx.resources.displayMetrics.density * 128).roundToInt(), ctx)
private val maxSpeed = 160f / 3.6f // m/s, speed gauge will show max if speed is higher
private val permissions = if (BuildConfig.FLAVOR_automotive == "automotive") {
@@ -66,6 +68,7 @@ class VehicleDataScreen(ctx: CarContext) : Screen(ctx), LifecycleObserver {
val energyLevel = energyLevel
val model = model
val speed = speed
+ val heading = heading
return GridTemplate.Builder().apply {
setTitle(
@@ -182,6 +185,25 @@ class VehicleDataScreen(ctx: CarContext) : Screen(ctx), LifecycleObserver {
}
}
}.build())
+ addItem(GridItem.Builder().apply {
+ setTitle(carContext.getString(R.string.auto_heading))
+ if (heading == null) {
+ setLoading(true)
+ } else {
+ val heading = heading.orientations.value
+ if (heading != null) {
+ setText(
+ "${heading[0].roundToInt()}°"
+ )
+
+ } else {
+ setText(carContext.getString(R.string.auto_no_data))
+ }
+ setImage(
+ compass.draw(heading?.get(0)).asCarIcon()
+ )
+ }
+ }.build())
}.build()
)
}
@@ -198,6 +220,11 @@ class VehicleDataScreen(ctx: CarContext) : Screen(ctx), LifecycleObserver {
invalidate()
}
+ private fun onCompassUpdated(compass: Compass) {
+ this.heading = compass
+ invalidate()
+ }
+
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
private fun setupListeners() {
if (!permissionsGranted()) return
@@ -207,6 +234,11 @@ class VehicleDataScreen(ctx: CarContext) : Screen(ctx), LifecycleObserver {
val exec = ContextCompat.getMainExecutor(carContext)
hardwareMan.carInfo.addEnergyLevelListener(exec, ::onEnergyLevelUpdated)
hardwareMan.carInfo.addSpeedListener(exec, ::onSpeedUpdated)
+ hardwareMan.carSensors.addCompassListener(
+ CarSensors.UPDATE_RATE_NORMAL,
+ exec,
+ ::onCompassUpdated
+ )
hardwareMan.carInfo.fetchModel(exec) {
this.model = it
@@ -219,6 +251,7 @@ class VehicleDataScreen(ctx: CarContext) : Screen(ctx), LifecycleObserver {
println("Removing energy level listener")
hardwareMan.carInfo.removeEnergyLevelListener(::onEnergyLevelUpdated)
hardwareMan.carInfo.removeSpeedListener(::onSpeedUpdated)
+ hardwareMan.carSensors.removeCompassListener(::onCompassUpdated)
}
private fun permissionsGranted(): Boolean =
diff --git a/app/src/google/java/net/vonforst/evmap/ui/CompassNeedle.kt b/app/src/google/java/net/vonforst/evmap/ui/CompassNeedle.kt
new file mode 100644
index 00000000..8aede7c9
--- /dev/null
+++ b/app/src/google/java/net/vonforst/evmap/ui/CompassNeedle.kt
@@ -0,0 +1,33 @@
+package net.vonforst.evmap.ui
+
+import android.content.Context
+import android.graphics.Bitmap
+import android.graphics.Canvas
+import android.graphics.Color
+import android.graphics.PorterDuff
+import androidx.core.content.ContextCompat
+import net.vonforst.evmap.R
+
+class CompassNeedle(val size: Int, ctx: Context) {
+ val image = ContextCompat.getDrawable(ctx, R.drawable.ic_navigation)!!
+
+ init {
+ image.setTint(Color.WHITE)
+ image.setBounds(0, 0, size, size)
+ }
+
+ fun draw(angle: Float?): Bitmap {
+ val bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888)
+ val canvas = Canvas(bitmap)
+
+ canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR)
+
+ if (angle != null) {
+ canvas.save()
+ canvas.rotate(-angle, size / 2f, size / 2f)
+ image.draw(canvas)
+ canvas.restore()
+ }
+ return bitmap
+ }
+}
\ No newline at end of file
diff --git a/app/src/google/res/values-de/values.xml b/app/src/google/res/values-de/values.xml
index fe2a74ad..42ccd5d9 100644
--- a/app/src/google/res/values-de/values.xml
+++ b/app/src/google/res/values-de/values.xml
@@ -27,6 +27,7 @@
Nicht verfügbar
Reichweite
Geschwindigkeit
+ Fahrtrichtung
Einstellungen
Android Auto-Unterstützung
Auf unterstützen Autos kannst du EVMap auch mit Android Auto nutzen. Öffne dazu einfach die EVMap-App aus dem Menü von Android Auto.
diff --git a/app/src/google/res/values/values.xml b/app/src/google/res/values/values.xml
index 1caa2199..2a5f399f 100644
--- a/app/src/google/res/values/values.xml
+++ b/app/src/google/res/values/values.xml
@@ -37,6 +37,7 @@
Unavailable
Range
Speed
+ Heading
Settings
Android Auto support
You can also use EVMap from within Android Auto on supported cars. Simply select the EVMap app in the Android Auto menu.