Skip to content

Commit

Permalink
Update android auto extension
Browse files Browse the repository at this point in the history
  • Loading branch information
kmadsen committed Jan 20, 2022
1 parent 7e62660 commit b38ffba
Show file tree
Hide file tree
Showing 22 changed files with 1,562 additions and 341 deletions.
2 changes: 1 addition & 1 deletion android-auto-app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,10 @@ dependencies {
implementation(Dependencies.googleCarAppLibrary)
implementation(Dependencies.kotlin)
implementation(Dependencies.androidxAppCompat)
implementation(Dependencies.androidxCoreKtx)

// By default, the Maps SDK uses the Android Location Provider to obtain raw location updates.
// And with Android 11, the raw location updates might suffer from precision issue.

// The Maps SDK also comes pre-compiled with support for the [Google's Fused Location Provider](https://developers.google.com/location-context/fused-location-provider)
// if that dependency is available. This means, that if your target devices support Google Play
// Services, [we recommend adding the Google Play Location Services dependency to your project](https://developers.google.com/android/guides/setup).
Expand Down
5 changes: 0 additions & 5 deletions android-auto-app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

<uses-permission android:name="androidx.car.app.NAVIGATION_TEMPLATES" />
<uses-permission android:name="androidx.car.app.ACCESS_SURFACE" />

<application
android:allowBackup="true"
Expand All @@ -17,10 +16,6 @@
android:supportsRtl="true"
android:extractNativeLibs="false">

<meta-data
android:name="androidx.car.app.minCarApiLevel"
android:value="1"/>

<meta-data
android:name="com.google.android.gms.car.application"
android:resource="@xml/automotive_app_desc"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,60 +1,87 @@
package com.mapbox.maps.testapp.auto.car

import android.graphics.Rect
import com.mapbox.geojson.Point
import com.mapbox.maps.CameraState
import com.mapbox.maps.EdgeInsets
import com.mapbox.maps.MapSurface
import com.mapbox.maps.dsl.cameraOptions
import com.mapbox.maps.extension.androidauto.OnMapScrollListener
import com.mapbox.maps.extension.androidauto.MapboxCarMapObserver
import com.mapbox.maps.extension.androidauto.MapboxCarMapSurface
import com.mapbox.maps.plugin.animation.camera
import com.mapbox.maps.plugin.locationcomponent.OnIndicatorPositionChangedListener
import com.mapbox.maps.plugin.locationcomponent.location

/**
* Controller class to handle map camera changes.
*/
class CarCameraController : OnIndicatorPositionChangedListener, OnMapScrollListener {
class CarCameraController : MapboxCarMapObserver {

private var lastGpsLocation: Point = HELSINKI
private var previousCameraState: CameraState? = null
private var isTrackingPuck = true

private lateinit var surface: MapSurface
private var surface: MapboxCarMapSurface? = null
private var insets: EdgeInsets = EdgeInsets(0.0, 0.0, 0.0, 0.0)

private val changePositionListener = OnIndicatorPositionChangedListener { point ->
lastGpsLocation = point
if (isTrackingPuck) {
surface?.mapSurface?.getMapboxMap()?.setCamera(
cameraOptions {
center(point)
padding(insets)
}
)
}
}

/**
* Initialise the car camera controller with a map surface.
*/
fun init(mapSurface: MapSurface, edgeInsets: EdgeInsets = EdgeInsets(0.0, 0.0, 0.0, 0.0)) {
insets = edgeInsets
surface = mapSurface
surface.getMapboxMap().setCamera(
override fun loaded(mapboxCarMapSurface: MapboxCarMapSurface) {
super.loaded(mapboxCarMapSurface)
this.surface = mapboxCarMapSurface
mapboxCarMapSurface.mapSurface.getMapboxMap().setCamera(
cameraOptions {
pitch(INITIAL_PITCH)
zoom(INITIAL_ZOOM)
pitch(previousCameraState?.pitch ?: INITIAL_PITCH)
zoom(previousCameraState?.zoom ?: INITIAL_ZOOM)
center(lastGpsLocation)
}
)
with(mapboxCarMapSurface.mapSurface.location) {
// Show a 3D location puck
locationPuck = CarLocationPuck.duckLocationPuckLowZoom
enabled = true
addOnIndicatorPositionChangedListener(changePositionListener)
}
}

override fun onIndicatorPositionChanged(point: Point) {
lastGpsLocation = point
if (isTrackingPuck) {
surface.getMapboxMap().setCamera(
cameraOptions {
center(point)
padding(insets)
}
)
override fun detached(mapboxCarMapSurface: MapboxCarMapSurface) {
previousCameraState = mapboxCarMapSurface.mapSurface.getMapboxMap().cameraState
with(mapboxCarMapSurface.mapSurface.location) {
removeOnIndicatorPositionChangedListener(changePositionListener)
}
super.detached(mapboxCarMapSurface)
}

override fun visibleAreaChanged(visibleArea: Rect, edgeInsets: EdgeInsets) {
insets = edgeInsets
}

override fun onMapScroll() {
override fun scroll(
mapboxCarMapSurface: MapboxCarMapSurface,
distanceX: Float,
distanceY: Float
): Boolean {
dismissTracking()
return false
}

/**
* Make camera center to location puck and track the location puck's position.
*/
fun focusOnLocationPuck() {
surface.camera.flyTo(
surface?.mapSurface?.camera?.flyTo(
cameraOptions {
center(lastGpsLocation)
}
Expand All @@ -67,23 +94,40 @@ class CarCameraController : OnIndicatorPositionChangedListener, OnMapScrollListe
}

/**
* Adjust the camera's zoom level by the given scale factor.
*
* @param scaleFactor the scale factor to be applied to the camera's current zoom level.
* Function dedicated to zoom in map action buttons.
*/
fun zoomBy(scaleFactor: Double) {
val cameraState = surface.getMapboxMap().cameraState
surface.camera.easeTo(
cameraOptions {
zoom(scaleFactor * cameraState.zoom)
}
)
fun zoomInAction() = scaleEaseBy(ZOOM_ACTION_DELTA)

/**
* Function dedicated to zoom in map action buttons.
*/
fun zoomOutAction() = scaleEaseBy(-ZOOM_ACTION_DELTA)

private fun scaleEaseBy(delta: Double) {
val mapSurface = surface?.mapSurface
val fromZoom = mapSurface?.getMapboxMap()?.cameraState?.zoom ?: return
val toZoom = (fromZoom + delta).coerceIn(MIN_ZOOM_OUT, MAX_ZOOM_IN)
mapSurface.camera.easeTo(cameraOptions { zoom(toZoom) })
}

companion object {
private val HELSINKI = Point.fromLngLat(24.9384, 60.1699)
private const val INITIAL_ZOOM = 16.0
private const val INITIAL_PITCH = 75.0
private const val TAG = "CarCameraController"

/**
* When zooming the camera by a delta, this is an estimated min-zoom.
*/
private const val MIN_ZOOM_OUT = 6.0

/**
* When zooming the camera by a delta, this is an estimated max-zoom.
*/
private const val MAX_ZOOM_IN = 20.0

/**
* Simple zoom delta to associate with the zoom action buttons.
*/
private const val ZOOM_ACTION_DELTA = 0.5
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package com.mapbox.maps.testapp.auto.car

import com.mapbox.maps.Style
import com.mapbox.maps.extension.androidauto.MapboxCarMapObserver
import com.mapbox.maps.extension.androidauto.MapboxCarMapSurface
import com.mapbox.maps.extension.style.layers.addLayer
import com.mapbox.maps.extension.style.layers.generated.SkyLayer
import com.mapbox.maps.extension.style.layers.getLayerAs
import com.mapbox.maps.extension.style.sources.addSource
import com.mapbox.maps.extension.style.sources.generated.RasterDemSource
import com.mapbox.maps.extension.style.sources.getSourceAs
import com.mapbox.maps.extension.style.terrain.generated.setTerrain
import com.mapbox.maps.extension.style.terrain.generated.terrain

/**
* Example showing how you can add a sky layer that has a sun direction,
* and adding a terrain layer to show mountains.
*/
class CarMapShowcase : MapboxCarMapObserver {

override fun loaded(mapboxCarMapSurface: MapboxCarMapSurface) {
with(mapboxCarMapSurface.style) {
updateSkyLayer(mapboxCarMapSurface.carContext.isDarkMode)
updateTerrainLayer()
}
}

private fun Style.updateSkyLayer(isDarkMode: Boolean) {
var skyLayer = getLayerAs<SkyLayer>(SKY_LAYER)
if (skyLayer == null) {
skyLayer = SkyLayer(SKY_LAYER)
addLayer(skyLayer)
}
// https://docs.mapbox.com/mapbox-gl-js/style-spec/layers/#paint-sky-sky-atmosphere-sun
// Position of the sun center [a azimuthal angle, p polar angle].
// Azimuthal is degrees from north, where 0.0 is north.
// Polar is degrees from overhead, where 0.0 is overhead.
if (isDarkMode) {
skyLayer.skyAtmosphereSun(listOf(-50.0, 90.2))
} else {
skyLayer.skyAtmosphereSun(listOf(0.0, 0.0))
}
}

private fun Style.updateTerrainLayer() {
var demSource = getSourceAs<RasterDemSource>(DEM_SOURCE)
if (demSource == null) {
demSource = RasterDemSource.Builder(DEM_SOURCE)
.url(TERRAIN_URL_TILE_RESOURCE)
.tileSize(514)
.build()
addSource(demSource)
}
setTerrain(terrain(DEM_SOURCE) { exaggeration(1.7) })
}

companion object {
private const val SKY_LAYER = "sky"
private const val DEM_SOURCE = "mapbox-dem"
private const val TERRAIN_URL_TILE_RESOURCE = "mapbox://mapbox.mapbox-terrain-dem-v1"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,31 @@ package com.mapbox.maps.testapp.auto.car
import androidx.car.app.CarContext
import androidx.car.app.CarToast
import androidx.car.app.Screen
import androidx.car.app.model.*
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.Template
import androidx.car.app.navigation.model.NavigationTemplate
import androidx.core.graphics.drawable.IconCompat
import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.LifecycleOwner
import com.mapbox.maps.extension.androidauto.MapboxCarMap
import com.mapbox.maps.testapp.auto.R
import java.lang.ref.WeakReference

/**
* Simple demo of how to show a Mapbox Map on the Android Auto screen.
*/
class MapScreen(carContext: CarContext) : Screen(carContext) {
class MapScreen(
carContext: CarContext,
val mapboxCarMap: MapboxCarMap
) : Screen(carContext) {
private var isInPanMode: Boolean = false
private lateinit var carCameraController: WeakReference<CarCameraController>

/**
* Set the map camera controller, so that the UI elements(such as action button) in the template
* can interact with the camera.
*/
fun setMapCameraController(controller: CarCameraController) {
carCameraController = WeakReference(controller)
}
private val carCameraController = CarCameraController()

override fun onGetTemplate(): Template {
val builder = NavigationTemplate.Builder()
builder.setBackgroundColor(CarColor.SECONDARY)
.setBackgroundColor(CarColor.SECONDARY)

builder.setActionStrip(
ActionStrip.Builder()
Expand All @@ -41,7 +42,7 @@ class MapScreen(carContext: CarContext) : Screen(carContext) {
).build()
)
.setOnClickListener {
carCameraController.get()?.focusOnLocationPuck()
carCameraController.focusOnLocationPuck()
}
.build()
)
Expand Down Expand Up @@ -76,7 +77,7 @@ class MapScreen(carContext: CarContext) : Screen(carContext) {
)
.setOnClickListener {
// handle zoom out
carCameraController.get()?.zoomBy(0.95)
carCameraController.zoomOutAction()
}
.build()
)
Expand All @@ -91,7 +92,7 @@ class MapScreen(carContext: CarContext) : Screen(carContext) {
).build()
)
.setOnClickListener {
carCameraController.get()?.zoomBy(1.05)
carCameraController.zoomInAction()
}
.build()
)
Expand All @@ -114,4 +115,16 @@ class MapScreen(carContext: CarContext) : Screen(carContext) {

return builder.build()
}

init {
lifecycle.addObserver(object : DefaultLifecycleObserver {
override fun onCreate(owner: LifecycleOwner) {
mapboxCarMap.registerObserver(carCameraController)
}

override fun onDestroy(owner: LifecycleOwner) {
mapboxCarMap.unregisterObserver(carCameraController)
}
})
}
}
Loading

0 comments on commit b38ffba

Please sign in to comment.