diff --git a/libnavui-androidauto/api/current.txt b/libnavui-androidauto/api/current.txt index 7b3cba94031..53c2e281dad 100644 --- a/libnavui-androidauto/api/current.txt +++ b/libnavui-androidauto/api/current.txt @@ -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 road, java.util.List 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 road, java.util.List 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 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? surfaceDimensions(); - property public final androidx.car.app.CarContext carContext; + ctor public RoadLabelSurfaceLayer(); } public abstract class RoadNameObserver implements com.mapbox.navigation.core.lifecycle.MapboxNavigationObserver { diff --git a/libnavui-androidauto/src/androidTest/java/com/mapbox/androidauto/car/navigation/roadlabel/RoadLabelRendererTest.kt b/libnavui-androidauto/src/androidTest/java/com/mapbox/androidauto/car/navigation/roadlabel/RoadLabelRendererTest.kt index 81957655c58..caf5bccb8a8 100644 --- a/libnavui-androidauto/src/androidTest/java/com/mapbox/androidauto/car/navigation/roadlabel/RoadLabelRendererTest.kt +++ b/libnavui-androidauto/src/androidTest/java/com/mapbox/androidauto/car/navigation/roadlabel/RoadLabelRendererTest.kt @@ -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() @@ -59,6 +60,7 @@ class RoadLabelRendererTest { @Test fun street_with_numbers() { val bitmap = roadLabelBitmapRenderer.render( + resources, createRoad("11th Street"), emptyList(), RoadLabelOptions.Builder() @@ -72,6 +74,7 @@ class RoadLabelRendererTest { @Test fun very_long_street_name() { val bitmap = roadLabelBitmapRenderer.render( + resources, createRoad( "Taumatawhakatangihangakoauauotamateaturipukakapikimaungahoronukupokaiwhen" + "uakitanatahu" @@ -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() @@ -106,6 +110,7 @@ class RoadLabelRendererTest { val byteArray = context.assets.open("shield.svg").use { it.readBytes() } val mapboxShield = mockk() val bitmap = roadLabelBitmapRenderer.render( + resources, listOf( createComponent("Clarksburg Road"), createComponent("/"), diff --git a/libnavui-androidauto/src/main/java/com/mapbox/androidauto/freedrive/FreeDriveCarScreen.kt b/libnavui-androidauto/src/main/java/com/mapbox/androidauto/freedrive/FreeDriveCarScreen.kt index b2aeca7958a..1cc0a9c7309 100644 --- a/libnavui-androidauto/src/main/java/com/mapbox/androidauto/freedrive/FreeDriveCarScreen.kt +++ b/libnavui-androidauto/src/main/java/com/mapbox/androidauto/freedrive/FreeDriveCarScreen.kt @@ -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 { diff --git a/libnavui-androidauto/src/main/java/com/mapbox/androidauto/navigation/ActiveGuidanceScreen.kt b/libnavui-androidauto/src/main/java/com/mapbox/androidauto/navigation/ActiveGuidanceScreen.kt index 167813244af..9b601df9522 100644 --- a/libnavui-androidauto/src/main/java/com/mapbox/androidauto/navigation/ActiveGuidanceScreen.kt +++ b/libnavui-androidauto/src/main/java/com/mapbox/androidauto/navigation/ActiveGuidanceScreen.kt @@ -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() diff --git a/libnavui-androidauto/src/main/java/com/mapbox/androidauto/navigation/roadlabel/RoadLabelRenderer.kt b/libnavui-androidauto/src/main/java/com/mapbox/androidauto/navigation/roadlabel/RoadLabelRenderer.kt index df89847ca3d..ca8fc9c319b 100644 --- a/libnavui-androidauto/src/main/java/com/mapbox/androidauto/navigation/roadlabel/RoadLabelRenderer.kt +++ b/libnavui-androidauto/src/main/java/com/mapbox/androidauto/navigation/roadlabel/RoadLabelRenderer.kt @@ -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, shields: List, 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) { @@ -54,17 +55,22 @@ class RoadLabelRenderer(private val resources: Resources) { } private fun measureRoadLabel( + resources: Resources, road: List, shields: List ): List { 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): Bitmap? { + private fun getShieldBitmap( + resources: Resources, + component: RoadComponent, + shields: List, + ): Bitmap? { val shield = component.shield?.let { shield -> shields.find { it is RouteShield.MapboxDesignedShield && it.compareWith(shield) } } ?: component.imageBaseUrl?.let { baseUrl -> diff --git a/libnavui-androidauto/src/main/java/com/mapbox/androidauto/navigation/roadlabel/RoadLabelSurfaceLayer.kt b/libnavui-androidauto/src/main/java/com/mapbox/androidauto/navigation/roadlabel/RoadLabelSurfaceLayer.kt index 1528f8cc3a8..6f3ccdd9c60 100644 --- a/libnavui-androidauto/src/main/java/com/mapbox/androidauto/navigation/roadlabel/RoadLabelSurfaceLayer.kt +++ b/libnavui-androidauto/src/main/java/com/mapbox/androidauto/navigation/roadlabel/RoadLabelSurfaceLayer.kt @@ -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 @@ -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 @@ -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, shields: List) { - val bitmap = roadLabelRenderer.render(road, shields, roadLabelOptions()) - carTextLayerHost.offerBitmap(bitmap) - } - } + private var roadNameObserver: RoadNameObserver? = null override fun children(): List = listOf(carTextLayerHost.mapScene) @@ -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, shields: List) { + 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) } @@ -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 {