Basic AR navigation
NOTE
This example is a part of the Vision SDK Examples. You can find the values for all referenced resources in the res
directory. For example, see res/values/strings.xml
for R.string.*
references used in this example.
This example requires two additional dependencies in the build.gradle:
implementation "com.mapbox.mapboxsdk:mapbox-android-navigation:0.42.6"
implementation "com.mapbox.mapboxsdk:mapbox-android-core:1.3.0"
<?xml version="1.0" encoding="utf-8"?><FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"> <com.mapbox.vision.ar.view.gl.VisionArViewandroid:id="@+id/mapbox_ar_view"android:layout_width="match_parent"android:layout_height="match_parent" /> </FrameLayout>
package com.mapbox.vision.examples; import android.location.Location;import android.os.Looper;import android.widget.Toast;import androidx.annotation.NonNull;import androidx.annotation.Nullable;import com.mapbox.android.core.location.LocationEngine;import com.mapbox.android.core.location.LocationEngineCallback;import com.mapbox.android.core.location.LocationEngineProvider;import com.mapbox.android.core.location.LocationEngineRequest;import com.mapbox.android.core.location.LocationEngineResult;import com.mapbox.api.directions.v5.models.DirectionsResponse;import com.mapbox.api.directions.v5.models.DirectionsRoute;import com.mapbox.api.directions.v5.models.LegStep;import com.mapbox.api.directions.v5.models.RouteLeg;import com.mapbox.core.constants.Constants;import com.mapbox.geojson.Point;import com.mapbox.geojson.utils.PolylineUtils;import com.mapbox.services.android.navigation.v5.navigation.MapboxNavigation;import com.mapbox.services.android.navigation.v5.navigation.MapboxNavigationOptions;import com.mapbox.services.android.navigation.v5.navigation.NavigationRoute;import com.mapbox.services.android.navigation.v5.offroute.OffRouteListener;import com.mapbox.services.android.navigation.v5.route.RouteFetcher;import com.mapbox.services.android.navigation.v5.route.RouteListener;import com.mapbox.services.android.navigation.v5.routeprogress.ProgressChangeListener;import com.mapbox.services.android.navigation.v5.routeprogress.RouteProgress;import com.mapbox.vision.VisionManager;import com.mapbox.vision.ar.VisionArManager;import com.mapbox.vision.ar.core.models.ManeuverType;import com.mapbox.vision.ar.core.models.Route;import com.mapbox.vision.ar.core.models.RoutePoint;import com.mapbox.vision.ar.view.gl.VisionArView;import com.mapbox.vision.mobile.core.interfaces.VisionEventsListener;import com.mapbox.vision.mobile.core.models.AuthorizationStatus;import com.mapbox.vision.mobile.core.models.Camera;import com.mapbox.vision.mobile.core.models.Country;import com.mapbox.vision.mobile.core.models.FrameSegmentation;import com.mapbox.vision.mobile.core.models.classification.FrameSignClassifications;import com.mapbox.vision.mobile.core.models.detection.FrameDetections;import com.mapbox.vision.mobile.core.models.position.GeoCoordinate;import com.mapbox.vision.mobile.core.models.position.VehicleState;import com.mapbox.vision.mobile.core.models.road.RoadDescription;import com.mapbox.vision.mobile.core.models.world.WorldDescription;import com.mapbox.vision.performance.ModelPerformance.On;import com.mapbox.vision.performance.ModelPerformanceConfig.Merged;import com.mapbox.vision.performance.ModelPerformanceMode;import com.mapbox.vision.performance.ModelPerformanceRate;import com.mapbox.vision.utils.VisionLogger;import org.jetbrains.annotations.NotNull;import java.util.ArrayList;import java.util.List;import retrofit2.Call;import retrofit2.Callback;import retrofit2.Response; /*** Example shows how Vision and VisionAR SDKs are used to draw AR lane over the video stream from camera.* Also, Mapbox navigation services are used to build route and navigation session.*/public class ArActivity extends BaseActivity implements RouteListener, ProgressChangeListener, OffRouteListener { private static final String TAG = ArActivity.class.getSimpleName(); // Handles navigation.private MapboxNavigation mapboxNavigation;// Fetches route from points.private RouteFetcher routeFetcher;private RouteProgress lastRouteProgress;private LocationEngine locationEngine;private LocationEngineCallback<LocationEngineResult> locationCallback; private boolean visionManagerWasInit = false;private boolean navigationWasStarted = false; // This dummy points will be used to build route. For real world test this needs to be changed to real values for// source and target locations.private final Point ROUTE_ORIGIN = Point.fromLngLat(27.654285, 53.928057);private final Point ROUTE_DESTINATION = Point.fromLngLat(27.655637, 53.935712); @Overrideprotected void initViews() {setContentView(R.layout.activity_ar_navigation);} protected void setArRenderOptions(@NotNull final VisionArView visionArView) {visionArView.setFenceVisible(true);} @Overrideprotected void onPermissionsGranted() {startVisionManager();startNavigation();} @Overrideprotected void onStart() {super.onStart();startVisionManager();startNavigation();} @Overrideprotected void onStop() {super.onStop();stopVisionManager();stopNavigation();} private void startVisionManager() {if (allPermissionsGranted() && !visionManagerWasInit) {// Create and start VisionManager.VisionManager.create();VisionManager.setModelPerformanceConfig(new Merged(new On(ModelPerformanceMode.DYNAMIC, ModelPerformanceRate.LOW)));VisionManager.start();VisionManager.setVisionEventsListener(new VisionEventsListener() {@Overridepublic void onAuthorizationStatusUpdated(@NotNull AuthorizationStatus authorizationStatus) {} @Overridepublic void onFrameSegmentationUpdated(@NotNull FrameSegmentation frameSegmentation) {} @Overridepublic void onFrameDetectionsUpdated(@NotNull FrameDetections frameDetections) {} @Overridepublic void onFrameSignClassificationsUpdated(@NotNull FrameSignClassifications frameSignClassifications) {} @Overridepublic void onRoadDescriptionUpdated(@NotNull RoadDescription roadDescription) {} @Overridepublic void onWorldDescriptionUpdated(@NotNull WorldDescription worldDescription) {} @Overridepublic void onVehicleStateUpdated(@NotNull VehicleState vehicleState) {} @Overridepublic void onCameraUpdated(@NotNull Camera camera) {} @Overridepublic void onCountryUpdated(@NotNull Country country) {} @Overridepublic void onUpdateCompleted() {}}); VisionArView visionArView = findViewById(R.id.mapbox_ar_view); // Create VisionArManager.VisionArManager.create(VisionManager.INSTANCE);visionArView.setArManager(VisionArManager.INSTANCE);setArRenderOptions(visionArView); visionManagerWasInit = true;}} private void stopVisionManager() {if (visionManagerWasInit) {VisionArManager.destroy();VisionManager.stop();VisionManager.destroy(); visionManagerWasInit = false;}} private void startNavigation() {if (allPermissionsGranted() && !navigationWasStarted) {// Initialize navigation with your Mapbox access token.mapboxNavigation = new MapboxNavigation(this,getString(R.string.mapbox_access_token),MapboxNavigationOptions.builder().build()); // Initialize route fetcher with your Mapbox access token.routeFetcher = new RouteFetcher(this, getString(R.string.mapbox_access_token));routeFetcher.addRouteListener(this); locationEngine = LocationEngineProvider.getBestLocationEngine(this); LocationEngineRequest arLocationEngineRequest = new LocationEngineRequest.Builder(0).setPriority(LocationEngineRequest.PRIORITY_HIGH_ACCURACY).setFastestInterval(1000).build(); locationCallback = new LocationEngineCallback<LocationEngineResult>() {@Overridepublic void onSuccess(LocationEngineResult result) { } @Overridepublic void onFailure(@NonNull Exception exception) { }}; try {locationEngine.requestLocationUpdates(arLocationEngineRequest, locationCallback, Looper.getMainLooper());} catch (SecurityException se) {VisionLogger.Companion.e(TAG, se.toString());} initDirectionsRoute(); // Route need to be reestablished if off route happens.mapboxNavigation.addOffRouteListener(this);mapboxNavigation.addProgressChangeListener(this); navigationWasStarted = true;}} private void stopNavigation() {if (navigationWasStarted) {locationEngine.removeLocationUpdates(locationCallback); mapboxNavigation.removeProgressChangeListener(this);mapboxNavigation.removeOffRouteListener(this);mapboxNavigation.stopNavigation(); navigationWasStarted = false;}} private void initDirectionsRoute() {// Get route from predefined points.NavigationRoute.builder(this).accessToken(getString(R.string.mapbox_access_token)).origin(ROUTE_ORIGIN).destination(ROUTE_DESTINATION).build().getRoute(new Callback<DirectionsResponse>() {@Overridepublic void onResponse(Call<DirectionsResponse> call, Response<DirectionsResponse> response) {if (response.body() == null || response.body().routes().isEmpty()) {return;} // Start navigation session with retrieved route.DirectionsRoute route = response.body().routes().get(0);mapboxNavigation.startNavigation(route); // Set route progress.VisionArManager.setRoute(new Route(getRoutePoints(route),route.duration().floatValue(),"",""));} @Overridepublic void onFailure(Call<DirectionsResponse> call, Throwable t) {}});} @Overridepublic void onErrorReceived(Throwable throwable) {if (throwable != null) {throwable.printStackTrace();} mapboxNavigation.stopNavigation();Toast.makeText(this, "Can not calculate the route requested", Toast.LENGTH_SHORT).show();} @Overridepublic void onResponseReceived(@NotNull DirectionsResponse response, RouteProgress routeProgress) {mapboxNavigation.stopNavigation();if (response.routes().isEmpty()) {Toast.makeText(this, "Can not calculate the route requested", Toast.LENGTH_SHORT).show();} else {DirectionsRoute route = response.routes().get(0); mapboxNavigation.startNavigation(route); // Set route progress.VisionArManager.setRoute(new Route(getRoutePoints(route),(float) routeProgress.durationRemaining(),"",""));}} @Overridepublic void onProgressChange(Location location, RouteProgress routeProgress) {lastRouteProgress = routeProgress;} @Overridepublic void userOffRoute(Location location) {routeFetcher.findRouteFromRouteProgress(location, lastRouteProgress);} private RoutePoint[] getRoutePoints(@NotNull DirectionsRoute route) {ArrayList<RoutePoint> routePoints = new ArrayList<>(); List<RouteLeg> legs = route.legs();if (legs != null) {for (RouteLeg leg : legs) { List<LegStep> steps = leg.steps();if (steps != null) {for (LegStep step : steps) {RoutePoint point = new RoutePoint((new GeoCoordinate(step.maneuver().location().latitude(),step.maneuver().location().longitude())), mapToManeuverType(step.maneuver().type())); routePoints.add(point); List<Point> geometryPoints = buildStepPointsFromGeometry(step.geometry());for (Point geometryPoint : geometryPoints) {point = new RoutePoint((new GeoCoordinate(geometryPoint.latitude(),geometryPoint.longitude())), ManeuverType.None); routePoints.add(point);}}}}} return routePoints.toArray(new RoutePoint[0]);} private List<Point> buildStepPointsFromGeometry(String geometry) {return PolylineUtils.decode(geometry, Constants.PRECISION_6);} private ManeuverType mapToManeuverType(@Nullable String maneuver) {if (maneuver == null) {return ManeuverType.None;}switch (maneuver) {case "turn":return ManeuverType.Turn;case "depart":return ManeuverType.Depart;case "arrive":return ManeuverType.Arrive;case "merge":return ManeuverType.Merge;case "on ramp":return ManeuverType.OnRamp;case "off ramp":return ManeuverType.OffRamp;case "fork":return ManeuverType.Fork;case "roundabout":return ManeuverType.Roundabout;case "exit roundabout":return ManeuverType.RoundaboutExit;case "end of road":return ManeuverType.EndOfRoad;case "new name":return ManeuverType.NewName;case "continue":return ManeuverType.Continue;case "rotary":return ManeuverType.Rotary;case "roundabout turn":return ManeuverType.RoundaboutTurn;case "notification":return ManeuverType.Notification;case "exit rotary":return ManeuverType.RotaryExit;default:return ManeuverType.None;}}}