Skip to content

Commit bb07856

Browse files
committed
Re-merge initial navigation native integration (#1299)
* Nav Native initial setup * Integrate more of NavigationStatus * Update for polling NavigationStatus system instead of triggered by Location * Add tunnel flag * Use runnable Date for snapped location / off route * Add voice instruction from NavigationStatus
1 parent ffadca2 commit bb07856

31 files changed

+538
-1490
lines changed

app/src/main/java/com/mapbox/services/android/navigation/testapp/activity/RerouteActivity.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import com.mapbox.services.android.navigation.v5.location.replay.ReplayRouteLocationEngine;
3333
import com.mapbox.services.android.navigation.v5.milestone.Milestone;
3434
import com.mapbox.services.android.navigation.v5.milestone.MilestoneEventListener;
35+
import com.mapbox.services.android.navigation.v5.milestone.VoiceInstructionMilestone;
3536
import com.mapbox.services.android.navigation.v5.navigation.MapboxNavigation;
3637
import com.mapbox.services.android.navigation.v5.navigation.MapboxNavigationOptions;
3738
import com.mapbox.services.android.navigation.v5.navigation.NavigationEventListener;
@@ -226,7 +227,9 @@ public void onProgressChange(Location location, RouteProgress routeProgress) {
226227

227228
@Override
228229
public void onMilestoneEvent(RouteProgress routeProgress, String instruction, Milestone milestone) {
229-
Timber.d("onMilestoneEvent - Current Instruction: " + instruction);
230+
if (milestone instanceof VoiceInstructionMilestone) {
231+
Snackbar.make(contentLayout, instruction, Snackbar.LENGTH_SHORT).show();
232+
}
230233
}
231234

232235
@Override
@@ -249,7 +252,7 @@ public void onResponse(Call<DirectionsResponse> call, Response<DirectionsRespons
249252

250253
@Override
251254
public void onFailure(Call<DirectionsResponse> call, Throwable throwable) {
252-
Timber.e("Getting directions failed: ", throwable);
255+
Timber.e(throwable);
253256
}
254257

255258
private void getRoute(Point origin, Point destination, Float bearing) {
@@ -270,12 +273,9 @@ private void drawRoute(DirectionsRoute route) {
270273
}
271274

272275
if (!points.isEmpty()) {
273-
274276
if (polyline != null) {
275277
mapboxMap.removePolyline(polyline);
276278
}
277-
278-
// Draw polyline on map
279279
polyline = mapboxMap.addPolyline(new PolylineOptions()
280280
.addAll(points)
281281
.color(Color.parseColor("#4264fb"))

build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ allprojects {
2727
google()
2828
jcenter()
2929
maven { url 'https://plugins.gradle.org/m2' }
30+
maven { url 'https://mapbox.bintray.com/mapbox' }
3031
}
3132

3233
group = GROUP

gradle/dependencies.gradle

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ ext {
1111
mapboxMapSdk : '6.5.0',
1212
mapboxSdkServices : '4.0.0',
1313
mapboxEvents : '3.2.0',
14+
mapboxNavigator : '2.0.0',
1415
locationLayerPlugin: '0.8.1',
1516
autoValue : '1.5.4',
1617
autoValueParcel : '0.2.5',
@@ -51,6 +52,7 @@ ext {
5152
mapboxSdkServices : "com.mapbox.mapboxsdk:mapbox-sdk-services:${version.mapboxSdkServices}",
5253
mapboxSdkTurf : "com.mapbox.mapboxsdk:mapbox-sdk-turf:${version.mapboxSdkServices}",
5354
mapboxEvents : "com.mapbox.mapboxsdk:mapbox-android-telemetry:${version.mapboxEvents}",
55+
mapboxNavigator : "com.mapbox.navigator:mapbox-navigation-native:${version.mapboxNavigator}",
5456
locationLayerPlugin : "com.mapbox.mapboxsdk:mapbox-android-plugin-locationlayer:${version.locationLayerPlugin}",
5557

5658
// AutoValue

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,7 @@ public void userOffRoute(Location location) {
309309
if (hasNetworkConnection()) {
310310
speechPlayer.onOffRoute();
311311
Point newOrigin = Point.fromLngLat(location.getLongitude(), location.getLatitude());
312-
sendEventOffRoute(newOrigin);
312+
handleOffRouteEvent(newOrigin);
313313
}
314314
}
315315
};
@@ -451,7 +451,7 @@ private void sendEventArrival(RouteProgress routeProgress, Milestone milestone)
451451
}
452452
}
453453

454-
private void sendEventOffRoute(Point newOrigin) {
454+
private void handleOffRouteEvent(Point newOrigin) {
455455
if (navigationViewEventDispatcher != null && navigationViewEventDispatcher.allowRerouteFrom(newOrigin)) {
456456
navigationViewEventDispatcher.onOffRoute(newOrigin);
457457
OffRouteEvent event = new OffRouteEvent(newOrigin, routeProgress);

libandroid-navigation-ui/src/test/java/com/mapbox/services/android/navigation/ui/v5/TestRouteProgressBuilder.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ RouteProgress buildTestRouteProgress(DirectionsRoute route,
6363
.intersectionDistancesAlongStep(intersectionDistances)
6464
.stepIndex(stepIndex)
6565
.legIndex(legIndex)
66+
.inTunnel(false)
6667
.build();
6768
}
6869

libandroid-navigation/build.gradle

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ dependencies {
4343
api dependenciesList.mapboxSdkServices
4444
api dependenciesList.mapboxSdkTurf
4545

46+
// Navigator
47+
implementation dependenciesList.mapboxNavigator
48+
4649
// Support
4750
implementation dependenciesList.supportAppcompatV7
4851

Lines changed: 32 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
11
package com.mapbox.services.android.navigation.v5.milestone;
22

33
import com.mapbox.api.directions.v5.models.DirectionsRoute;
4-
import com.mapbox.api.directions.v5.models.LegStep;
5-
import com.mapbox.api.directions.v5.models.VoiceInstructions;
64
import com.mapbox.services.android.navigation.v5.instruction.Instruction;
75
import com.mapbox.services.android.navigation.v5.navigation.VoiceInstructionLoader;
86
import com.mapbox.services.android.navigation.v5.routeprogress.RouteProgress;
9-
import com.mapbox.services.android.navigation.v5.utils.RouteUtils;
107

118
/**
129
* A default milestone that is added to {@link com.mapbox.services.android.navigation.v5.navigation.MapboxNavigation}
@@ -18,39 +15,25 @@
1815
public class VoiceInstructionMilestone extends Milestone {
1916

2017
private static final String EMPTY_STRING = "";
21-
22-
private VoiceInstructions instructions;
23-
private DirectionsRoute currentRoute;
24-
private RouteUtils routeUtils;
18+
private String announcement = EMPTY_STRING;
19+
private String ssmlAnnouncement = EMPTY_STRING;
2520

2621
VoiceInstructionMilestone(Builder builder) {
2722
super(builder);
28-
routeUtils = new RouteUtils();
2923
}
3024

3125
@Override
3226
public boolean isOccurring(RouteProgress previousRouteProgress, RouteProgress routeProgress) {
33-
if (isNewRoute(routeProgress)) {
34-
cacheInstructions(routeProgress, true);
35-
}
36-
LegStep currentStep = routeProgress.currentLegProgress().currentStep();
37-
double stepDistanceRemaining = routeProgress.currentLegProgress().currentStepProgress().distanceRemaining();
38-
VoiceInstructions instructions = routeUtils.findCurrentVoiceInstructions(currentStep, stepDistanceRemaining);
39-
if (shouldBeVoiced(instructions, stepDistanceRemaining)) {
40-
return updateInstructions(routeProgress, instructions);
41-
}
42-
return false;
27+
checkForNewRoute(previousRouteProgress, routeProgress);
28+
return updateCurrentAnnouncement(routeProgress);
4329
}
4430

4531
@Override
4632
public Instruction getInstruction() {
4733
return new Instruction() {
4834
@Override
4935
public String buildInstruction(RouteProgress routeProgress) {
50-
if (instructions == null) {
51-
return routeProgress.currentLegProgress().currentStep().name();
52-
}
53-
return instructions.announcement();
36+
return announcement;
5437
}
5538
};
5639
}
@@ -65,10 +48,7 @@ public String buildInstruction(RouteProgress routeProgress) {
6548
* @since 0.8.0
6649
*/
6750
public String getSsmlAnnouncement() {
68-
if (instructions == null) {
69-
return EMPTY_STRING;
70-
}
71-
return instructions.ssmlAnnouncement();
51+
return ssmlAnnouncement;
7252
}
7353

7454
/**
@@ -80,55 +60,7 @@ public String getSsmlAnnouncement() {
8060
* @since 0.12.0
8161
*/
8262
public String getAnnouncement() {
83-
if (instructions == null) {
84-
return EMPTY_STRING;
85-
}
86-
return instructions.announcement();
87-
}
88-
89-
/**
90-
* Looks to see if we have a new route.
91-
*
92-
* @param routeProgress provides updated route information
93-
* @return true if new route, false if not
94-
*/
95-
private boolean isNewRoute(RouteProgress routeProgress) {
96-
boolean newRoute = currentRoute == null || !currentRoute.equals(routeProgress.directionsRoute());
97-
currentRoute = routeProgress.directionsRoute();
98-
return newRoute;
99-
}
100-
101-
/**
102-
* Checks if the current instructions are different from the instructions
103-
* determined by the step distance remaining.
104-
*
105-
* @param instructions the current voice instructions from the list of step instructions
106-
* @param stepDistanceRemaining the current step distance remaining
107-
* @return true if time to voice the announcement, false if not
108-
*/
109-
private boolean shouldBeVoiced(VoiceInstructions instructions, double stepDistanceRemaining) {
110-
boolean isNewInstruction = this.instructions == null || !this.instructions.equals(instructions);
111-
boolean isValidNewInstruction = instructions != null && isNewInstruction;
112-
return isValidNewInstruction && instructions.distanceAlongGeometry() >= stepDistanceRemaining;
113-
}
114-
115-
private boolean updateInstructions(RouteProgress routeProgress, VoiceInstructions instructions) {
116-
cacheInstructions(routeProgress, false);
117-
this.instructions = instructions;
118-
return true;
119-
}
120-
121-
/**
122-
* Caches the instructions in the VoiceInstructionLoader if it has been initialized
123-
*
124-
* @param routeProgress containing the instructions
125-
* @param isFirst whether it's the first routeProgress of the route
126-
*/
127-
private void cacheInstructions(RouteProgress routeProgress, boolean isFirst) {
128-
VoiceInstructionLoader voiceInstructionLoader = VoiceInstructionLoader.getInstance();
129-
if (voiceInstructionLoader != null) {
130-
voiceInstructionLoader.cacheInstructions(routeProgress, isFirst);
131-
}
63+
return announcement;
13264
}
13365

13466
public static final class Builder extends Milestone.Builder {
@@ -155,4 +87,29 @@ public VoiceInstructionMilestone build() {
15587
return new VoiceInstructionMilestone(this);
15688
}
15789
}
90+
91+
private void checkForNewRoute(RouteProgress previousRouteProgress, RouteProgress routeProgress) {
92+
DirectionsRoute previousRoute = previousRouteProgress.directionsRoute();
93+
DirectionsRoute currentRoute = routeProgress.directionsRoute();
94+
if (!previousRoute.equals(currentRoute)) {
95+
cacheInstructions(routeProgress, true);
96+
}
97+
}
98+
99+
private void cacheInstructions(RouteProgress routeProgress, boolean isFirst) {
100+
VoiceInstructionLoader voiceInstructionLoader = VoiceInstructionLoader.getInstance();
101+
if (voiceInstructionLoader != null) {
102+
voiceInstructionLoader.cacheInstructions(routeProgress, isFirst);
103+
}
104+
}
105+
106+
private boolean updateCurrentAnnouncement(RouteProgress routeProgress) {
107+
if (!announcement.equals(routeProgress.currentAnnouncement())) {
108+
announcement = routeProgress.currentAnnouncement();
109+
ssmlAnnouncement = routeProgress.currentSsmlAnnouncement();
110+
cacheInstructions(routeProgress, false);
111+
return true;
112+
}
113+
return false;
114+
}
158115
}

libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/navigation/MapboxNavigation.java

Lines changed: 54 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import com.mapbox.android.core.location.LocationEnginePriority;
1414
import com.mapbox.android.core.location.LocationEngineProvider;
1515
import com.mapbox.api.directions.v5.models.DirectionsRoute;
16+
import com.mapbox.navigator.Navigator;
1617
import com.mapbox.services.android.navigation.v5.milestone.BannerInstructionMilestone;
1718
import com.mapbox.services.android.navigation.v5.milestone.Milestone;
1819
import com.mapbox.services.android.navigation.v5.milestone.MilestoneEventListener;
@@ -52,15 +53,20 @@ public class MapboxNavigation implements ServiceConnection {
5253

5354
private NavigationEventDispatcher navigationEventDispatcher;
5455
private NavigationEngineFactory navigationEngineFactory;
56+
private NavigationTelemetry navigationTelemetry = null;
5557
private NavigationService navigationService;
58+
private MapboxNavigator mapboxNavigator;
5659
private DirectionsRoute directionsRoute;
5760
private MapboxNavigationOptions options;
5861
private LocationEngine locationEngine = null;
5962
private Set<Milestone> milestones;
6063
private final String accessToken;
6164
private Context applicationContext;
6265
private boolean isBound;
63-
private NavigationTelemetry navigationTelemetry = null;
66+
67+
static {
68+
NavigationLibraryLoader.load();
69+
}
6470

6571
/**
6672
* Constructs a new instance of this class using the default options. This should be used over
@@ -137,7 +143,7 @@ public MapboxNavigation(@NonNull Context context, @NonNull String accessToken,
137143
this.options = options;
138144
this.navigationTelemetry = navigationTelemetry;
139145
this.locationEngine = locationEngine;
140-
initialize();
146+
initializeForTest();
141147
}
142148

143149
// Package private (no modifier) for testing purposes
@@ -148,7 +154,22 @@ public MapboxNavigation(@NonNull Context context, @NonNull String accessToken,
148154
this.options = MapboxNavigationOptions.builder().build();
149155
this.navigationTelemetry = navigationTelemetry;
150156
this.locationEngine = locationEngine;
151-
initialize();
157+
initializeForTest();
158+
}
159+
160+
private void initializeForTest() {
161+
// Initialize event dispatcher and add internal listeners
162+
navigationEventDispatcher = new NavigationEventDispatcher();
163+
navigationEngineFactory = new NavigationEngineFactory();
164+
initializeDefaultLocationEngine();
165+
initializeTelemetry();
166+
167+
// Create and add default milestones if enabled.
168+
milestones = new HashSet<>();
169+
if (options.defaultMilestonesEnabled()) {
170+
addMilestone(new VoiceInstructionMilestone.Builder().setIdentifier(VOICE_INSTRUCTION_MILESTONE_ID).build());
171+
addMilestone(new BannerInstructionMilestone.Builder().setIdentifier(BANNER_INSTRUCTION_MILESTONE_ID).build());
172+
}
152173
}
153174

154175
/**
@@ -158,6 +179,7 @@ public MapboxNavigation(@NonNull Context context, @NonNull String accessToken,
158179
*/
159180
private void initialize() {
160181
// Initialize event dispatcher and add internal listeners
182+
mapboxNavigator = new MapboxNavigator(new Navigator());
161183
navigationEventDispatcher = new NavigationEventDispatcher();
162184
navigationEngineFactory = new NavigationEngineFactory();
163185
initializeDefaultLocationEngine();
@@ -388,28 +410,7 @@ public LocationEngine getLocationEngine() {
388410
* @since 0.1.0
389411
*/
390412
public void startNavigation(@NonNull DirectionsRoute directionsRoute) {
391-
ValidationUtils.validDirectionsRoute(directionsRoute, options.defaultMilestonesEnabled());
392-
this.directionsRoute = directionsRoute;
393-
Timber.d("MapboxNavigation startNavigation called.");
394-
if (!isBound) {
395-
// Begin telemetry session
396-
navigationTelemetry.startSession(directionsRoute);
397-
398-
// Start the NavigationService
399-
Intent intent = getServiceIntent();
400-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
401-
applicationContext.startForegroundService(intent);
402-
} else {
403-
applicationContext.startService(intent);
404-
}
405-
applicationContext.bindService(intent, this, Context.BIND_AUTO_CREATE);
406-
407-
// Send navigation event running: true
408-
navigationEventDispatcher.onNavigationEvent(true);
409-
} else {
410-
// Update telemetry directions route
411-
navigationTelemetry.updateSessionRoute(directionsRoute);
412-
}
413+
startNavigationWith(directionsRoute);
413414
}
414415

415416
/**
@@ -813,10 +814,37 @@ NavigationEventDispatcher getEventDispatcher() {
813814
return navigationEventDispatcher;
814815
}
815816

816-
NavigationEngineFactory retrieveEngineProvider() {
817+
NavigationEngineFactory retrieveEngineFactory() {
817818
return navigationEngineFactory;
818819
}
819820

821+
MapboxNavigator retrieveMapboxNavigator() {
822+
return mapboxNavigator;
823+
}
824+
825+
private void startNavigationWith(@NonNull DirectionsRoute directionsRoute) {
826+
ValidationUtils.validDirectionsRoute(directionsRoute, options.defaultMilestonesEnabled());
827+
this.directionsRoute = directionsRoute;
828+
mapboxNavigator.updateRoute(directionsRoute.toJson());
829+
if (!isBound) {
830+
navigationTelemetry.startSession(directionsRoute);
831+
startNavigationService();
832+
navigationEventDispatcher.onNavigationEvent(true);
833+
} else {
834+
navigationTelemetry.updateSessionRoute(directionsRoute);
835+
}
836+
}
837+
838+
private void startNavigationService() {
839+
Intent intent = getServiceIntent();
840+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
841+
applicationContext.startForegroundService(intent);
842+
} else {
843+
applicationContext.startService(intent);
844+
}
845+
applicationContext.bindService(intent, this, Context.BIND_AUTO_CREATE);
846+
}
847+
820848
private Intent getServiceIntent() {
821849
return new Intent(applicationContext, NavigationService.class);
822850
}

0 commit comments

Comments
 (0)