Automotive: implement map rotation by compass

This commit is contained in:
johan12345
2025-10-26 23:09:23 +01:00
parent 6c206c7a25
commit 15fdac6348
4 changed files with 56 additions and 15 deletions

View File

@@ -325,7 +325,7 @@ dependencies {
automotiveImplementation("androidx.car.app:app-automotive:$carAppVersion")
// AnyMaps
val anyMapsVersion = "b1c6d18244"
val anyMapsVersion = "a6fb85f9bc"
implementation("com.github.ev-map.AnyMaps:anymaps-base:$anyMapsVersion")
googleImplementation("com.github.ev-map.AnyMaps:anymaps-google:$anyMapsVersion")
googleImplementation("com.google.android.gms:play-services-maps:19.2.0")

View File

@@ -59,7 +59,6 @@ import net.vonforst.evmap.storage.ChargeLocationsRepository
import net.vonforst.evmap.storage.PreferenceDataSource
import net.vonforst.evmap.ui.MarkerManager
import net.vonforst.evmap.utils.distanceBetween
import net.vonforst.evmap.utils.headingDiff
import net.vonforst.evmap.viewmodel.Resource
import net.vonforst.evmap.viewmodel.Status
import net.vonforst.evmap.viewmodel.await
@@ -70,9 +69,7 @@ import java.io.IOException
import java.time.Duration
import java.time.Instant
import java.time.ZonedDateTime
import kotlin.collections.set
import kotlin.math.min
import kotlin.math.roundToInt
import kotlin.time.DurationUnit
import kotlin.time.TimeSource
@@ -146,6 +143,7 @@ class MapScreen(ctx: CarContext, val session: EVMapSession) :
private var map: AnyMap? = null
private var markerManager: MarkerManager? = null
private var myLocationEnabled = false
private var compassEnabled = false
private var myLocationNeedsUpdate = false
private val formatter = ChargerListFormatter(ctx, this, session.cas)
@@ -241,11 +239,16 @@ class MapScreen(ctx: CarContext, val session: EVMapSession) :
.addAction(Action.PAN)
.addAction(
Action.Builder().setIcon(
CarIcon.Builder(IconCompat.createWithResource(carContext, R.drawable.ic_location))
CarIcon.Builder(
IconCompat.createWithResource(
carContext,
if (compassEnabled) R.drawable.ic_compass else R.drawable.ic_location
)
)
.setTint(if (myLocationEnabled) CarColor.SECONDARY else CarColor.DEFAULT)
.build()
).setOnClickListener {
enableLocation(true)
enableLocation(true, myLocationEnabled && !compassEnabled)
}.build()
)
.addAction(
@@ -385,8 +388,15 @@ class MapScreen(ctx: CarContext, val session: EVMapSession) :
val map = map ?: return
if (myLocationEnabled) {
val bearing = if (compassEnabled) getBearing(location) else 0f
if (oldLoc == null) {
mapSurfaceCallback.animateCamera(map.cameraUpdateFactory.newLatLngZoom(latLng, 13f))
mapSurfaceCallback.animateCamera(
map.cameraUpdateFactory.newLatLngZoomBearing(
latLng,
13f,
bearing
)
)
} else if (latLng != oldLoc && distanceBetween(
latLng.latitude,
latLng.longitude,
@@ -395,7 +405,11 @@ class MapScreen(ctx: CarContext, val session: EVMapSession) :
) > 1
) {
// only update map if location changed by more than 1 meter
val camUpdate = map.cameraUpdateFactory.newLatLng(latLng)
val camUpdate = map.cameraUpdateFactory.newLatLngZoomBearing(
latLng,
map.cameraPosition.zoom,
bearing
)
mapSurfaceCallback.animateCamera(camUpdate)
}
}
@@ -545,6 +559,7 @@ class MapScreen(ctx: CarContext, val session: EVMapSession) :
availabilities.clear()
location = null
myLocationEnabled = false
compassEnabled = false
removeListeners()
}
@@ -556,6 +571,7 @@ class MapScreen(ctx: CarContext, val session: EVMapSession) :
prefs.currentMapZoom = it.cameraPosition.zoom
}
prefs.currentMapMyLocationEnabled = myLocationEnabled
prefs.androidAutoCompassEnabled = compassEnabled
}
private fun removeListeners() {
@@ -625,9 +641,10 @@ class MapScreen(ctx: CarContext, val session: EVMapSession) :
onClusterClick = {
val newZoom = map.cameraPosition.zoom + 2
mapSurfaceCallback.animateCamera(
map.cameraUpdateFactory.newLatLngZoom(
map.cameraUpdateFactory.newLatLngZoomBearing(
LatLng(it.coordinates.lat, it.coordinates.lng),
newZoom
newZoom,
if (compassEnabled) location?.let { getBearing(it) } ?: 0f else 0f
)
)
}
@@ -657,6 +674,7 @@ class MapScreen(ctx: CarContext, val session: EVMapSession) :
prefs.placeSearchResultAndroidAuto?.let { place ->
// move to the location of the search result
myLocationEnabled = false
compassEnabled = false
markerManager?.searchResult = place
if (place.viewport != null) {
map.moveCamera(map.cameraUpdateFactory.newLatLngBounds(place.viewport, 0))
@@ -664,7 +682,7 @@ class MapScreen(ctx: CarContext, val session: EVMapSession) :
map.moveCamera(map.cameraUpdateFactory.newLatLngZoom(place.latLng, 12f))
}
} ?: if (prefs.currentMapMyLocationEnabled) {
enableLocation(false)
enableLocation(false, prefs.androidAutoCompassEnabled)
} else {
// use position saved in preferences, fall back to default (Europe)
val cameraUpdate =
@@ -692,14 +710,16 @@ class MapScreen(ctx: CarContext, val session: EVMapSession) :
loadChargers()
}
private fun enableLocation(animated: Boolean) {
private fun enableLocation(animated: Boolean, withCompass: Boolean) {
myLocationEnabled = true
compassEnabled = withCompass
myLocationNeedsUpdate = true
if (location != null) {
location?.let { location ->
val map = map ?: return
val update = map.cameraUpdateFactory.newLatLngZoom(
val update = map.cameraUpdateFactory.newLatLngZoomBearing(
LatLng.fromLocation(location),
13f
13f,
if (withCompass) getBearing(location) else 0f
)
if (animated) {
mapSurfaceCallback.animateCamera(update)
@@ -708,4 +728,7 @@ class MapScreen(ctx: CarContext, val session: EVMapSession) :
}
}
}
private fun getBearing(location: Location): Float =
heading?.orientations?.value?.get(0) ?: location.bearing
}

View File

@@ -248,6 +248,12 @@ class PreferenceDataSource(val context: Context) {
set(value) {
sp.edit().putBoolean("privacy_accepted", value).apply()
}
var androidAutoCompassEnabled: Boolean
get() = sp.getBoolean("android_auto_compass_enabled", false)
set(value) {
sp.edit().putBoolean("android_auto_compass_enabled", value).apply()
}
}
fun SharedPreferences.getLatLng(key: String): LatLng? =

View File

@@ -0,0 +1,12 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:tint="#000000"
android:viewportHeight="24"
android:viewportWidth="24"
android:width="24dp">
<path
android:fillColor="@android:color/white"
android:pathData="M12,10.9c-0.61,0 -1.1,0.49 -1.1,1.1s0.49,1.1 1.1,1.1c0.61,0 1.1,-0.49 1.1,-1.1s-0.49,-1.1 -1.1,-1.1zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM14.19,14.19L6,18l3.81,-8.19L18,6l-3.81,8.19z" />
</vector>