diff --git a/app/src/main/java/com/mapbox/services/android/navigation/testapp/activity/navigationui/NavigationLauncherActivity.java b/app/src/main/java/com/mapbox/services/android/navigation/testapp/activity/navigationui/NavigationLauncherActivity.java index 1d70d9ae8d3..2d8d2fbbf43 100644 --- a/app/src/main/java/com/mapbox/services/android/navigation/testapp/activity/navigationui/NavigationLauncherActivity.java +++ b/app/src/main/java/com/mapbox/services/android/navigation/testapp/activity/navigationui/NavigationLauncherActivity.java @@ -30,14 +30,11 @@ import com.mapbox.geojson.LineString; import com.mapbox.geojson.Point; import com.mapbox.mapboxsdk.Mapbox; -import com.mapbox.mapboxsdk.annotations.Marker; -import com.mapbox.mapboxsdk.annotations.MarkerOptions; import com.mapbox.mapboxsdk.camera.CameraPosition; import com.mapbox.mapboxsdk.camera.CameraUpdateFactory; import com.mapbox.mapboxsdk.exceptions.InvalidLatLngBoundsException; import com.mapbox.mapboxsdk.geometry.LatLng; import com.mapbox.mapboxsdk.geometry.LatLngBounds; -import com.mapbox.mapboxsdk.location.LocationComponent; import com.mapbox.mapboxsdk.location.modes.RenderMode; import com.mapbox.mapboxsdk.maps.MapView; import com.mapbox.mapboxsdk.maps.MapboxMap; @@ -47,11 +44,13 @@ import com.mapbox.services.android.navigation.testapp.R; import com.mapbox.services.android.navigation.ui.v5.NavigationLauncher; import com.mapbox.services.android.navigation.ui.v5.NavigationLauncherOptions; -import com.mapbox.services.android.navigation.ui.v5.route.NavigationMapRoute; +import com.mapbox.services.android.navigation.ui.v5.map.NavigationMapboxMap; import com.mapbox.services.android.navigation.ui.v5.route.OnRouteSelectionChangeListener; import com.mapbox.services.android.navigation.v5.navigation.NavigationRoute; import com.mapbox.services.android.navigation.v5.utils.LocaleUtils; +import org.jetbrains.annotations.NotNull; + import java.io.File; import java.lang.ref.WeakReference; import java.util.ArrayList; @@ -78,14 +77,12 @@ public class NavigationLauncherActivity extends AppCompatActivity implements OnM private static final long FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS = 500; private final NavigationLauncherLocationCallback callback = new NavigationLauncherLocationCallback(this); + private final LocaleUtils localeUtils = new LocaleUtils(); + private final List wayPoints = new ArrayList<>(); private LocationEngine locationEngine; - private NavigationMapRoute mapRoute; - private MapboxMap mapboxMap; - private Marker currentMarker; - private Point currentLocation; - private Point destination; + private NavigationMapboxMap map; private DirectionsRoute route; - private LocaleUtils localeUtils; + private Point currentLocation; private boolean locationFound; @BindView(R.id.mapView) @@ -104,7 +101,6 @@ protected void onCreate(@Nullable Bundle savedInstanceState) { ButterKnife.bind(this); mapView.onCreate(savedInstanceState); mapView.getMapAsync(this); - localeUtils = new LocaleUtils(); } @Override @@ -131,7 +127,7 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == CHANGE_SETTING_REQUEST_CODE && resultCode == RESULT_OK) { boolean shouldRefetch = data.getBooleanExtra(NavigationSettingsActivity.UNIT_TYPE_CHANGED, false) || data.getBooleanExtra(NavigationSettingsActivity.LANGUAGE_CHANGED, false); - if (destination != null && shouldRefetch) { + if (!wayPoints.isEmpty() && shouldRefetch) { fetchRoute(); } } @@ -192,23 +188,30 @@ public void onRouteLaunchClick() { } @Override - public void onMapReady(MapboxMap mapboxMap) { - this.mapboxMap = mapboxMap; + public void onMapReady(@NotNull MapboxMap mapboxMap) { mapboxMap.setStyle(Style.MAPBOX_STREETS, style -> { mapboxMap.addOnMapLongClickListener(this); + map = new NavigationMapboxMap(mapView, mapboxMap); + map.setOnRouteSelectionChangeListener(this); + map.updateLocationLayerRenderMode(RenderMode.COMPASS); initializeLocationEngine(); - initializeLocationComponent(style); - initializeMapRoute(); }); } @Override public boolean onMapLongClick(@NonNull LatLng point) { - destination = Point.fromLngLat(point.getLongitude(), point.getLatitude()); + if (wayPoints.size() == 2) { + Snackbar.make(mapView, "Max way points exceeded. Clearing route...", Snackbar.LENGTH_SHORT).show(); + wayPoints.clear(); + map.clearMarkers(); + map.removeRoute(); + return false; + } + wayPoints.add(Point.fromLngLat(point.getLongitude(), point.getLatitude())); launchRouteBtn.setEnabled(false); loading.setVisibility(View.VISIBLE); setCurrentMarkerPosition(point); - if (currentLocation != null) { + if (locationFound) { fetchRoute(); } return false; @@ -224,6 +227,7 @@ void updateCurrentLocation(Point currentLocation) { } void onLocationFound(Location location) { + map.updateLocation(location); if (!locationFound) { animateCamera(new LatLng(location.getLatitude(), location.getLongitude())); Snackbar.make(mapView, R.string.explanation_long_press_waypoint, Snackbar.LENGTH_LONG).show(); @@ -244,44 +248,34 @@ private void initializeLocationEngine() { locationEngine.getLastLocation(callback); } - @SuppressWarnings( {"MissingPermission"}) - private void initializeLocationComponent(Style style) { - LocationComponent locationComponent = mapboxMap.getLocationComponent(); - locationComponent.activateLocationComponent(this, style, locationEngine); - locationComponent.setLocationComponentEnabled(true); - locationComponent.setRenderMode(RenderMode.COMPASS); - } - - private void initializeMapRoute() { - mapRoute = new NavigationMapRoute(mapView, mapboxMap); - mapRoute.setOnRouteSelectionChangeListener(this); - } - private void fetchRoute() { NavigationRoute.Builder builder = NavigationRoute.builder(this) .accessToken(Mapbox.getAccessToken()) .origin(currentLocation) - .destination(destination) .profile(getRouteProfileFromSharedPreferences()) .alternatives(true); + + for (Point wayPoint : wayPoints) { + builder.addWaypoint(wayPoint); + } + setFieldsFromSharedPreferences(builder); - builder.build() - .getRoute(new SimplifiedCallback() { - @Override - public void onResponse(Call call, Response response) { - if (validRouteResponse(response)) { - hideLoading(); - route = response.body().routes().get(0); - if (route.distance() > 25d) { - launchRouteBtn.setEnabled(true); - mapRoute.addRoutes(response.body().routes()); - boundCameraToRoute(); - } else { - Snackbar.make(mapView, R.string.error_select_longer_route, Snackbar.LENGTH_SHORT).show(); - } + builder.build().getRoute(new SimplifiedCallback() { + @Override + public void onResponse(Call call, Response response) { + if (validRouteResponse(response)) { + hideLoading(); + route = response.body().routes().get(0); + if (route.distance() > 25d) { + launchRouteBtn.setEnabled(true); + map.drawRoutes(response.body().routes()); + boundCameraToRoute(); + } else { + Snackbar.make(mapView, R.string.error_select_longer_route, Snackbar.LENGTH_SHORT).show(); } } - }); + } + }); loading.setVisibility(View.VISIBLE); } @@ -392,23 +386,19 @@ public void boundCameraToRoute() { } private void animateCameraBbox(LatLngBounds bounds, int animationTime, int[] padding) { - CameraPosition position = mapboxMap.getCameraForLatLngBounds(bounds, padding); - mapboxMap.animateCamera(CameraUpdateFactory.newCameraPosition(position), animationTime); + CameraPosition position = map.retrieveMap().getCameraForLatLngBounds(bounds, padding); + map.retrieveMap().animateCamera(CameraUpdateFactory.newCameraPosition(position), animationTime); } private void animateCamera(LatLng point) { - mapboxMap.animateCamera(CameraUpdateFactory.newLatLngZoom(point, DEFAULT_CAMERA_ZOOM), CAMERA_ANIMATION_DURATION); + map.retrieveMap().animateCamera( + CameraUpdateFactory.newLatLngZoom(point, DEFAULT_CAMERA_ZOOM), CAMERA_ANIMATION_DURATION + ); } private void setCurrentMarkerPosition(LatLng position) { if (position != null) { - if (currentMarker == null) { - MarkerOptions markerViewOptions = new MarkerOptions() - .position(position); - currentMarker = mapboxMap.addMarker(markerViewOptions); - } else { - currentMarker.setPosition(position); - } + map.addDestinationMarker(Point.fromLngLat(position.getLongitude(), position.getLatitude())); } } diff --git a/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/navigation/NavigationRouteProcessor.java b/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/navigation/NavigationRouteProcessor.java index 15ffcf0527e..9e23f44fa16 100644 --- a/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/navigation/NavigationRouteProcessor.java +++ b/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/navigation/NavigationRouteProcessor.java @@ -34,6 +34,7 @@ class NavigationRouteProcessor { private static final int FIRST_BANNER_INSTRUCTION = 0; private final RouteProgressStateMap progressStateMap = new RouteProgressStateMap(); private RouteProgress previousRouteProgress; + private NavigationStatus previousStatus; private DirectionsRoute route; private RouteLeg currentLeg; private LegStep currentStep; @@ -45,6 +46,7 @@ class NavigationRouteProcessor { private CurrentLegAnnotation currentLegAnnotation; RouteProgress buildNewRouteProgress(MapboxNavigator navigator, NavigationStatus status, DirectionsRoute route) { + previousStatus = status; updateRoute(route); return buildRouteProgressFrom(status, navigator); } @@ -58,6 +60,11 @@ RouteProgress retrievePreviousRouteProgress() { return previousRouteProgress; } + @Nullable + NavigationStatus retrievePreviousStatus() { + return previousStatus; + } + private void updateRoute(DirectionsRoute route) { if (this.route == null || !this.route.equals(route)) { this.route = route; diff --git a/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/navigation/RouteProcessorRunnable.java b/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/navigation/RouteProcessorRunnable.java index 4a77bbfeaa3..bd5acd4e14b 100644 --- a/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/navigation/RouteProcessorRunnable.java +++ b/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/navigation/RouteProcessorRunnable.java @@ -58,7 +58,8 @@ private void process() { Date date = new Date(); NavigationStatus status = mapboxNavigator.retrieveStatus(date, options.navigationLocationEngineIntervalLagInMilliseconds()); - status = checkForNewLegIndex(mapboxNavigator, route, status, options.enableAutoIncrementLegIndex()); + NavigationStatus previousStatus = routeProcessor.retrievePreviousStatus(); + status = checkForNewLegIndex(mapboxNavigator, route, status, previousStatus, options.enableAutoIncrementLegIndex()); RouteProgress routeProgress = routeProcessor.buildNewRouteProgress(mapboxNavigator, status, route); RouteRefresher routeRefresher = navigation.retrieveRouteRefresher(); @@ -79,14 +80,18 @@ private void process() { } private NavigationStatus checkForNewLegIndex(MapboxNavigator mapboxNavigator, DirectionsRoute route, - NavigationStatus currentStatus, boolean autoIncrementEnabled) { - RouteState currentState = currentStatus.getRouteState(); - int currentLegIndex = currentStatus.getLegIndex(); + NavigationStatus currentStatus, NavigationStatus previousStatus, + boolean autoIncrementEnabled) { + if (previousStatus == null) { + return currentStatus; + } + RouteState previousState = previousStatus.getRouteState(); + int previousLegIndex = previousStatus.getLegIndex(); int routeLegsSize = route.legs().size() - 1; - boolean canUpdateLeg = currentState == RouteState.COMPLETE && currentLegIndex < routeLegsSize; - boolean isValidDistanceRemaining = currentStatus.getRemainingLegDistance() < ARRIVAL_ZONE_RADIUS; + boolean canUpdateLeg = previousState == RouteState.COMPLETE && previousLegIndex < routeLegsSize; + boolean isValidDistanceRemaining = previousStatus.getRemainingLegDistance() < ARRIVAL_ZONE_RADIUS; if (autoIncrementEnabled && (canUpdateLeg && isValidDistanceRemaining)) { - int newLegIndex = currentLegIndex + 1; + int newLegIndex = previousLegIndex + 1; return mapboxNavigator.updateLegIndex(newLegIndex); } return currentStatus; diff --git a/libandroid-navigation/src/test/java/com/mapbox/services/android/navigation/v5/navigation/NavigationRouteProcessorTest.java b/libandroid-navigation/src/test/java/com/mapbox/services/android/navigation/v5/navigation/NavigationRouteProcessorTest.java index b779dd60092..a5c4f0c6f24 100644 --- a/libandroid-navigation/src/test/java/com/mapbox/services/android/navigation/v5/navigation/NavigationRouteProcessorTest.java +++ b/libandroid-navigation/src/test/java/com/mapbox/services/android/navigation/v5/navigation/NavigationRouteProcessorTest.java @@ -4,24 +4,35 @@ import com.mapbox.services.android.navigation.v5.BaseTest; import com.mapbox.services.android.navigation.v5.routeprogress.RouteProgress; -import org.junit.Ignore; import org.junit.Test; import java.io.IOException; +import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertNotNull; import static org.mockito.Mockito.mock; -@Ignore public class NavigationRouteProcessorTest extends BaseTest { @Test public void buildNewRouteProgress_routeProgressReturned() throws IOException { + MapboxNavigator navigator = mock(MapboxNavigator.class); + NavigationStatus status = mock(NavigationStatus.class); NavigationRouteProcessor processor = new NavigationRouteProcessor(); - // TODO mock final status - RouteProgress progress = processor.buildNewRouteProgress(mock(MapboxNavigator.class), mock(NavigationStatus.class), buildTestDirectionsRoute()); + RouteProgress progress = processor.buildNewRouteProgress(navigator, status, buildTestDirectionsRoute()); assertNotNull(progress); } + + @Test + public void buildNewRouteProgress_previousStatusIsReturned() throws IOException { + MapboxNavigator navigator = mock(MapboxNavigator.class); + NavigationStatus status = mock(NavigationStatus.class); + NavigationRouteProcessor processor = new NavigationRouteProcessor(); + + processor.buildNewRouteProgress(navigator, status, buildTestDirectionsRoute()); + + assertEquals(status, processor.retrievePreviousStatus()); + } } diff --git a/libandroid-navigation/src/test/java/com/mapbox/services/android/navigation/v5/navigation/RouteProcessorRunnableTest.java b/libandroid-navigation/src/test/java/com/mapbox/services/android/navigation/v5/navigation/RouteProcessorRunnableTest.java index e7c24c59354..c275a2d7e4c 100644 --- a/libandroid-navigation/src/test/java/com/mapbox/services/android/navigation/v5/navigation/RouteProcessorRunnableTest.java +++ b/libandroid-navigation/src/test/java/com/mapbox/services/android/navigation/v5/navigation/RouteProcessorRunnableTest.java @@ -96,14 +96,15 @@ public void onRun_snapToRouteReceivesStatus() { public void onRun_legIndexIncrementsOnLegCompletionWithValidDistanceRemaining() { SnapToRoute snapToRoute = mock(SnapToRoute.class); NavigationEngineFactory factory = buildMockFactory(snapToRoute); + NavigationStatus previousStatus = buildMockStatus(); NavigationStatus status = buildMockStatus(); - when(status.getRouteState()).thenReturn(RouteState.COMPLETE); - when(status.getRemainingLegDistance()).thenReturn(20f); + when(previousStatus.getRouteState()).thenReturn(RouteState.COMPLETE); + when(previousStatus.getRemainingLegDistance()).thenReturn(20f); MapboxNavigator navigator = mock(MapboxNavigator.class); DirectionsRoute route = buildTwoLegRoute(); boolean autoIncrementEnabled = true; RouteProcessorRunnable runnable = buildRouteProcessorRunnableWith( - navigator, factory, status, route, autoIncrementEnabled + navigator, factory, previousStatus, status, route, autoIncrementEnabled ); Location rawLocation = mock(Location.class); runnable.updateRawLocation(rawLocation); @@ -117,14 +118,15 @@ public void onRun_legIndexIncrementsOnLegCompletionWithValidDistanceRemaining() public void onRun_legIndexDoesNotIncrementsOnLegCompletionWithInvalidDistanceRemaining() { SnapToRoute snapToRoute = mock(SnapToRoute.class); NavigationEngineFactory factory = buildMockFactory(snapToRoute); + NavigationStatus previousStatus = buildMockStatus(); NavigationStatus status = buildMockStatus(); - when(status.getRouteState()).thenReturn(RouteState.COMPLETE); - when(status.getRemainingLegDistance()).thenReturn(50f); + when(previousStatus.getRouteState()).thenReturn(RouteState.COMPLETE); + when(previousStatus.getRemainingLegDistance()).thenReturn(50f); MapboxNavigator navigator = mock(MapboxNavigator.class); DirectionsRoute route = buildTwoLegRoute(); boolean autoIncrementEnabled = true; RouteProcessorRunnable runnable = buildRouteProcessorRunnableWith( - navigator, factory, status, route, autoIncrementEnabled + navigator, factory, previousStatus, status, route, autoIncrementEnabled ); Location rawLocation = mock(Location.class); runnable.updateRawLocation(rawLocation); @@ -138,15 +140,16 @@ public void onRun_legIndexDoesNotIncrementsOnLegCompletionWithInvalidDistanceRem public void onRun_legIndexDoesNotIncrementsOnLegCompletionWithInvalidLegsRemaining() { SnapToRoute snapToRoute = mock(SnapToRoute.class); NavigationEngineFactory factory = buildMockFactory(snapToRoute); + NavigationStatus previousStatus = buildMockStatus(); NavigationStatus status = buildMockStatus(); - when(status.getRouteState()).thenReturn(RouteState.COMPLETE); - when(status.getRemainingLegDistance()).thenReturn(20f); - when(status.getLegIndex()).thenReturn(1); + when(previousStatus.getRouteState()).thenReturn(RouteState.COMPLETE); + when(previousStatus.getRemainingLegDistance()).thenReturn(20f); + when(previousStatus.getLegIndex()).thenReturn(1); MapboxNavigator navigator = mock(MapboxNavigator.class); DirectionsRoute route = buildTwoLegRoute(); boolean autoIncrementEnabled = true; RouteProcessorRunnable runnable = buildRouteProcessorRunnableWith( - navigator, factory, status, route, autoIncrementEnabled + navigator, factory, previousStatus, status, route, autoIncrementEnabled ); Location rawLocation = mock(Location.class); runnable.updateRawLocation(rawLocation); @@ -160,14 +163,15 @@ public void onRun_legIndexDoesNotIncrementsOnLegCompletionWithInvalidLegsRemaini public void onRun_legIndexDoesNotIncrementOnLegCompletionWithAutoIncrementDisabled() { SnapToRoute snapToRoute = mock(SnapToRoute.class); NavigationEngineFactory factory = buildMockFactory(snapToRoute); + NavigationStatus previousStatus = buildMockStatus(); NavigationStatus status = buildMockStatus(); - when(status.getRouteState()).thenReturn(RouteState.COMPLETE); - when(status.getRemainingLegDistance()).thenReturn(20f); + when(previousStatus.getRouteState()).thenReturn(RouteState.COMPLETE); + when(previousStatus.getRemainingLegDistance()).thenReturn(20f); MapboxNavigator navigator = mock(MapboxNavigator.class); DirectionsRoute route = buildTwoLegRoute(); boolean autoIncrementEnabled = false; RouteProcessorRunnable runnable = buildRouteProcessorRunnableWith( - navigator, factory, status, route, autoIncrementEnabled + navigator, factory, previousStatus, status, route, autoIncrementEnabled ); Location rawLocation = mock(Location.class); runnable.updateRawLocation(rawLocation); @@ -218,6 +222,31 @@ private RouteProcessorRunnable buildRouteProcessorRunnableWith(MapboxNavigator n ); } + private RouteProcessorRunnable buildRouteProcessorRunnableWith(MapboxNavigator navigator, + NavigationEngineFactory factory, + NavigationStatus previousStatus, + NavigationStatus status, + DirectionsRoute route, + boolean autoIncrementEnabled) { + MapboxNavigationOptions options = MapboxNavigationOptions.builder() + .enableAutoIncrementLegIndex(autoIncrementEnabled) + .build(); + when(navigator.retrieveStatus(any(Date.class), any(Long.class))).thenReturn(status); + MapboxNavigation navigation = mock(MapboxNavigation.class); + when(navigation.options()).thenReturn(options); + when(navigation.getRoute()).thenReturn(route); + when(navigation.retrieveMapboxNavigator()).thenReturn(navigator); + when(navigation.retrieveEngineFactory()).thenReturn(factory); + NavigationRouteProcessor routeProcessor = mock(NavigationRouteProcessor.class); + when(routeProcessor.retrievePreviousStatus()).thenReturn(previousStatus); + return new RouteProcessorRunnable( + routeProcessor, + navigation, + mock(Handler.class), + mock(Handler.class), + mock(RouteProcessorBackgroundThread.Listener.class) + ); + } private RouteProcessorRunnable buildRouteProcessorRunnableWith(NavigationEngineFactory factory, NavigationStatus status) {