diff --git a/app/src/main/java/com/mapbox/services/android/navigation/testapp/activity/MockNavigationActivity.java b/app/src/main/java/com/mapbox/services/android/navigation/testapp/activity/MockNavigationActivity.java
index ec12200acaa..6618e0c0f11 100644
--- a/app/src/main/java/com/mapbox/services/android/navigation/testapp/activity/MockNavigationActivity.java
+++ b/app/src/main/java/com/mapbox/services/android/navigation/testapp/activity/MockNavigationActivity.java
@@ -32,6 +32,7 @@
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
import com.mapbox.mapboxsdk.maps.Style;
import com.mapbox.services.android.navigation.testapp.utils.Utils;
+import com.mapbox.services.android.navigation.v5.navigation.NavigationRoute;
import com.mapbox.services.android.navigation.v5.navigation.metrics.MapboxMetricsReporter;
import com.mapbox.services.android.navigation.v5.navigation.metrics.MetricEvent;
import com.mapbox.services.android.navigation.v5.navigation.metrics.MetricsObserver;
@@ -48,7 +49,6 @@
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.NavigationEventListener;
-import com.mapbox.services.android.navigation.v5.navigation.NavigationRoute;
import com.mapbox.services.android.navigation.v5.navigation.RefreshCallback;
import com.mapbox.services.android.navigation.v5.navigation.RefreshError;
import com.mapbox.services.android.navigation.v5.navigation.RouteRefresh;
diff --git a/examples/build.gradle b/examples/build.gradle
index f2c2f986245..d02e95ac6d8 100644
--- a/examples/build.gradle
+++ b/examples/build.gradle
@@ -84,9 +84,11 @@ android {
dependencies {
implementation project(':libdirections-offboard')
+ implementation project(':libdirections-onboard')
implementation project(':libtrip-notification')
implementation project(':libnavigation-util')
implementation project(':liblogger')
+ implementation project(':libnavigator')
//ktlint
ktlint dependenciesList.ktlint
diff --git a/examples/src/main/AndroidManifest.xml b/examples/src/main/AndroidManifest.xml
index 45bdf80fe04..7dd37100ad2 100644
--- a/examples/src/main/AndroidManifest.xml
+++ b/examples/src/main/AndroidManifest.xml
@@ -48,6 +48,22 @@
android:value=".MainActivity"/>
+
+
+
+
+
+
+
+
diff --git a/examples/src/main/java/com/mapbox/navigation/examples/MainActivity.java b/examples/src/main/java/com/mapbox/navigation/examples/MainActivity.java
index 076cde6750f..e09dae8e0da 100644
--- a/examples/src/main/java/com/mapbox/navigation/examples/MainActivity.java
+++ b/examples/src/main/java/com/mapbox/navigation/examples/MainActivity.java
@@ -22,6 +22,8 @@
import com.mapbox.navigation.examples.activity.MockNavigationActivity;
import com.mapbox.navigation.examples.activity.OffboardRouterActivityJava;
import com.mapbox.navigation.examples.activity.OffboardRouterActivityKt;
+import com.mapbox.navigation.examples.activity.OnboardRouterActivityJava;
+import com.mapbox.navigation.examples.activity.OnboardRouterActivityKt;
import java.util.ArrayList;
import java.util.Arrays;
@@ -67,6 +69,16 @@ protected void onCreate(Bundle savedInstanceState) {
getString(R.string.title_offboard_router_java),
getString(R.string.description_offboard_router_java),
OffboardRouterActivityJava.class
+ ),
+ new SampleItem(
+ getString(R.string.title_onboard_router_kotlin),
+ getString(R.string.description_onboard_router_kotlin),
+ OnboardRouterActivityKt.class
+ ),
+ new SampleItem(
+ getString(R.string.title_onboard_router_java),
+ getString(R.string.description_onboard_router_java),
+ OnboardRouterActivityJava.class
)
));
diff --git a/examples/src/main/java/com/mapbox/navigation/examples/activity/OnboardRouterActivityJava.java b/examples/src/main/java/com/mapbox/navigation/examples/activity/OnboardRouterActivityJava.java
new file mode 100644
index 00000000000..e5b32702a1e
--- /dev/null
+++ b/examples/src/main/java/com/mapbox/navigation/examples/activity/OnboardRouterActivityJava.java
@@ -0,0 +1,214 @@
+package com.mapbox.navigation.examples.activity;
+
+import android.os.Bundle;
+import android.os.Environment;
+import android.widget.Toast;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AppCompatActivity;
+
+import com.google.android.material.snackbar.Snackbar;
+import com.mapbox.api.directions.v5.models.DirectionsRoute;
+import com.mapbox.geojson.Point;
+import com.mapbox.mapboxsdk.annotations.MarkerOptions;
+import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
+import com.mapbox.mapboxsdk.geometry.LatLng;
+import com.mapbox.mapboxsdk.maps.MapView;
+import com.mapbox.mapboxsdk.maps.MapboxMap;
+import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
+import com.mapbox.mapboxsdk.maps.Style;
+import com.mapbox.navigation.base.route.Router;
+import com.mapbox.navigation.base.route.model.Route;
+import com.mapbox.navigation.base.route.model.RouteOptionsNavigation;
+import com.mapbox.navigation.examples.R;
+import com.mapbox.navigation.examples.utils.Utils;
+import com.mapbox.navigation.examples.utils.extensions.Mappers;
+import com.mapbox.navigation.route.onboard.MapboxOnboardRouter;
+import com.mapbox.navigation.route.onboard.model.Config;
+import com.mapbox.services.android.navigation.ui.v5.route.NavigationMapRoute;
+
+import org.jetbrains.annotations.NotNull;
+
+import java.io.File;
+import java.util.List;
+
+import butterknife.BindView;
+import butterknife.ButterKnife;
+import butterknife.OnClick;
+import timber.log.Timber;
+
+public class OnboardRouterActivityJava extends AppCompatActivity implements OnMapReadyCallback,
+ MapboxMap.OnMapClickListener {
+
+ private Router onboardRouter;
+ private MapboxMap mapboxMap;
+
+ private DirectionsRoute route;
+ private NavigationMapRoute navigationMapRoute;
+ private Point origin;
+ private Point destination;
+ private Point waypoint;
+
+ @BindView(R.id.mapView)
+ MapView mapView;
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_mock_navigation);
+ ButterKnife.bind(this);
+
+ setupRouter();
+
+ mapView.onCreate(savedInstanceState);
+ mapView.getMapAsync(this);
+ }
+
+ private void setupRouter() {
+ File file = new File(
+ Environment.getExternalStoragePublicDirectory("Offline").getAbsolutePath(),
+ "2019_04_13-00_00_11");
+ File fileTiles = new File(file, "tiles");
+ Config config = new Config(
+ fileTiles.getAbsolutePath(),
+ null,
+ null,
+ null,
+ null // working with pre-fetched tiles only
+ );
+
+ onboardRouter = new MapboxOnboardRouter(config, null);
+ }
+
+
+ @OnClick(R.id.newLocationFab)
+ public void onNewLocationClick() {
+ newOrigin();
+ }
+
+ private void newOrigin() {
+ if (mapboxMap != null) {
+ clearMap();
+ LatLng latLng = new LatLng(47.05991, 9.49183);
+ origin = Point.fromLngLat(latLng.getLongitude(), latLng.getLatitude());
+ mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng, 12));
+ }
+ }
+
+ @Override
+ public void onMapReady(@NonNull MapboxMap mapboxMap) {
+ this.mapboxMap = mapboxMap;
+ this.mapboxMap.addOnMapClickListener(this);
+ mapboxMap.setStyle(Style.MAPBOX_STREETS, style -> {
+ navigationMapRoute = new NavigationMapRoute(mapView, mapboxMap);
+ Snackbar.make(findViewById(R.id.container), "Tap map to place waypoint", Snackbar.LENGTH_LONG).show();
+ newOrigin();
+ });
+ }
+
+ private void clearMap() {
+ if (mapboxMap != null) {
+ mapboxMap.clear();
+ route = null;
+ destination = null;
+ waypoint = null;
+ navigationMapRoute.updateRouteVisibilityTo(false);
+ navigationMapRoute.updateRouteArrowVisibilityTo(false);
+ }
+ }
+
+ private void findRoute() {
+ RouteOptionsNavigation.Builder optionsBuilder = new RouteOptionsNavigation.Builder()
+ .accessToken(Utils.getMapboxAccessToken(this))
+ .origin(origin)
+ .destination(destination);
+ if (waypoint != null) {
+ optionsBuilder.addWaypoint(waypoint);
+ }
+ onboardRouter.getRoute(optionsBuilder.build(), new Router.Callback() {
+ @Override
+ public void onResponse(@NotNull List routes) {
+ if (!routes.isEmpty()) {
+ route = Mappers.mapToDirectionsRoute(routes.get(0));
+ navigationMapRoute.addRoute(route);
+ }
+ }
+
+ @Override
+ public void onFailure(@NotNull Throwable throwable) {
+ Timber.e(throwable, "onRoutesRequestFailure: navigation.getRoute()");
+ }
+ });
+ }
+
+ @Override
+ public boolean onMapClick(@NonNull LatLng point) {
+ if (destination == null) {
+ destination = Point.fromLngLat(point.getLongitude(), point.getLatitude());
+ mapboxMap.addMarker(new MarkerOptions().position(point));
+ findRoute();
+ } else if (waypoint == null) {
+ waypoint = Point.fromLngLat(point.getLongitude(), point.getLatitude());
+ mapboxMap.addMarker(new MarkerOptions().position(point));
+ findRoute();
+ } else {
+ Toast.makeText(this, "Only 2 waypoints supported for this example", Toast.LENGTH_LONG).show();
+ clearMap();
+ }
+ return false;
+ }
+
+ /*
+ * Activity lifecycle methods
+ */
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ mapView.onResume();
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ mapView.onPause();
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ mapView.onStart();
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+ mapView.onStop();
+ }
+
+ @Override
+ public void onLowMemory() {
+ super.onLowMemory();
+ mapView.onLowMemory();
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ if (onboardRouter != null) {
+ onboardRouter.cancel();
+ onboardRouter = null;
+ }
+ if (mapboxMap != null) {
+ mapboxMap.removeOnMapClickListener(this);
+ mapView.onDestroy();
+ }
+ }
+
+ @Override
+ protected void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ mapView.onSaveInstanceState(outState);
+ }
+}
diff --git a/examples/src/main/java/com/mapbox/navigation/examples/activity/OnboardRouterActivityKt.kt b/examples/src/main/java/com/mapbox/navigation/examples/activity/OnboardRouterActivityKt.kt
new file mode 100644
index 00000000000..4867c2dd68c
--- /dev/null
+++ b/examples/src/main/java/com/mapbox/navigation/examples/activity/OnboardRouterActivityKt.kt
@@ -0,0 +1,192 @@
+package com.mapbox.navigation.examples.activity
+
+import android.os.Bundle
+import android.os.Environment
+import android.widget.Toast
+import androidx.appcompat.app.AppCompatActivity
+import com.google.android.material.snackbar.Snackbar
+import com.mapbox.api.directions.v5.models.DirectionsRoute
+import com.mapbox.geojson.Point
+import com.mapbox.mapboxsdk.annotations.MarkerOptions
+import com.mapbox.mapboxsdk.camera.CameraUpdateFactory
+import com.mapbox.mapboxsdk.geometry.LatLng
+import com.mapbox.mapboxsdk.maps.MapboxMap
+import com.mapbox.mapboxsdk.maps.OnMapReadyCallback
+import com.mapbox.mapboxsdk.maps.Style
+import com.mapbox.navigation.base.route.Router
+import com.mapbox.navigation.base.route.model.Route
+import com.mapbox.navigation.base.route.model.RouteOptionsNavigation
+import com.mapbox.navigation.examples.R
+import com.mapbox.navigation.examples.utils.Utils
+import com.mapbox.navigation.examples.utils.extensions.mapToDirectionsRoute
+import com.mapbox.navigation.route.onboard.MapboxOnboardRouter
+import com.mapbox.navigation.route.onboard.model.Config
+import com.mapbox.navigation.utils.extensions.ifNonNull
+import com.mapbox.services.android.navigation.ui.v5.route.NavigationMapRoute
+import com.mapbox.turf.TurfConstants
+import com.mapbox.turf.TurfMeasurement
+import java.io.File
+import kotlinx.android.synthetic.main.activity_mock_navigation.*
+import timber.log.Timber
+
+class OnboardRouterActivityKt : AppCompatActivity(), OnMapReadyCallback,
+ MapboxMap.OnMapClickListener {
+
+ private lateinit var onboardRouter: Router
+ private lateinit var mapboxMap: MapboxMap
+
+ private var route: DirectionsRoute? = null
+ private lateinit var navigationMapRoute: NavigationMapRoute
+ private var origin: Point? = null
+ private var destination: Point? = null
+ private var waypoint: Point? = null
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_mock_navigation)
+ setupRouter()
+ mapView.onCreate(savedInstanceState)
+ mapView.getMapAsync(this)
+ newLocationFab?.setOnClickListener { newOrigin() }
+ }
+
+ private fun setupRouter() {
+ val file = File(
+ Environment.getExternalStoragePublicDirectory("Offline").absolutePath,
+ "2019_04_13-00_00_11"
+ )
+ val fileTiles = File(file, "tiles")
+ val config = Config(
+ fileTiles.absolutePath,
+ null,
+ null,
+ null,
+ null // working with pre-fetched tiles only
+ )
+ onboardRouter = MapboxOnboardRouter(config, null)
+ }
+
+ private fun newOrigin() {
+ clearMap()
+ val latLng = LatLng(47.05991, 9.49183)
+ origin = Point.fromLngLat(latLng.longitude, latLng.latitude)
+ mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng, 12.0))
+ }
+
+ override fun onMapReady(mapboxMap: MapboxMap) {
+ this.mapboxMap = mapboxMap
+ this.mapboxMap.addOnMapClickListener(this)
+ mapboxMap.setStyle(
+ Style.MAPBOX_STREETS
+ ) {
+ navigationMapRoute = NavigationMapRoute(mapView, mapboxMap)
+ Snackbar.make(
+ findViewById(R.id.container),
+ "Tap map to place waypoint",
+ Snackbar.LENGTH_LONG
+ ).show()
+ newOrigin()
+ }
+ }
+
+ private fun clearMap() {
+ mapboxMap.clear()
+ route = null
+ destination = null
+ waypoint = null
+ navigationMapRoute.updateRouteVisibilityTo(false)
+ navigationMapRoute.updateRouteArrowVisibilityTo(false)
+ }
+
+ private fun findRoute() {
+ ifNonNull(origin, destination) { origin, destination ->
+ if (TurfMeasurement.distance(origin, destination, TurfConstants.UNIT_METERS) > 50) {
+
+ val optionsBuilder =
+ RouteOptionsNavigation.Builder()
+ .accessToken(Utils.getMapboxAccessToken(this))
+ .origin(origin)
+ .destination(destination)
+ waypoint?.let { optionsBuilder.addWaypoint(it) }
+
+ onboardRouter.getRoute(optionsBuilder.build(), object : Router.Callback {
+ override fun onResponse(routes: List) {
+ if (routes.isNotEmpty()) {
+ route = routes[0].mapToDirectionsRoute()
+ navigationMapRoute.addRoute(route)
+ }
+ }
+
+ override fun onFailure(throwable: Throwable) {
+ Timber.e(throwable, "onRoutesRequestFailure: navigation.getRoute()")
+ }
+ })
+ }
+ }
+ }
+
+ override fun onMapClick(point: LatLng): Boolean {
+ when {
+ destination == null -> {
+ destination = Point.fromLngLat(point.longitude, point.latitude)
+ mapboxMap.addMarker(MarkerOptions().position(point))
+ findRoute()
+ }
+ waypoint == null -> {
+ waypoint = Point.fromLngLat(point.longitude, point.latitude)
+ mapboxMap.addMarker(MarkerOptions().position(point))
+ findRoute()
+ }
+ else -> {
+ Toast.makeText(
+ this,
+ "Only 2 waypoints supported for this example",
+ Toast.LENGTH_LONG
+ )
+ .show()
+ clearMap()
+ }
+ }
+ return false
+ }
+
+ /*
+ * Activity lifecycle methods
+ */
+ override fun onResume() {
+ super.onResume()
+ mapView.onResume()
+ }
+
+ override fun onPause() {
+ super.onPause()
+ mapView.onPause()
+ }
+
+ override fun onStart() {
+ super.onStart()
+ mapView.onStart()
+ }
+
+ override fun onStop() {
+ super.onStop()
+ mapView.onStop()
+ }
+
+ override fun onLowMemory() {
+ super.onLowMemory()
+ mapView.onLowMemory()
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ onboardRouter.cancel()
+ mapboxMap.removeOnMapClickListener(this)
+ mapView.onDestroy()
+ }
+
+ override fun onSaveInstanceState(outState: Bundle) {
+ super.onSaveInstanceState(outState)
+ mapView.onSaveInstanceState(outState)
+ }
+}
diff --git a/examples/src/main/res/values/strings.xml b/examples/src/main/res/values/strings.xml
index 24ecb3826f2..3f714330c48 100644
--- a/examples/src/main/res/values/strings.xml
+++ b/examples/src/main/res/values/strings.xml
@@ -10,6 +10,12 @@
Offboard Router Java
Shows routes using offboard routing api in Java code.
+ Onboard Router Kotlin
+ Shows routes using onboard routing api in Kotlin code.
+
+ Onboard Router Java
+ Shows routes using onboard routing api in Java code.
+
Trip Service Kotlin
Shows how to use the Service to push notifications in Kotlin code.
diff --git a/gradle/dependencies.gradle b/gradle/dependencies.gradle
index 9e53a48683a..029919224a3 100644
--- a/gradle/dependencies.gradle
+++ b/gradle/dependencies.gradle
@@ -49,7 +49,9 @@ ext {
crashlytics : '2.9.9',
multidex : '2.0.0',
json : '20180813',
- coroutinesAndroid : '1.3.3'
+ coroutinesAndroid : '1.3.3',
+ okhttp : '3.12.0',
+ okio : '2.4.3'
]
dependenciesList = [
// mapbox
@@ -77,6 +79,13 @@ ext {
// code style
ktlint : "com.pinterest:ktlint:${version.ktlint}",
+ // network
+ okhttp : "com.squareup.okhttp3:okhttp:${version.okhttp}",
+ okhttpInterceptor : "com.squareup.okhttp3:logging-interceptor:${version.okhttp}",
+
+ // I/O
+ okio : "com.squareup.okio:okio:${version.okio}",
+
// AutoValue
autoValue : "com.google.auto.value:auto-value:${version.autoValue}",
autoValuesParcel : "com.ryanharter.auto.value:auto-value-parcel:${version.autoValueParcel}",
@@ -141,7 +150,7 @@ ext {
errorprone : '0.0.13',
coveralls : '2.8.1',
spotbugs : '1.3',
- gradle : '3.5.1',
+ gradle : '3.5.3',
dependencyGraph : '0.3.0',
dependencyUpdates: '0.20.0',
kotlin : '1.3.61',
diff --git a/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/internal/navigation/DepartEventHandler.kt b/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/internal/navigation/DepartEventHandler.kt
index 0c12082fc86..5856b5100c6 100644
--- a/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/internal/navigation/DepartEventHandler.kt
+++ b/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/internal/navigation/DepartEventHandler.kt
@@ -2,11 +2,11 @@ package com.mapbox.services.android.navigation.v5.internal.navigation
import android.content.Context
import com.mapbox.services.android.navigation.v5.internal.location.MetricsLocation
-import com.mapbox.services.android.navigation.v5.internal.navigation.metrics.MetricsReporter
import com.mapbox.services.android.navigation.v5.internal.navigation.metrics.NavigationEventFactory
import com.mapbox.services.android.navigation.v5.internal.navigation.metrics.PhoneState
import com.mapbox.services.android.navigation.v5.internal.navigation.metrics.SessionState
import com.mapbox.services.android.navigation.v5.internal.navigation.routeprogress.MetricsRouteProgress
+import com.mapbox.services.android.navigation.v5.navigation.metrics.MetricsReporter
internal class DepartEventHandler(
private val applicationContext: Context,
diff --git a/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/internal/navigation/HttpClient.kt b/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/internal/navigation/HttpClient.kt
index 31d872de64a..76b7cc8f217 100644
--- a/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/internal/navigation/HttpClient.kt
+++ b/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/internal/navigation/HttpClient.kt
@@ -28,8 +28,10 @@ internal class HttpClient(
private val client: OkHttpClient by lazy {
if (BuildConfig.DEBUG) {
- val interceptor = HttpLoggingInterceptor(HttpLoggingInterceptor.Logger { message ->
- Timber.d(message)
+ val interceptor = HttpLoggingInterceptor(object : HttpLoggingInterceptor.Logger {
+ override fun log(message: String) {
+ Timber.d(message)
+ }
}).setLevel(HttpLoggingInterceptor.Level.BASIC)
clientBuilder.addInterceptor(interceptor)
diff --git a/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/internal/navigation/InitialGpsEventFactory.kt b/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/internal/navigation/InitialGpsEventFactory.kt
index 53df2b73ba3..bdd559d5c8e 100644
--- a/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/internal/navigation/InitialGpsEventFactory.kt
+++ b/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/internal/navigation/InitialGpsEventFactory.kt
@@ -1,6 +1,6 @@
package com.mapbox.services.android.navigation.v5.internal.navigation
-import com.mapbox.services.android.navigation.v5.internal.navigation.metrics.MetricsReporter
+import com.mapbox.services.android.navigation.v5.navigation.metrics.MetricsReporter
import com.mapbox.services.android.navigation.v5.utils.time.ElapsedTime
internal class InitialGpsEventFactory @JvmOverloads constructor(
diff --git a/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/internal/navigation/InitialGpsEventHandler.kt b/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/internal/navigation/InitialGpsEventHandler.kt
index ac13a44d9d2..902946c6608 100644
--- a/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/internal/navigation/InitialGpsEventHandler.kt
+++ b/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/internal/navigation/InitialGpsEventHandler.kt
@@ -1,6 +1,6 @@
package com.mapbox.services.android.navigation.v5.internal.navigation
-import com.mapbox.services.android.navigation.v5.internal.navigation.metrics.MetricsReporter
+import com.mapbox.services.android.navigation.v5.navigation.metrics.MetricsReporter
internal class InitialGpsEventHandler(
private val metricsReporter: MetricsReporter
diff --git a/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/internal/navigation/NavigationTelemetry.kt b/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/internal/navigation/NavigationTelemetry.kt
index cd8cae8a3be..4c24df213fa 100644
--- a/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/internal/navigation/NavigationTelemetry.kt
+++ b/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/internal/navigation/NavigationTelemetry.kt
@@ -13,7 +13,6 @@ import com.mapbox.geojson.utils.PolylineUtils
import com.mapbox.services.android.navigation.BuildConfig
import com.mapbox.services.android.navigation.v5.internal.location.MetricsLocation
import com.mapbox.services.android.navigation.v5.internal.navigation.metrics.FeedbackEvent
-import com.mapbox.services.android.navigation.v5.internal.navigation.metrics.MetricsReporter
import com.mapbox.services.android.navigation.v5.internal.navigation.metrics.NavigationAppUserTurnstileEvent
import com.mapbox.services.android.navigation.v5.internal.navigation.metrics.NavigationEventFactory
import com.mapbox.services.android.navigation.v5.internal.navigation.metrics.NavigationMetricListener
@@ -25,6 +24,7 @@ import com.mapbox.services.android.navigation.v5.internal.utils.RingBuffer
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.metrics.MapboxMetricsReporter
+import com.mapbox.services.android.navigation.v5.navigation.metrics.MetricsReporter
import com.mapbox.services.android.navigation.v5.routeprogress.RouteProgress
import com.mapbox.services.android.navigation.v5.utils.exceptions.NavigationException
import com.mapbox.services.android.navigation.v5.utils.extensions.ifNonNull
diff --git a/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/navigation/NavigationRoute.kt b/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/navigation/NavigationRoute.kt
index 00722b16a73..8ad014a4bb1 100644
--- a/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/navigation/NavigationRoute.kt
+++ b/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/navigation/NavigationRoute.kt
@@ -13,7 +13,6 @@ import com.mapbox.geojson.Point
import com.mapbox.services.android.navigation.v5.internal.accounts.SkuInterceptor
import com.mapbox.services.android.navigation.v5.utils.extensions.getUnitTypeForLocale
import com.mapbox.services.android.navigation.v5.utils.extensions.inferDeviceLocale
-import com.mapbox.services.android.navigation.v5.utils.extensions.mapToWalkingOptions
import java.util.Locale
import okhttp3.EventListener
import okhttp3.Interceptor
@@ -626,8 +625,8 @@ internal constructor(
* @param navigationWalkingOptions object holding walking options
* @return this builder for chaining options together
*/
- fun walkingOptions(navigationWalkingOptions: WalkingOptionsNavigation): Builder {
- directionsBuilder.walkingOptions(navigationWalkingOptions.mapToWalkingOptions())
+ fun walkingOptions(navigationWalkingOptions: NavigationWalkingOptions): Builder {
+ directionsBuilder.walkingOptions(navigationWalkingOptions.walkingOptions)
return this
}
diff --git a/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/navigation/NavigationRouteWaypoint.kt b/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/navigation/NavigationRouteWaypoint.kt
index 6d5f5620cae..c648dae2384 100644
--- a/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/navigation/NavigationRouteWaypoint.kt
+++ b/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/navigation/NavigationRouteWaypoint.kt
@@ -2,7 +2,7 @@ package com.mapbox.services.android.navigation.v5.navigation
import com.mapbox.geojson.Point
-internal data class NavigationRouteWaypoint(
+data class NavigationRouteWaypoint(
val point: Point,
val bearingAngle: Double?,
val tolerance: Double?
diff --git a/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/navigation/NavigationWalkingOptions.kt b/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/navigation/NavigationWalkingOptions.kt
new file mode 100644
index 00000000000..ce63379be8a
--- /dev/null
+++ b/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/navigation/NavigationWalkingOptions.kt
@@ -0,0 +1,73 @@
+package com.mapbox.services.android.navigation.v5.navigation
+
+import com.mapbox.api.directions.v5.WalkingOptions
+
+/**
+ * Class for specifying options for use with the walking profile.
+ */
+class NavigationWalkingOptions internal constructor(val walkingOptions: WalkingOptions) {
+
+ companion object {
+ /**
+ * Build a new [WalkingOptions] object with no defaults.
+ *
+ * @return a [Builder] object for creating a [NavigationWalkingOptions] object
+ */
+ @JvmStatic
+ fun builder(): Builder {
+ return Builder(WalkingOptions.builder())
+ }
+ }
+
+ /**
+ * This builder is used to create a new object with specifications relating to walking directions.
+ */
+ class Builder internal constructor(private val builder: WalkingOptions.Builder) {
+
+ /**
+ * Builds a [NavigationWalkingOptions] object with the specified configurations.
+ *
+ * @return a NavigationWalkingOptions object
+ */
+ fun build(): NavigationWalkingOptions = NavigationWalkingOptions(builder.build())
+
+ /**
+ * Walking speed in meters per second. Must be between 0.14 and 6.94 meters per second.
+ * Defaults to 1.42 meters per second
+ *
+ * @param walkingSpeed in meters per second
+ * @return this builder
+ */
+ fun walkingSpeed(walkingSpeed: Double?): Builder {
+ builder.walkingSpeed(walkingSpeed)
+ return this
+ }
+
+ /**
+ * A bias which determines whether the route should prefer or avoid the use of roads or paths
+ * that are set aside for pedestrian-only use (walkways). The allowed range of values is from
+ * -1 to 1, where -1 indicates preference to avoid walkways, 1 indicates preference to favor
+ * walkways, and 0 indicates no preference (the default).
+ *
+ * @param walkwayBias bias to prefer or avoid walkways
+ * @return this builder
+ */
+ fun walkwayBias(walkwayBias: Double?): Builder {
+ builder.walkwayBias(walkwayBias)
+ return this
+ }
+
+ /**
+ * A bias which determines whether the route should prefer or avoid the use of alleys. The
+ * allowed range of values is from -1 to 1, where -1 indicates preference to avoid alleys, 1
+ * indicates preference to favor alleys, and 0 indicates no preference (the default).
+ *
+ * @param alleyBias bias to prefer or avoid alleys
+ * @return this builder
+ */
+ fun alleyBias(alleyBias: Double?): Builder {
+ builder.alleyBias(alleyBias)
+ return this
+ }
+ }
+}
diff --git a/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/navigation/metrics/MapboxMetricsReporter.kt b/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/navigation/metrics/MapboxMetricsReporter.kt
index 1ae4e2b115f..a0aea60c434 100644
--- a/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/navigation/metrics/MapboxMetricsReporter.kt
+++ b/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/navigation/metrics/MapboxMetricsReporter.kt
@@ -3,7 +3,6 @@ package com.mapbox.services.android.navigation.v5.navigation.metrics
import android.content.Context
import com.google.gson.Gson
import com.mapbox.android.telemetry.MapboxTelemetry
-import com.mapbox.services.android.navigation.v5.internal.navigation.metrics.MetricsReporter
import com.mapbox.services.android.navigation.v5.internal.utils.extensions.toTelemetryEvent
import com.mapbox.services.android.navigation.v5.utils.thread.WorkThreadHandler
diff --git a/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/navigation/metrics/MetricsReporter.kt b/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/navigation/metrics/MetricsReporter.kt
new file mode 100644
index 00000000000..a6855f4f5eb
--- /dev/null
+++ b/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/navigation/metrics/MetricsReporter.kt
@@ -0,0 +1,32 @@
+package com.mapbox.services.android.navigation.v5.navigation.metrics
+
+/**
+ * Interface for handling metric events.
+ *
+ * @since 0.43.0
+ */
+interface MetricsReporter {
+
+ /**
+ * Add event to metrics reporter when this event occurs.
+ *
+ * @param metricEvent event that should be handled
+ * @since 0.43.0
+ */
+ fun addEvent(metricEvent: MetricEvent)
+
+ /**
+ * Add observer that triggered when metric event handled
+ *
+ * @param metricsObserver metric event handle observer
+ * @since 0.43.0
+ */
+ fun setMetricsObserver(metricsObserver: MetricsObserver)
+
+ /**
+ * Remove metrics observer
+ *
+ * @since 0.43.0
+ */
+ fun removeObserver()
+}
diff --git a/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/utils/extensions/Mappers.kt b/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/utils/extensions/Mappers.kt
deleted file mode 100644
index b414d7c0dc1..00000000000
--- a/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/utils/extensions/Mappers.kt
+++ /dev/null
@@ -1,13 +0,0 @@
-@file:JvmName("Mappers")
-
-package com.mapbox.services.android.navigation.v5.utils.extensions
-
-import com.mapbox.api.directions.v5.WalkingOptions
-import com.mapbox.services.android.navigation.v5.navigation.WalkingOptionsNavigation
-
-fun WalkingOptionsNavigation.mapToWalkingOptions(): WalkingOptions = WalkingOptions
- .builder()
- .walkingSpeed(walkingSpeed)
- .walkwayBias(walkwayBias)
- .alleyBias(alleyBias)
- .build()
diff --git a/libandroid-navigation/src/test/java/com/mapbox/services/android/navigation/v5/internal/navigation/InitialGpsEventFactoryTest.java b/libandroid-navigation/src/test/java/com/mapbox/services/android/navigation/v5/internal/navigation/InitialGpsEventFactoryTest.java
index 66e3332d391..2af41a53e22 100644
--- a/libandroid-navigation/src/test/java/com/mapbox/services/android/navigation/v5/internal/navigation/InitialGpsEventFactoryTest.java
+++ b/libandroid-navigation/src/test/java/com/mapbox/services/android/navigation/v5/internal/navigation/InitialGpsEventFactoryTest.java
@@ -1,6 +1,6 @@
package com.mapbox.services.android.navigation.v5.internal.navigation;
-import com.mapbox.services.android.navigation.v5.internal.navigation.metrics.MetricsReporter;
+import com.mapbox.services.android.navigation.v5.navigation.metrics.MetricsReporter;
import com.mapbox.services.android.navigation.v5.utils.time.ElapsedTime;
import org.junit.Test;
diff --git a/libdirections-offboard/src/main/java/com/mapbox/navigation/route/offboard/MapboxOffboardRouter.kt b/libdirections-offboard/src/main/java/com/mapbox/navigation/route/offboard/MapboxOffboardRouter.kt
index 1ff18714492..a943c060dae 100644
--- a/libdirections-offboard/src/main/java/com/mapbox/navigation/route/offboard/MapboxOffboardRouter.kt
+++ b/libdirections-offboard/src/main/java/com/mapbox/navigation/route/offboard/MapboxOffboardRouter.kt
@@ -26,7 +26,9 @@ class MapboxOffboardRouter(private val accessToken: String, private val context:
routeOptions: RouteOptionsNavigation,
callback: Router.Callback
) {
- navigationRoute = RouteBuilderProvider.getBuilder(accessToken, context).routeOptions(routeOptions).build()
+ navigationRoute = RouteBuilderProvider.getBuilder(accessToken, context)
+ .routeOptions(routeOptions)
+ .build()
navigationRoute?.getRoute(object : Callback {
override fun onResponse(
diff --git a/libdirections-offboard/src/main/java/com/mapbox/navigation/route/offboard/extension/Mappers.kt b/libdirections-offboard/src/main/java/com/mapbox/navigation/route/offboard/extension/Mappers.kt
index c78acde76fe..b9f1a97b0f1 100644
--- a/libdirections-offboard/src/main/java/com/mapbox/navigation/route/offboard/extension/Mappers.kt
+++ b/libdirections-offboard/src/main/java/com/mapbox/navigation/route/offboard/extension/Mappers.kt
@@ -4,16 +4,32 @@ package com.mapbox.navigation.route.offboard.extension
import com.mapbox.api.directions.v5.DirectionsCriteria
import com.mapbox.api.directions.v5.WalkingOptions
+import com.mapbox.api.directions.v5.models.BannerComponents
+import com.mapbox.api.directions.v5.models.BannerInstructions
+import com.mapbox.api.directions.v5.models.BannerText
import com.mapbox.api.directions.v5.models.DirectionsRoute
+import com.mapbox.api.directions.v5.models.IntersectionLanes
+import com.mapbox.api.directions.v5.models.LegAnnotation
import com.mapbox.api.directions.v5.models.LegStep
+import com.mapbox.api.directions.v5.models.MaxSpeed
import com.mapbox.api.directions.v5.models.RouteLeg
import com.mapbox.api.directions.v5.models.RouteOptions
+import com.mapbox.api.directions.v5.models.StepIntersection
import com.mapbox.api.directions.v5.models.StepManeuver
+import com.mapbox.api.directions.v5.models.VoiceInstructions
+import com.mapbox.navigation.base.route.model.BannerComponentsNavigation
+import com.mapbox.navigation.base.route.model.BannerInstructionsNavigation
+import com.mapbox.navigation.base.route.model.BannerTextNavigation
+import com.mapbox.navigation.base.route.model.IntersectionLanesNavigation
+import com.mapbox.navigation.base.route.model.LegAnnotationNavigation
import com.mapbox.navigation.base.route.model.LegStepNavigation
+import com.mapbox.navigation.base.route.model.MaxSpeedNavigation
import com.mapbox.navigation.base.route.model.Route
import com.mapbox.navigation.base.route.model.RouteLegNavigation
import com.mapbox.navigation.base.route.model.RouteOptionsNavigation
+import com.mapbox.navigation.base.route.model.StepIntersectionNavigation
import com.mapbox.navigation.base.route.model.StepManeuverNavigation
+import com.mapbox.navigation.base.route.model.VoiceInstructionsNavigation
import com.mapbox.navigation.base.route.model.WalkingOptionsNavigation
import java.util.Locale
@@ -43,8 +59,8 @@ fun RouteLeg.mapToRouteLeg() = RouteLegNavigation.Builder()
fun DirectionsRoute.mapToRoute() = Route(
routeIndex = routeIndex(),
- distance = distance()!!,
- duration = duration()?.toLong()!!,
+ distance = distance() ?: .0,
+ duration = duration()?.toLong() ?: 0,
geometry = geometry(),
weight = weight(),
weightName = weightName(),
@@ -57,6 +73,21 @@ fun DirectionsRoute.mapToRoute() = Route(
voiceLanguage = voiceLanguage()
)
+fun RouteLeg.mapToRouteLegNavigation() = RouteLegNavigation.Builder()
+ .distance(distance())
+ .duration(duration())
+ .steps(steps()?.map { it.mapToLegStep() })
+ .summary(summary())
+ .build()
+
+fun LegStep.mapToLegStepNavigation() = LegStepNavigation.Builder()
+ .stepManeuver(maneuver().mapToStepManeuverNavigation())
+ .distance(distance())
+ .drivingSide(drivingSide())
+ .duration(duration())
+ .geometry(geometry())
+ .build()
+
fun RouteOptions.mapToRouteOptionsNavigation(): RouteOptionsNavigation {
val routeOptionsNavigationBuilder = RouteOptionsNavigation
.builder()
@@ -99,6 +130,73 @@ fun RouteOptions.mapToRouteOptionsNavigation(): RouteOptionsNavigation {
.build()
}
+fun VoiceInstructions.mapToVoiceInstructionsNavigation() = VoiceInstructionsNavigation(
+ distanceAlongGeometry = distanceAlongGeometry(),
+ announcement = announcement(),
+ ssmlAnnouncement = ssmlAnnouncement()
+)
+
+fun BannerInstructions.mapToBannerInstructionsNavigation() = BannerInstructionsNavigation(
+ distanceAlongGeometry = distanceAlongGeometry(),
+ primary = primary().mapToBannerTextNavigation(),
+ secondary = secondary()?.mapToBannerTextNavigation(),
+ sub = sub()?.mapToBannerTextNavigation()
+)
+
+fun BannerText.mapToBannerTextNavigation() = BannerTextNavigation(
+ text = text(),
+ components = components()?.map { it.mapToBannerComponentsNavigation() },
+ type = type(),
+ modifier = modifier(),
+ degrees = degrees(),
+ drivingSide = drivingSide()
+)
+
+fun BannerComponents.mapToBannerComponentsNavigation() = BannerComponentsNavigation(
+ text = text(),
+ type = type(),
+ abbreviation = abbreviation(),
+ abbreviationPriority = abbreviationPriority(),
+ imageBaseUrl = imageBaseUrl(),
+ directions = directions(),
+ active = active()
+)
+
+fun StepManeuver.mapToStepManeuverNavigation() = StepManeuverNavigation.Builder()
+ .modifier(modifier())
+ .type(type())
+ .build()
+
+fun StepIntersection.mapToStepIntersectionNavigation() = StepIntersectionNavigation(
+ location = location(),
+ bearings = bearings(),
+ classes = classes(),
+ entry = entry(),
+ into = `in`(),
+ out = out(),
+ lanes = lanes()?.map { it.mapToIntersectionLanesNavigation() }
+)
+
+fun IntersectionLanes.mapToIntersectionLanesNavigation() = IntersectionLanesNavigation(
+ valid = valid(),
+ indications = indications()
+)
+
+fun LegAnnotation.mapToLegAnnotationNavigation() = LegAnnotationNavigation(
+ distance = distance(),
+ duration = duration(),
+ speed = speed(),
+ maxspeed = maxspeed()?.map(MaxSpeed::mapToMaxSpeedNavigation),
+ congestion = congestion()
+)
+
+fun MaxSpeed.mapToMaxSpeedNavigation() = MaxSpeedNavigation(
+ speed = speed(),
+ unit = unit(),
+ unknown = unknown(),
+ none = none()
+)
+
fun WalkingOptionsNavigation.mapToWalkingOptions(): WalkingOptions = WalkingOptions
.builder()
.walkingSpeed(walkingSpeed)
diff --git a/libdirections-offboard/src/main/java/com/mapbox/navigation/route/offboard/router/NavigationOffboardRoute.kt b/libdirections-offboard/src/main/java/com/mapbox/navigation/route/offboard/router/NavigationOffboardRoute.kt
index c4afd4b77c3..b04583422fc 100644
--- a/libdirections-offboard/src/main/java/com/mapbox/navigation/route/offboard/router/NavigationOffboardRoute.kt
+++ b/libdirections-offboard/src/main/java/com/mapbox/navigation/route/offboard/router/NavigationOffboardRoute.kt
@@ -18,7 +18,7 @@ import retrofit2.Call
import retrofit2.Callback
/**
- * The NavigationRoute class wraps the [MapboxDirections] class with parameters which
+ * The NavigationOffboardRoute class wraps the [MapboxDirections] class with parameters which
* must be set in order for a navigation session to successfully begin. While it is possible
* to pass in any [com.mapbox.api.directions.v5.models.DirectionsRoute] into
* [MapboxNavigation.startNavigation], using this class will ensure your
@@ -26,9 +26,8 @@ import retrofit2.Callback
*
* Developer Note: MapboxDirections cannot be directly extended since it is an AutoValue class.
*
- * 1.0
+ * 1.0.0
*/
-
internal class NavigationOffboardRoute
constructor(
private val mapboxDirections: MapboxDirections
@@ -53,7 +52,7 @@ constructor(
* [Callback] must be passed into the method to handle both the response and failure.
*
* @param callback a RetroFit callback which contains an onResponse and onFailure
- * @since 0.5.0
+ * @since 1.0.0
*/
fun getRoute(callback: Callback) {
mapboxDirections.enqueueCall(callback)
@@ -82,33 +81,33 @@ constructor(
* reflect your users use-case.
*
*
- * @since 0.5.0
+ * @since 1.0.0
*/
class Builder internal constructor(private val directionsBuilder: MapboxDirections.Builder) {
- private val eventListener: NavigationRouteEventListener
+
+ companion object {
+ private const val SEMICOLON = ";"
+ private const val COMMA = ","
+ }
+
+ private val eventListener: NavigationRouteEventListener = EVENT_LISTENER
private var origin: RoutePointNavigation? = null
private var destination: RoutePointNavigation? = null
private val waypoints = ArrayList()
- private val SEMICOLON = ";"
- private val COMMA = ","
/**
* Private constructor for initializing the raw MapboxDirections.Builder
*/
- constructor() : this(MapboxDirections.builder()) {}
-
- init {
- this.eventListener = EVENT_LISTENER
- }
+ constructor() : this(MapboxDirections.builder())
/**
* This selects which mode of transportation the user will be using while navigating from the
* origin to the final destination. The options include driving, driving considering traffic,
* walking, and cycling. Using each of these profiles will result in different routing biases.
*
- * @param profile required to be one of the String values found in the [ProfileCriteria]
+ * @param profile required to be one of the String values found in the [DirectionsCriteria.ProfileCriteria]
* @return this builder for chaining options together
- * @since 0.5.0
+ * @since 1.0.0
*/
internal fun profile(@DirectionsCriteria.ProfileCriteria profile: String): Builder {
directionsBuilder.profile(profile)
@@ -180,7 +179,7 @@ constructor(
*
* @param clientAppName base package name or other simple string identifier
* @return this builder for chaining options together
- * @since 0.5.0
+ * @since 1.0.0
*/
fun clientAppName(clientAppName: String): Builder {
directionsBuilder.clientAppName(clientAppName)
@@ -242,31 +241,23 @@ constructor(
*
* @param options containing all variables for request
* @return this builder for chaining options together
- * @since 0.9.0
+ * @since 1.0.0
*/
- internal fun routeOptions(options: RouteOptionsNavigation): Builder {
- options.baseUrl?.let {
- directionsBuilder.baseUrl(it)
- }
+ fun routeOptions(options: RouteOptionsNavigation): Builder {
+ directionsBuilder.baseUrl(options.baseUrl)
- options.user?.let {
- directionsBuilder.user(it)
- }
+ directionsBuilder.user(options.user)
- options.profile?.let {
- directionsBuilder.profile(it)
- }
+ directionsBuilder.profile(options.profile)
- origin = options.coordinates.first()
+ origin = options.origin
waypoints.clear()
- waypoints.addAll(options.coordinates.drop(1).dropLast(1))
+ waypoints.addAll(options.waypoints)
- destination = options.coordinates.last()
+ destination = options.destination
- options.alternatives?.let {
- directionsBuilder.alternatives(it)
- }
+ directionsBuilder.alternatives(options.alternatives)
options.language?.let {
directionsBuilder.language(Locale(it))
@@ -289,45 +280,33 @@ constructor(
}
}
- options.continueStraight?.let {
- directionsBuilder.continueStraight(it)
- }
+ directionsBuilder.continueStraight(options.continueStraight)
- options.roundaboutExits?.let {
- directionsBuilder.roundaboutExits(it)
- }
+ directionsBuilder.roundaboutExits(options.roundaboutExits)
options.geometries?.let {
- directionsBuilder.geometries(it)
+ directionsBuilder.geometries(options.geometries)
}
options.overview?.let {
directionsBuilder.overview(it)
}
- options.steps?.let {
- directionsBuilder.steps(it)
- }
+ directionsBuilder.steps(options.steps)
options.annotations?.let {
directionsBuilder.annotations(it)
}
- options.voiceInstructions?.let {
- directionsBuilder.voiceInstructions(it)
- }
+ directionsBuilder.voiceInstructions(options.voiceInstructions)
- options.bannerInstructions?.let {
- directionsBuilder.bannerInstructions(it)
- }
+ directionsBuilder.bannerInstructions(options.bannerInstructions)
options.voiceUnits?.let {
directionsBuilder.voiceUnits(it)
}
- options.accessToken?.let {
- directionsBuilder.accessToken(it)
- }
+ directionsBuilder.accessToken(options.accessToken)
options.requestUuid?.let {
// TODO Check if needed as it is only set at response time
@@ -381,7 +360,7 @@ constructor(
* settings for navigation to work correctly.
*
* @return a new instance of Navigation Route
- * @since 0.5.0
+ * @since 1.0.0
*/
fun build(): NavigationOffboardRoute {
// Set the default values which the user cannot alter.
@@ -395,11 +374,10 @@ constructor(
val splitWaypointIndices =
waypointIndices.split(SEMICOLON.toRegex()).dropLastWhile { it.isEmpty() }
.toTypedArray()
- val indices = Array(splitWaypointIndices.size, { 0 })
- var index = 0
- for (waypointIndex in splitWaypointIndices) {
+ val indices = Array(splitWaypointIndices.size) { 0 }
+ for ((index, waypointIndex) in splitWaypointIndices.withIndex()) {
val parsedIndex = Integer.valueOf(waypointIndex)
- indices[index++] = parsedIndex
+ indices[index] = parsedIndex
}
return indices
}
diff --git a/libdirections-offboard/src/test/java/com/mapbox/navigation/route/offboard/MapboxOffboardRouterTest.kt b/libdirections-offboard/src/test/java/com/mapbox/navigation/route/offboard/MapboxOffboardRouterTest.kt
index 2e90ff5e9a5..171319b1acc 100644
--- a/libdirections-offboard/src/test/java/com/mapbox/navigation/route/offboard/MapboxOffboardRouterTest.kt
+++ b/libdirections-offboard/src/test/java/com/mapbox/navigation/route/offboard/MapboxOffboardRouterTest.kt
@@ -6,7 +6,6 @@ import com.mapbox.api.directions.v5.models.DirectionsRoute
import com.mapbox.navigation.base.route.Router
import com.mapbox.navigation.base.route.model.RouteOptionsNavigation
import com.mapbox.navigation.route.offboard.base.BaseTest
-import com.mapbox.navigation.route.offboard.extension.mapToRoute
import com.mapbox.navigation.route.offboard.router.NavigationOffboardRoute
import io.mockk.every
import io.mockk.mockk
@@ -80,7 +79,7 @@ class MapboxOffboardRouterTest : BaseTest() {
callback.onResponse(mockk(), response)
- verify { routerCallback.onResponse(listOf(route.mapToRoute())) }
+ verify { routerCallback.onResponse(any()) }
}
@Test
diff --git a/libdirections-onboard/build.gradle b/libdirections-onboard/build.gradle
index feb58a297d1..95b230534c0 100644
--- a/libdirections-onboard/build.gradle
+++ b/libdirections-onboard/build.gradle
@@ -27,9 +27,18 @@ dependencies {
ktlint dependenciesList.ktlint
implementation dependenciesList.kotlinStdLib
+ implementation dependenciesList.supportAnnotation
+
+ //networks
+ implementation dependenciesList.okhttp
+ implementation dependenciesList.okhttpInterceptor
+
+ // I/O
+ implementation dependenciesList.okio
testImplementation dependenciesList.mockk
testImplementation dependenciesList.junit
+ testImplementation dependenciesList.robolectric
}
apply from: "${rootDir}/gradle/bintray-publish.gradle"
\ No newline at end of file
diff --git a/libdirections-onboard/src/main/java/com/mapbox/navigation/route/onboard/MapboxOnboardRouter.kt b/libdirections-onboard/src/main/java/com/mapbox/navigation/route/onboard/MapboxOnboardRouter.kt
index 0ce6fa0d3d1..74787bcdb1c 100644
--- a/libdirections-onboard/src/main/java/com/mapbox/navigation/route/onboard/MapboxOnboardRouter.kt
+++ b/libdirections-onboard/src/main/java/com/mapbox/navigation/route/onboard/MapboxOnboardRouter.kt
@@ -2,21 +2,90 @@ package com.mapbox.navigation.route.onboard
import com.mapbox.annotation.navigation.module.MapboxNavigationModule
import com.mapbox.annotation.navigation.module.MapboxNavigationModuleType
+import com.mapbox.navigation.base.logger.Logger
+import com.mapbox.navigation.base.route.RouteUrl
import com.mapbox.navigation.base.route.Router
+import com.mapbox.navigation.base.route.model.Route
import com.mapbox.navigation.base.route.model.RouteOptionsNavigation
import com.mapbox.navigation.navigator.MapboxNativeNavigator
+import com.mapbox.navigation.navigator.MapboxNativeNavigatorImpl
+import com.mapbox.navigation.route.onboard.model.Config
+import com.mapbox.navigation.route.onboard.model.OfflineError
+import com.mapbox.navigation.route.onboard.model.mapToRouteConfig
+import com.mapbox.navigation.route.onboard.network.HttpClient
+import com.mapbox.navigation.route.onboard.task.OfflineRouteRetrievalTask
+import com.mapbox.navigation.utils.exceptions.NavigationException
+import java.io.File
@MapboxNavigationModule(MapboxNavigationModuleType.OnboardRouter, skipConfiguration = true)
-class MapboxOnboardRouter(private val navigator: MapboxNativeNavigator) : Router {
+class MapboxOnboardRouter : Router {
+
+ companion object {
+ private const val TILES_DIR_NAME = "tiles"
+ }
+
+ private val navigatorNative: MapboxNativeNavigator
+ private val config: Config
+ private val logger: Logger?
+
+ /**
+ * Creates an offline router which uses the specified offline path for storing and retrieving
+ * data.
+ *
+ * @param config offline config
+ */
+ constructor(config: Config, logger: Logger?) {
+ val tileDir = File(config.tilePath, TILES_DIR_NAME)
+ if (!tileDir.exists()) {
+ tileDir.mkdirs()
+ }
+
+ this.navigatorNative = MapboxNativeNavigatorImpl
+ this.config = config
+ this.logger = logger
+ val httpClient = HttpClient()
+ MapboxNativeNavigatorImpl.configureRouter(config.mapToRouteConfig(), httpClient, httpClient.userAgent)
+ }
+
+ // Package private for testing purposes
+ internal constructor(
+ navigator: MapboxNativeNavigator,
+ config: Config
+ ) {
+ this.navigatorNative = navigator
+ this.config = config
+ this.logger = null
+ }
override fun getRoute(
routeOptions: RouteOptionsNavigation,
callback: Router.Callback
- ) = Unit
+ ) {
+ val offlineRouter = OfflineRoute.builder(
+ RouteUrl(
+ accessToken = routeOptions.accessToken,
+ user = routeOptions.user,
+ profile = routeOptions.profile,
+ orgin = routeOptions.origin.point,
+ waypoints = routeOptions.waypoints.map { it.point },
+ destination = routeOptions.destination.point,
+ steps = routeOptions.steps,
+ voiceIntruction = routeOptions.voiceInstructions,
+ bannerIntruction = routeOptions.bannerInstructions,
+ roundaboutExits = routeOptions.roundaboutExits
+ )
+ ).build()
- override fun cancel() = Unit
+ OfflineRouteRetrievalTask(navigatorNative, logger, object : OnOfflineRouteFoundCallback {
+ override fun onRouteFound(routes: List) {
+ callback.onResponse(routes)
+ }
- class Config {
- fun compile(): String = TODO("not implemented")
+ override fun onError(error: OfflineError) {
+ callback.onFailure(NavigationException(error.message))
+ }
+ }).execute(offlineRouter.buildUrl())
}
+
+ override fun cancel() = Unit
}
diff --git a/libdirections-onboard/src/main/java/com/mapbox/navigation/route/onboard/OfflineCriteria.kt b/libdirections-onboard/src/main/java/com/mapbox/navigation/route/onboard/OfflineCriteria.kt
new file mode 100644
index 00000000000..9a47f080ae1
--- /dev/null
+++ b/libdirections-onboard/src/main/java/com/mapbox/navigation/route/onboard/OfflineCriteria.kt
@@ -0,0 +1,49 @@
+package com.mapbox.navigation.route.onboard
+
+object OfflineCriteria {
+
+ /**
+ * BicycleType parameter in the Directions API.
+ */
+ enum class BicycleType(val type: String) {
+ /**
+ * Bicycle type for road bike.
+ */
+ ROAD("Road"),
+
+ /**
+ * Bicycle type for hybrid bike.
+ */
+ HYBRID("Hybrid"),
+
+ /**
+ * Bicycle type for city bike.
+ */
+ CITY("City"),
+
+ /**
+ * Bicycle type for cross bike.
+ */
+ CROSS("Cross"),
+
+ /**
+ * Bicycle type for mountain bike.
+ */
+ MOUNTAIN("Mountain");
+ }
+
+ /**
+ * WaypointType parameter in the Directions API.
+ */
+ enum class WaypointType(val type: String) {
+ /**
+ * Break waypoint type.
+ */
+ BREAK("break"),
+
+ /**
+ * Through waypoint type.
+ */
+ THROUGH("through")
+ }
+}
diff --git a/libdirections-onboard/src/main/java/com/mapbox/navigation/route/onboard/OfflineRoute.kt b/libdirections-onboard/src/main/java/com/mapbox/navigation/route/onboard/OfflineRoute.kt
new file mode 100644
index 00000000000..e680caaf2c3
--- /dev/null
+++ b/libdirections-onboard/src/main/java/com/mapbox/navigation/route/onboard/OfflineRoute.kt
@@ -0,0 +1,228 @@
+package com.mapbox.navigation.route.onboard
+
+import android.net.Uri
+import androidx.annotation.FloatRange
+import com.mapbox.navigation.base.route.RouteUrl
+import com.mapbox.navigation.utils.extensions.ifNonNull
+
+/**
+ * The [OfflineRoute] class wraps the [NavigationRoute] class with parameters which
+ * could be set in order for an offline navigation session to successfully begin.
+ */
+internal class OfflineRoute
+private constructor(
+ private val routeUrl: RouteUrl,
+ bicycleType: OfflineCriteria.BicycleType?,
+ private val cyclingSpeed: Float?,
+ private val cyclewayBias: Float?,
+ private val hillBias: Float?,
+ private val ferryBias: Float?,
+ private val roughSurfaceBias: Float?,
+ waypointTypes: List?
+) {
+ private val bicycleType: String?
+ private val waypointTypes: String?
+
+ init {
+ this.bicycleType = bicycleType?.type
+ this.waypointTypes = checkWaypointTypes(waypointTypes)
+ }
+
+ companion object {
+
+ private const val BICYCLE_TYPE_QUERY_PARAMETER = "bicycle_type"
+ private const val CYCLING_SPEED_QUERY_PARAMETER = "cycling_speed"
+ private const val CYCLEWAY_BIAS_QUERY_PARAMETER = "cycleway_bias"
+ private const val HILL_BIAS_QUERY_PARAMETER = "hill_bias"
+ private const val FERRY_BIAS_QUERY_PARAMETER = "ferry_bias"
+ private const val ROUGH_SURFACE_BIAS_QUERY_PARAMETER = "rough_surface_bias"
+ private const val WAYPOINT_TYPES_QUERY_PARAMETER = "waypoint_types"
+
+ /**
+ * Build a new [OfflineRoute] object with the proper offline navigation parameters already setup.
+ *
+ * @return a [Builder] object for creating this object
+ */
+ @JvmStatic
+ fun builder(routeUrl: RouteUrl): Builder {
+ return Builder(routeUrl)
+ }
+ }
+
+ /**
+ * Builds a URL string for offline.
+ *
+ * @return the offline url string
+ */
+ fun buildUrl(): String {
+ return buildOfflineUrl(routeUrl.getRequest())
+ }
+
+ private fun checkWaypointTypes(waypointTypes: List?): String? {
+ return if (waypointTypes.isNullOrEmpty()) {
+ null
+ } else {
+ formatWaypointTypes(waypointTypes)
+ ?: throw IllegalStateException("All waypoint types values must be one of break, through or null")
+ }
+ }
+
+ private fun formatWaypointTypes(waypointTypesToFormat: List): String? {
+ val waypointTypes = waypointTypesToFormat.map { it?.type ?: "" }.toTypedArray()
+ return waypointTypes.joinTo(StringBuilder(), ";").toString()
+ }
+
+ private fun buildOfflineUrl(url: Uri): String {
+ val offlineUrlBuilder = url.buildUpon()
+
+ offlineUrlBuilder.appendQueryParamIfNonNull(BICYCLE_TYPE_QUERY_PARAMETER, bicycleType)
+ offlineUrlBuilder.appendQueryParamIfNonNull(CYCLING_SPEED_QUERY_PARAMETER, cyclingSpeed)
+ offlineUrlBuilder.appendQueryParamIfNonNull(CYCLEWAY_BIAS_QUERY_PARAMETER, cyclewayBias)
+ offlineUrlBuilder.appendQueryParamIfNonNull(HILL_BIAS_QUERY_PARAMETER, hillBias)
+ offlineUrlBuilder.appendQueryParamIfNonNull(FERRY_BIAS_QUERY_PARAMETER, ferryBias)
+ offlineUrlBuilder.appendQueryParamIfNonNull(
+ ROUGH_SURFACE_BIAS_QUERY_PARAMETER,
+ roughSurfaceBias
+ )
+ offlineUrlBuilder.appendQueryParamIfNonNull(WAYPOINT_TYPES_QUERY_PARAMETER, waypointTypes)
+
+ return offlineUrlBuilder.build().toString()
+ }
+
+ private fun Uri.Builder.appendQueryParamIfNonNull(key: String, value: Float?): Uri.Builder =
+ appendQueryParamIfNonNull(key, value?.toString())
+
+ private fun Uri.Builder.appendQueryParamIfNonNull(key: String, value: String?): Uri.Builder =
+ ifNonNull(value) {
+ appendQueryParameter(key, it)
+ } ?: this
+
+ class Builder internal constructor(private val routeUrl: RouteUrl) {
+ private var bicycleType: OfflineCriteria.BicycleType? = null
+ private var cyclingSpeed: Float? = null
+ private var cyclewayBias: Float? = null
+ private var hillBias: Float? = null
+ private var ferryBias: Float? = null
+ private var roughSurfaceBias: Float? = null
+ private var waypointTypes: List? = null
+
+ /**
+ * The type of bicycle, either Road, Hybrid, City, Cross, Mountain.
+ * The default type is Hybrid.
+ *
+ * @param bicycleType the type of bicycle
+ * @return this builder for chaining options together
+ */
+ fun bicycleType(bicycleType: OfflineCriteria.BicycleType?): Builder {
+ this.bicycleType = bicycleType
+ return this
+ }
+
+ /**
+ * Cycling speed is the average travel speed along smooth, flat roads. This is meant to be the
+ * speed a rider can comfortably maintain over the desired distance of the route. It can be
+ * modified (in the costing method) by surface type in conjunction with bicycle type and
+ * (coming soon) by hilliness of the road section. When no speed is specifically provided, the
+ * default speed is determined by the bicycle type and are as follows: Road = 25 KPH (15.5 MPH),
+ * Cross = 20 KPH (13 MPH), Hybrid/City = 18 KPH (11.5 MPH), and Mountain = 16 KPH (10 MPH).
+ *
+ * @param cyclingSpeed in kmh
+ * @return this builder for chaining options together
+ */
+ fun cyclingSpeed(@FloatRange(from = 5.0, to = 60.0) cyclingSpeed: Float?): Builder {
+ this.cyclingSpeed = cyclingSpeed
+ return this
+ }
+
+ /**
+ * A cyclist's propensity to use roads alongside other vehicles. This is a range of values from -1
+ * to 1, where -1 attempts to avoid roads and stay on cycleways and paths, and 1 indicates the
+ * rider is more comfortable riding on roads. Based on the use_roads factor, roads with certain
+ * classifications and higher speeds are penalized in an attempt to avoid them when finding the
+ * best path. The default value is 0.
+ *
+ * @param cyclewayBias a cyclist's propensity to use roads alongside other vehicles
+ * @return this builder for chaining options together
+ */
+ fun cyclewayBias(@FloatRange(from = -1.0, to = 1.0) cyclewayBias: Float?): Builder {
+ this.cyclewayBias = cyclewayBias
+ return this
+ }
+
+ /**
+ * A cyclist's desire to tackle hills in their routes. This is a range of values from -1 to 1,
+ * where -1 attempts to avoid hills and steep grades even if it means a longer (time and
+ * distance) path, while 1 indicates the rider does not fear hills and steeper grades. Based on
+ * the hill bias factor, penalties are applied to roads based on elevation change and grade.
+ * These penalties help the path avoid hilly roads in favor of flatter roads or less steep
+ * grades where available. Note that it is not always possible to find alternate paths to avoid
+ * hills (for example when route locations are in mountainous areas). The default value is 0.
+ *
+ * @param hillBias a cyclist's desire to tackle hills in their routes
+ * @return this builder for chaining options together
+ */
+ fun hillBias(@FloatRange(from = -1.0, to = 1.0) hillBias: Float?): Builder {
+ this.hillBias = hillBias
+ return this
+ }
+
+ /**
+ * This value indicates the willingness to take ferries. This is a range of values between -1 and 1.
+ * Values near -1 attempt to avoid ferries and values near 1 will favor ferries. Note that
+ * sometimes ferries are required to complete a route so values of -1 are not guaranteed to avoid
+ * ferries entirely. The default value is 0.
+ *
+ * @param ferryBias the willingness to take ferries
+ * @return this builder for chaining options together
+ */
+ fun ferryBias(@FloatRange(from = -1.0, to = 1.0) ferryBias: Float?): Builder {
+ this.ferryBias = ferryBias
+ return this
+ }
+
+ /**
+ * This value is meant to represent how much a cyclist wants to favor or avoid roads with poor/rough
+ * surfaces relative to the bicycle type being used. This is a range of values between -1 and 1.
+ * When the value approaches -1, we attempt to penalize heavier or avoid roads with rough surface types
+ * so that they are only taken if they significantly improve travel time; only bicycle
+ * speed on each surface is taken into account. As the value approaches 1, we will favor rough surfaces.
+ * When the value is equal to -1, all bad surfaces are completely disallowed from routing,
+ * including start and end points. The default value is 0.
+ *
+ * @param roughSurfaceBias how much a cyclist wants to avoid roads with poor surfaces
+ * @return this builder for chaining options together
+ */
+ fun roughSurfaceBias(@FloatRange(from = -1.0, to = 1.0) roughSurfaceBias: Float?): Builder {
+ this.roughSurfaceBias = roughSurfaceBias
+ return this
+ }
+
+ /**
+ * The same waypoint types the user originally made when the request was made.
+ *
+ * @param waypointTypes break, through or omitted null
+ * @return this builder for chaining options together
+ */
+ fun waypointTypes(waypointTypes: List?): Builder {
+ this.waypointTypes = waypointTypes
+ return this
+ }
+
+ /**
+ * This uses the provided parameters set using the [Builder] and adds the required
+ * settings for offline navigation to work correctly.
+ *
+ * @return a new instance of [OfflineRoute]
+ */
+ fun build(): OfflineRoute = OfflineRoute(
+ routeUrl,
+ bicycleType,
+ cyclingSpeed,
+ cyclewayBias,
+ hillBias,
+ ferryBias,
+ roughSurfaceBias,
+ waypointTypes
+ )
+ }
+}
diff --git a/libdirections-onboard/src/main/java/com/mapbox/navigation/route/onboard/OnOfflineRouteFoundCallback.kt b/libdirections-onboard/src/main/java/com/mapbox/navigation/route/onboard/OnOfflineRouteFoundCallback.kt
new file mode 100644
index 00000000000..4cab47e8f76
--- /dev/null
+++ b/libdirections-onboard/src/main/java/com/mapbox/navigation/route/onboard/OnOfflineRouteFoundCallback.kt
@@ -0,0 +1,24 @@
+package com.mapbox.navigation.route.onboard
+
+import com.mapbox.navigation.base.route.model.Route
+import com.mapbox.navigation.route.onboard.model.OfflineError
+
+/**
+ * Callback used for finding offline routes.
+ */
+internal interface OnOfflineRouteFoundCallback {
+
+ /**
+ * Called when an offline routes are found.
+ *
+ * @param routes offline routes
+ */
+ fun onRouteFound(routes: List)
+
+ /**
+ * Called when there was an error fetching the offline route.
+ *
+ * @param error with message explanation
+ */
+ fun onError(error: OfflineError)
+}
diff --git a/libdirections-onboard/src/main/java/com/mapbox/navigation/route/onboard/OnOfflineTilesRemovedCallback.kt b/libdirections-onboard/src/main/java/com/mapbox/navigation/route/onboard/OnOfflineTilesRemovedCallback.kt
new file mode 100644
index 00000000000..f9e916a2f00
--- /dev/null
+++ b/libdirections-onboard/src/main/java/com/mapbox/navigation/route/onboard/OnOfflineTilesRemovedCallback.kt
@@ -0,0 +1,18 @@
+package com.mapbox.navigation.route.onboard
+
+import com.mapbox.geojson.BoundingBox
+
+/**
+ * Listener that needs to be added to
+ * [MapboxOfflineRouter.removeTiles] to know when the routing
+ * tiles within the provided [BoundingBox] have been removed
+ */
+interface OnOfflineTilesRemovedCallback {
+
+ /**
+ * Called when the routing tiles within the provided [BoundingBox] have been removed completely.
+ *
+ * @param numberOfTiles removed within the [BoundingBox] provided
+ */
+ fun onRemoved(numberOfTiles: Long)
+}
diff --git a/libdirections-onboard/src/main/java/com/mapbox/navigation/route/onboard/model/Config.kt b/libdirections-onboard/src/main/java/com/mapbox/navigation/route/onboard/model/Config.kt
new file mode 100644
index 00000000000..e9e01925958
--- /dev/null
+++ b/libdirections-onboard/src/main/java/com/mapbox/navigation/route/onboard/model/Config.kt
@@ -0,0 +1,20 @@
+package com.mapbox.navigation.route.onboard.model
+
+import com.mapbox.navigation.navigator.model.RouterConfig
+
+data class Config(
+ val tilePath: String,
+ val inMemoryTileCache: Int? = null,
+ val mapMatchingSpatialCache: Int? = null,
+ val threadsCount: Int? = null,
+ val endpoint: Endpoint? = null
+)
+
+fun Config.mapToRouteConfig(): RouterConfig =
+ RouterConfig(
+ tilePath = tilePath,
+ inMemoryTileCache = inMemoryTileCache,
+ mapMatchingSpatialCache = mapMatchingSpatialCache,
+ threadsCount = threadsCount,
+ endpointConfig = endpoint?.mapToEndpointConfig()
+ )
diff --git a/libdirections-onboard/src/main/java/com/mapbox/navigation/route/onboard/model/Endpoint.kt b/libdirections-onboard/src/main/java/com/mapbox/navigation/route/onboard/model/Endpoint.kt
new file mode 100644
index 00000000000..59e3ad38c45
--- /dev/null
+++ b/libdirections-onboard/src/main/java/com/mapbox/navigation/route/onboard/model/Endpoint.kt
@@ -0,0 +1,18 @@
+package com.mapbox.navigation.route.onboard.model
+
+import com.mapbox.navigation.navigator.model.EndpointConfig
+
+data class Endpoint(
+ val host: String,
+ val version: String,
+ val token: String,
+ val userAgent: String
+)
+
+fun Endpoint.mapToEndpointConfig() =
+ EndpointConfig(
+ host = host,
+ version = version,
+ token = token,
+ userAgent = userAgent
+ )
diff --git a/libdirections-onboard/src/main/java/com/mapbox/navigation/route/onboard/model/OfflineError.kt b/libdirections-onboard/src/main/java/com/mapbox/navigation/route/onboard/model/OfflineError.kt
new file mode 100644
index 00000000000..a22627b9a61
--- /dev/null
+++ b/libdirections-onboard/src/main/java/com/mapbox/navigation/route/onboard/model/OfflineError.kt
@@ -0,0 +1,5 @@
+package com.mapbox.navigation.route.onboard.model
+
+data class OfflineError(
+ val message: String
+)
diff --git a/libdirections-onboard/src/main/java/com/mapbox/navigation/route/onboard/model/OfflineRouteError.kt b/libdirections-onboard/src/main/java/com/mapbox/navigation/route/onboard/model/OfflineRouteError.kt
new file mode 100644
index 00000000000..6c09dc11ac5
--- /dev/null
+++ b/libdirections-onboard/src/main/java/com/mapbox/navigation/route/onboard/model/OfflineRouteError.kt
@@ -0,0 +1,12 @@
+package com.mapbox.navigation.route.onboard.model
+
+import com.google.gson.annotations.SerializedName
+
+internal data class OfflineRouteError(
+ val status: String,
+ @SerializedName("status_code")
+ val statusCode: Int,
+ val error: String,
+ @SerializedName("error_code")
+ val errorCode: Int
+)
diff --git a/libdirections-onboard/src/main/java/com/mapbox/navigation/route/onboard/network/HttpClient.kt b/libdirections-onboard/src/main/java/com/mapbox/navigation/route/onboard/network/HttpClient.kt
new file mode 100644
index 00000000000..e139d94cf9b
--- /dev/null
+++ b/libdirections-onboard/src/main/java/com/mapbox/navigation/route/onboard/network/HttpClient.kt
@@ -0,0 +1,84 @@
+package com.mapbox.navigation.route.onboard.network
+
+import androidx.annotation.Keep
+import com.mapbox.navigation.base.logger.Logger
+import com.mapbox.navigation.base.logger.model.Message
+import com.mapbox.navigator.BuildConfig
+import com.mapbox.navigator.HttpCode
+import com.mapbox.navigator.HttpInterface
+import com.mapbox.navigator.HttpResponse
+import java.io.ByteArrayOutputStream
+import okhttp3.OkHttpClient
+import okhttp3.Request
+import okhttp3.logging.HttpLoggingInterceptor
+import okio.buffer
+import okio.sink
+
+@Keep
+internal class HttpClient(
+ internal val userAgent: String = USER_AGENT,
+ private val acceptGzipEncoding: Boolean = false,
+ private val logger: Logger? = null,
+ private val clientBuilder: OkHttpClient.Builder = OkHttpClient.Builder()
+) : HttpInterface() {
+
+ companion object {
+ private const val USER_AGENT = "MapboxNavigationNative"
+
+ private const val ERROR_EMPTY_USER_AGENT = "Empty UserAgent is not allowed"
+ private const val HEADER_USER_AGENT = "User-Agent"
+ private const val HEADER_ENCODING = "Accept-Encoding"
+ private const val GZIP = "gzip"
+ }
+
+ private val client: OkHttpClient by lazy {
+ if (BuildConfig.DEBUG) {
+ val interceptor = HttpLoggingInterceptor(object : HttpLoggingInterceptor.Logger {
+ override fun log(message: String) {
+ logger?.d(msg = Message(message))
+ }
+ }).setLevel(HttpLoggingInterceptor.Level.BASIC)
+
+ clientBuilder.addInterceptor(interceptor)
+ }
+
+ clientBuilder.build()
+ }
+
+ init {
+ check(userAgent.isNotEmpty()) {
+ ERROR_EMPTY_USER_AGENT
+ }
+ }
+
+ override fun isGzipped(): Boolean {
+ return acceptGzipEncoding
+ }
+
+ override fun get(url: String): HttpResponse {
+ val requestBuilder = Request.Builder()
+ .addHeader(HEADER_USER_AGENT, userAgent)
+ .url(url)
+
+ if (acceptGzipEncoding) {
+ requestBuilder.addHeader(HEADER_ENCODING, GZIP)
+ }
+
+ client.newCall(requestBuilder.build()).execute().use { response ->
+ val outputStream = ByteArrayOutputStream()
+ val result = if (response.isSuccessful) HttpCode.SUCCESS else HttpCode.FAILURE
+
+ response.body()?.let { body ->
+ val sink = outputStream.sink().buffer()
+ sink.writeAll(body.source())
+ sink.close()
+ }
+
+ // FIXME core should receive Array, not List. It is List now because of bindgen
+ val bytes = outputStream.toByteArray().toList()
+ outputStream.close()
+
+ return HttpResponse(bytes, result)
+ }
+ }
+}
diff --git a/libdirections-onboard/src/main/java/com/mapbox/navigation/route/onboard/task/OfflineRouteRetrievalTask.kt b/libdirections-onboard/src/main/java/com/mapbox/navigation/route/onboard/task/OfflineRouteRetrievalTask.kt
new file mode 100644
index 00000000000..18482579a4f
--- /dev/null
+++ b/libdirections-onboard/src/main/java/com/mapbox/navigation/route/onboard/task/OfflineRouteRetrievalTask.kt
@@ -0,0 +1,66 @@
+package com.mapbox.navigation.route.onboard.task
+
+import android.os.AsyncTask
+import com.google.gson.Gson
+import com.mapbox.navigation.base.logger.Logger
+import com.mapbox.navigation.base.logger.model.Message
+import com.mapbox.navigation.base.logger.model.Tag
+import com.mapbox.navigation.base.route.dto.RouteResponseDto
+import com.mapbox.navigation.base.route.dto.mapToModel
+import com.mapbox.navigation.base.route.model.Route
+import com.mapbox.navigation.navigator.MapboxNativeNavigator
+import com.mapbox.navigation.route.onboard.OnOfflineRouteFoundCallback
+import com.mapbox.navigation.route.onboard.model.OfflineError
+import com.mapbox.navigation.route.onboard.model.OfflineRouteError
+import com.mapbox.navigator.RouterResult
+
+internal class OfflineRouteRetrievalTask(
+ private val navigator: MapboxNativeNavigator,
+ private val logger: Logger?,
+ private val callback: OnOfflineRouteFoundCallback
+) : AsyncTask>() {
+
+ @Volatile
+ private lateinit var routerResult: RouterResult
+
+ private val gson = Gson()
+
+ // For testing only
+ internal constructor(
+ navigator: MapboxNativeNavigator,
+ callback: OnOfflineRouteFoundCallback,
+ routerResult: RouterResult
+ ) : this(navigator, null, callback) {
+ this.routerResult = routerResult
+ }
+
+ override fun doInBackground(vararg params: String): List? {
+ val url = params.first()
+
+ synchronized(navigator) {
+ routerResult = navigator.getRoute(url)
+ }
+
+ return gson.fromJson(routerResult.json, RouteResponseDto::class.java)?.mapToModel()?.routes
+ }
+
+ public override fun onPostExecute(offlineRoute: List?) {
+ if (!offlineRoute.isNullOrEmpty()) {
+ callback.onRouteFound(offlineRoute)
+ } else {
+ callback.onError(OfflineError(generateErrorMessage()))
+ }
+ }
+
+ private fun generateErrorMessage(): String {
+ val (_, _, error, errorCode) = gson.fromJson(
+ routerResult.json,
+ OfflineRouteError::class.java
+ )
+
+ val errorMessage = "Error occurred fetching offline route: $error - Code: $errorCode"
+
+ logger?.e(Tag("OfflineRouteRetrievalTask"), Message(errorMessage))
+ return errorMessage
+ }
+}
diff --git a/libdirections-onboard/src/main/java/com/mapbox/navigation/route/onboard/task/RemoveTilesTask.kt b/libdirections-onboard/src/main/java/com/mapbox/navigation/route/onboard/task/RemoveTilesTask.kt
new file mode 100644
index 00000000000..c5d262645da
--- /dev/null
+++ b/libdirections-onboard/src/main/java/com/mapbox/navigation/route/onboard/task/RemoveTilesTask.kt
@@ -0,0 +1,20 @@
+package com.mapbox.navigation.route.onboard.task
+
+import android.os.AsyncTask
+import com.mapbox.geojson.Point
+import com.mapbox.navigation.route.onboard.OnOfflineTilesRemovedCallback
+import com.mapbox.navigator.Navigator
+
+internal class RemoveTilesTask(
+ private val navigator: Navigator,
+ private val tilePath: String,
+ private val southwest: Point,
+ private val northeast: Point,
+ private val callback: OnOfflineTilesRemovedCallback
+) : AsyncTask() {
+
+ override fun doInBackground(vararg paramsUnused: Void): Long =
+ navigator.removeTiles(tilePath, southwest, northeast)
+
+ public override fun onPostExecute(numberOfTiles: Long) = callback.onRemoved(numberOfTiles)
+}
diff --git a/libdirections-onboard/src/test/java/com/mapbox/navigation/route/onboard/MapboxOnboardRouterGenerationTest.kt b/libdirections-onboard/src/test/java/com/mapbox/navigation/route/onboard/MapboxOnboardRouterTest.kt
similarity index 69%
rename from libdirections-onboard/src/test/java/com/mapbox/navigation/route/onboard/MapboxOnboardRouterGenerationTest.kt
rename to libdirections-onboard/src/test/java/com/mapbox/navigation/route/onboard/MapboxOnboardRouterTest.kt
index d4738b70240..2e3a9fe3185 100644
--- a/libdirections-onboard/src/test/java/com/mapbox/navigation/route/onboard/MapboxOnboardRouterGenerationTest.kt
+++ b/libdirections-onboard/src/test/java/com/mapbox/navigation/route/onboard/MapboxOnboardRouterTest.kt
@@ -1,19 +1,20 @@
package com.mapbox.navigation.route.onboard
import com.mapbox.navigation.navigator.MapboxNativeNavigator
+import com.mapbox.navigation.route.onboard.model.Config
import io.mockk.mockk
import org.junit.Assert
import org.junit.Before
import org.junit.Test
-class MapboxOnboardRouterGenerationTest {
-
+class MapboxOnboardRouterTest {
private lateinit var onboardRouter: MapboxOnboardRouter
private val navigator: MapboxNativeNavigator = mockk()
+ private val tilePath = "tiles"
@Before
fun setUp() {
- onboardRouter = MapboxOnboardRouter(navigator)
+ onboardRouter = MapboxOnboardRouter(navigator, Config(tilePath))
}
@Test
diff --git a/libdirections-onboard/src/test/java/com/mapbox/navigation/route/onboard/OfflineRouteTest.kt b/libdirections-onboard/src/test/java/com/mapbox/navigation/route/onboard/OfflineRouteTest.kt
new file mode 100644
index 00000000000..a87d048d0a9
--- /dev/null
+++ b/libdirections-onboard/src/test/java/com/mapbox/navigation/route/onboard/OfflineRouteTest.kt
@@ -0,0 +1,111 @@
+package com.mapbox.navigation.route.onboard
+
+import com.mapbox.geojson.Point
+import com.mapbox.navigation.base.route.RouteUrl
+import java.io.UnsupportedEncodingException
+import java.net.URLDecoder
+import org.junit.Assert.assertTrue
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.robolectric.RobolectricTestRunner
+import org.robolectric.annotation.Config
+
+@RunWith(RobolectricTestRunner::class)
+@Config(manifest = Config.NONE)
+class OfflineRouteTest {
+
+ @Test
+ fun addBicycleTypeIncludedInRequest() {
+ val routeUrl = provideOnlineRouteBuilder()
+ val offlineRoute = OfflineRoute.builder(routeUrl)
+ .bicycleType(OfflineCriteria.BicycleType.ROAD).build()
+
+ val offlineUrl = offlineRoute.buildUrl()
+
+ assertTrue(offlineUrl.contains("bicycle_type=Road"))
+ }
+
+ @Test
+ fun addCyclingSpeedIncludedInRequest() {
+ val routeUrl = provideOnlineRouteBuilder()
+ val offlineRoute = OfflineRoute.builder(routeUrl)
+ .cyclingSpeed(10.0f).build()
+
+ val offlineUrl = offlineRoute.buildUrl()
+
+ assertTrue(offlineUrl.contains("cycling_speed=10.0"))
+ }
+
+ @Test
+ fun addCyclewayBiasIncludedInRequest() {
+ val routeUrl = provideOnlineRouteBuilder()
+ val offlineRoute = OfflineRoute.builder(routeUrl)
+ .cyclewayBias(0.0f).build()
+
+ val offlineUrl = offlineRoute.buildUrl()
+
+ assertTrue(offlineUrl.contains("cycleway_bias=0.0"))
+ }
+
+ @Test
+ fun addHillBiasIncludedInRequest() {
+ val routeUrl = provideOnlineRouteBuilder()
+ val offlineRoute = OfflineRoute.builder(routeUrl)
+ .hillBias(0.0f).build()
+
+ val offlineUrl = offlineRoute.buildUrl()
+
+ assertTrue(offlineUrl.contains("hill_bias=0.0"))
+ }
+
+ @Test
+ fun addFerryBiasIncludedInRequest() {
+ val routeUrl = provideOnlineRouteBuilder()
+ val offlineRoute = OfflineRoute.builder(routeUrl)
+ .ferryBias(0.0f).build()
+
+ val offlineUrl = offlineRoute.buildUrl()
+
+ assertTrue(offlineUrl.contains("ferry_bias=0.0"))
+ }
+
+ @Test
+ fun addRoughSurfaceBiasIncludedInRequest() {
+ val routeUrl = provideOnlineRouteBuilder()
+ val offlineRoute = OfflineRoute.builder(routeUrl)
+ .roughSurfaceBias(0.0f).build()
+
+ val offlineUrl = offlineRoute.buildUrl()
+
+ assertTrue(offlineUrl.contains("rough_surface_bias=0.0"))
+ }
+
+ @Test
+ @Throws(UnsupportedEncodingException::class)
+ fun addWaypointTypesIncludedInRequest() {
+ val routeUrl = provideOnlineRouteBuilder()
+ val waypointTypes = listOf(
+ OfflineCriteria.WaypointType.BREAK,
+ OfflineCriteria.WaypointType.THROUGH,
+ null,
+ OfflineCriteria.WaypointType.BREAK
+ )
+ val offlineRoute = OfflineRoute.builder(routeUrl)
+ .waypointTypes(waypointTypes).build()
+ val offlineUrl = offlineRoute.buildUrl()
+
+ val offlineUrlDecoded = URLDecoder.decode(offlineUrl, "UTF-8")
+
+ assertTrue(offlineUrlDecoded.contains("break;through;;break"))
+ }
+
+ private fun provideOnlineRouteBuilder(): RouteUrl {
+ return RouteUrl(
+ accessToken = "pk.XXX",
+ profile = RouteUrl.PROFILE_CYCLING,
+ orgin = Point.fromLngLat(1.0, 2.0),
+ waypoints = listOf(Point.fromLngLat(3.0, 2.0)),
+ destination = Point.fromLngLat(1.0, 5.0)
+ )
+ }
+}
diff --git a/libdirections-onboard/src/test/java/com/mapbox/navigation/route/onboard/task/OfflineRouteRetrievalTaskTest.kt b/libdirections-onboard/src/test/java/com/mapbox/navigation/route/onboard/task/OfflineRouteRetrievalTaskTest.kt
new file mode 100644
index 00000000000..5dec5fd28e3
--- /dev/null
+++ b/libdirections-onboard/src/test/java/com/mapbox/navigation/route/onboard/task/OfflineRouteRetrievalTaskTest.kt
@@ -0,0 +1,74 @@
+package com.mapbox.navigation.route.onboard.task
+
+import com.mapbox.navigation.base.route.model.Route
+import com.mapbox.navigation.navigator.MapboxNativeNavigator
+import com.mapbox.navigation.route.onboard.OnOfflineRouteFoundCallback
+import com.mapbox.navigation.route.onboard.model.OfflineError
+import com.mapbox.navigator.RouterResult
+import io.mockk.every
+import io.mockk.mockk
+import io.mockk.slot
+import io.mockk.verify
+import org.junit.Assert.assertEquals
+import org.junit.Test
+
+class OfflineRouteRetrievalTaskTest {
+
+ @Test
+ fun checksOnErrorIsCalledIfRouteIsNotFetched() {
+ val mockedNavigator = mockk()
+ val mockedCallback = mockk(relaxed = true)
+ val mockedResult = mockk()
+ every { mockedResult.json } returns "{\"status\": \"Bad Request\", \"status_code\": 400, \"error\": \"No suitable edges near location\", \"error_code\": 171}"
+ val theOfflineRouteRetrievalTask = OfflineRouteRetrievalTask(
+ mockedNavigator,
+ mockedCallback,
+ mockedResult
+ )
+ val nullRoute = null
+
+ theOfflineRouteRetrievalTask.onPostExecute(nullRoute)
+
+ verify { mockedCallback.onError(any()) }
+ }
+
+ @Test
+ fun checksErrorMessageIsWellFormedIfRouteIsNotFetched() {
+ val mockedNavigator = mockk()
+ val mockedCallback = mockk(relaxed = true)
+ val slot = slot()
+ every { mockedCallback.onError(capture(slot)) } answers {}
+ val mockedResult = mockk()
+ every { mockedResult.json } returns "{\"status\": \"Bad Request\", \"status_code\": 400, \"error\": \"No suitable edges near location\", \"error_code\": 171}"
+ val theOfflineRouteRetrievalTask = OfflineRouteRetrievalTask(
+ mockedNavigator,
+ mockedCallback,
+ mockedResult
+ )
+ val nullRoute = null
+
+ theOfflineRouteRetrievalTask.onPostExecute(nullRoute)
+
+ verify { mockedCallback.onError(eq(slot.captured)) }
+ assertEquals(
+ "Error occurred fetching offline route: No suitable edges near location - Code: 171",
+ slot.captured.message
+ )
+ }
+
+ @Test
+ fun checksOnRouteFoundIsCalledIfRouteIsFetched() {
+ val mockedNavigator = mockk()
+ val mockedCallback = mockk(relaxed = true)
+ val theOfflineRouteRetrievalTask = OfflineRouteRetrievalTask(
+ mockedNavigator,
+ null,
+ mockedCallback
+ )
+ val routes = listOf(mockk())
+
+ theOfflineRouteRetrievalTask.onPostExecute(routes)
+
+ verify { mockedCallback.onRouteFound(eq(routes)) }
+ }
+}
diff --git a/libdirections-onboard/src/test/java/com/mapbox/navigation/route/onboard/task/RemoveTilesTaskTestTest.kt b/libdirections-onboard/src/test/java/com/mapbox/navigation/route/onboard/task/RemoveTilesTaskTestTest.kt
new file mode 100644
index 00000000000..ecb3ff731b7
--- /dev/null
+++ b/libdirections-onboard/src/test/java/com/mapbox/navigation/route/onboard/task/RemoveTilesTaskTestTest.kt
@@ -0,0 +1,28 @@
+package com.mapbox.navigation.route.onboard.task
+
+import com.mapbox.geojson.Point
+import com.mapbox.navigation.route.onboard.OnOfflineTilesRemovedCallback
+import com.mapbox.navigator.Navigator
+import io.mockk.mockk
+import io.mockk.verify
+import org.junit.Test
+
+class RemoveTilesTaskTestTest {
+
+ @Test
+ fun checksOnRemoveIsCalledWhenTilesAreRemoved() {
+ val mockedNavigator = mockk()
+ val aTilePath = "/some/path/version"
+ val southwest = Point.fromLngLat(1.0, 2.0)
+ val northeast = Point.fromLngLat(3.0, 4.0)
+ val mockedCallback = mockk(relaxed = true)
+ val theRemoveTilesTask = RemoveTilesTask(
+ mockedNavigator, aTilePath, southwest,
+ northeast, mockedCallback
+ )
+
+ theRemoveTilesTask.onPostExecute(9L)
+
+ verify { mockedCallback.onRemoved(eq(9L)) }
+ }
+}
diff --git a/libnavigation-base/build.gradle b/libnavigation-base/build.gradle
index 9e6c7e06b25..608b13cdbf5 100644
--- a/libnavigation-base/build.gradle
+++ b/libnavigation-base/build.gradle
@@ -28,6 +28,6 @@ dependencies {
// Unit testing
testImplementation dependenciesList.junit
testImplementation dependenciesList.mockk
+ testImplementation dependenciesList.robolectric
}
-
apply from: "${rootDir}/gradle/bintray-publish.gradle"
\ No newline at end of file
diff --git a/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/RouteUrl.kt b/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/RouteUrl.kt
new file mode 100644
index 00000000000..fa6a3f1c1d3
--- /dev/null
+++ b/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/RouteUrl.kt
@@ -0,0 +1,135 @@
+package com.mapbox.navigation.base.route
+
+import android.net.Uri
+import com.mapbox.geojson.Point
+
+class RouteUrl(
+ val accessToken: String,
+ val orgin: Point,
+ val waypoints: List? = null,
+ val destination: Point,
+ val user: String = PROFILE_DEFAULT_USER,
+ val profile: String = PROFILE_DRIVING,
+ val steps: Boolean = true,
+ val geometries: String = GEOMETRY_POLYLINE6,
+ val overview: String = OVERVIEW_FULL,
+ val voiceIntruction: Boolean = true,
+ val bannerIntruction: Boolean = true,
+ val roundaboutExits: Boolean = true,
+ val enableRefresh: Boolean = true
+) {
+
+ companion object {
+ const val BASE_URL = "https://api.mapbox.com"
+
+ const val BASE_URL_API_NAME = "directions"
+ const val BASE_URL_API_VERSION = "v5"
+
+ private const val QUERY_PARAM_ACCESS_TOKEN = "access_token"
+ private const val QUERY_PARAM_STEPS = "steps"
+ private const val QUERY_PARAM_GEOMERTY = "geometries"
+ private const val QUERY_PARAM_OVERVIEW = "overview"
+ private const val QUERY_PARAM_VOICE_INSTRUCTIONS = "voice_instructions"
+ private const val QUERY_PARAM_BANNER_INSTRUCTIONS = "banner_instructions"
+ private const val QUERY_PARAM_ROUNDABOUT_EXITS = "roundabout_exits"
+ private const val QUERY_PARAM_ENABLE_REFRESH = "enable_refresh"
+
+ /**
+ * Mapbox default username.
+ *
+ * @since 1.0
+ */
+ const val PROFILE_DEFAULT_USER = "mapbox"
+ /**
+ * For car and motorcycle routing. This profile factors in current and historic traffic
+ * conditions to avoid slowdowns.
+ *
+ * @since 1.0
+ */
+ const val PROFILE_DRIVING_TRAFFIC = "driving-traffic"
+
+ /**
+ * For car and motorcycle routing. This profile shows the fastest routes by preferring
+ * high-speed roads like highways.
+ *
+ * @since 1.0
+ */
+ const val PROFILE_DRIVING = "driving"
+
+ /**
+ * For pedestrian and hiking routing. This profile shows the shortest path by using sidewalks
+ * and trails.
+ *
+ * @since 1.0
+ */
+ const val PROFILE_WALKING = "walking"
+
+ /**
+ * For bicycle routing. This profile shows routes that are short and safe for cyclist, avoiding
+ * highways and preferring streets with bike lanes.
+ *
+ * @since 1.0
+ */
+ const val PROFILE_CYCLING = "cycling"
+
+ /**
+ * Format to return route geometry will be an encoded polyline.
+ *
+ * @since 1.0
+ */
+ const val GEOMETRY_POLYLINE = "polyline"
+
+ /**
+ * Format to return route geometry will be an encoded polyline with precision 6.
+ *
+ * @since 1.0
+ */
+ const val GEOMETRY_POLYLINE6 = "polyline6"
+
+ /**
+ * A simplified version of the [.OVERVIEW_FULL] geometry. If not specified simplified is
+ * the default.
+ *
+ * @since 1.0
+ */
+ const val OVERVIEW_SIMPLIFIED = "simplified"
+
+ /**
+ * The most detailed geometry available.
+ *
+ * @since 1.0
+ */
+ const val OVERVIEW_FULL = "full"
+
+ /**
+ * No overview geometry.
+ *
+ * @since 1.0
+ */
+ const val OVERVIEW_FALSE = "false"
+ }
+
+ fun getRequest(): Uri =
+ Uri.parse(BASE_URL)
+ .buildUpon()
+ .appendPath(BASE_URL_API_NAME)
+ .appendPath(BASE_URL_API_VERSION)
+ .appendPath(user)
+ .appendPath(profile)
+ .appendPath(retrieveCoordinates())
+ .appendQueryParameter(QUERY_PARAM_ACCESS_TOKEN, accessToken)
+ .appendQueryParameter(QUERY_PARAM_STEPS, steps.toString())
+ .appendQueryParameter(QUERY_PARAM_GEOMERTY, geometries)
+ .appendQueryParameter(QUERY_PARAM_OVERVIEW, overview)
+ .appendQueryParameter(QUERY_PARAM_VOICE_INSTRUCTIONS, voiceIntruction.toString())
+ .appendQueryParameter(QUERY_PARAM_BANNER_INSTRUCTIONS, bannerIntruction.toString())
+ .appendQueryParameter(QUERY_PARAM_ROUNDABOUT_EXITS, roundaboutExits.toString())
+ .appendQueryParameter(QUERY_PARAM_ENABLE_REFRESH, enableRefresh.toString())
+ .build()
+
+ private fun retrieveCoordinates(): String {
+ val route: List = listOf(orgin) + (waypoints ?: emptyList()) + destination
+
+ return route.joinToString(separator = ";") { "${it.longitude()},${it.latitude()}" }
+ }
+}
diff --git a/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/dto/BannerComponentsNavigationDto.kt b/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/dto/BannerComponentsNavigationDto.kt
new file mode 100644
index 00000000000..c413429ff2b
--- /dev/null
+++ b/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/dto/BannerComponentsNavigationDto.kt
@@ -0,0 +1,27 @@
+package com.mapbox.navigation.base.route.dto
+
+import com.google.gson.annotations.SerializedName
+import com.mapbox.navigation.base.route.model.BannerComponentsNavigation
+
+class BannerComponentsNavigationDto(
+ val text: String,
+ val type: String,
+ @SerializedName("abbr")
+ val abbreviation: String?,
+ @SerializedName("abbr_priority")
+ val abbreviationPriority: Int?,
+ @SerializedName("imageBaseURL")
+ val imageBaseUrl: String?,
+ val directions: List?,
+ val active: Boolean?
+)
+
+fun BannerComponentsNavigationDto.mapToModel() = BannerComponentsNavigation(
+ text = text,
+ type = type,
+ abbreviation = abbreviation,
+ abbreviationPriority = abbreviationPriority,
+ imageBaseUrl = imageBaseUrl,
+ directions = directions,
+ active = active
+)
diff --git a/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/dto/BannerInstructionsNavigationDto.kt b/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/dto/BannerInstructionsNavigationDto.kt
new file mode 100644
index 00000000000..edf9f5d354f
--- /dev/null
+++ b/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/dto/BannerInstructionsNavigationDto.kt
@@ -0,0 +1,17 @@
+package com.mapbox.navigation.base.route.dto
+
+import com.mapbox.navigation.base.route.model.BannerInstructionsNavigation
+
+class BannerInstructionsNavigationDto(
+ val distanceAlongGeometry: Double,
+ val primary: BannerTextNavigationDto?,
+ val secondary: BannerTextNavigationDto?,
+ val sub: BannerTextNavigationDto?
+)
+
+fun BannerInstructionsNavigationDto.mapToModel() = BannerInstructionsNavigation(
+ distanceAlongGeometry = distanceAlongGeometry,
+ primary = primary?.mapToModel(),
+ secondary = secondary?.mapToModel(),
+ sub = sub?.mapToModel()
+)
diff --git a/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/dto/BannerTextNavigationDto.kt b/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/dto/BannerTextNavigationDto.kt
new file mode 100644
index 00000000000..212b76a0aa9
--- /dev/null
+++ b/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/dto/BannerTextNavigationDto.kt
@@ -0,0 +1,23 @@
+package com.mapbox.navigation.base.route.dto
+
+import com.google.gson.annotations.SerializedName
+import com.mapbox.navigation.base.route.model.BannerTextNavigation
+
+class BannerTextNavigationDto(
+ val text: String?,
+ val components: List?,
+ val type: String?,
+ val modifier: String?,
+ val degrees: Double?,
+ @SerializedName("driving_side")
+ val drivingSide: String?
+)
+
+fun BannerTextNavigationDto.mapToModel() = BannerTextNavigation(
+ text = text,
+ components = components?.map { it.mapToModel() },
+ type = type,
+ modifier = modifier,
+ degrees = degrees,
+ drivingSide = drivingSide
+)
diff --git a/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/dto/IntersectionLanesNavigationDto.kt b/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/dto/IntersectionLanesNavigationDto.kt
new file mode 100644
index 00000000000..3e0b17a499e
--- /dev/null
+++ b/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/dto/IntersectionLanesNavigationDto.kt
@@ -0,0 +1,13 @@
+package com.mapbox.navigation.base.route.dto
+
+import com.mapbox.navigation.base.route.model.IntersectionLanesNavigation
+
+class IntersectionLanesNavigationDto(
+ val valid: Boolean?,
+ val indications: List?
+)
+
+fun IntersectionLanesNavigationDto.mapToModel() = IntersectionLanesNavigation(
+ valid = valid,
+ indications = indications
+)
diff --git a/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/dto/LegAnnotationNavigationDto.kt b/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/dto/LegAnnotationNavigationDto.kt
new file mode 100644
index 00000000000..ad80dee07a7
--- /dev/null
+++ b/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/dto/LegAnnotationNavigationDto.kt
@@ -0,0 +1,19 @@
+package com.mapbox.navigation.base.route.dto
+
+import com.mapbox.navigation.base.route.model.LegAnnotationNavigation
+
+class LegAnnotationNavigationDto(
+ val distance: List?,
+ val duration: List?,
+ val speed: List?,
+ val maxspeed: List?,
+ val congestion: List?
+)
+
+fun LegAnnotationNavigationDto.mapToModel() = LegAnnotationNavigation(
+ distance = distance,
+ duration = duration,
+ speed = speed,
+ maxspeed = maxspeed?.map(MaxSpeedNavigationDto::mapToModel),
+ congestion = congestion
+)
diff --git a/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/dto/LegStepNavigationDto.kt b/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/dto/LegStepNavigationDto.kt
new file mode 100644
index 00000000000..a448632f06d
--- /dev/null
+++ b/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/dto/LegStepNavigationDto.kt
@@ -0,0 +1,35 @@
+package com.mapbox.navigation.base.route.dto
+
+import com.google.gson.annotations.SerializedName
+import com.mapbox.navigation.base.route.model.LegStepNavigation
+
+class LegStepNavigationDto(
+ val distance: Double,
+ val duration: Double,
+ val geometry: String?,
+ val name: String?,
+ val ref: String?,
+ val destinations: String?,
+ val mode: String,
+ val pronunciation: String?,
+ @SerializedName("rotary_name")
+ val rotaryName: String?,
+ @SerializedName("rotary_pronunciation")
+ val rotaryPronunciation: String?,
+ val maneuver: StepManeuverNavigationDto,
+ val voiceInstructions: List?,
+ val bannerInstructions: List?,
+ @SerializedName("driving_side")
+ val drivingSide: String?,
+ val weight: Double,
+ val intersections: List?,
+ val exits: String?
+)
+
+fun LegStepNavigationDto.mapToModel() = LegStepNavigation.Builder()
+ .distance(distance)
+ .drivingSide(drivingSide)
+ .duration(duration)
+ .geometry(geometry)
+ .stepManeuver(maneuver.mapToModel())
+ .build()
diff --git a/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/dto/MaxSpeedNavigationDto.kt b/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/dto/MaxSpeedNavigationDto.kt
new file mode 100644
index 00000000000..78aa10812be
--- /dev/null
+++ b/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/dto/MaxSpeedNavigationDto.kt
@@ -0,0 +1,17 @@
+package com.mapbox.navigation.base.route.dto
+
+import com.mapbox.navigation.base.route.model.MaxSpeedNavigation
+
+class MaxSpeedNavigationDto(
+ val speed: Int?,
+ val unit: String?,
+ val unknown: Boolean?,
+ val none: Boolean?
+)
+
+fun MaxSpeedNavigationDto.mapToModel() = MaxSpeedNavigation(
+ speed = speed,
+ unit = unit,
+ unknown = unknown,
+ none = none
+)
diff --git a/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/dto/RouteDto.kt b/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/dto/RouteDto.kt
new file mode 100644
index 00000000000..25c86a05ad1
--- /dev/null
+++ b/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/dto/RouteDto.kt
@@ -0,0 +1,27 @@
+package com.mapbox.navigation.base.route.dto
+
+import com.mapbox.navigation.base.route.model.Route
+
+class RouteDto(
+ val routeIndex: String?,
+ val distance: Double,
+ val duration: Long,
+ val geometry: String?,
+ val weight: Double?,
+ val weightName: String?,
+ val legs: List?,
+ val routeOptions: RouteOptionsNavigationDto?,
+ val voiceLanguage: String?
+)
+
+fun RouteDto.mapToModelRoute() = Route(
+ routeIndex = routeIndex,
+ distance = distance,
+ duration = duration,
+ geometry = geometry,
+ weight = weight,
+ weightName = weightName,
+ legs = legs?.map { it.mapToRouteLegNavigation() },
+ routeOptions = routeOptions?.mapToModel(),
+ voiceLanguage = voiceLanguage
+)
diff --git a/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/dto/RouteLegNavigationDto.kt b/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/dto/RouteLegNavigationDto.kt
new file mode 100644
index 00000000000..8fc1b1939a1
--- /dev/null
+++ b/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/dto/RouteLegNavigationDto.kt
@@ -0,0 +1,19 @@
+package com.mapbox.navigation.base.route.dto
+
+import com.mapbox.navigation.base.route.model.RouteLegNavigation
+
+class RouteLegNavigationDto(
+ val distance: Double?,
+ val duration: Double?,
+ val summary: String?,
+ val steps: List?,
+ val annotation: LegAnnotationNavigationDto?
+)
+
+fun RouteLegNavigationDto.mapToRouteLegNavigation(): RouteLegNavigation =
+ RouteLegNavigation.Builder()
+ .distance(distance)
+ .duration(duration)
+ .summary(summary)
+ .steps(steps?.map { it.mapToModel() })
+ .build()
diff --git a/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/dto/RouteOptionsNavigationDto.kt b/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/dto/RouteOptionsNavigationDto.kt
new file mode 100644
index 00000000000..debbf297c9a
--- /dev/null
+++ b/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/dto/RouteOptionsNavigationDto.kt
@@ -0,0 +1,91 @@
+package com.mapbox.navigation.base.route.dto
+
+import com.google.gson.annotations.SerializedName
+import com.mapbox.geojson.Point
+import com.mapbox.navigation.base.route.RouteUrl
+import com.mapbox.navigation.base.route.model.RouteOptionsNavigation
+
+data class RouteOptionsNavigationDto(
+ val baseUrl: String?,
+ val user: String?,
+ val profile: String?,
+ val coordinates: List,
+ val alternatives: Boolean?,
+ val language: String?,
+ val radiuses: String?,
+ val bearings: String?,
+ @SerializedName("continue_straight")
+ val continueStraight: Boolean?,
+ @SerializedName("roundabout_exits")
+ val roundaboutExits: Boolean?,
+ val geometries: String?,
+ val overview: String?,
+ val steps: Boolean?,
+ val annotations: String?,
+ @SerializedName("voice_instructions")
+ val voiceInstructions: Boolean?,
+ @SerializedName("banner_instructions")
+ val bannerInstructions: Boolean?,
+ @SerializedName("voice_units")
+ val voiceUnits: String?,
+ @SerializedName("access_token")
+ val accessToken: String?,
+ @SerializedName("uuid")
+ val requestUuid: String?,
+ val exclude: String?,
+ val approaches: String?,
+ @SerializedName("waypoints")
+ val waypointIndices: String?,
+ @SerializedName("waypoint_names")
+ val waypointNames: String?,
+ @SerializedName("waypoint_targets")
+ val waypointTargets: String?,
+ val walkingOptions: WalkingOptionsNavigationDto?
+)
+
+fun RouteOptionsNavigationDto.mapToModel() = RouteOptionsNavigation(
+ baseUrl = baseUrl ?: RouteUrl.BASE_URL,
+ user = user ?: RouteUrl.PROFILE_DEFAULT_USER,
+ profile = profile ?: RouteUrl.PROFILE_DRIVING,
+ origin = coordinates.retrieveOrigin().mapToModel(),
+ waypoints = coordinates.retrieveWaypoints().map { it.mapToModel() },
+ destination = coordinates.retrieveDestination().mapToModel(),
+ alternatives = alternatives ?: RouteOptionsNavigation.ALTERNATIVES_DEFAULT_VALUE,
+ language = language,
+ radiuses = radiuses,
+ bearings = bearings,
+ continueStraight = continueStraight ?: RouteOptionsNavigation.CONTINUE_STRAIGHT_DEFAULT_VALUE,
+ roundaboutExits = roundaboutExits ?: RouteOptionsNavigation.ROUNDABOUT_EXITS_DEFAULT_VALUE,
+ geometries = geometries,
+ overview = overview,
+ steps = steps ?: RouteOptionsNavigation.STEPS_DEFAULT_VALUE,
+ annotations = annotations,
+ voiceInstructions = voiceInstructions
+ ?: RouteOptionsNavigation.VOICE_INSTRUCTIONS_DEFAULT_VALUE,
+ bannerInstructions = bannerInstructions
+ ?: RouteOptionsNavigation.BANNER_INSTRUCTIONS_DEFAULT_VALUE,
+ voiceUnits = voiceUnits,
+ accessToken = accessToken ?: "",
+ requestUuid = requestUuid,
+ exclude = exclude,
+ approaches = approaches,
+ waypointIndices = waypointIndices,
+ waypointNames = waypointNames,
+ waypointTargets = waypointTargets,
+ walkingOptions = walkingOptions?.mapToModel()
+)
+
+private fun List.retrieveOrigin(): RoutePointNavigationDto =
+ this.first().let { RoutePointNavigationDto(Point.fromLngLat(it[0], it[1]), null, null) }
+
+private fun List.retrieveWaypoints(): List =
+ this.drop(1).dropLast(1).map {
+ RoutePointNavigationDto(
+ Point.fromLngLat(it[0], it[1]),
+ null,
+ null
+ )
+ }
+
+private fun List.retrieveDestination(): RoutePointNavigationDto =
+ this.last().let { RoutePointNavigationDto(Point.fromLngLat(it[0], it[1]), null, null) }
diff --git a/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/dto/RoutePointNavigationDto.kt b/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/dto/RoutePointNavigationDto.kt
new file mode 100644
index 00000000000..f1be38a08d5
--- /dev/null
+++ b/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/dto/RoutePointNavigationDto.kt
@@ -0,0 +1,16 @@
+package com.mapbox.navigation.base.route.dto
+
+import com.mapbox.geojson.Point
+import com.mapbox.navigation.base.route.model.RoutePointNavigation
+
+data class RoutePointNavigationDto(
+ val point: Point,
+ val bearingAngle: Double?,
+ val tolerance: Double?
+)
+
+fun RoutePointNavigationDto.mapToModel() = RoutePointNavigation(
+ point = point,
+ bearingAngle = bearingAngle,
+ tolerance = tolerance
+)
diff --git a/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/dto/RouteResponseDto.kt b/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/dto/RouteResponseDto.kt
new file mode 100644
index 00000000000..16ecc4315ed
--- /dev/null
+++ b/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/dto/RouteResponseDto.kt
@@ -0,0 +1,17 @@
+package com.mapbox.navigation.base.route.dto
+
+import com.mapbox.navigation.base.route.model.RouteResponse
+
+class RouteResponseDto(
+ val message: String?,
+ val code: String?,
+ val uuid: String?,
+ val routes: List?
+)
+
+fun RouteResponseDto.mapToModel() = RouteResponse(
+ message = message,
+ code = code,
+ uuid = uuid,
+ routes = routes?.map(RouteDto::mapToModelRoute)
+)
diff --git a/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/dto/StepIntersectionNavigationDto.kt b/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/dto/StepIntersectionNavigationDto.kt
new file mode 100644
index 00000000000..746363c448a
--- /dev/null
+++ b/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/dto/StepIntersectionNavigationDto.kt
@@ -0,0 +1,26 @@
+package com.mapbox.navigation.base.route.dto
+
+import com.google.gson.annotations.SerializedName
+import com.mapbox.geojson.Point
+import com.mapbox.navigation.base.route.model.StepIntersectionNavigation
+
+class StepIntersectionNavigationDto(
+ @SerializedName("location")
+ val rawLocation: DoubleArray,
+ val bearings: List?,
+ val classes: List?,
+ val entry: List?,
+ val `in`: Int?,
+ val out: Int?,
+ val lanes: List?
+)
+
+fun StepIntersectionNavigationDto.mapToModel() = StepIntersectionNavigation(
+ location = Point.fromLngLat(rawLocation[0], rawLocation[1]),
+ bearings = bearings,
+ classes = classes,
+ entry = entry,
+ into = `in`,
+ out = out,
+ lanes = lanes?.map(IntersectionLanesNavigationDto::mapToModel)
+)
diff --git a/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/dto/StepManeuverNavigationDto.kt b/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/dto/StepManeuverNavigationDto.kt
new file mode 100644
index 00000000000..853764bca91
--- /dev/null
+++ b/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/dto/StepManeuverNavigationDto.kt
@@ -0,0 +1,24 @@
+package com.mapbox.navigation.base.route.dto
+
+import com.google.gson.annotations.SerializedName
+import com.mapbox.navigation.base.route.model.StepManeuverNavigation
+import com.mapbox.navigation.base.route.model.StepManeuverType
+
+class StepManeuverNavigationDto(
+ @SerializedName("location")
+ val rawLocation: DoubleArray,
+ @SerializedName("bearing_before")
+ val bearingBefore: Double?,
+ @SerializedName("bearing_after")
+ val bearingAfter: Double?,
+ val instruction: String?,
+ @StepManeuverType
+ val type: String?,
+ val modifier: String?,
+ val exit: Int?
+)
+
+fun StepManeuverNavigationDto.mapToModel() = StepManeuverNavigation.Builder()
+ .modifier(modifier)
+ .type(type)
+ .build()
diff --git a/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/dto/VoiceInstructionsNavigationDto.kt b/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/dto/VoiceInstructionsNavigationDto.kt
new file mode 100644
index 00000000000..ebddf3640ce
--- /dev/null
+++ b/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/dto/VoiceInstructionsNavigationDto.kt
@@ -0,0 +1,15 @@
+package com.mapbox.navigation.base.route.dto
+
+import com.mapbox.navigation.base.route.model.VoiceInstructionsNavigation
+
+class VoiceInstructionsNavigationDto(
+ val distanceAlongGeometry: Double?,
+ val announcement: String?,
+ val ssmlAnnouncement: String?
+)
+
+fun VoiceInstructionsNavigationDto.mapToModel() = VoiceInstructionsNavigation(
+ distanceAlongGeometry = distanceAlongGeometry,
+ announcement = announcement,
+ ssmlAnnouncement = ssmlAnnouncement
+)
diff --git a/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/dto/WalkingOptionsNavigationDto.kt b/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/dto/WalkingOptionsNavigationDto.kt
new file mode 100644
index 00000000000..176f1a1dc02
--- /dev/null
+++ b/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/dto/WalkingOptionsNavigationDto.kt
@@ -0,0 +1,34 @@
+package com.mapbox.navigation.base.route.dto
+
+import com.google.gson.annotations.SerializedName
+import com.mapbox.navigation.base.route.model.WalkingOptionsNavigation
+
+/**
+ * Class for specifying options for use with the walking profile.
+ *
+ * @param walkingSpeed Walking speed in meters per second. Must be between 0.14 and 6.94 meters per second.
+ * Defaults to 1.42 meters per second
+ *
+ * @param walkwayBias A bias which determines whether the route should prefer or avoid the use of roads or paths
+ * that are set aside for pedestrian-only use (walkways). The allowed range of values is from
+ * -1 to 1, where -1 indicates indicates preference to avoid walkways, 1 indicates preference
+ * to favor walkways, and 0 indicates no preference (the default).
+ *
+ * @param alleyBias A bias which determines whether the route should prefer or avoid the use of alleys. The
+ * allowed range of values is from -1 to 1, where -1 indicates indicates preference to avoid
+ * alleys, 1 indicates preference to favor alleys, and 0 indicates no preference (the default).
+ */
+class WalkingOptionsNavigationDto(
+ @SerializedName("walking_speed")
+ val walkingSpeed: Double?,
+ @SerializedName("walkway_bias")
+ val walkwayBias: Double?,
+ @SerializedName("alley_bias")
+ val alleyBias: Double?
+)
+
+fun WalkingOptionsNavigationDto.mapToModel() = WalkingOptionsNavigation(
+ walkingSpeed = walkingSpeed,
+ walkwayBias = walkwayBias,
+ alleyBias = alleyBias
+)
diff --git a/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/model/BannerComponentsNavigation.kt b/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/model/BannerComponentsNavigation.kt
new file mode 100644
index 00000000000..8ef1049c92f
--- /dev/null
+++ b/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/model/BannerComponentsNavigation.kt
@@ -0,0 +1,62 @@
+package com.mapbox.navigation.base.route.model
+
+/**
+ *
+ * @property text A snippet of the full [BannerTextNavigation.text] which can be used for visually
+ * altering parts of the full string.
+ * @since 1.0
+ *
+ * @property type String giving you more context about the component which may help in visual markup/display
+ * choices. If the type of the components is unknown it should be treated as text.
+ *
+ * Possible values:
+ *
+ * * **text (default)**: indicates the text is part of
+ * the instructions and no other type
+ * * **icon**: this is text that can be replaced by an icon, see imageBaseURL
+ * * **delimiter**: this is text that can be dropped and
+ * should be dropped if you are rendering icons
+ * * **exit-number**: the exit number for the maneuver
+ * * **exit**: the word for exit in the local language
+ * @since 1.0
+ *
+ * @property abbreviation The abbreviated form of text.
+ *
+ * If this is present, there will also be an abbr_priority value
+ * @since 1.0
+ *
+ * @property abbreviationPriority An integer indicating the order in which the abbreviation abbr should be used in
+ * place of text. The highest priority is 0 and a higher integer value indicates a lower
+ * priority. There are no gaps in integer values.
+ *
+ * Multiple components can have the same abbreviationPriority and when this happens all
+ * components with the same abbr_priority should be abbreviated at the same time.
+ * Finding no larger values of abbreviationPriority indicates that the string is
+ * fully abbreviated.
+ * @since 1.0
+ *
+ * @property imageBaseUrl In some cases when the [LegStepNavigation] is a highway or major roadway,
+ * there might be a shield icon that's included to better identify to your user to roadway.
+ * Note that this doesn't return the image itself but rather the url which can be used to download the file.
+ * @since 1.0
+ *
+ * @property directions A List of directions indicating which way you can go from a lane
+ * (left, right, or straight). If the value is ['left', 'straight'],
+ * the driver can go straight or left from that lane.
+ * Present if this is a lane component.
+ * @since 1.0
+ *
+ * @property active A boolean telling you if that lane can be used to complete the upcoming maneuver.
+ * If multiple lanes are active, then they can all be used to complete the upcoming maneuver.
+ * Present if this is a lane component.
+ * @since 1.0
+ */
+data class BannerComponentsNavigation(
+ val text: String,
+ val type: String,
+ val abbreviation: String?,
+ val abbreviationPriority: Int?,
+ val imageBaseUrl: String?,
+ val directions: List?,
+ val active: Boolean?
+)
diff --git a/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/model/BannerInstructionsNavigation.kt b/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/model/BannerInstructionsNavigation.kt
new file mode 100644
index 00000000000..97553f6f58d
--- /dev/null
+++ b/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/model/BannerInstructionsNavigation.kt
@@ -0,0 +1,31 @@
+package com.mapbox.navigation.base.route.model
+
+/**
+ * Visual instruction information related to a particular [LegStepNavigation] useful for making UI
+ * elements inside your application such as banners. To receive this information, your request must
+ * have {@link MapboxDirections#bannerInstructions()} set to true.
+ *
+ * @property distanceAlongGeometry Distance in meters from the beginning of the step at which the visual instruction should be
+ * visible.
+ * @since 1.0
+ *
+ * @property primary A plain text representation stored inside a [BannerTextNavigation] object.
+ * @since 1.0
+ *
+ * @property secondary Ancillary visual information about the [LegStepNavigation].
+ * @return [BannerTextNavigation] representing the secondary visual information
+ * @since 1.0
+ *
+ * @property sub Additional information that is included if we feel the driver needs a heads up about something.
+ * Can include information about the next maneuver (the one after the upcoming one),
+ * if the step is short - can be null, or can be lane information.
+ * If we have lane information, that trumps information about the next maneuver.
+ * @return [BannerTextNavigation] representing the sub visual information
+ * @since 1.0
+ */
+class BannerInstructionsNavigation(
+ val distanceAlongGeometry: Double,
+ val primary: BannerTextNavigation?,
+ val secondary: BannerTextNavigation?,
+ val sub: BannerTextNavigation?
+)
diff --git a/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/model/BannerTextNavigation.kt b/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/model/BannerTextNavigation.kt
new file mode 100644
index 00000000000..f34fe118371
--- /dev/null
+++ b/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/model/BannerTextNavigation.kt
@@ -0,0 +1,41 @@
+package com.mapbox.navigation.base.route.model
+
+/**
+ * Includes both plain text information that can be visualized inside your navigation application
+ * along with the text string broken down into {@link BannerComponents} which may or may not
+ * include a image url. To receive this information, your request must have
+ * {@link MapboxDirections#bannerInstructions()} set to true.
+ *
+ * @property text Plain text with all the [BannerComponentsNavigation] text combined.
+ * @since 1.0
+ *
+ * @property components A part or element of the [BannerInstructionsNavigation].
+ * Return [BannerComponentsNavigation] specific to a [LegStepNavigation]
+ * @since 1.0
+ *
+ * @property type This indicates the type of maneuver.
+ * @see StepManeuverNavigation.StepManeuverTypeNavigation
+ * @since 1.0
+ *
+ * @property modifier This indicates the mode of the maneuver. If type is of turn, the modifier indicates the
+ * change in direction accomplished through the turn. If the type is of depart/arrive, the
+ * modifier indicates the position of waypoint from the current direction of travel.
+ * @since 1.0
+ *
+ * @property degrees The degrees at which you will be exiting a roundabout, assuming `180` indicates
+ * going straight through the roundabout.
+ * @since 1.0
+ *
+ * @property drivingSide A string representing which side the of the street people drive on
+ * in that location. Can be 'left' or 'right'.
+ * @since 1.0
+ */
+class BannerTextNavigation(
+ val text: String?,
+ val components: List?,
+ @StepManeuverType
+ val type: String?,
+ val modifier: String?,
+ val degrees: Double?,
+ val drivingSide: String?
+)
diff --git a/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/model/IntersectionLanesNavigation.kt b/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/model/IntersectionLanesNavigation.kt
new file mode 100644
index 00000000000..088de249a33
--- /dev/null
+++ b/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/model/IntersectionLanesNavigation.kt
@@ -0,0 +1,18 @@
+package com.mapbox.navigation.base.route.model
+
+/**
+ *
+ * @property valid Boolean value for whether this lane can be taken to complete the maneuver. For
+ * instance, if the lane array has four objects and the first two are marked as valid, then the
+ * driver can take either of the left lanes and stay on the route.
+ * @since 1.0
+ *
+ * @property indications Array of signs for each turn lane. There can be multiple signs. For example, a turning
+ * lane can have a sign with an arrow pointing left and another sign with an arrow pointing
+ * straight.
+ * @since 1.0
+ */
+class IntersectionLanesNavigation(
+ val valid: Boolean?,
+ val indications: List?
+)
diff --git a/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/model/LegAnnotationNavigation.kt b/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/model/LegAnnotationNavigation.kt
new file mode 100644
index 00000000000..0bdcb689920
--- /dev/null
+++ b/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/model/LegAnnotationNavigation.kt
@@ -0,0 +1,28 @@
+package com.mapbox.navigation.base.route.model
+
+/**
+ *
+ * @property distance The distance, in meters, between each pair of coordinates.
+ * @since 1.0
+ *
+ * @property duration The speed, in meters per second, between each pair of coordinates.
+ * @since 1.0
+ *
+ * @property speed The speed, in meters per second, between each pair of coordinates.
+ * @since 1.0
+ *
+ * @property maxspeed The posted speed limit, between each pair of coordinates.
+ * Maxspeed is only available for the `mapbox/driving` and `mapbox/driving-traffic`
+ * profiles, other profiles will return `unknown`s only.
+ * @since 1.0
+ *
+ * @property congestion The congestion between each pair of coordinates.
+ * @since 1.0
+ */
+data class LegAnnotationNavigation(
+ val distance: List?,
+ val duration: List?,
+ val speed: List?,
+ val maxspeed: List?,
+ val congestion: List?
+)
diff --git a/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/model/MaxSpeedNavigation.kt b/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/model/MaxSpeedNavigation.kt
new file mode 100644
index 00000000000..f8cc70db65d
--- /dev/null
+++ b/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/model/MaxSpeedNavigation.kt
@@ -0,0 +1,22 @@
+package com.mapbox.navigation.base.route.model
+
+/**
+ *
+ * @property speed Number indicating the posted speed limit.
+ * @since 1.0
+ *
+ * @property unit String indicating the unit of speed, either as `km/h` or `mph`.
+ * @since 1.0
+ *
+ * @property unknown Boolean is true if the speed limit is not known, otherwise null.
+ * @since 1.0
+ *
+ * @property none Boolean is `true` if the speed limit is unlimited, otherwise null.
+ * @since 1.0
+ */
+class MaxSpeedNavigation(
+ val speed: Int?,
+ val unit: String?,
+ val unknown: Boolean?,
+ val none: Boolean?
+)
diff --git a/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/model/RouteOptionsNavigation.kt b/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/model/RouteOptionsNavigation.kt
index 7656e306525..061a01667dc 100644
--- a/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/model/RouteOptionsNavigation.kt
+++ b/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/model/RouteOptionsNavigation.kt
@@ -1,66 +1,75 @@
package com.mapbox.navigation.base.route.model
-import com.google.gson.annotations.SerializedName
import com.mapbox.geojson.Point
-
-class RouteOptionsNavigation private constructor(
- val baseUrl: String?,
- val user: String?,
- val profile: String?,
- val coordinates: List,
- val alternatives: Boolean?,
+import com.mapbox.navigation.base.route.RouteUrl
+
+class RouteOptionsNavigation(
+ val baseUrl: String,
+ val user: String,
+ val profile: String,
+ val origin: RoutePointNavigation,
+ val waypoints: List,
+ val destination: RoutePointNavigation,
+ val alternatives: Boolean,
val language: String?,
val radiuses: String?,
val bearings: String?,
- @SerializedName("continue_straight") val continueStraight: Boolean?,
- @SerializedName("roundabout_exits") val roundaboutExits: Boolean?,
+ val continueStraight: Boolean,
+ val roundaboutExits: Boolean,
val geometries: String?,
val overview: String?,
- val steps: Boolean?,
+ val steps: Boolean,
val annotations: String?,
- @SerializedName("voice_instructions") val voiceInstructions: Boolean?,
- @SerializedName("banner_instructions") val bannerInstructions: Boolean?,
- @SerializedName("voice_units") val voiceUnits: String?,
- val accessToken: String?,
- @SerializedName("uuid") val requestUuid: String?,
+ val voiceInstructions: Boolean,
+ val bannerInstructions: Boolean,
+ val voiceUnits: String?,
+ val accessToken: String,
+ val requestUuid: String?,
val exclude: String?,
val approaches: String?,
- @SerializedName("waypoints") val waypointIndices: String?,
- @SerializedName("waypoint_names") val waypointNames: String?,
- @SerializedName("waypoint_targets") val waypointTargets: String?,
+ val waypointIndices: String?,
+ val waypointNames: String?,
+ val waypointTargets: String?,
val walkingOptions: WalkingOptionsNavigation?
) {
companion object {
@JvmStatic
- fun builder(): Builder {
- return Builder()
- }
+ fun builder(): Builder = Builder()
+
+ const val ALTERNATIVES_DEFAULT_VALUE = false
+ const val STEPS_DEFAULT_VALUE = true
+ const val CONTINUE_STRAIGHT_DEFAULT_VALUE = false
+ const val ROUNDABOUT_EXITS_DEFAULT_VALUE = false
+ const val VOICE_INSTRUCTIONS_DEFAULT_VALUE = true
+ const val BANNER_INSTRUCTIONS_DEFAULT_VALUE = true
}
- class Builder internal constructor() {
- private var _origin: RoutePointNavigation? = null
- private var _destination: RoutePointNavigation? = null
+ val coordinates: List
+ get() = listOf(origin.point) + waypoints.map { it.point } + destination.point
+
+ class Builder {
+ private lateinit var _origin: RoutePointNavigation
+ private lateinit var _destination: RoutePointNavigation
private val _waypoints = mutableListOf()
+ private lateinit var _accessToken: String
private var baseUrl: String? = null
private var user: String? = null
private var profile: String? = null
- private val coordinates = mutableListOf()
- private var alternatives: Boolean? = null
+ private var alternatives: Boolean = ALTERNATIVES_DEFAULT_VALUE
private var language: String? = null
private var radiuses: String? = null
private var bearings: String? = null
- private var continueStraight: Boolean? = null
- private var roundaboutExits: Boolean? = null
+ private var continueStraight: Boolean = CONTINUE_STRAIGHT_DEFAULT_VALUE
+ private var roundaboutExits: Boolean = ROUNDABOUT_EXITS_DEFAULT_VALUE
private var geometries: String? = null
private var overview: String? = null
- private var steps: Boolean? = null
+ private var steps: Boolean = STEPS_DEFAULT_VALUE
private var annotations: String? = null
- private var voiceInstructions: Boolean? = null
- private var bannerInstructions: Boolean? = null
+ private var voiceInstructions: Boolean = VOICE_INSTRUCTIONS_DEFAULT_VALUE
+ private var bannerInstructions: Boolean = BANNER_INSTRUCTIONS_DEFAULT_VALUE
private var voiceUnits: String? = null
- private var accessToken: String? = null
private var requestUuid: String? = null
private var exclude: String? = null
private var approaches: String? = null
@@ -133,7 +142,7 @@ class RouteOptionsNavigation private constructor(
fun voiceUnits(voiceUnits: String): Builder = also { this.voiceUnits = voiceUnits }
- fun accessToken(accessToken: String): Builder = also { this.accessToken = accessToken }
+ fun accessToken(accessToken: String): Builder = also { this._accessToken = accessToken }
fun requestUuid(requestUuid: String): Builder = also { this.requestUuid = requestUuid }
@@ -154,12 +163,14 @@ class RouteOptionsNavigation private constructor(
also { this.walkingOptions = walkingOptions }
fun build(): RouteOptionsNavigation {
- assembleCoordinates()
+ checkFields()
return RouteOptionsNavigation(
- baseUrl,
- user,
- profile,
- coordinates,
+ baseUrl ?: RouteUrl.BASE_URL,
+ user ?: RouteUrl.PROFILE_DEFAULT_USER,
+ profile ?: RouteUrl.PROFILE_DRIVING,
+ _origin,
+ _waypoints,
+ _destination,
alternatives,
language,
radiuses,
@@ -173,7 +184,7 @@ class RouteOptionsNavigation private constructor(
voiceInstructions,
bannerInstructions,
voiceUnits,
- accessToken,
+ _accessToken,
requestUuid,
exclude,
approaches,
@@ -184,18 +195,12 @@ class RouteOptionsNavigation private constructor(
)
}
- private fun assembleCoordinates() {
- _origin?.let { origin ->
- coordinates.add(origin)
- }
+ private fun checkFields() {
+ check(::_origin.isInitialized) { "Property origin hasn't been initialized" }
- for (waypoint in _waypoints) {
- coordinates.add(waypoint)
- }
+ check(::_destination.isInitialized) { "Property destination hasn't been initialized" }
- _destination?.let { destination ->
- coordinates.add(destination)
- }
+ check(::_accessToken.isInitialized) { "Property accessToken hasn't been initialized" }
}
}
}
diff --git a/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/model/RouteResponse.kt b/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/model/RouteResponse.kt
new file mode 100644
index 00000000000..7d941eec275
--- /dev/null
+++ b/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/model/RouteResponse.kt
@@ -0,0 +1,8 @@
+package com.mapbox.navigation.base.route.model
+
+class RouteResponse(
+ val message: String?,
+ val code: String?,
+ val uuid: String?,
+ val routes: List?
+)
diff --git a/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/model/StepIntersectionNavigation.kt b/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/model/StepIntersectionNavigation.kt
new file mode 100644
index 00000000000..b3aa567768b
--- /dev/null
+++ b/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/model/StepIntersectionNavigation.kt
@@ -0,0 +1,69 @@
+package com.mapbox.navigation.base.route.model
+
+import com.mapbox.geojson.Point
+
+/**
+ * Object representing an intersection along the step.
+ *
+ * @property location A [Point] representing this intersection location.
+ * @since 1.0
+ *
+ * @property bearings An integer list of bearing values available at the step intersection.
+ * @return An array of bearing values (for example [0,90,180,270]) that are available at the
+ * intersection. The bearings describe all available roads at the intersection.
+ * @since 1.0
+ *
+ * @property classes A list of strings signifying the classes of the road exiting the intersection. Possible
+ * values:
+ *
+ * * **toll**: the road continues on a toll road
+ * * **ferry**: the road continues on a ferry
+ * * **restricted**: the road continues on with access restrictions
+ * * **motorway**: the road continues on a motorway
+ * * **tunnel**: the road continues on a tunnel
+ *
+ * @return a string list containing the classes of the road exiting the intersection
+ * @since 1.0
+ *
+ * @property entry A list of entry flags, corresponding in a 1:1 relationship to the bearings. A value of true
+ * indicates that the respective road could be entered on a valid route. false indicates that the
+ * turn onto the respective road would violate a restriction.
+ *
+ * @return a list of entry flags, corresponding in a 1:1 relationship to the bearings
+ * @since 1.0
+ *
+ * @property into Index into bearings/entry array. Used to calculate the bearing before the turn. Namely, the
+ * clockwise angle from true north to the direction of travel before the maneuver/passing the
+ * intersection. To get the bearing in the direction of driving, the bearing has to be rotated by
+ * a value of 180. The value is not supplied for departure
+ * maneuvers.
+ *
+ * @return index into bearings/entry array
+ * @since 1.0
+ *
+ * @property out Index out of the bearings/entry array. Used to extract the bearing after the turn. Namely, The
+ * clockwise angle from true north to the direction of travel after the maneuver/passing the
+ * intersection. The value is not supplied for arrive maneuvers.
+ *
+ * @return index out of the bearings/entry array
+ * @since 1.0
+ *
+ * @property lanes Array of lane objects that represent the available turn lanes at the intersection. If no lane
+ * information is available for an intersection, the lanes property will not be present. Lanes are
+ * provided in their order on the street, from left to right.
+ *
+ * @return array of lane objects that represent the available turn lanes at the intersection
+ * @since 1.0
+ */
+class StepIntersectionNavigation(
+ val location: Point,
+ val bearings: List?,
+ val classes: List?,
+ val entry: List?,
+ val into: Int?,
+ val out: Int?,
+ val lanes: List?
+) {
+ val rawLocation: DoubleArray
+ get() = doubleArrayOf(location.longitude(), location.latitude())
+}
diff --git a/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/model/VoiceInstructionsNavigation.kt b/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/model/VoiceInstructionsNavigation.kt
new file mode 100644
index 00000000000..f6511ba6e58
--- /dev/null
+++ b/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/model/VoiceInstructionsNavigation.kt
@@ -0,0 +1,22 @@
+package com.mapbox.navigation.base.route.model
+
+/**
+ *
+ * @property distanceAlongGeometry This provides the missing piece in which is needed to announce
+ * instructions at accuratetimes. If the user is less distance away from the maneuver than
+ * what this `distanceAlongGeometry` than, the announcement should be called.
+ * @since 1.0
+ *
+ * @property announcement Provides the instruction string which was build on the server-side and can sometimes
+ * concatenate instructions together if maneuver instructions are too close to each other.
+ * @since 1.0
+ *
+ * @property ssmlAnnouncement Get the same instruction string you'd get from [.announcement] but this one includes
+ * Speech Synthesis Markup Language which helps voice synthesiser read information more humanely.
+ * @since 1.0
+ */
+class VoiceInstructionsNavigation(
+ val distanceAlongGeometry: Double?,
+ val announcement: String?,
+ val ssmlAnnouncement: String?
+)
diff --git a/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/model/WalkingOptionsNavigation.kt b/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/model/WalkingOptionsNavigation.kt
index 6d906b822a1..198d2ca46f2 100644
--- a/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/model/WalkingOptionsNavigation.kt
+++ b/libnavigation-base/src/main/java/com/mapbox/navigation/base/route/model/WalkingOptionsNavigation.kt
@@ -1,26 +1,24 @@
package com.mapbox.navigation.base.route.model
-import com.google.gson.annotations.SerializedName
-
/**
* Class for specifying options for use with the walking profile.
*
- * @param walkingSpeed Walking speed in meters per second. Must be between 0.14 and 6.94 meters per second.
+ * @property walkingSpeed Walking speed in meters per second. Must be between 0.14 and 6.94 meters per second.
* Defaults to 1.42 meters per second
*
- * @param walkwayBias A bias which determines whether the route should prefer or avoid the use of roads or paths
+ * @property walkwayBias A bias which determines whether the route should prefer or avoid the use of roads or paths
* that are set aside for pedestrian-only use (walkways). The allowed range of values is from
* -1 to 1, where -1 indicates indicates preference to avoid walkways, 1 indicates preference
* to favor walkways, and 0 indicates no preference (the default).
*
- * @param alleyBias A bias which determines whether the route should prefer or avoid the use of alleys. The
+ * @property alleyBias A bias which determines whether the route should prefer or avoid the use of alleys. The
* allowed range of values is from -1 to 1, where -1 indicates indicates preference to avoid
* alleys, 1 indicates preference to favor alleys, and 0 indicates no preference (the default).
*/
data class WalkingOptionsNavigation(
- @SerializedName("walking_speed") val walkingSpeed: Double? = null,
- @SerializedName("walkway_bias") val walkwayBias: Double? = null,
- @SerializedName("alley_bias") val alleyBias: Double? = null
+ val walkingSpeed: Double? = null,
+ val walkwayBias: Double? = null,
+ val alleyBias: Double? = null
) {
companion object {
/**
@@ -57,7 +55,7 @@ data class WalkingOptionsNavigation(
* Walking speed in meters per second. Must be between 0.14 and 6.94 meters per second.
* Defaults to 1.42 meters per second
*
- * @param walkingSpeed in meters per second
+ * @property walkingSpeed in meters per second
* @return this builder
*/
fun walkingSpeed(walkingSpeed: Double?): Builder {
@@ -71,7 +69,7 @@ data class WalkingOptionsNavigation(
* -1 to 1, where -1 indicates preference to avoid walkways, 1 indicates preference to favor
* walkways, and 0 indicates no preference (the default).
*
- * @param walkwayBias bias to prefer or avoid walkways
+ * @property walkwayBias bias to prefer or avoid walkways
* @return this builder
*/
fun walkwayBias(walkwayBias: Double?): Builder {
@@ -84,7 +82,7 @@ data class WalkingOptionsNavigation(
* allowed range of values is from -1 to 1, where -1 indicates preference to avoid alleys, 1
* indicates preference to favor alleys, and 0 indicates no preference (the default).
*
- * @param alleyBias bias to prefer or avoid alleys
+ * @property alleyBias bias to prefer or avoid alleys
* @return this builder
*/
fun alleyBias(alleyBias: Double?): Builder {
diff --git a/libnavigation-base/src/test/java/com/mapbox/navigation/base/route/RouteUrlTest.kt b/libnavigation-base/src/test/java/com/mapbox/navigation/base/route/RouteUrlTest.kt
new file mode 100644
index 00000000000..00470cfe194
--- /dev/null
+++ b/libnavigation-base/src/test/java/com/mapbox/navigation/base/route/RouteUrlTest.kt
@@ -0,0 +1,119 @@
+package com.mapbox.navigation.base.route
+
+import android.net.Uri
+import com.mapbox.geojson.Point
+import java.net.URLDecoder
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertNotNull
+import org.junit.Assert.assertTrue
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.robolectric.RobolectricTestRunner
+import org.robolectric.annotation.Config
+
+@RunWith(RobolectricTestRunner::class)
+@Config(manifest = Config.NONE)
+class RouteUrlTest {
+
+ @Test
+ fun checkBaseUrl() {
+ setupRouteUrl()
+ .checkContain("${RouteUrl.BASE_URL}/${RouteUrl.BASE_URL_API_NAME}/${RouteUrl.BASE_URL_API_VERSION}/")
+ }
+
+ @Test
+ fun checkCoordinates() {
+ val routeUrl = setupRouteUrl(
+ orgin = Point.fromLngLat(12.2, 43.4),
+ waypoints = listOf(Point.fromLngLat(54.0, 90.01), Point.fromLngLat(32.9, 81.23)),
+ destination = Point.fromLngLat(42.00210201, 13.123121)
+ )
+
+ assertNotNull(routeUrl.path)
+ assertTrue(
+ routeUrl.path?.contains("/12.2,43.4;54.0,90.01;32.9,81.23;42.00210201,13.123121") ?: false
+ )
+ }
+
+ @Test
+ fun checkUserAndProfile() {
+ val routeUrl = setupRouteUrl()
+
+ routeUrl.checkContain("/${RouteUrl.PROFILE_DEFAULT_USER}/${RouteUrl.PROFILE_DRIVING}/")
+ }
+
+ @Test
+ fun checkNonDefaultUserAndProfile() {
+ val routeUrl = setupRouteUrl(user = "vitalik", profile = RouteUrl.PROFILE_CYCLING)
+
+ routeUrl.checkContain("/vitalik/${RouteUrl.PROFILE_CYCLING}/")
+ }
+
+ @Test
+ fun checkQueries() {
+ val token = "pk_token1212.dsda"
+ val routeUri = setupRouteUrl(
+ accessToken = token,
+ steps = true,
+ geometries = RouteUrl.GEOMETRY_POLYLINE,
+ overview = RouteUrl.OVERVIEW_SIMPLIFIED,
+ voiceIntruction = false,
+ bannerIntruction = true,
+ roundaboutExits = true,
+ enableRefresh = false
+ )
+ val expectedQueries =
+ listOf(
+ "access_token" to token,
+ "steps" to "true",
+ "geometries" to RouteUrl.GEOMETRY_POLYLINE,
+ "overview" to RouteUrl.OVERVIEW_SIMPLIFIED,
+ "voice_instructions" to "false",
+ "roundabout_exits" to "true",
+ "enable_refresh" to "false"
+ )
+
+ expectedQueries.forEach { (key, value) ->
+ assertEquals("Check Query param", value, routeUri.getQueryParameter(key))
+ }
+ }
+
+ private fun Uri.checkContain(string: String, decode: String? = "UTF-8") =
+ assertTrue(this.toString()
+ .let { url ->
+ decode?.let { decode -> URLDecoder.decode(url, decode) } ?: url
+ }
+ .contains(string)
+ )
+
+ private fun setupRouteUrl(
+ accessToken: String = "",
+ orgin: Point = Point.fromLngLat(.0, .0),
+ waypoints: List? = null,
+ destination: Point = Point.fromLngLat(.0, .0),
+ user: String = RouteUrl.PROFILE_DEFAULT_USER,
+ profile: String = RouteUrl.PROFILE_DRIVING,
+ steps: Boolean = true,
+ geometries: String = RouteUrl.GEOMETRY_POLYLINE6,
+ overview: String = RouteUrl.OVERVIEW_FULL,
+ voiceIntruction: Boolean = true,
+ bannerIntruction: Boolean = true,
+ roundaboutExits: Boolean = true,
+ enableRefresh: Boolean = true
+ ): Uri =
+ RouteUrl(
+ accessToken,
+ orgin,
+ waypoints,
+ destination,
+ user,
+ profile,
+ steps,
+ geometries,
+ overview,
+ voiceIntruction,
+ bannerIntruction,
+ roundaboutExits,
+ enableRefresh
+ ).getRequest()
+}
diff --git a/libnavigation-base/src/test/java/com/mapbox/navigation/base/route/model/WalkingOptionsNavigationTest.kt b/libnavigation-base/src/test/java/com/mapbox/navigation/base/route/model/WalkingOptionsNavigationTest.kt
new file mode 100644
index 00000000000..ceb0c464430
--- /dev/null
+++ b/libnavigation-base/src/test/java/com/mapbox/navigation/base/route/model/WalkingOptionsNavigationTest.kt
@@ -0,0 +1,28 @@
+package com.mapbox.navigation.base.route.model
+
+import org.junit.Assert.assertEquals
+import org.junit.Test
+
+class WalkingOptionsNavigationTest {
+
+ @Test
+ fun alleyBias_walkingOptionSet() {
+ val options = WalkingOptionsNavigation.builder().alleyBias(0.7).build()
+
+ assertEquals(0.7, options.alleyBias)
+ }
+
+ @Test
+ fun walkwayBias_walkingOptionSet() {
+ val options = WalkingOptionsNavigation.builder().walkwayBias(0.8).build()
+
+ assertEquals(0.8, options.walkwayBias)
+ }
+
+ @Test
+ fun walkingSpeed_walkingOptionSet() {
+ val options = WalkingOptionsNavigation.builder().walkingSpeed(2.0).build()
+
+ assertEquals(2.0, options.walkingSpeed)
+ }
+}
diff --git a/libnavigator/build.gradle b/libnavigator/build.gradle
index 35af2cdc34e..0e3a74880d3 100644
--- a/libnavigator/build.gradle
+++ b/libnavigator/build.gradle
@@ -15,7 +15,9 @@ android {
}
dependencies {
- api project(':libnavigation-base')
+ implementation(project(':libnavigation-base'))
+ implementation(project(':liblogger'))
+ implementation project(':libnavigation-util')
// Navigator
api dependenciesList.mapboxNavigator
@@ -27,6 +29,14 @@ dependencies {
ktlint dependenciesList.ktlint
implementation dependenciesList.kotlinStdLib
+
+ implementation dependenciesList.supportAnnotation
+
+ implementation dependenciesList.mapboxSdkGeoJSON
+
+ // Unit testing
+ testImplementation dependenciesList.junit
+ testImplementation dependenciesList.mockk
}
apply from: "${rootDir}/gradle/bintray-publish.gradle"
\ No newline at end of file
diff --git a/libnavigator/src/main/java/com/mapbox/navigation/navigator/MapboxNativeNavigator.kt b/libnavigator/src/main/java/com/mapbox/navigation/navigator/MapboxNativeNavigator.kt
index 97d467b56ce..bf593bb9775 100644
--- a/libnavigator/src/main/java/com/mapbox/navigation/navigator/MapboxNativeNavigator.kt
+++ b/libnavigator/src/main/java/com/mapbox/navigation/navigator/MapboxNativeNavigator.kt
@@ -2,9 +2,15 @@ package com.mapbox.navigation.navigator
import android.location.Location
import com.mapbox.navigation.base.route.model.Route
+import com.mapbox.navigation.navigator.model.RouterConfig
+import com.mapbox.navigator.HttpInterface
+import com.mapbox.navigator.RouterResult
import java.util.Date
interface MapboxNativeNavigator {
+
+ fun configureRouter(routerConfig: RouterConfig, httpClient: HttpInterface, userAgent: String)
+ fun getRoute(url: String): RouterResult
fun updateLocation(rawLocation: Location)
fun getStatus(date: Date): TripStatus
fun setRoute(route: Route)
diff --git a/libnavigator/src/main/java/com/mapbox/navigation/navigator/MapboxNativeNavigatorImpl.kt b/libnavigator/src/main/java/com/mapbox/navigation/navigator/MapboxNativeNavigatorImpl.kt
index b728089ec52..94a8a79358d 100644
--- a/libnavigator/src/main/java/com/mapbox/navigation/navigator/MapboxNativeNavigatorImpl.kt
+++ b/libnavigator/src/main/java/com/mapbox/navigation/navigator/MapboxNativeNavigatorImpl.kt
@@ -4,9 +4,14 @@ import android.location.Location
import com.mapbox.geojson.Point
import com.mapbox.navigation.base.route.model.Route
import com.mapbox.navigation.base.trip.model.RouteProgress
+import com.mapbox.navigation.navigator.model.RouterConfig
import com.mapbox.navigator.FixLocation
+import com.mapbox.navigator.HttpInterface
import com.mapbox.navigator.NavigationStatus
import com.mapbox.navigator.Navigator
+import com.mapbox.navigator.RouterParams
+import com.mapbox.navigator.RouterResult
+import com.mapbox.navigator.TileEndpointConfiguration
import java.util.Date
object MapboxNativeNavigatorImpl : MapboxNativeNavigator {
@@ -17,10 +22,32 @@ object MapboxNativeNavigatorImpl : MapboxNativeNavigator {
private val navigator: Navigator = Navigator()
+ override fun configureRouter(routerConfig: RouterConfig, httpClient: HttpInterface, userAgent: String) {
+ navigator.configureRouter(
+ RouterParams(
+ routerConfig.tilePath,
+ routerConfig.inMemoryTileCache,
+ routerConfig.mapMatchingSpatialCache,
+ routerConfig.threadsCount,
+ routerConfig.endpointConfig?.let {
+ TileEndpointConfiguration(
+ it.host,
+ it.version,
+ it.token,
+ userAgent,
+ ""
+ )
+ }),
+ httpClient
+ )
+ }
+
override fun updateLocation(rawLocation: Location) {
navigator.updateLocation(rawLocation.toFixLocation())
}
+ override fun getRoute(url: String): RouterResult = navigator.getRoute(url)
+
override fun setRoute(route: Route) {
TODO("not implemented")
}
diff --git a/libnavigator/src/main/java/com/mapbox/navigation/navigator/model/EndpointConfig.kt b/libnavigator/src/main/java/com/mapbox/navigation/navigator/model/EndpointConfig.kt
new file mode 100644
index 00000000000..32effba5c8d
--- /dev/null
+++ b/libnavigator/src/main/java/com/mapbox/navigation/navigator/model/EndpointConfig.kt
@@ -0,0 +1,8 @@
+package com.mapbox.navigation.navigator.model
+
+data class EndpointConfig(
+ val host: String,
+ val version: String,
+ val token: String,
+ val userAgent: String
+)
diff --git a/libnavigator/src/main/java/com/mapbox/navigation/navigator/model/RouterConfig.kt b/libnavigator/src/main/java/com/mapbox/navigation/navigator/model/RouterConfig.kt
new file mode 100644
index 00000000000..150a1ac7748
--- /dev/null
+++ b/libnavigator/src/main/java/com/mapbox/navigation/navigator/model/RouterConfig.kt
@@ -0,0 +1,9 @@
+package com.mapbox.navigation.navigator.model
+
+data class RouterConfig(
+ val tilePath: String,
+ val inMemoryTileCache: Int?,
+ val mapMatchingSpatialCache: Int?,
+ val threadsCount: Int?,
+ val endpointConfig: EndpointConfig?
+)