Skip to content

Commit 579b496

Browse files
dzinadgithub-actions[bot]
authored andcommitted
NAVAND-5763: support DVAs in Coordinator (#9473)
* NAVAND-5763: support DVAs in Coordinator * NAVAND-5763: handle DVA clicks under the hood * NAVAND-5763: do not intercept clicks from custom view if it already has OnCLickListener * NAVAND-5763: rename callout view and api to callouts GitOrigin-RevId: fbe091e6846e9c2a3170b9fb6531204874da52fd
1 parent a14ce57 commit 579b496

File tree

11 files changed

+79
-48
lines changed

11 files changed

+79
-48
lines changed

ui-maps/api/current.txt

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -984,16 +984,29 @@ package com.mapbox.navigation.ui.maps.route.callout.api {
984984
method public abstract void onUpdateAnchor(android.view.View view, com.mapbox.maps.ViewAnnotationAnchorConfig anchor);
985985
}
986986

987-
@RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @com.mapbox.navigation.base.ExperimentalPreviewMapboxNavigationAPI public final class MapboxRouteCalloutApi {
987+
@RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @com.mapbox.navigation.base.ExperimentalPreviewMapboxNavigationAPI public final class MapboxRouteCalloutsApi {
988+
ctor public MapboxRouteCalloutsApi();
988989
method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public com.mapbox.navigation.ui.maps.route.callout.model.RouteCalloutData setNavigationRoutes(java.util.List<com.mapbox.navigation.base.route.NavigationRoute> newRoutes, java.util.List<com.mapbox.navigation.core.routealternatives.AlternativeRouteMetadata> alternativeRoutesMetadata);
989990
}
990991

992+
@RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public final class MapboxRouteCalloutsView {
993+
ctor public MapboxRouteCalloutsView(com.mapbox.maps.viewannotation.ViewAnnotationManager viewAnnotationManager, com.mapbox.navigation.ui.maps.route.callout.api.MapboxRouteCalloutAdapter routeCalloutAdapter, com.mapbox.navigation.ui.maps.route.callout.api.RouteLayerIdProvider layerIdProvider);
994+
method public void release();
995+
method public void renderCallouts(com.mapbox.navigation.ui.maps.route.callout.model.RouteCalloutData routeCalloutResult);
996+
}
997+
998+
@RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public fun interface RouteLayerIdProvider {
999+
method public String? getLayerId(String routeId);
1000+
}
1001+
9911002
}
9921003

9931004
package com.mapbox.navigation.ui.maps.route.callout.model {
9941005

9951006
@com.mapbox.navigation.base.ExperimentalPreviewMapboxNavigationAPI public final class CalloutViewHolder {
1007+
method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public android.view.View getView();
9961008
method public com.mapbox.navigation.ui.maps.route.callout.model.CalloutViewHolder.Builder toBuilder();
1009+
property @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public final android.view.View view;
9971010
}
9981011

9991012
@com.mapbox.navigation.base.ExperimentalPreviewMapboxNavigationAPI public static final class CalloutViewHolder.Builder {

ui-maps/src/main/java/com/mapbox/navigation/ui/maps/internal/route/callout/model/MapboxRouteCalloutApiFactory.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@ package com.mapbox.navigation.ui.maps.internal.route.callout.model
22

33
import androidx.annotation.RestrictTo
44
import com.mapbox.navigation.base.ExperimentalPreviewMapboxNavigationAPI
5-
import com.mapbox.navigation.ui.maps.route.callout.api.MapboxRouteCalloutApi
5+
import com.mapbox.navigation.ui.maps.route.callout.api.MapboxRouteCalloutsApi
66

77
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
88
object MapboxRouteCalloutApiFactory {
99
@OptIn(ExperimentalPreviewMapboxNavigationAPI::class)
10-
fun create(): MapboxRouteCalloutApi {
11-
return MapboxRouteCalloutApi()
10+
fun create(): MapboxRouteCalloutsApi {
11+
return MapboxRouteCalloutsApi()
1212
}
1313
}

ui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/callout/api/MapboxRouteCalloutApi.kt renamed to ui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/callout/api/MapboxRouteCalloutsApi.kt

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,26 +15,26 @@ import kotlin.time.DurationUnit
1515
* Responsible for generating route line annotation data which can be rendered on the map
1616
* to visualize a callout.
1717
* The callout is calculated based on the routes and the data returned should
18-
* be rendered on the map using the [MapboxRouteCalloutView] class. Generally this class should be
18+
* be rendered on the map using the [MapboxRouteCalloutsView] class. Generally this class should be
1919
* called once new route (or set of routes) is available
2020
*
21-
* The two principal classes for the route callouts are the [MapboxRouteCalloutApi] and the
22-
* [MapboxRouteCalloutView].
21+
* The two principal classes for the route callouts are the [MapboxRouteCalloutsApi] and the
22+
* [MapboxRouteCalloutsView].
2323
*
24-
* Like the route line components the [MapboxRouteCalloutApi] consumes data from the Navigation SDK,
24+
* Like the route line components the [MapboxRouteCalloutsApi] consumes data from the Navigation SDK,
2525
* specifically the [NavigationRoute], and produces data for rendering on the map by the
26-
* [MapboxRouteCalloutView].
26+
* [MapboxRouteCalloutsView].
2727
*/
2828
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
2929
@ExperimentalPreviewMapboxNavigationAPI
30-
class MapboxRouteCalloutApi internal constructor() {
30+
class MapboxRouteCalloutsApi {
3131

3232
/**
3333
* Sets the routes that will be operated on.
3434
*
3535
* @param newRoutes one or more routes. The first route in the collection will be considered
3636
* the primary route and any additional routes will be alternate routes.
37-
* @param alternativeRoutesMetadata if available, helps [MapboxRouteCalloutApi] find
37+
* @param alternativeRoutesMetadata if available, helps [MapboxRouteCalloutsApi] find
3838
* the deviation point to extract different geometry segment the callout should be attaching to.
3939
* See [MapboxNavigation.getAlternativeMetadataFor].
4040
*/
@@ -75,6 +75,8 @@ class MapboxRouteCalloutApi internal constructor() {
7575
)
7676

7777
alternativeRoutes.mapTo(destination = this) { alternativeRoute ->
78+
// Query AlternativeMetadata first, because for CAs it will contain full duration (from start of primary route),
79+
// while in Directions it will be the "cut" duration from the point where it was requested.
7880
val altRouteDuration =
7981
alternativeRouteMetadata.firstOrNull {
8082
it.navigationRoute.id == alternativeRoute.id

ui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/callout/api/MapboxRouteCalloutView.kt renamed to ui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/callout/api/MapboxRouteCalloutsView.kt

Lines changed: 16 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,28 @@
11
package com.mapbox.navigation.ui.maps.route.callout.api
22

33
import android.view.View
4+
import androidx.annotation.RestrictTo
45
import com.mapbox.maps.AnnotatedLayerFeature
56
import com.mapbox.maps.ViewAnnotationAnchorConfig
67
import com.mapbox.maps.logW
78
import com.mapbox.maps.viewannotation.OnViewAnnotationUpdatedListener
89
import com.mapbox.maps.viewannotation.ViewAnnotationManager
910
import com.mapbox.maps.viewannotation.annotatedLayerFeature
1011
import com.mapbox.navigation.base.ExperimentalPreviewMapboxNavigationAPI
11-
import com.mapbox.navigation.ui.maps.route.RouteLayerConstants
1212
import com.mapbox.navigation.ui.maps.route.callout.model.CalloutViewHolder
1313
import com.mapbox.navigation.ui.maps.route.callout.model.RouteCallout
1414
import com.mapbox.navigation.ui.maps.route.callout.model.RouteCalloutData
15-
import com.mapbox.navigation.ui.maps.route.line.api.MapboxRouteLineView
1615

1716
/**
18-
* Responsible for rendering data generated by the [MapboxRouteCalloutApi] class. The
17+
* Responsible for rendering data generated by the [MapboxRouteCalloutsApi] class. The
1918
* data will change the appearance/behaviour of the route callout(s) on the map.
2019
*/
2120
@OptIn(ExperimentalPreviewMapboxNavigationAPI::class)
22-
internal class MapboxRouteCalloutView(
21+
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
22+
class MapboxRouteCalloutsView(
2323
private val viewAnnotationManager: ViewAnnotationManager,
2424
private val routeCalloutAdapter: MapboxRouteCalloutAdapter,
25-
private val routeLineView: MapboxRouteLineView,
25+
private val layerIdProvider: RouteLayerIdProvider,
2626
) {
2727

2828
private var routeCalloutResult: RouteCalloutData? = null
@@ -37,30 +37,29 @@ internal class MapboxRouteCalloutView(
3737
private val dataChangedObserver: () -> Unit = {
3838
routeCalloutResult?.let { renderCallouts(it) }
3939
}
40+
private val currentLayersToAttach = mutableSetOf<String>()
4041

4142
init {
4243
viewAnnotationManager.addOnViewAnnotationUpdatedListener(onViewAnnotationUpdatedListener)
43-
viewAnnotationManager.viewAnnotationAvoidLayers =
44-
HashSet(
45-
viewAnnotationManager.viewAnnotationAvoidLayers + layersToAttach,
46-
)
4744
routeCalloutAdapter.registerDataObserver(dataChangedObserver)
4845
}
4946

5047
/**
5148
* Renders [RouteCalloutData]
5249
*/
53-
internal fun renderCallouts(
50+
fun renderCallouts(
5451
routeCalloutResult: RouteCalloutData,
5552
) {
5653
this.routeCalloutResult = routeCalloutResult
5754
clear()
5855

5956
routeCalloutResult.callouts.forEach { calloutRoute ->
60-
val layer = routeLineView.getRouteMainLayerIdForFeature(calloutRoute.route.id)
57+
val layer = layerIdProvider.getLayerId(calloutRoute.route.id)
6158
if (layer != null) {
6259
val viewHolder = createViewHolder(calloutRoute)
6360

61+
viewAnnotationManager.viewAnnotationAvoidLayers += layer
62+
currentLayersToAttach.add(layer)
6463
addViewAnnotation(layer, viewHolder)
6564
} else {
6665
logW(
@@ -71,7 +70,9 @@ internal class MapboxRouteCalloutView(
7170
}
7271
}
7372

74-
internal fun release() {
73+
fun release() {
74+
this.routeCalloutResult = null
75+
clear()
7576
viewAnnotationManager.removeOnViewAnnotationUpdatedListener(onViewAnnotationUpdatedListener)
7677
routeCalloutAdapter.removeDataObserver(dataChangedObserver)
7778
}
@@ -89,6 +90,8 @@ internal class MapboxRouteCalloutView(
8990

9091
private fun clear() {
9192
getAllCalloutViews().forEach { viewAnnotationManager.removeViewAnnotation(it) }
93+
viewAnnotationManager.viewAnnotationAvoidLayers -= currentLayersToAttach
94+
currentLayersToAttach.clear()
9295
}
9396

9497
private fun createViewHolder(callout: RouteCallout): CalloutViewHolder {
@@ -98,20 +101,14 @@ internal class MapboxRouteCalloutView(
98101
}
99102

100103
private fun getAllCalloutViews(): List<View> {
101-
return layersToAttach.mapNotNull {
104+
return currentLayersToAttach.mapNotNull {
102105
viewAnnotationManager.getViewAnnotation(
103106
AnnotatedLayerFeature.Builder().layerId(it).build(),
104107
)
105108
}
106109
}
107110

108111
private companion object {
109-
private val layersToAttach = setOf(
110-
RouteLayerConstants.LAYER_GROUP_1_MAIN,
111-
RouteLayerConstants.LAYER_GROUP_2_MAIN,
112-
RouteLayerConstants.LAYER_GROUP_3_MAIN,
113-
)
114-
115112
private const val TAG = "MapboxRouteCalloutView"
116113
}
117114
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package com.mapbox.navigation.ui.maps.route.callout.api
2+
3+
import androidx.annotation.RestrictTo
4+
5+
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
6+
fun interface RouteLayerIdProvider {
7+
fun getLayerId(routeId: String): String?
8+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package com.mapbox.navigation.ui.maps.route.callout.api
2+
3+
import com.mapbox.navigation.ui.maps.route.line.api.MapboxRouteLineView
4+
5+
internal class RouteLineViewBasedLayerIdProvider(
6+
private val routeLineView: MapboxRouteLineView,
7+
) : RouteLayerIdProvider {
8+
override fun getLayerId(routeId: String): String? {
9+
return routeLineView.getRouteMainLayerIdForFeature(routeId)
10+
}
11+
}

ui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/callout/model/CalloutViewHolder.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.mapbox.navigation.ui.maps.route.callout.model
22

33
import android.view.View
4+
import androidx.annotation.RestrictTo
45
import com.mapbox.maps.ViewAnnotationOptions
56
import com.mapbox.navigation.base.ExperimentalPreviewMapboxNavigationAPI
67
import com.mapbox.navigation.ui.maps.route.line.api.MapboxRouteLineView
@@ -12,7 +13,7 @@ import com.mapbox.navigation.ui.maps.route.line.api.MapboxRouteLineView
1213
*/
1314
@ExperimentalPreviewMapboxNavigationAPI
1415
class CalloutViewHolder private constructor(
15-
internal val view: View,
16+
@get:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) val view: View,
1617
internal val options: ViewAnnotationOptions,
1718
) {
1819

ui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/api/MapboxRouteLineApi.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ import com.mapbox.navigation.ui.maps.internal.route.line.MapboxRouteLineUtils.la
3737
import com.mapbox.navigation.ui.maps.internal.route.line.MapboxRouteLineUtils.layerGroup3SourceLayerIds
3838
import com.mapbox.navigation.ui.maps.internal.route.line.toStylePropertyValue
3939
import com.mapbox.navigation.ui.maps.route.RouteLayerConstants
40-
import com.mapbox.navigation.ui.maps.route.callout.api.MapboxRouteCalloutApi
40+
import com.mapbox.navigation.ui.maps.route.callout.api.MapboxRouteCalloutsApi
4141
import com.mapbox.navigation.ui.maps.route.callout.model.RouteCalloutData
4242
import com.mapbox.navigation.ui.maps.route.line.RouteLineHistoryRecordingApiSender
4343
import com.mapbox.navigation.ui.maps.route.line.model.ClosestRouteValue
@@ -262,7 +262,7 @@ class MapboxRouteLineApi @VisibleForTesting internal constructor(
262262
private var lastLocationPoint: Point? = null
263263

264264
@OptIn(ExperimentalPreviewMapboxNavigationAPI::class)
265-
private val calloutApi: MapboxRouteCalloutApi?
265+
private val calloutApi: MapboxRouteCalloutsApi?
266266

267267
companion object {
268268
private const val INVALID_ACTIVE_LEG_INDEX = -1
@@ -293,7 +293,7 @@ class MapboxRouteLineApi @VisibleForTesting internal constructor(
293293
)
294294
@OptIn(ExperimentalPreviewMapboxNavigationAPI::class)
295295
calloutApi = if (routeLineOptions.isRouteCalloutsEnabled) {
296-
MapboxRouteCalloutApi()
296+
MapboxRouteCalloutsApi()
297297
} else {
298298
null
299299
}

ui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/api/MapboxRouteLineView.kt

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,8 @@ import com.mapbox.navigation.ui.maps.route.RouteLayerConstants.MASKING_LAYER_TRA
6060
import com.mapbox.navigation.ui.maps.route.RouteLayerConstants.MASKING_LAYER_TRAIL_CASING
6161
import com.mapbox.navigation.ui.maps.route.callout.api.DefaultRouteCalloutAdapter
6262
import com.mapbox.navigation.ui.maps.route.callout.api.MapboxRouteCalloutAdapter
63-
import com.mapbox.navigation.ui.maps.route.callout.api.MapboxRouteCalloutView
63+
import com.mapbox.navigation.ui.maps.route.callout.api.MapboxRouteCalloutsView
64+
import com.mapbox.navigation.ui.maps.route.callout.api.RouteLineViewBasedLayerIdProvider
6465
import com.mapbox.navigation.ui.maps.route.callout.model.RouteCalloutData
6566
import com.mapbox.navigation.ui.maps.route.line.RouteLineHistoryRecordingViewSender
6667
import com.mapbox.navigation.ui.maps.route.line.model.MapboxRouteLineApiOptions
@@ -139,7 +140,7 @@ class MapboxRouteLineView @VisibleForTesting internal constructor(
139140
RouteLineHistoryRecordingViewSender(),
140141
)
141142

142-
private var routeCalloutView: MapboxRouteCalloutView? = null
143+
private var routeCalloutView: MapboxRouteCalloutsView? = null
143144

144145
@OptIn(ExperimentalPreviewMapboxNavigationAPI::class)
145146
private var lastRouteCalloutData: RouteCalloutData? = null
@@ -708,10 +709,10 @@ class MapboxRouteLineView @VisibleForTesting internal constructor(
708709
routeCalloutView?.release()
709710
}
710711

711-
routeCalloutView = MapboxRouteCalloutView(
712+
routeCalloutView = MapboxRouteCalloutsView(
712713
viewAnnotationManager,
713714
adapter,
714-
routeLineView = this,
715+
layerIdProvider = RouteLineViewBasedLayerIdProvider(this),
715716
)
716717

717718
lastRouteCalloutData?.let { data -> routeCalloutView?.renderCallouts(data) }

ui-maps/src/test/java/com/mapbox/navigation/ui/maps/route/callout/api/MapboxRouteCalloutApiTest.kt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ class MapboxRouteCalloutApiTest {
1717
@Test
1818
fun `generate a single callout when there is only one route`() {
1919
val routes = createMockRoutes(routeCount = 1)
20-
val result = MapboxRouteCalloutApi().setNavigationRoutes(routes, emptyList())
20+
val result = MapboxRouteCalloutsApi().setNavigationRoutes(routes, emptyList())
2121

2222
assertTrue(result.callouts.first().isPrimary)
2323
assertEquals(1, result.callouts.size)
@@ -27,7 +27,7 @@ class MapboxRouteCalloutApiTest {
2727
fun `generate eta callouts for each route`() {
2828
val routes = createMockRoutes(routeCount = 5)
2929

30-
val result = MapboxRouteCalloutApi().setNavigationRoutes(routes, emptyList())
30+
val result = MapboxRouteCalloutsApi().setNavigationRoutes(routes, emptyList())
3131

3232
assertEquals(5, result.callouts.size)
3333
}
@@ -36,7 +36,7 @@ class MapboxRouteCalloutApiTest {
3636
fun `only one eta callouts should be primary`() {
3737
val routes = createMockRoutes(routeCount = 5)
3838

39-
val result = MapboxRouteCalloutApi().setNavigationRoutes(routes, emptyList())
39+
val result = MapboxRouteCalloutsApi().setNavigationRoutes(routes, emptyList())
4040

4141
assertEquals(1, result.callouts.count { it.isPrimary })
4242
}
@@ -45,7 +45,7 @@ class MapboxRouteCalloutApiTest {
4545
fun `first route callout should have duration difference 0`() {
4646
val routes = createMockRoutes(routeCount = 5)
4747

48-
val result = MapboxRouteCalloutApi().setNavigationRoutes(routes, emptyList())
48+
val result = MapboxRouteCalloutsApi().setNavigationRoutes(routes, emptyList())
4949

5050
assertEquals(0.seconds, result.callouts.first().durationDifferenceWithPrimary)
5151
}
@@ -57,7 +57,7 @@ class MapboxRouteCalloutApiTest {
5757
durationList = listOf(120.0, 60.0, 180.0),
5858
)
5959

60-
val callouts = MapboxRouteCalloutApi().setNavigationRoutes(routes, emptyList()).callouts
60+
val callouts = MapboxRouteCalloutsApi().setNavigationRoutes(routes, emptyList()).callouts
6161
val actualDuration = callouts.map { it.durationDifferenceWithPrimary }
6262

6363
assertEquals(listOf(0.seconds, 60.seconds, (-60).seconds), actualDuration)

0 commit comments

Comments
 (0)