Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 3 additions & 9 deletions libnavui-androidauto/api/current.txt
Original file line number Diff line number Diff line change
Expand Up @@ -488,18 +488,12 @@ package com.mapbox.androidauto.navigation.roadlabel {
}

public final class RoadLabelRenderer {
ctor public RoadLabelRenderer(android.content.res.Resources resources);
method public android.graphics.Bitmap? render(java.util.List<com.mapbox.navigation.base.road.model.RoadComponent> road, java.util.List<? extends com.mapbox.navigation.ui.shield.model.RouteShield> shields, com.mapbox.androidauto.navigation.roadlabel.RoadLabelOptions options = RoadLabelOptions.default);
ctor public RoadLabelRenderer();
method public android.graphics.Bitmap? render(android.content.res.Resources resources, java.util.List<com.mapbox.navigation.base.road.model.RoadComponent> road, java.util.List<? extends com.mapbox.navigation.ui.shield.model.RouteShield> shields, com.mapbox.androidauto.navigation.roadlabel.RoadLabelOptions options = RoadLabelOptions.default);
}

public final class RoadLabelSurfaceLayer implements com.mapbox.maps.extension.androidauto.MapboxCarMapObserver {
ctor public RoadLabelSurfaceLayer(androidx.car.app.CarContext carContext);
method public java.util.List<com.mapbox.maps.extension.androidauto.MapboxCarMapObserver> children();
method public androidx.car.app.CarContext getCarContext();
method public final com.mapbox.maps.EdgeInsets? getEdgeInsets();
method public final android.graphics.Rect? getVisibleArea();
method public final kotlin.Pair<java.lang.Integer,java.lang.Integer>? surfaceDimensions();
property public final androidx.car.app.CarContext carContext;
ctor public RoadLabelSurfaceLayer();
}

public abstract class RoadNameObserver implements com.mapbox.navigation.core.lifecycle.MapboxNavigationObserver {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,13 @@ class RoadLabelRendererTest {
"test_road_label_images"
)

private val roadLabelBitmapRenderer =
RoadLabelRenderer(InstrumentationRegistry.getInstrumentation().context.resources)
private val roadLabelBitmapRenderer = RoadLabelRenderer()
private val resources = InstrumentationRegistry.getInstrumentation().context.resources

@Test
fun street_with_name() {
val bitmap = roadLabelBitmapRenderer.render(
resources,
createRoad("Pennsylvania Avenue"),
emptyList(),
RoadLabelOptions.Builder()
Expand All @@ -59,6 +60,7 @@ class RoadLabelRendererTest {
@Test
fun street_with_numbers() {
val bitmap = roadLabelBitmapRenderer.render(
resources,
createRoad("11th Street"),
emptyList(),
RoadLabelOptions.Builder()
Expand All @@ -72,6 +74,7 @@ class RoadLabelRendererTest {
@Test
fun very_long_street_name() {
val bitmap = roadLabelBitmapRenderer.render(
resources,
createRoad(
"Taumatawhakatangihangakoauauotamateaturipukakapikimaungahoronukupokaiwhen" +
"uakitanatahu"
Expand All @@ -88,6 +91,7 @@ class RoadLabelRendererTest {
@Test
fun blue_label_without_shadow() {
val bitmap = roadLabelBitmapRenderer.render(
resources,
createRoad("Eu Tong Sen Street"),
emptyList(),
RoadLabelOptions.Builder()
Expand All @@ -106,6 +110,7 @@ class RoadLabelRendererTest {
val byteArray = context.assets.open("shield.svg").use { it.readBytes() }
val mapboxShield = mockk<MapboxShield>()
val bitmap = roadLabelBitmapRenderer.render(
resources,
listOf(
createComponent("Clarksburg Road"),
createComponent("/"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class FreeDriveCarScreen @UiThread constructor(
initialCarCameraMode = CarCameraMode.FOLLOWING,
alternativeCarCameraMode = null,
)
private val roadLabelSurfaceLayer = RoadLabelSurfaceLayer(carContext)
private val roadLabelSurfaceLayer = RoadLabelSurfaceLayer()
private val mapActionStripBuilder = MapboxMapActionStrip(this, carNavigationCamera)

init {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ internal class ActiveGuidanceScreen constructor(
initialCarCameraMode = CarCameraMode.FOLLOWING,
alternativeCarCameraMode = CarCameraMode.OVERVIEW,
)
private val roadLabelSurfaceLayer = RoadLabelSurfaceLayer(carContext)
private val roadLabelSurfaceLayer = RoadLabelSurfaceLayer()
private val navigationInfoProvider = CarNavigationInfoProvider()
.invalidateOnChange(this)
private val carActiveGuidanceMarkers = CarActiveGuidanceMarkers()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,20 @@ import kotlin.math.roundToInt
/**
* This class will a road name and create a bitmap that fits the text.
*/
class RoadLabelRenderer(private val resources: Resources) {
class RoadLabelRenderer {

/**
* Render [road] and [shields] to a [Bitmap]
*/
fun render(
resources: Resources,
road: List<RoadComponent>,
shields: List<RouteShield>,
options: RoadLabelOptions = RoadLabelOptions.default
): Bitmap? {
if (road.isEmpty()) return null
textPaint.color = options.textColor
val components = measureRoadLabel(road, shields)
val components = measureRoadLabel(resources, road, shields)
val spaceWidth = textPaint.measureText(" ").roundToInt()
val width = components.sumOf { component ->
when (component) {
Expand Down Expand Up @@ -54,17 +55,22 @@ class RoadLabelRenderer(private val resources: Resources) {
}

private fun measureRoadLabel(
resources: Resources,
road: List<RoadComponent>,
shields: List<RouteShield>
): List<Component> {
return road.map { component ->
getShieldBitmap(component, shields)
getShieldBitmap(resources, component, shields)
?.let { Component.Shield(it) }
?: Component.Text(component.text, getTextBounds(component.text))
}
}

private fun getShieldBitmap(component: RoadComponent, shields: List<RouteShield>): Bitmap? {
private fun getShieldBitmap(
resources: Resources,
component: RoadComponent,
shields: List<RouteShield>,
): Bitmap? {
val shield = component.shield?.let { shield ->
shields.find { it is RouteShield.MapboxDesignedShield && it.compareWith(shield) }
} ?: component.imageBaseUrl?.let { baseUrl ->
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.mapbox.androidauto.navigation.roadlabel

import android.graphics.Color
import android.graphics.Rect
import androidx.car.app.CarContext
import androidx.car.app.Screen
import com.mapbox.androidauto.internal.extensions.getStyleAsync
Expand All @@ -11,6 +12,7 @@ import com.mapbox.androidauto.internal.logAndroidAutoFailure
import com.mapbox.androidauto.internal.surfacelayer.CarSurfaceLayer
import com.mapbox.androidauto.internal.surfacelayer.textview.CarTextLayerHost
import com.mapbox.androidauto.navigation.MapUserStyleObserver
import com.mapbox.maps.EdgeInsets
import com.mapbox.maps.LayerPosition
import com.mapbox.maps.MapboxExperimental
import com.mapbox.maps.extension.androidauto.MapboxCarMap
Expand All @@ -31,25 +33,38 @@ import com.mapbox.navigation.ui.shield.model.RouteShield
* removing the listener with [MapboxCarMap.unregisterObserver].
*/
@OptIn(MapboxExperimental::class)
class RoadLabelSurfaceLayer(
val carContext: CarContext,
) : CarSurfaceLayer() {
class RoadLabelSurfaceLayer internal constructor(
private val delegate: RoadLabelSurfaceLayerDelegate,
) : MapboxCarMapObserver {

private val roadLabelRenderer = RoadLabelRenderer(carContext.resources)
constructor() : this(RoadLabelSurfaceLayerDelegate())

override fun onAttached(mapboxCarMapSurface: MapboxCarMapSurface) {
delegate.onAttached(mapboxCarMapSurface)
}

override fun onDetached(mapboxCarMapSurface: MapboxCarMapSurface) {
delegate.onDetached(mapboxCarMapSurface)
}

override fun onVisibleAreaChanged(visibleArea: Rect, edgeInsets: EdgeInsets) {
delegate.onVisibleAreaChanged(visibleArea, edgeInsets)
}

override fun onStableAreaChanged(stableArea: Rect, edgeInsets: EdgeInsets) {
delegate.onStableAreaChanged(stableArea, edgeInsets)
}
}

@OptIn(MapboxExperimental::class)
internal class RoadLabelSurfaceLayerDelegate : CarSurfaceLayer() {

private val roadLabelRenderer = RoadLabelRenderer()
private val carTextLayerHost = CarTextLayerHost()
private val routeShieldApi = MapboxRouteShieldApi()
private val mapUserStyleObserver = MapUserStyleObserver()
private var styleLoadedListener: OnStyleLoadedListener? = null

private val roadNameObserver = object : RoadNameObserver(
routeShieldApi,
mapUserStyleObserver
) {
override fun onRoadUpdate(road: List<RoadComponent>, shields: List<RouteShield>) {
val bitmap = roadLabelRenderer.render(road, shields, roadLabelOptions())
carTextLayerHost.offerBitmap(bitmap)
}
}
private var roadNameObserver: RoadNameObserver? = null

override fun children(): List<MapboxCarMapObserver> = listOf(carTextLayerHost.mapScene)

Expand All @@ -68,11 +83,20 @@ class RoadLabelSurfaceLayer(
logAndroidAutoFailure("Add custom layer exception $it")
}
}
val carContext = mapboxCarMapSurface.carContext
val roadNameObserver = object : RoadNameObserver(routeShieldApi, mapUserStyleObserver) {
override fun onRoadUpdate(road: List<RoadComponent>, shields: List<RouteShield>) {
val options = roadLabelOptions(carContext)
val bitmap = roadLabelRenderer.render(carContext.resources, road, shields, options)
carTextLayerHost.offerBitmap(bitmap)
}
}.also { roadNameObserver = it }
styleLoadedListener = mapboxCarMapSurface.handleStyleOnAttached {
val bitmap = roadLabelRenderer.render(
carContext.resources,
roadNameObserver.currentRoad,
roadNameObserver.currentShields,
roadLabelOptions()
roadLabelOptions(carContext)
)
carTextLayerHost.offerBitmap(bitmap)
}
Expand All @@ -85,13 +109,14 @@ class RoadLabelSurfaceLayer(
logAndroidAuto("RoadLabelSurfaceLayer carMapSurface detached")
mapboxCarMapSurface.handleStyleOnDetached(styleLoadedListener)
?.removeStyleLayer(CAR_NAVIGATION_VIEW_LAYER_ID)
MapboxNavigationApp.unregisterObserver(roadNameObserver)
roadNameObserver?.let { MapboxNavigationApp.unregisterObserver(it) }
roadNameObserver = null
routeShieldApi.cancel()
mapUserStyleObserver.onDetached(mapboxCarMapSurface)
super.onDetached(mapboxCarMapSurface)
}

private fun roadLabelOptions(): RoadLabelOptions =
private fun roadLabelOptions(carContext: CarContext): RoadLabelOptions =
if (carContext.isDarkMode) {
DARK_OPTIONS
} else {
Expand Down