Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Navigate route with rerouting #316

Open
wants to merge 6 commits into
base: v.next
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,10 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.tooling.preview.Preview
import androidx.lifecycle.ViewModel
import com.arcgismaps.exceptions.ArcGISException
import com.esri.arcgismaps.sample.sampleslib.theme.SampleAppTheme

/**
Expand All @@ -39,14 +41,15 @@ import com.esri.arcgismaps.sample.sampleslib.theme.SampleAppTheme
fun MessageDialog(
title: String,
description: String = "",
icon: ImageVector = Icons.Filled.Info,
onDismissRequest: () -> Unit
) {
Log.e("SampleAlertMessage", "$title: $description")
// display a dialog with a description text
if (description.isNotEmpty()) {
AlertDialog(
onDismissRequest = { onDismissRequest() },
icon = { Icon(Icons.Filled.Info, contentDescription = null) },
icon = { Icon(imageVector = icon, contentDescription = null) },
title = { Text(title) },
text = { Text(description) },
confirmButton = {
Expand Down Expand Up @@ -103,6 +106,18 @@ class MessageDialogViewModel : ViewModel() {
dialogStatus = true
}

fun showMessageDialog(throwable: Throwable) {
messageTitle = throwable.message.toString()
messageDescription = throwable.cause.toString()
dialogStatus = true
}

fun showMessageDialog(exception: ArcGISException) {
messageTitle = exception.message
messageDescription = exception.additionalMessage.toString() + "\n" + exception.cause
dialogStatus = true
}

/**
* Dismiss the message dialog
*/
Expand Down
52 changes: 52 additions & 0 deletions samples/navigate-route-with-rerouting/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# Navigate route with rerouting

Navigate between two points and dynamically recalculate an alternate route when the original route is unavailable.

![Image of navigate route with rerouting](navigate-route-with-rerouting.png)

## Use case

While traveling between destinations, field workers use navigation to get live directions based on their locations. In cases where a field worker makes a wrong turn, or if the route suggested is blocked due to a road closure, it is necessary to calculate an alternate route to the original destination.

## How to use the sample

Tap "Navigate" to simulate traveling and to receive directions from a preset starting point to a preset destination. Observe how the route is recalculated when the simulation does not follow the suggested route. Tap "Recenter" to reposition the viewpoint. Tap "Reset" to start the simulation from the beginning.

## How it works

1. Create a `RouteTask` using local network data.
2. Generate default `RouteParameters` using `RouteTask.createDefaultParameters()`.
3. Set `returnRoutes`, `returnStops`, and `returnDirections` on the `RouteParameters` to `true`.
4. Add `Stop`s to the parameters' list of `stops` using `RouteParameters.setStops(...)`.
5. Solve the route using `routeTask.solveRoute(routeParameters)` to get an `RouteResult`.
6. Create an `RouteTracker` using the route result, and the index of the desired route to take.
7. Enable rerouting in the route tracker using `routeTracker.enableRerouting(reroutingParameters)`. Pass `ReroutingStrategy.ToNextWaypoint` as the value of `strategy` to specify that in the case of a reroute, the new route goes from present location to next waypoint or stop.
8. Retrieve the `routeTracker.trackingStatus` state flow values to track status and progress updates as a route is traversed.

## Relevant API

* DestinationStatus
* DirectionManeuver
* Location
* LocationDataSource
* ReroutingStrategy
* Route
* RouteParameters
* RouteTask
* RouteTracker
* RouteTrackerLocationDataSource
* SimulatedLocationDataSource
* Stop
* VoiceGuidance

## About the data

The [San Diego Geodatabase](https://arcgisruntime.maps.arcgis.com/home/item.html?id=df193653ed39449195af0c9725701dca) route taken in this sample goes from the San Diego Convention Center, site of the annual Esri User Conference, to the Fleet Science Center, San Diego.

## Additional information

The route tracker will start a rerouting calculation automatically as necessary when the device's location indicates that it is off-route. The route tracker also validates that the device is "on" the transportation network. If it is not (e.g. in a parking lot), rerouting will not occur until the device location indicates that it is back "on" the transportation network.

## Tags

directions, maneuver, navigation, route, turn-by-turn, voice
54 changes: 54 additions & 0 deletions samples/navigate-route-with-rerouting/README.metadata.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
{
"category": "Routing and Logistics",
"description": "Navigate between two points and dynamically recalculate an alternate route when the original route is unavailable.",
"formal_name": "NavigateRouteWithRerouting",
"ignore": false,
"images": [
"navigate-route-with-rerouting.png"
],
"keywords": [
"directions",
"maneuver",
"navigation",
"route",
"turn-by-turn",
"voice",
"DestinationStatus",
"DirectionManeuver",
"Location",
"LocationDataSource",
"ReroutingStrategy",
"Route",
"RouteParameters",
"RouteTask",
"RouteTracker",
"RouteTrackerLocationDataSource",
"SimulatedLocationDataSource",
"Stop",
"VoiceGuidance"
],
"language": "kotlin",
"redirect_from": "",
"relevant_apis": [
"DestinationStatus",
"DirectionManeuver",
"Location",
"LocationDataSource",
"ReroutingStrategy",
"Route",
"RouteParameters",
"RouteTask",
"RouteTracker",
"RouteTrackerLocationDataSource",
"SimulatedLocationDataSource",
"Stop",
"VoiceGuidance"
],
"snippets": [
"src/main/java/com/esri/arcgismaps/sample/navigateroutewithrerouting/components/NavigateRouteWithReroutingViewModel.kt",
"src/main/java/com/esri/arcgismaps/sample/navigateroutewithrerouting/DownloadActivity.kt",
"src/main/java/com/esri/arcgismaps/sample/navigateroutewithrerouting/MainActivity.kt",
"src/main/java/com/esri/arcgismaps/sample/navigateroutewithrerouting/screens/NavigateRouteWithReroutingScreen.kt"
],
"title": "Navigate route with rerouting"
}
22 changes: 22 additions & 0 deletions samples/navigate-route-with-rerouting/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
plugins {
alias(libs.plugins.arcgismaps.android.library)
alias(libs.plugins.arcgismaps.android.library.compose)
alias(libs.plugins.arcgismaps.kotlin.sample)
alias(libs.plugins.gradle.secrets)
}

secrets {
// this file doesn't contain secrets, it just provides defaults which can be committed into git.
defaultPropertiesFileName = "secrets.defaults.properties"
}

android {
namespace = "com.esri.arcgismaps.sample.navigateroutewithrerouting"
buildFeatures {
buildConfig = true
}
}

dependencies {
// Only module specific dependencies needed here
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
23 changes: 23 additions & 0 deletions samples/navigate-route-with-rerouting/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

<uses-permission android:name="android.permission.INTERNET" />

<application>
<activity
android:name=".DownloadActivity"
android:exported="true"
android:label="@string/navigate_route_with_rerouting_app_name">

</activity>
<activity
android:name=".MainActivity"
android:exported="true"
android:label="@string/navigate_route_with_rerouting_app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
</intent-filter>
</activity>
</application>

</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/* Copyright 2025 Esri
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/

package com.esri.arcgismaps.sample.navigateroutewithrerouting

import android.content.Intent
import android.os.Bundle
import com.esri.arcgismaps.sample.sampleslib.DownloaderActivity

class DownloadActivity : DownloaderActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
downloadAndStartSample(
Intent(this, MainActivity::class.java),
// get the app name of the sample
getString(R.string.navigate_route_with_rerouting_app_name),
listOf(
// ArcGIS Portal item containing the zip of offline routing network and tpkx basemap.
"https://www.arcgis.com/home/item.html?id=df193653ed39449195af0c9725701dca"
)
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/* Copyright 2025 Esri
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/

package com.esri.arcgismaps.sample.navigateroutewithrerouting

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.runtime.Composable
import com.arcgismaps.ApiKey
import com.arcgismaps.ArcGISEnvironment
import com.esri.arcgismaps.sample.sampleslib.theme.SampleAppTheme
import com.esri.arcgismaps.sample.navigateroutewithrerouting.screens.NavigateRouteWithReroutingScreen

class MainActivity : ComponentActivity() {

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// authentication with an API key or named user is
// required to access basemaps and other location services
ArcGISEnvironment.apiKey = ApiKey.create(BuildConfig.ACCESS_TOKEN)

setContent {
SampleAppTheme {
NavigateRouteWithReroutingApp()
}
}
}

@Composable
private fun NavigateRouteWithReroutingApp() {
Surface(color = MaterialTheme.colorScheme.background) {
NavigateRouteWithReroutingScreen(
sampleName = getString(R.string.navigate_route_with_rerouting_app_name)
)
}
}
}
Loading
Loading