Skip to content

Commit 4ab858b

Browse files
authored
Add listener for updates to map way name (#1544)
1 parent 60b1f66 commit 4ab858b

File tree

8 files changed

+256
-60
lines changed

8 files changed

+256
-60
lines changed

libandroid-navigation-ui/build.gradle

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,16 @@ android {
2929
testCoverageEnabled = true
3030
}
3131
}
32+
33+
testOptions {
34+
unitTests.returnDefaultValues = true
35+
unitTests.includeAndroidResources = true
36+
unitTests.all {
37+
jacoco {
38+
includeNoLocationClasses = true
39+
}
40+
}
41+
}
3242
}
3343

3444
dependencies {

libandroid-navigation-ui/src/main/java/com/mapbox/services/android/navigation/ui/v5/map/MapWayname.java

Lines changed: 49 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@
1414
import com.mapbox.services.android.navigation.v5.navigation.MapboxNavigation;
1515

1616
import java.util.ArrayList;
17+
import java.util.HashSet;
1718
import java.util.List;
19+
import java.util.Set;
1820

1921
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconImage;
2022
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.visibility;
@@ -24,13 +26,14 @@
2426
class MapWayname {
2527

2628
private static final String NAME_PROPERTY = "name";
29+
private final MapWaynameProgressChangeListener progressChangeListener = new MapWaynameProgressChangeListener(this);
30+
private final Set<OnWayNameChangedListener> onWayNameChangedListeners;
2731
private WaynameLayoutProvider layoutProvider;
2832
private MapLayerInteractor layerInteractor;
2933
private WaynameFeatureFinder featureInteractor;
3034
private List<Point> currentStepPoints = new ArrayList<>();
3135
private Location currentLocation = null;
3236
private MapboxNavigation navigation;
33-
private final MapWaynameProgressChangeListener progressChangeListener = new MapWaynameProgressChangeListener(this);
3437
private boolean isAutoQueryEnabled;
3538
private boolean isVisible;
3639
private FeatureFilterTask filterTask;
@@ -42,19 +45,20 @@ class MapWayname {
4245
this.layerInteractor = layerInteractor;
4346
this.featureInteractor = featureInteractor;
4447
paddingAdjustor.updatePaddingWithDefault();
48+
this.onWayNameChangedListeners = new HashSet<>();
4549
}
4650

4751
void updateWaynameWithPoint(PointF point, SymbolLayer waynameLayer) {
48-
if (!isAutoQueryEnabled || !isVisible) {
52+
if (!isAutoQueryEnabled) {
4953
return;
5054
}
51-
List<Feature> roads = findRoadLabelFeatures(point);
52-
boolean shouldBeVisible = !roads.isEmpty();
53-
adjustWaynameVisibility(shouldBeVisible, waynameLayer);
54-
if (!shouldBeVisible) {
55+
List<Feature> roadLabelFeatures = findRoadLabelFeatures(point);
56+
boolean invalidLabelFeatures = roadLabelFeatures.isEmpty();
57+
if (invalidLabelFeatures) {
58+
updateVisibility(false, waynameLayer);
5559
return;
5660
}
57-
updateLayerWithRoadLabelFeatures(roads, waynameLayer);
61+
executeFeatureFilterTask(roadLabelFeatures, waynameLayer);
5862
}
5963

6064
void updateWaynameLayer(String wayname, SymbolLayer waynameLayer) {
@@ -63,14 +67,6 @@ void updateWaynameLayer(String wayname, SymbolLayer waynameLayer) {
6367
}
6468
}
6569

66-
void updateWaynameVisibility(boolean isVisible, SymbolLayer waynameLayer) {
67-
this.isVisible = isVisible;
68-
if (checkWaynameVisibility(isVisible, waynameLayer)) {
69-
return;
70-
}
71-
adjustWaynameVisibility(isVisible, waynameLayer);
72-
}
73-
7470
void updateProgress(Location currentLocation, List<Point> currentStepPoints) {
7571
if (!this.currentStepPoints.equals(currentStepPoints)) {
7672
this.currentStepPoints = currentStepPoints;
@@ -80,6 +76,11 @@ void updateProgress(Location currentLocation, List<Point> currentStepPoints) {
8076
}
8177
}
8278

79+
void updateWaynameVisibility(boolean isVisible, SymbolLayer waynameLayer) {
80+
this.isVisible = isVisible;
81+
updateVisibility(isVisible, waynameLayer);
82+
}
83+
8384
void updateWaynameQueryMap(boolean isEnabled) {
8485
isAutoQueryEnabled = isEnabled;
8586
}
@@ -97,6 +98,14 @@ void addProgressChangeListener(MapboxNavigation navigation) {
9798
navigation.addProgressChangeListener(progressChangeListener);
9899
}
99100

101+
boolean addOnWayNameChangedListener(OnWayNameChangedListener listener) {
102+
return onWayNameChangedListeners.add(listener);
103+
}
104+
105+
boolean removeOnWayNameChangedListener(OnWayNameChangedListener listener) {
106+
return onWayNameChangedListeners.remove(listener);
107+
}
108+
100109
void onStart() {
101110
if (navigation != null) {
102111
navigation.addProgressChangeListener(progressChangeListener);
@@ -117,15 +126,6 @@ private List<Feature> findRoadLabelFeatures(PointF point) {
117126
return featureInteractor.queryRenderedFeatures(point, layerIds);
118127
}
119128

120-
private void updateLayerWithRoadLabelFeatures(List<Feature> roadFeatures, final SymbolLayer waynameLayer) {
121-
boolean isValidFeatureList = !roadFeatures.isEmpty();
122-
if (isValidFeatureList) {
123-
executeFeatureFilterTask(roadFeatures, waynameLayer);
124-
} else {
125-
updateWaynameVisibility(false, waynameLayer);
126-
}
127-
}
128-
129129
private void executeFeatureFilterTask(List<Feature> roadFeatures, final SymbolLayer waynameLayer) {
130130
if (isTaskRunning()) {
131131
filterTask.cancel(true);
@@ -145,22 +145,27 @@ public void onFeatureFiltered(@NonNull Feature feature) {
145145

146146
private boolean isTaskRunning() {
147147
return filterTask != null
148-
&& (filterTask.getStatus() == AsyncTask.Status.PENDING || filterTask.getStatus() == AsyncTask.Status.RUNNING);
148+
&& (filterTask.getStatus() == AsyncTask.Status.PENDING
149+
|| filterTask.getStatus() == AsyncTask.Status.RUNNING);
149150
}
150151

151152
private boolean hasValidProgressData() {
152153
return currentLocation != null && !currentStepPoints.isEmpty();
153154
}
154155

155156
private void createWaynameIcon(String wayname, Layer waynameLayer) {
156-
boolean isVisible = waynameLayer.getVisibility().getValue().contentEquals(Property.VISIBLE);
157-
if (isVisible) {
158-
Bitmap waynameLayoutBitmap = layoutProvider.generateLayoutBitmap(wayname);
159-
if (waynameLayoutBitmap != null) {
160-
layerInteractor.addLayerImage(MAPBOX_WAYNAME_ICON, waynameLayoutBitmap);
161-
waynameLayer.setProperties(iconImage(MAPBOX_WAYNAME_ICON));
162-
}
157+
Bitmap waynameLayoutBitmap = layoutProvider.generateLayoutBitmap(wayname);
158+
if (waynameLayoutBitmap != null) {
159+
layerInteractor.addLayerImage(MAPBOX_WAYNAME_ICON, waynameLayoutBitmap);
160+
waynameLayer.setProperties(iconImage(MAPBOX_WAYNAME_ICON));
161+
}
162+
}
163+
164+
private void updateVisibility(boolean isVisible, SymbolLayer waynameLayer) {
165+
if (checkWaynameVisibility(isVisible, waynameLayer)) {
166+
return;
163167
}
168+
adjustWaynameVisibility(isVisible, waynameLayer);
164169
}
165170

166171
private boolean checkWaynameVisibility(boolean isVisible, Layer waynameLayer) {
@@ -183,10 +188,21 @@ private void updateWaynameLayerWithNameProperty(SymbolLayer waynameLayer, Featur
183188
String currentWayname = roadFeature.getStringProperty(NAME_PROPERTY);
184189
boolean newWayname = !wayname.contentEquals(currentWayname);
185190
if (newWayname) {
191+
updateListenersWith(currentWayname);
186192
wayname = currentWayname;
187-
updateWaynameVisibility(true, waynameLayer);
193+
if (isVisible) {
194+
updateVisibility(true, waynameLayer);
195+
}
188196
updateWaynameLayer(wayname, waynameLayer);
189197
}
198+
} else {
199+
updateVisibility(false, waynameLayer);
200+
}
201+
}
202+
203+
private void updateListenersWith(String currentWayName) {
204+
for (OnWayNameChangedListener listener : onWayNameChangedListeners) {
205+
listener.onWayNameChanged(currentWayName);
190206
}
191207
}
192208
}

libandroid-navigation-ui/src/main/java/com/mapbox/services/android/navigation/ui/v5/map/NavigationMapboxMap.java

Lines changed: 39 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ public class NavigationMapboxMap {
8080
private NavigationMapRoute mapRoute;
8181
private LocationComponent locationComponent;
8282
private MapPaddingAdjustor mapPaddingAdjustor;
83-
private MapWayname mapWayname;
83+
private MapWayname mapWayName;
8484
private SymbolLayer waynameLayer;
8585
private MapLayerInteractor layerInteractor;
8686
private List<Marker> mapMarkers = new ArrayList<>();
@@ -117,6 +117,11 @@ public NavigationMapboxMap(@NonNull MapView mapView, @NonNull MapboxMap mapboxMa
117117
this.mapRoute = mapRoute;
118118
}
119119

120+
// Package private (no modifier) for testing purposes
121+
NavigationMapboxMap(MapWayname mapWayName) {
122+
this.mapWayName = mapWayName;
123+
}
124+
120125
/**
121126
* Adds a marker icon on the map at the given position.
122127
* <p>
@@ -178,7 +183,7 @@ public void updateLocationLayerRenderMode(@RenderMode.Mode int renderMode) {
178183
public void addProgressChangeListener(MapboxNavigation navigation) {
179184
mapRoute.addProgressChangeListener(navigation);
180185
mapCamera.addProgressChangeListener(navigation);
181-
mapWayname.addProgressChangeListener(navigation);
186+
mapWayName.addProgressChangeListener(navigation);
182187
}
183188

184189
/**
@@ -192,8 +197,8 @@ public void addProgressChangeListener(MapboxNavigation navigation) {
192197
* @param outState to store state variables
193198
*/
194199
public void saveStateWith(String key, Bundle outState) {
195-
boolean isVisible = mapWayname.isVisible();
196-
String waynameText = mapWayname.retrieveWayname();
200+
boolean isVisible = mapWayName.isVisible();
201+
String waynameText = mapWayName.retrieveWayname();
197202
int[] mapPadding = mapPaddingAdjustor.retrieveCurrentPadding();
198203
boolean isUsingDefault = mapPaddingAdjustor.isUsingDefault();
199204
@NavigationCamera.TrackingMode
@@ -366,7 +371,7 @@ public void showRouteOverview(int[] padding) {
366371
* @param wayname text to be set
367372
*/
368373
public void updateWaynameView(String wayname) {
369-
mapWayname.updateWaynameLayer(wayname, waynameLayer);
374+
mapWayName.updateWaynameLayer(wayname, waynameLayer);
370375
}
371376

372377
/**
@@ -375,7 +380,7 @@ public void updateWaynameView(String wayname) {
375380
* @param isVisible true to show, false to hide
376381
*/
377382
public void updateWaynameVisibility(boolean isVisible) {
378-
mapWayname.updateWaynameVisibility(isVisible, waynameLayer);
383+
mapWayName.updateWaynameVisibility(isVisible, waynameLayer);
379384
}
380385

381386
/**
@@ -384,7 +389,7 @@ public void updateWaynameVisibility(boolean isVisible) {
384389
* @return true if visible, false if not
385390
*/
386391
public boolean isWaynameVisible() {
387-
return mapWayname.isVisible();
392+
return mapWayName.isVisible();
388393
}
389394

390395
/**
@@ -393,7 +398,7 @@ public boolean isWaynameVisible() {
393398
* @param isEnabled true to enable, false to disable
394399
*/
395400
public void updateWaynameQueryMap(boolean isEnabled) {
396-
mapWayname.updateWaynameQueryMap(isEnabled);
401+
mapWayName.updateWaynameQueryMap(isEnabled);
397402
}
398403

399404
/**
@@ -403,7 +408,7 @@ public void updateWaynameQueryMap(boolean isEnabled) {
403408
public void onStart() {
404409
mapCamera.onStart();
405410
mapRoute.onStart();
406-
mapWayname.onStart();
411+
mapWayName.onStart();
407412
}
408413

409414
/**
@@ -413,7 +418,7 @@ public void onStart() {
413418
public void onStop() {
414419
mapCamera.onStop();
415420
mapRoute.onStop();
416-
mapWayname.onStop();
421+
mapWayName.onStop();
417422
}
418423

419424
/**
@@ -496,6 +501,28 @@ public void removeOnCameraTrackingChangedListener(OnCameraTrackingChangedListene
496501
locationComponent.removeOnCameraTrackingChangedListener(listener);
497502
}
498503

504+
/**
505+
* Add a {@link OnWayNameChangedListener} for listening to updates
506+
* to the way name shown on the map below the location icon.
507+
*
508+
* @param listener to be added
509+
* @return true if added, false if listener was not found
510+
*/
511+
public boolean addOnWayNameChangedListener(OnWayNameChangedListener listener) {
512+
return mapWayName.addOnWayNameChangedListener(listener);
513+
}
514+
515+
/**
516+
* Remove a {@link OnWayNameChangedListener} for listening to updates
517+
* to the way name shown on the map below the location icon.
518+
*
519+
* @param listener to be removed
520+
* @return true if removed, false if listener was not found
521+
*/
522+
public boolean removeOnWayNameChangedListener(OnWayNameChangedListener listener) {
523+
return mapWayName.removeOnWayNameChangedListener(listener);
524+
}
525+
499526
/**
500527
* Use this method to position the location icon on the map.
501528
* <p>
@@ -541,7 +568,7 @@ private void initializeWayname(MapView mapView, MapboxMap mapboxMap, MapLayerInt
541568
WaynameLayoutProvider layoutProvider = new WaynameLayoutProvider(mapView.getContext());
542569
WaynameFeatureFinder featureInteractor = new WaynameFeatureFinder(mapboxMap);
543570
initializeWaynameLayer(layerInteractor);
544-
mapWayname = new MapWayname(layoutProvider, layerInteractor, featureInteractor, paddingAdjustor);
571+
mapWayName = new MapWayname(layoutProvider, layerInteractor, featureInteractor, paddingAdjustor);
545572
}
546573

547574
private void initializeWaynameLayer(MapLayerInteractor layerInteractor) {
@@ -607,6 +634,6 @@ private void removeAllMarkers() {
607634
private void updateMapWaynameWithLocation(Location location) {
608635
LatLng latLng = new LatLng(location);
609636
PointF mapPoint = mapboxMap.getProjection().toScreenLocation(latLng);
610-
mapWayname.updateWaynameWithPoint(mapPoint, waynameLayer);
637+
mapWayName.updateWaynameWithPoint(mapPoint, waynameLayer);
611638
}
612639
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package com.mapbox.services.android.navigation.ui.v5.map;
2+
3+
/**
4+
* A listener that can be added to the {@link NavigationMapboxMap} with
5+
* {@link NavigationMapboxMap#addOnWayNameChangedListener(OnWayNameChangedListener)}.
6+
* <p>
7+
* This listener is triggered when a new way name is found along the route. It will be triggered
8+
* regardless of the map way name visibility ({@link NavigationMapboxMap#updateWaynameVisibility(boolean)}).
9+
* This is so you can hide our implementation of the way name UI and update your own if you'd like.
10+
*/
11+
public interface OnWayNameChangedListener {
12+
13+
/**
14+
* Triggered every time a new way name is found along the route.
15+
* This will mainly be when transitioning steps, onto new roads.
16+
*
17+
* @param wayName found along the route
18+
*/
19+
void onWayNameChanged(String wayName);
20+
}

0 commit comments

Comments
 (0)