├── jitpack.yml
├── app
├── src
│ ├── main
│ │ ├── res
│ │ │ ├── values
│ │ │ │ ├── .gitignore
│ │ │ │ ├── colors.xml
│ │ │ │ ├── dimens.xml
│ │ │ │ ├── arrays.xml
│ │ │ │ ├── styles.xml
│ │ │ │ └── strings.xml
│ │ │ ├── values-he
│ │ │ │ └── strings.xml
│ │ │ ├── values-hu
│ │ │ │ └── strings.xml
│ │ │ ├── values-it
│ │ │ │ └── strings.xml
│ │ │ ├── values-bn
│ │ │ │ └── strings.xml
│ │ │ ├── values-pt-rBR
│ │ │ │ └── strings.xml
│ │ │ ├── mipmap-hdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-mdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── drawable-hdpi
│ │ │ │ ├── ic_settings.png
│ │ │ │ └── paella_icon.png
│ │ │ ├── drawable-ldpi
│ │ │ │ └── ic_settings.png
│ │ │ ├── drawable-mdpi
│ │ │ │ ├── ic_settings.png
│ │ │ │ └── paella_icon.png
│ │ │ ├── drawable-xhdpi
│ │ │ │ ├── ic_settings.png
│ │ │ │ └── paella_icon.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── drawable-xxhdpi
│ │ │ │ ├── ic_settings.png
│ │ │ │ └── paella_icon.png
│ │ │ ├── drawable-xxxhdpi
│ │ │ │ ├── ic_car_top.png
│ │ │ │ ├── ic_settings.png
│ │ │ │ └── paella_icon.png
│ │ │ ├── drawable
│ │ │ │ ├── demo_switch_background.xml
│ │ │ │ ├── ic_delete_black_24dp.xml
│ │ │ │ ├── ic_layers.xml
│ │ │ │ ├── ic_new_location.xml
│ │ │ │ ├── ic_refresh.xml
│ │ │ │ └── ic_car.xml
│ │ │ ├── menu
│ │ │ │ ├── navigation_view_activity_menu.xml
│ │ │ │ └── menu_off_route_detection.xml
│ │ │ ├── values-id
│ │ │ │ └── strings.xml
│ │ │ ├── values-bg
│ │ │ │ └── strings.xml
│ │ │ ├── values-sv
│ │ │ │ └── strings.xml
│ │ │ ├── values-da
│ │ │ │ └── strings.xml
│ │ │ ├── values-ca
│ │ │ │ └── strings.xml
│ │ │ ├── values-fr
│ │ │ │ └── strings.xml
│ │ │ ├── layout
│ │ │ │ ├── activity_main.xml
│ │ │ │ ├── item_main_feature.xml
│ │ │ │ ├── activity_snap_to_route_navigation.xml
│ │ │ │ ├── activity_navigation_ui.xml
│ │ │ │ └── activity_mock_navigation.xml
│ │ │ ├── xml
│ │ │ │ └── fragment_navigation_view_preferences.xml
│ │ │ ├── values-uk
│ │ │ │ └── strings.xml
│ │ │ ├── values-my
│ │ │ │ └── strings.xml
│ │ │ ├── values-cs
│ │ │ │ └── strings.xml
│ │ │ ├── values-vi
│ │ │ │ └── strings.xml
│ │ │ ├── values-ru
│ │ │ │ └── strings.xml
│ │ │ ├── values-pt-rPT
│ │ │ │ └── strings.xml
│ │ │ ├── values-de
│ │ │ │ └── strings.xml
│ │ │ └── values-es
│ │ │ │ └── strings.xml
│ │ ├── java
│ │ │ └── com
│ │ │ │ └── mapbox
│ │ │ │ └── services
│ │ │ │ └── android
│ │ │ │ └── navigation
│ │ │ │ └── testapp
│ │ │ │ ├── NavigationApplication.java
│ │ │ │ ├── SampleItem.java
│ │ │ │ ├── Utils.java
│ │ │ │ ├── CustomNavigationNotification.java
│ │ │ │ ├── MainActivity.java
│ │ │ │ ├── SnapToRouteNavigationActivity.kt
│ │ │ │ ├── NavigationUIActivity.kt
│ │ │ │ └── MockNavigationActivity.kt
│ │ ├── assets
│ │ │ ├── long_step.json
│ │ │ └── reroute.json
│ │ └── AndroidManifest.xml
│ └── androidTest
│ │ └── java
│ │ └── testapp
│ │ ├── NavigationViewTest.java
│ │ ├── action
│ │ └── OrientationChangeAction.java
│ │ ├── activity
│ │ └── BaseNavigationActivityTest.java
│ │ ├── NavigationViewOrientationTest.java
│ │ └── utils
│ │ └── OnNavigationReadyIdlingResource.java
└── build.gradle
├── settings.gradle
├── .github
├── preview.png
└── ISSUE_TEMPLATE.md
├── gradle
├── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── checkstyle.gradle
├── dependency-updates.gradle
├── dependencies-graph.gradle
├── developer-config.gradle
├── mvn-push-android.gradle
└── dependencies.gradle
├── .gitignore
├── README.md
├── config
└── checkstyle
│ ├── suppressions.xml
│ └── checkstyle.xml
├── .tx
└── config
├── LICENSE
├── gradle.properties
├── CONTRIBUTING.md
├── gradlew.bat
├── Makefile
├── localization.md
├── circle.yml
├── gradlew
└── scripts
└── release.py
/jitpack.yml:
--------------------------------------------------------------------------------
1 | jdk:
2 | - openjdk11
3 |
--------------------------------------------------------------------------------
/app/src/main/res/values/.gitignore:
--------------------------------------------------------------------------------
1 | developer-config.xml
2 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 | include ':libandroid-navigation'
3 | include ':libandroid-navigation-ui'
4 |
--------------------------------------------------------------------------------
/.github/preview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/graphhopper/graphhopper-navigation-example/HEAD/.github/preview.png
--------------------------------------------------------------------------------
/app/src/main/res/values-he/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Maplibre Navigation SDK for Android
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values-hu/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Mapbox Navigációs SDK Androidhoz
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values-it/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Maplibre Navigation SDK per Android
3 |
4 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/graphhopper/graphhopper-navigation-example/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/app/src/main/res/values-bn/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Android এর জন্য ম্যাপবক্স নেভিগেশন SDK
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values-pt-rBR/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | SDK de Navegação Mapbox para Android
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/graphhopper/graphhopper-navigation-example/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/graphhopper/graphhopper-navigation-example/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/graphhopper/graphhopper-navigation-example/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_settings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/graphhopper/graphhopper-navigation-example/HEAD/app/src/main/res/drawable-hdpi/ic_settings.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/paella_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/graphhopper/graphhopper-navigation-example/HEAD/app/src/main/res/drawable-hdpi/paella_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-ldpi/ic_settings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/graphhopper/graphhopper-navigation-example/HEAD/app/src/main/res/drawable-ldpi/ic_settings.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_settings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/graphhopper/graphhopper-navigation-example/HEAD/app/src/main/res/drawable-mdpi/ic_settings.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/paella_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/graphhopper/graphhopper-navigation-example/HEAD/app/src/main/res/drawable-mdpi/paella_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_settings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/graphhopper/graphhopper-navigation-example/HEAD/app/src/main/res/drawable-xhdpi/ic_settings.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/paella_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/graphhopper/graphhopper-navigation-example/HEAD/app/src/main/res/drawable-xhdpi/paella_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/graphhopper/graphhopper-navigation-example/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/graphhopper/graphhopper-navigation-example/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_settings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/graphhopper/graphhopper-navigation-example/HEAD/app/src/main/res/drawable-xxhdpi/ic_settings.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/paella_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/graphhopper/graphhopper-navigation-example/HEAD/app/src/main/res/drawable-xxhdpi/paella_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxxhdpi/ic_car_top.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/graphhopper/graphhopper-navigation-example/HEAD/app/src/main/res/drawable-xxxhdpi/ic_car_top.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxxhdpi/ic_settings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/graphhopper/graphhopper-navigation-example/HEAD/app/src/main/res/drawable-xxxhdpi/ic_settings.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxxhdpi/paella_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/graphhopper/graphhopper-navigation-example/HEAD/app/src/main/res/drawable-xxxhdpi/paella_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/graphhopper/graphhopper-navigation-example/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/graphhopper/graphhopper-navigation-example/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/graphhopper/graphhopper-navigation-example/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/graphhopper/graphhopper-navigation-example/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/graphhopper/graphhopper-navigation-example/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Gradle
2 | .gradle
3 | /local.properties
4 |
5 | # IntelliJ
6 | out/
7 |
8 | build/
9 | /captures
10 | .externalNativeBuild
11 |
12 | # Idea
13 | .idea
14 | *.iml
15 |
16 | # MacOS
17 | .DS_Store
18 |
19 | # joe
20 | *~
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/demo_switch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #8D64F9
4 | #7845F3
5 | #F56FA3
6 | #FF0000
7 | #FFFFFF
8 |
9 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # GraphHopper Navigation Example for Android
2 |
3 | You can use this repository which uses the Maplibre SDK.
4 |
5 | But it might be simpler to use the Maplibre SDK directly. See [this PR](https://github.com/maplibre/maplibre-navigation-android/pull/162).
6 |
7 | Furthermore you can use GraphHopper with the ferrostar SDK. See [this PR](https://github.com/stadiamaps/ferrostar/pull/514).
8 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/navigation_view_activity_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_delete_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values-id/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Navigasi Rekayasa
3 | Mengubah Rute
4 | Navigasi Rute Peta
5 | Gambar Rute pada Peta
6 |
7 | Coba Tampilan Drop-in
8 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_layers.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_new_location.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/config/checkstyle/suppressions.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 16dp
6 | 16dp
7 | 16dp
8 | 50sp
9 | 10sp
10 | 96dp
11 | 56dp
12 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_refresh.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 |
8 |
9 | **Android API:**
10 | **Maplibre Navigation SDK version:**
11 |
12 | ### Steps to trigger behavior
13 |
14 | 1.
15 | 2.
16 | 3.
17 |
18 | ### Expected behavior
19 |
20 | ### Actual behavior
21 |
--------------------------------------------------------------------------------
/gradle/checkstyle.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'checkstyle'
2 |
3 | checkstyle.toolVersion = '7.1.1'
4 |
5 | task checkstyle(type: Checkstyle) {
6 | description 'Checks if the code adheres to coding standards'
7 | group 'verification'
8 |
9 | configFile = new File(rootDir, "config/checkstyle/checkstyle.xml")
10 | source 'src'
11 | include '**/*.java'
12 | exclude '**/gen/**'
13 | exclude '**/*Test.java'
14 | exclude '**/*FeatureOverviewActivity.java'
15 | exclude '**/*ManeuversStyleKit.java'
16 | exclude '**/*LanesStyleKit.java'
17 |
18 | classpath = files()
19 | ignoreFailures = false
20 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/mapbox/services/android/navigation/testapp/NavigationApplication.java:
--------------------------------------------------------------------------------
1 | package com.mapbox.services.android.navigation.testapp;
2 |
3 | import android.app.Application;
4 |
5 | import com.mapbox.mapboxsdk.BuildConfig;
6 | import com.mapbox.mapboxsdk.Mapbox;
7 |
8 | import timber.log.Timber;
9 |
10 | public class NavigationApplication extends Application {
11 |
12 | @Override
13 | public void onCreate() {
14 | super.onCreate();
15 |
16 | if (BuildConfig.DEBUG) {
17 | Timber.plant(new Timber.DebugTree());
18 | }
19 |
20 | Mapbox.getInstance(getApplicationContext());
21 | }
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mapbox/services/android/navigation/testapp/SampleItem.java:
--------------------------------------------------------------------------------
1 | package com.mapbox.services.android.navigation.testapp;
2 |
3 | public class SampleItem {
4 |
5 | private String name;
6 | private String description;
7 | private Class activity;
8 |
9 | public SampleItem(String name, String description, Class activity) {
10 | this.name = name;
11 | this.description = description;
12 | this.activity = activity;
13 | }
14 |
15 | public String getName() {
16 | return name;
17 | }
18 |
19 | public String getDescription() {
20 | return description;
21 | }
22 |
23 | public Class getActivity() {
24 | return activity;
25 | }
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_car.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_off_route_detection.xml:
--------------------------------------------------------------------------------
1 |
2 |
25 |
--------------------------------------------------------------------------------
/app/src/main/res/values-bg/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Тестова навигация
3 | Имитирай навигационна сесия с тестовия локализатор.
4 |
5 | Откриване извън маршрута
6 | Използва Route Utils клас за определяне дали потребител е извън маршрута.
7 |
8 | Пренасочване
9 | Тествай функцията за пренасочване вътре в SDK навигацията
10 |
11 | Навигационен картов маршрут
12 | Изчертава маршрут на картата
13 |
14 |
15 |
--------------------------------------------------------------------------------
/gradle/dependency-updates.gradle:
--------------------------------------------------------------------------------
1 | import com.github.benmanes.gradle.versions.VersionsPlugin
2 |
3 | buildscript {
4 | repositories {
5 | gradlePluginPortal()
6 | }
7 | dependencies {
8 | classpath 'com.github.ben-manes:gradle-versions-plugin:0.44.0'
9 | }
10 | }
11 |
12 | apply plugin: VersionsPlugin
13 |
14 | // disallow release candidates as upgradable versions
15 | dependencyUpdates.resolutionStrategy {
16 | componentSelection { rules ->
17 | rules.all { ComponentSelection selection ->
18 | boolean rejected = ['alpha', 'beta', 'rc', 'cr', 'm'].any { qualifier ->
19 | selection.candidate.version ==~ /(?i).*[.-]${qualifier}[.\d-]*/
20 | }
21 | if (rejected) {
22 | selection.reject('Release candidate')
23 | }
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/src/main/res/values-sv/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Simulera Navigering
3 | Simulera navigering med en platsmotor
4 |
5 | Avvägsdetektering
6 | Använder klassen RouteUtils för att avgöra om en användare är på rätt väg.
7 |
8 | Omdirigera
9 | Testa omdirigering via Navigations SDKt
10 |
11 | Navigeringskarta Rutt
12 | Rita en rutt på kartan
13 |
14 | Drop-in användarupplevelse
15 |
16 |
17 |
--------------------------------------------------------------------------------
/.tx/config:
--------------------------------------------------------------------------------
1 | [main]
2 | host = https://www.transifex.com
3 | minimum_perc = 20
4 | lang_map = pt_BR: pt-rBR, pt_PT: pt-rPT
5 |
6 | [mapbox-navigation-sdk-for-android.test-app-strings-file]
7 | file_filter = app/src/main/res/values-/strings.xml
8 | source_file = app/src/main/res/values/strings.xml
9 | source_lang = en
10 | type = ANDROID
11 |
12 | [mapbox-navigation-sdk-for-android.libandroid-navigation-strings-file]
13 | file_filter = libandroid-navigation/src/main/res/values-/strings.xml
14 | source_file = libandroid-navigation/src/main/res/values/strings.xml
15 | source_lang = en
16 | type = ANDROID
17 |
18 | [mapbox-navigation-sdk-for-android.libandroid-navigation-ui-strings-file]
19 | file_filter = libandroid-navigation-ui/src/main/res/values-/strings.xml
20 | source_file = libandroid-navigation-ui/src/main/res/values/strings.xml
21 | source_lang = en
22 | type = ANDROID
23 |
24 |
--------------------------------------------------------------------------------
/app/src/main/res/values-da/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Mock navigation
3 | Kør en navigationsession ved hjælp af en lokations simulering
4 |
5 | tabt rute detektion
6 | Brug Route Utils class til at bestemme om brugeren har forladt ruten.
7 |
8 | Omdirigere
9 | Test funktionen omdirigering inde i navigation SDK
10 |
11 | Navigation kort rute
12 | Tegner en rute på kortet
13 |
14 | Drop-in UI oplevelse
15 |
16 |
17 |
--------------------------------------------------------------------------------
/app/src/main/res/values-ca/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Simular navegació
3 | Simular una sessió de navegació amb un motor simulat d\'ubicació.
4 |
5 | Detecció fora de ruta
6 | Empra les classes Route Utils per determinar si un usuari és fora de la ruta.
7 |
8 | Redirigir
9 | Prova la funció de redirecció dins del SDK de navegació
10 |
11 | Mapa de navegació de la ruta
12 | Dibuixa una ruta al mapa
13 |
14 | Experiència UI casual
15 |
16 |
17 |
--------------------------------------------------------------------------------
/app/src/main/res/values-fr/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Navigation simulée
3 | Simule une session de navigation en utilisant un moteur de localisation simulée.
4 |
5 | Détection de sortie d’itinéraire
6 | Utilise la classe Utilitaires d’Itinéraire pour déterminer is un utilisateur sort de l’itinéraire prévu.
7 |
8 | Recalcul d’itinéraire
9 | Teste la fonction de recalcul d’itinéraire du SDK de navigation
10 |
11 | Itinéraire de navigation sur carte
12 | Trace un itinéraire sur la carte
13 |
14 | Expérimentation de l’interface utilisateur
15 |
16 | Langue
17 |
18 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/testapp/NavigationViewTest.java:
--------------------------------------------------------------------------------
1 | package testapp;
2 |
3 | import com.mapbox.services.android.navigation.ui.v5.map.NavigationMapboxMap;
4 | import com.mapbox.services.android.navigation.v5.navigation.MapboxNavigation;
5 |
6 | import org.junit.Test;
7 |
8 | import testapp.activity.BaseNavigationActivityTest;
9 |
10 | import static junit.framework.Assert.assertNotNull;
11 |
12 | public class NavigationViewTest extends BaseNavigationActivityTest {
13 |
14 | @Override
15 | protected Class getActivityClass() {
16 | return NavigationViewTest.class;
17 | }
18 |
19 | @Test
20 | public void onInitialization_navigationMapboxMapIsNotNull() {
21 | validateTestSetup();
22 |
23 | NavigationMapboxMap navigationMapboxMap = getNavigationView().retrieveNavigationMapboxMap();
24 |
25 | assertNotNull(navigationMapboxMap);
26 | }
27 |
28 | @Test
29 | public void onNavigationStart_mapboxNavigationIsNotNull() {
30 | validateTestSetup();
31 |
32 | MapboxNavigation mapboxNavigation = getNavigationView().retrieveMapboxNavigation();
33 |
34 | assertNotNull(mapboxNavigation);
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/gradle/dependencies-graph.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | repositories {
3 | mavenCentral()
4 | }
5 |
6 | dependencies {
7 | classpath pluginDependencies.dependencyGraph
8 | }
9 | }
10 |
11 | import com.vanniktech.dependency.graph.generator.DependencyGraphGeneratorPlugin
12 | import com.vanniktech.dependency.graph.generator.DependencyGraphGeneratorExtension.Generator
13 | import com.vanniktech.dependency.graph.generator.dot.GraphFormattingOptions
14 | import com.vanniktech.dependency.graph.generator.dot.Color
15 | import com.vanniktech.dependency.graph.generator.dot.Shape
16 | import com.vanniktech.dependency.graph.generator.dot.Style
17 |
18 | plugins.apply(DependencyGraphGeneratorPlugin)
19 |
20 | def mapboxGenerator = new Generator(
21 | "mapboxLibraries", // Suffix for our Gradle task.
22 | "", // Root suffix that we don't want in this case.
23 | { dependency -> dependency.getModuleGroup().startsWith("com.mapbox.mapboxsdk") }, // Only want Mapbox libs.
24 | { dependency -> true }, // Include transitive dependencies.
25 | )
26 |
27 | dependencyGraphGenerator {
28 | generators = [mapboxGenerator]
29 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2021 Maplibre
4 | Copyright (c) 2019 Flitsmeister
5 | Copyright (c) 2018 Mapbox
6 |
7 | Permission is hereby granted, free of charge, to any person obtaining a copy
8 | of this software and associated documentation files (the "Software"), to deal
9 | in the Software without restriction, including without limitation the rights
10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | copies of the Software, and to permit persons to whom the Software is
12 | furnished to do so, subject to the following conditions:
13 |
14 | The above copyright notice and this permission notice shall be included in all
15 | copies or substantial portions of the Software.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 | SOFTWARE.
24 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/fragment_navigation_view_preferences.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
10 |
16 |
22 |
27 |
--------------------------------------------------------------------------------
/app/src/main/res/values/arrays.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | - Default for Device
6 | - English
7 | - French
8 | - German
9 | - Indonesian
10 |
11 |
12 |
13 | - @string/default_locale
14 | - en
15 | - fr
16 | - de
17 | - in
18 |
19 |
20 |
21 | - Default for Device
22 | - Metric
23 | - Imperial
24 |
25 |
26 |
27 | - @string/default_unit_type
28 | - metric
29 | - imperial
30 |
31 |
32 |
33 | - Driving
34 | - Cycling
35 | - Walking
36 |
37 |
38 |
39 | - driving-traffic
40 | - cycling
41 | - walking
42 |
43 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_main_feature.xml:
--------------------------------------------------------------------------------
1 |
2 |
13 |
14 |
24 |
25 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | VERSION_NAME=1.0.3
3 | GROUP=com.mapbox.mapboxsdk
4 | POM_URL=https://github.com/mapbox/mapbox-navigation-android
5 | POM_SCM_URL=https://github.com/mapbox/mapbox-navigation-android
6 | POM_SCM_CONNECTION=scm:git@github.com:mapbox/mapbox-navigation-android.git
7 | POM_SCM_DEV_CONNECTION=scm:git@github.com:mapbox/mapbox-navigation-android.git
8 | POM_LICENCE_NAME=The Apache Software License, Version 2.0
9 | POM_LICENCE_URL=http://www.apache.org/licenses/LICENSE-2.0.txt
10 | POM_LICENCE_DIST=repo
11 | POM_DEVELOPER_ID=mapbox
12 | POM_DEVELOPER_NAME=Mapbox
13 | # IDE (e.g. Android Studio) users:
14 | # Gradle settings configured through the IDE *will override*
15 | # any settings specified in this file.
16 | # For more details on how to configure your build environment visit
17 | # http://www.gradle.org/docs/current/userguide/build_environment.html
18 | # Specifies the JVM arguments used for the daemon process.
19 | # The setting is particularly useful for tweaking memory settings.
20 | org.gradle.jvmargs=-Xmx2048M
21 | android.useAndroidX=true
22 | android.enableJetifier=true
23 | # When configured, Gradle will run in incubating parallel mode.
24 | # This option should only be used with decoupled projects. More details, visit
25 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
26 | # org.gradle.parallel=true
27 |
--------------------------------------------------------------------------------
/gradle/developer-config.gradle:
--------------------------------------------------------------------------------
1 | //
2 | // Configuration file for gradle build execution.
3 | //
4 |
5 | task accessToken {
6 | def tokenFile = new File("${projectDir}/src/main/res/values/developer-config.xml")
7 | if (!tokenFile.exists()) {
8 | String mapboxAccessToken = "$System.env.GRAPHHOPPER_API_KEY"
9 | if (mapboxAccessToken == "null") {
10 | System.out.println("You can set the GRAPHHOPPER_API_KEY environment variable.")
11 | mapboxAccessToken = "GRAPHHOPPER_API_KEY"
12 | }
13 | String tokenFileContents = "\n" +
14 | "\n" +
15 | " https://graphhopper.com/api/1/navigate/" +
16 | " \n" +
17 | " " + mapboxAccessToken + "\n" +
18 | " \n" +
19 | " https://tiles.mapilion.com/assets/osm-bright/style.json?key=MAPTILER_API_KEY\n" +
20 | " \n" +
21 | " https://tiles.mapilion.com/assets/dark-matter/style.json?key=MAPTILER_API_KEY\n" +
22 | ""
23 | tokenFile.write(tokenFileContents)
24 | }
25 | }
26 |
27 | gradle.projectsEvaluated {
28 | preBuild.dependsOn('accessToken')
29 | }
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | If you have a usage question pertaining to the Maplibre Navigation SDK for Android, or any of our other products, contact us through [our support page](https://www.mapbox.com/contact/).
4 |
5 | If you want to contribute code:
6 |
7 | 1. Please familiarize yourself with the [install process](README.md).
8 |
9 | 2. Ensure that existing [pull requests](https://github.com/maplibre/maplibre-navigation-android/pulls) and [issues](https://github.com/maplibre/maplibre-navigation-android/issues) don’t already cover your contribution or question.
10 |
11 | 3. Pull requests are gladly accepted. If there are any changes that developers should be aware of, please update the [change log](CHANGELOG.md)
12 |
13 | 4. ~~We use checkstyle to enforce good coding standards. CI will fail if your PR contains any issues.~~ Lints are currently disabled; PRs welcome to improve the situation. Unit tests still run though!
14 |
15 | ## Getting started building
16 |
17 | You can check out the repo and build locally using Android Studio or the gradle wrapper CLI,
18 | just as with any other Kotlin/Java project.
19 | Do note however that currently the lints fail, so you should run build excluding lints.
20 | For example: `./gradlew build -x lint`.
21 |
22 | # Code of conduct
23 |
24 | Everyone is invited to participate in MapLibre’s open source projects and public discussions: we want to create a welcoming and friendly environment. Harassment of participants or other unethical and unprofessional behavior will not be tolerated in our spaces. The [Contributor Covenant](http://contributor-covenant.org) applies to all projects under the Mapbox organization and we ask that you please read [the full text](http://contributor-covenant.org/version/1/2/0/).
25 |
26 | You can learn more about MapLibre at [maplibre.org](https://maplibre.org/).
27 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mapbox/services/android/navigation/testapp/Utils.java:
--------------------------------------------------------------------------------
1 | package com.mapbox.services.android.navigation.testapp;
2 |
3 | import android.content.Context;
4 | import android.graphics.Bitmap;
5 | import android.graphics.Canvas;
6 | import android.graphics.drawable.Drawable;
7 |
8 | import androidx.annotation.DrawableRes;
9 | import androidx.annotation.NonNull;
10 | import androidx.core.content.res.ResourcesCompat;
11 |
12 | import com.mapbox.mapboxsdk.Mapbox;
13 | import com.mapbox.mapboxsdk.annotations.Icon;
14 | import com.mapbox.mapboxsdk.annotations.IconFactory;
15 | import com.mapbox.mapboxsdk.geometry.LatLng;
16 |
17 | import java.util.Random;
18 |
19 | import timber.log.Timber;
20 |
21 | public class Utils {
22 |
23 | /**
24 | * Demonstrates converting any Drawable to an Icon, for use as a marker icon.
25 | */
26 | public static Icon drawableToIcon(@NonNull Context context, @DrawableRes int id) {
27 | Drawable vectorDrawable = ResourcesCompat.getDrawable(context.getResources(), id, context.getTheme());
28 | Bitmap bitmap = Bitmap.createBitmap(vectorDrawable.getIntrinsicWidth(),
29 | vectorDrawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
30 | Canvas canvas = new Canvas(bitmap);
31 | vectorDrawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
32 | vectorDrawable.draw(canvas);
33 | return IconFactory.getInstance(context).fromBitmap(bitmap);
34 | }
35 |
36 | public static LatLng getRandomLatLng(double[] bbox) {
37 | Random random = new Random();
38 |
39 | double randomLat = bbox[1] + (bbox[3] - bbox[1]) * random.nextDouble();
40 | double randomLon = bbox[0] + (bbox[2] - bbox[0]) * random.nextDouble();
41 |
42 | LatLng latLng = new LatLng(randomLat, randomLon);
43 | Timber.d("getRandomLatLng: %s", latLng.toString());
44 | return latLng;
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/app/src/main/assets/long_step.json:
--------------------------------------------------------------------------------
1 | {
2 | "waypoints": [
3 | {
4 | "name": "Kendree Street",
5 | "location": [
6 | -121.848098,
7 | 38.002812
8 | ]
9 | },
10 | {
11 | "name": "Mountain Wood Lane",
12 | "location": [
13 | -122.261111,
14 | 37.420639
15 | ]
16 | }
17 | ],
18 | "routes": [
19 | {
20 | "legs": [
21 | {
22 | "steps": [
23 | {
24 | "intersections": [
25 | {
26 | "out": 0,
27 | "entry": [
28 | true
29 | ],
30 | "location": [
31 | -121.848098,
32 | 38.002812
33 | ],
34 | "bearings": [
35 | 19
36 | ]
37 | }
38 | ],
39 | "geometry": "}jongAx``lgF|bpb@z`eX",
40 | "duration": 4986.5,
41 | "distance": 119541.2,
42 | "name": "Kendree Street",
43 | "weight": 5012.2,
44 | "mode": "driving",
45 | "maneuver": {
46 | "bearing_after": 19,
47 | "location": [
48 | -121.848098,
49 | 38.002812
50 | ],
51 | "type": "depart",
52 | "bearing_before": 0,
53 | "modifier": "left",
54 | "instruction": "Head north on Kendree Street"
55 | }
56 | }
57 | ],
58 | "weight": 5012.2,
59 | "distance": 119541.2,
60 | "summary": "CA 24, Junipero Serra Freeway",
61 | "duration": 4986.5
62 | }
63 | ],
64 | "weight_name": "routability",
65 | "geometry": "}jongAx``lgF|bpb@z`eX",
66 | "weight": 5012.2,
67 | "distance": 119541.2,
68 | "duration": 4986.5
69 | }
70 | ],
71 | "code": "Ok"
72 | }
73 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
17 |
20 |
23 |
24 |
27 |
30 |
31 |
34 |
37 |
38 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/testapp/action/OrientationChangeAction.java:
--------------------------------------------------------------------------------
1 | package testapp.action;
2 |
3 | import android.app.Activity;
4 | import android.content.Context;
5 | import android.content.ContextWrapper;
6 | import android.content.pm.ActivityInfo;
7 | import androidx.test.espresso.UiController;
8 | import androidx.test.espresso.ViewAction;
9 | import android.view.View;
10 | import android.view.ViewGroup;
11 |
12 | import org.hamcrest.Matcher;
13 |
14 | import static androidx.test.espresso.matcher.ViewMatchers.isRoot;
15 |
16 | public class OrientationChangeAction implements ViewAction {
17 |
18 | private final int orientation;
19 |
20 | private OrientationChangeAction(int orientation) {
21 | this.orientation = orientation;
22 | }
23 |
24 | public static ViewAction orientationLandscape() {
25 | return new OrientationChangeAction(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
26 | }
27 |
28 | public static ViewAction orientationPortrait() {
29 | return new OrientationChangeAction(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
30 | }
31 |
32 | @Override
33 | public Matcher getConstraints() {
34 | return isRoot();
35 | }
36 |
37 | @Override
38 | public String getDescription() {
39 | return "change orientation to " + orientation;
40 | }
41 |
42 | @Override
43 | public void perform(UiController uiController, View view) {
44 | uiController.loopMainThreadUntilIdle();
45 | Activity activity = getActivity(view.getContext());
46 | if (activity == null && view instanceof ViewGroup) {
47 | ViewGroup viewGroup = (ViewGroup) view;
48 | int childCount = viewGroup.getChildCount();
49 | for (int i = 0; i < childCount && activity == null; ++i) {
50 | activity = getActivity(viewGroup.getChildAt(i).getContext());
51 | }
52 | }
53 | activity.setRequestedOrientation(orientation);
54 | }
55 |
56 | private Activity getActivity(Context context) {
57 | while (context instanceof ContextWrapper) {
58 | if (context instanceof Activity) {
59 | return (Activity) context;
60 | }
61 | context = ((ContextWrapper) context).getBaseContext();
62 | }
63 | return null;
64 | }
65 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_snap_to_route_navigation.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
35 |
36 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/app/src/main/res/values-uk/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Maplibre Navigation SDK для Android
3 |
4 | Симуляція навігації
5 | Симуляція навігації за маршрутом з використанням рушія підстановки даних про місцеположення.
6 |
7 | Визначення сходу з маршруту
8 | Використовує клас Route Utils для визначення сходу з маршруту.
9 |
10 | Зміна маршрут
11 | Перевірка функції зміни маршруту в середині SDK навігації
12 |
13 | Навігація - Маршрут на мапі
14 | Показує маршрут поверх мапи
15 |
16 | Інтерфейс для вводу місця призначення.
17 |
18 | Навігація з проміжними точками
19 | Навігація з проміжними точками до пункту призначення
20 |
21 | Вбудована навігація
22 | Навігація у формі, що містить інші форми
23 |
24 | NavigationView реалізовано через Fragment
25 | NavigationView реалізовано через Fragment
26 |
27 | Налаштування
28 | Імітация маршрута
29 | Мова
30 | Одиниці виміру
31 | Тип маршрута
32 |
33 | Поточний маршрут недоступний
34 | Будь ласка, виберіть довший маршрут
35 | Маршрут не знайдено.
36 | Довге натискання на мапі для додавання дорожньої точки
37 |
38 |
--------------------------------------------------------------------------------
/app/src/main/res/values-my/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Mapbox လမ်းညွန်ခြင်း development tookkit
3 |
4 | စမ်းသပ်လမ်းညွှန်ခြင်း
5 | စမ်းသပ်လမ်းညွန်မှုအပိုင်းကို စမ်းသပ်တည်နေရာပြengine အသုံးပြုသည်
6 |
7 | လမ်းကြောင်းမှားခြင်းကိုခြေရာခံခြင်း
8 | Route Utils class ကိုအသုံးပြုကာ အသုံးပြုသူများလမ်းကြောင်းမှားခြင်းကိုခြေရာခံခြင်း
9 |
10 | လမ်းကြောင်းပြန်ပြောင်းသည်
11 | လမ်းကြောင်းပြန်ပြောင်းသည့်အလုပ်ကိုစမ်းသပ်သည်
12 |
13 | လမ်းညွန်မှုမြေပုံလမ်းကြောင်း
14 | မြေပုံပေါ်တွင်လမ်းကြောင်းဆွဲသည်
15 |
16 | Drop-in UI အေတြ႕အၾကံဳ
17 |
18 | Waypoint လမ်းညွန်ခြင်း
19 | ခရီးဆုံမှတ်များကြားလမ်းကြောင်းများနှင့်လမ်းညွန်ခြင်း
20 |
21 | Embedded လမ်းညွန်ခြင်း
22 | အခြားမြင်ကွင်းများပါဝင်သောမြင်ကွင်းတွင်လမ်းညွန်ခြင်း
23 |
24 | NavigationView implemented with Fragment
25 | NavigationView implemented with Fragment
26 |
27 | ချိန်ညှိမှုများ
28 | လမ်းကြောင်းစမ်းသပ်သည်
29 | ဘာသာစကား
30 | ယူနစ်အမျိုးအစား
31 | လမ်းကြောင်းပရိုဖိုင်
32 |
33 | လက်ရှိလမ်းကြောင်းသည်မရရှိနိုင်ပါ
34 | ကျေးဇူးပြု၍ရှည်သောလမ်းကြောင်းရွေးချယ်ပါ
35 | အဆင်ပြေသောလမ်းကြောင်းရှာမတွေ့ပါ
36 | လမ်းကြောင်းမှတ်နေရာချရန်မြေပုံကိုကြာကြာနှိပ်ပါ
37 |
38 |
--------------------------------------------------------------------------------
/app/src/main/res/values-cs/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Maplibre Navigation SDK pro Android
3 |
4 | Simulované navigování
5 | Simulované navigování využívá simulované určování polohy.
6 |
7 | Opuštění trasy
8 | Používá třídu nástrojů trasování k určení, zda uživatelé opustili trasu.
9 |
10 | Přepočítat
11 | Testovat funkci přepočítání trasy uvnitř navigačního SDK
12 |
13 | Mapa trasy
14 | Zobrazit trasu na mapě
15 |
16 | Obsluha navigace
17 | Opustit uživatelské prostředí
18 |
19 | Ukončit navigaci
20 | Zobrazit, jak ukončit navigaci v prostředí NavigationView
21 |
22 | Dvojitá navigační mapa
23 | Zobrazit, jak přidat NavigationView a MapView ve stejném okně
24 |
25 | Navigace s trasovými body
26 | Navigace s trasovými body mezi cíli
27 |
28 | Vestavěná navigace
29 | Navigace v zobrazení, které obsahuje další zobrazení
30 |
31 | NavigationView implementovaný s Fragment
32 | NavigationView implementovaný s Fragment
33 |
34 | Nastavení
35 | Simulovat trasu
36 | Jazyk
37 | Jednotka
38 | Profil trasy
39 |
40 | Aktuální trasa již není platná
41 | Vyberte, prosím, delší trasu
42 | Trasa nenalezena
43 | Dlouhým dotykem mapy přidáte průjezdní bod
44 |
45 |
--------------------------------------------------------------------------------
/app/src/main/res/values-vi/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | SDK Điều hướng của Mapbox
3 |
4 | Giả bộ Điều hướng
5 | Giả bộ phiên điều hướng dùng máy định vị giả.
6 |
7 | Nhận ra Lạc đường
8 | Sử dụng lớp RouteUtils để xác định người dùng bị lạc đường.
9 |
10 | Tìm Đường đi Mới
11 | Thử chức năng tìm đường đi mới trong SDK Điều hướng
12 |
13 | Tuyến đường trên Bản đồ Điều hướng
14 | Vẽ tuyến đường trên bản đồ
15 |
16 | Trình khởi động Điều hướng
17 | Trải nghiệm giao diện người dùng có thể xen vào
18 |
19 | Kết thúc Điều hướng
20 | Cho biết cách kết thúc điều hướng dùng NavigationView
21 |
22 | Đôi Bản đồ Điều hướng
23 | Chỉ cách thêm NavigationView và MapView vào cùng bố cục
24 |
25 | Điều hướng giữa các Tọa độ điểm
26 | Điều hướng giữa các tọa độ điểm
27 |
28 | Điều hướng được Nhúng
29 | Điều hướng trong khung nhìn chứa các khung nhìn khác
30 |
31 | NavigationView thực hiện bằng Fragment
32 | NavigationView thực hiện bằng Fragment
33 |
34 | Thiết lập
35 | Mô phỏng Tuyến đường
36 | Ngôn ngữ
37 | Hệ Đo lường
38 | Chế độ
39 |
40 | Tuyến đường hiện tại không có sẵn
41 | Vui lòng chọn một tuyến đường dài hơn
42 | Không tìm thấy tuyến đi được.
43 | Chạm lâu vào bản đồ để thả ghim tọa độ điểm
44 |
45 |
--------------------------------------------------------------------------------
/app/src/main/res/values-ru/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Навигация Mapbox для Android
3 |
4 | Моделирование маршрута
5 | Начать моделирование маршрута c помощью эмулятора местоположения.
6 |
7 | Движение по бездорожью
8 | Используйте класс Route Utils для обнаружения движения по бездорожью
9 |
10 | Объезд
11 | Проверить функциональность объезда внутри Navigation SDK
12 |
13 | Маршрут на карте
14 | Отобразить маршрут на карте
15 |
16 | Запуск навигации
17 | Различное представление маршрута на экране
18 |
19 | Завершить
20 | Показывает, как завершить маршрут из его отображения
21 |
22 | Двойная карта маршрута
23 | Показывает, как добавить отображение маршрута и карты на один экран
24 |
25 | Маршрут с промежуточными точками
26 | Маршрут с промежуточными пунктами назначения между начальным и конечным
27 |
28 | Вложенный маршрут
29 | Отображение маршрута в области, включающей другие области
30 |
31 | Маршрут внутри фрагмента
32 | Отображение маршрута в области-фрагменте
33 |
34 | Настройки
35 | Моделирование маршрута
36 | Язык
37 | Единицы измерения
38 | Тип маршрута
39 |
40 | Текущий маршрут недоступен
41 | Пожалуйста, выберите более длинный маршрут
42 | Корректный маршрут не найден.
43 | Нажмите и удерживайте, чтобы разместить промежуточную точку маршрута
44 |
45 |
--------------------------------------------------------------------------------
/app/src/main/res/values-pt-rPT/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Navegação Mapbox SDK para Android
3 |
4 | Navegação Simulada
5 | Simule uma sessão de navegação usando um serviço de localizações simuladas.
6 |
7 | Deteção fora de percurso
8 | Usa a classe Route Utils para determinar se o utilizador está fora do percurso.
9 |
10 | Redirecionar
11 | Teste a função de redirecionamento dentro do SDK de navegação
12 |
13 | Mapa de Percurso de Navegação
14 | Desenha um percurso no mapa
15 |
16 | Lançador de Navegação
17 | Experiência de UI Drop-In
18 |
19 | Terminar Navegação
20 | Mostra como terminar a navegação utilizando NavigationView
21 |
22 | Mapa Duplo de Navegação
23 | Mostra como adicionar NavigationView e MapView no mesmo layout
24 |
25 | Navegação de Pontos de Passagem
26 | Navegação com pontos de passagem entre destinos
27 |
28 | Navegação Embutida
29 | Navegação numa vista que contém outras vistas
30 |
31 | NavigationView implementado com Fragment
32 | NavigationView implementado com Fragment
33 |
34 | Definições
35 | Simular Rota
36 | Idioma
37 | Tipo de Unidade
38 | Perfil da Rota
39 |
40 | A rota atual não está disponível
41 | Por favor selecione uma rota mais longa
42 | Não foi encontrada uma rota válida.
43 | Toque longo no mapa para adicionar um ponto de passagem
44 |
45 |
--------------------------------------------------------------------------------
/app/src/main/res/values-de/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Maplibre Navigation SDK für Android
3 |
4 | Simulierte Navigation
5 | Simuliere eine Navigationssitzung durch Verwendung von simulierten Standorten
6 |
7 | Abseits der Route-Erkennung
8 | Verwendet die Routenwerkzeug-Klasse, um zu erkennen, ob ein Nutzer abseits der Route ist
9 |
10 | Routenneuberechnung
11 | Routenneuberechnung innerhalb des Navigation SDK ausprobieren
12 |
13 | Navigation / Karte / Route
14 | Zeichnet eine Route auf der Karte
15 |
16 | Navigations-Starter
17 | Eingebautes UI Erlebnis
18 |
19 | Navigation beenden
20 | Zeigt, wie die Navigation mit NavigationView beendet wird
21 |
22 | Duale Navigationskarte
23 | Zeigt, wie die NavigationView und MapView im selben Layout hinzugefügt werden
24 |
25 | Wegpunkt-Navigation
26 | Navigation mit Wegpunkten zwischen den Zielen
27 |
28 | Eingebettete Navigation
29 | NavigationView in einer View, welche eine andere View enthält
30 |
31 | NavigationView mit Fragment implementiert
32 | NavigationView mit Fragment implementiert
33 |
34 | Einstellungen
35 | Route simulieren
36 | Sprache
37 | Einheitstyp
38 | Routenprofil
39 |
40 | Aktuelle Route ist nicht verfügbar
41 | Bitte wähle eine längere Route
42 | Keine gültige Route gefunden
43 | Lange auf die Karte drücken um ein Wegpunkt zu setzen
44 |
45 |
--------------------------------------------------------------------------------
/app/src/main/res/values-es/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | SDK de mapas y navegación para Android
3 |
4 | Ejemplo de navegación
5 | Simula una sesión de navegación usando un ejemplo del motor de localización
6 |
7 | Apagar detección de ruta
8 | Emplea la clase \"Route Utils\" para determinar si un usuario se encuentra fuera de la ruta.
9 |
10 | Enrutado
11 | Prueba la función de enrutación perteneciente al SDK de navegación
12 |
13 | Ruta del mapa de navegación
14 | Muestra diferentes rutas en el mapa de navegación
15 |
16 | Motor de navegación
17 | Entra en la experiencia de la interfaz
18 |
19 | Finaliza navegación
20 | Muestra como finalizar la navegación utilizando la vista de navegación
21 |
22 | Doble mapa de navegación
23 | Muestra como añadir vista de mapas y navegación en la misma disposición
24 |
25 | Punto de referencia de navegación
26 | Navegación con puntos de referencia entre destinos
27 |
28 | Navegación incrustada
29 | Navegación en una vista que contiene otras vistas
30 |
31 | Vista de navegación implementada con Fragment
32 | Vista de navegación implementada con Fragment
33 |
34 | Ajustes
35 | Simular Ruta
36 | Idioma
37 | Sistema de medida
38 | Perfil de ruta
39 |
40 | La ruta actual no está disponible
41 | Por favor seleccione una ruta más larga
42 | Ruta válida no encontrada.
43 | Mantener el cursor sobre el mapa para agregar un punto de referencia
44 |
45 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/testapp/activity/BaseNavigationActivityTest.java:
--------------------------------------------------------------------------------
1 | package testapp.activity;
2 |
3 | import android.app.Activity;
4 | import android.content.Context;
5 | import android.net.ConnectivityManager;
6 | import android.net.NetworkInfo;
7 | import androidx.test.espresso.IdlingRegistry;
8 | import androidx.test.espresso.IdlingResourceTimeoutException;
9 | import androidx.test.rule.ActivityTestRule;
10 |
11 | import com.mapbox.services.android.navigation.testapp.R;
12 | import com.mapbox.services.android.navigation.ui.v5.NavigationView;
13 |
14 | import junit.framework.Assert;
15 |
16 | import org.junit.After;
17 | import org.junit.Before;
18 | import org.junit.Rule;
19 |
20 | import testapp.utils.OnNavigationReadyIdlingResource;
21 | import timber.log.Timber;
22 |
23 | import static androidx.test.espresso.Espresso.onView;
24 | import static androidx.test.espresso.assertion.ViewAssertions.matches;
25 | import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
26 | import static androidx.test.espresso.matcher.ViewMatchers.withId;
27 |
28 | public abstract class BaseNavigationActivityTest {
29 |
30 | @Rule
31 | public ActivityTestRule rule = new ActivityTestRule<>(getActivityClass());
32 | private NavigationView navigationView;
33 | private OnNavigationReadyIdlingResource idlingResource;
34 |
35 | @Before
36 | public void beforeTest() {
37 | try {
38 | idlingResource = new OnNavigationReadyIdlingResource(rule.getActivity());
39 | IdlingRegistry.getInstance().register(idlingResource);
40 | checkViewIsDisplayed(R.id.navigationView);
41 | navigationView = idlingResource.getNavigationView();
42 | } catch (IdlingResourceTimeoutException idlingResourceTimeoutException) {
43 | Timber.e("Idling resource timed out. Could not validate if navigation is ready.");
44 | throw new RuntimeException("Could not start test for " + getActivityClass().getSimpleName() + ".\n"
45 | + "The ViewHierarchy doesn't contain a view with resource id = R.id.navigationView");
46 | }
47 | }
48 |
49 | protected void validateTestSetup() {
50 | Assert.assertTrue("Device is not connected to the Internet.", isConnected(rule.getActivity()));
51 | checkViewIsDisplayed(R.id.navigationView);
52 | }
53 |
54 | protected NavigationView getNavigationView() {
55 | return navigationView;
56 | }
57 |
58 | protected abstract Class getActivityClass();
59 |
60 | private void checkViewIsDisplayed(int id) {
61 | onView(withId(id)).check(matches(isDisplayed()));
62 | }
63 |
64 | private boolean isConnected(Context context) {
65 | ConnectivityManager connectivityManager
66 | = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
67 | NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
68 | return activeNetworkInfo != null && activeNetworkInfo.isConnected();
69 | }
70 |
71 | @After
72 | public void afterTest() {
73 | IdlingRegistry.getInstance().unregister(idlingResource);
74 | }
75 | }
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
10 |
11 |
40 |
41 |
42 |
48 |
49 |
52 |
53 |
56 |
57 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | checkstyle:
2 | ./gradlew checkstyle
3 |
4 | test:
5 | # See libandroid-navigation/build.gradle for details
6 | ./gradlew :libandroid-navigation:test
7 | ./gradlew :libandroid-navigation-ui:test
8 |
9 | build-release:
10 | ./gradlew :libandroid-navigation:assembleRelease
11 | ./gradlew :libandroid-navigation-ui:assembleRelease
12 |
13 | javadoc:
14 | ./gradlew :libandroid-navigation:javadocrelease
15 | ./gradlew :libandroid-navigation-ui:javadocrelease
16 |
17 | publish:
18 | export IS_LOCAL_DEVELOPMENT=false; ./gradlew :libandroid-navigation:uploadArchives
19 | export IS_LOCAL_DEVELOPMENT=false; ./gradlew :libandroid-navigation-ui:uploadArchives
20 |
21 | publish-local:
22 | # This publishes to ~/.m2/repository/com/mapbox/mapboxsdk
23 | export IS_LOCAL_DEVELOPMENT=true; ./gradlew :libandroid-navigation:uploadArchives
24 | export IS_LOCAL_DEVELOPMENT=true; ./gradlew :libandroid-navigation-ui:uploadArchives
25 |
26 | graphs:
27 | ./gradlew :libandroid-navigation:generateDependencyGraphMapboxLibraries
28 | ./gradlew :libandroid-navigation-ui:generateDependencyGraphMapboxLibraries
29 |
30 | dependency-updates:
31 | ./gradlew :libandroid-navigation:dependencyUpdates
32 | ./gradlew :libandroid-navigation-ui:dependencyUpdates
33 | ./gradlew :app:dependencyUpdates
34 |
35 | dex-count:
36 | ./gradlew countDebugDexMethods
37 | ./gradlew countReleaseDexMethods
38 |
39 | navigation-fixtures:
40 | # Navigation: Taylor street to Page street
41 | curl "https://api.mapbox.com/directions/v5/mapbox/driving/-122.413165,37.795042;-122.433378,37.7727?geometries=polyline6&overview=full&steps=true&access_token=$(MAPBOX_ACCESS_TOKEN)" \
42 | -o libandroid-navigation/src/test/resources/navigation.json
43 |
44 | # Directions: polyline geometry with precision 5
45 | curl "https://api.mapbox.com/directions/v5/mapbox/driving/-122.416667,37.783333;-121.900000,37.333333?geometries=polyline&steps=true&access_token=$(MAPBOX_ACCESS_TOKEN)" \
46 | -o libandroid-navigation/src/test/resources/directions_v5.json
47 |
48 | # Intersection:
49 | curl "https://api.mapbox.com/directions/v5/mapbox/driving/-101.70939001157072,33.62145406099651;-101.68721910152767,33.6213852194939?geometries=polyline6&steps=true&access_token=$(MAPBOX_ACCESS_TOKEN)" \
50 | -o libandroid-navigation/src/test/resources/single_intersection.json
51 |
52 | # Distance Congestion annotation: Mapbox DC to National Mall
53 | curl "https://api.mapbox.com/directions/v5/mapbox/driving-traffic/-77.034042,38.899949;-77.03949,38.888871?geometries=polyline6&overview=full&steps=true&annotations=congestion%2Cdistance&access_token=$(MAPBOX_ACCESS_TOKEN)" \
54 | -o libandroid-navigation/src/test/resources/directions_distance_congestion_annotation.json
55 |
56 | # Default Directions
57 | curl "https://api.mapbox.com/directions/v5/mapbox/driving/-122.416686,37.783425;-121.90034,37.333317?geometries=polyline6&steps=true&banner_instructions=true&voice_instructions=true&access_token=$(MAPBOX_ACCESS_TOKEN)" \
58 | -o libandroid-navigation/src/test/resources/directions_v5_precision_6.json
59 |
60 | # No VoiceInstructions
61 | curl "https://api.mapbox.com/directions/v5/mapbox/driving/-77.034013,38.899994;-77.033757,38.903311?geometries=polyline6&steps=true&access_token=$(MAPBOX_ACCESS_TOKEN)" \
62 | -o libandroid-navigation/src/test/resources/directions_v5_no_voice.json
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 | apply plugin: 'kotlin-android'
3 |
4 | android {
5 | compileSdkVersion androidVersions.compileSdkVersion
6 | buildToolsVersion androidVersions.buildToolsVersion
7 |
8 | compileOptions {
9 | sourceCompatibility JavaVersion.VERSION_1_8
10 | targetCompatibility JavaVersion.VERSION_1_8
11 | }
12 |
13 | defaultConfig {
14 | applicationId "com.mapbox.services.android.navigation.testapp"
15 | minSdkVersion androidVersions.minSdkVersion
16 | targetSdkVersion androidVersions.targetSdkVersion
17 | versionCode 1
18 | versionName "0.1"
19 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
20 | multiDexEnabled true
21 | }
22 |
23 | buildTypes {
24 | debug {
25 | testCoverageEnabled = false
26 | }
27 | release {
28 | minifyEnabled true
29 | }
30 | }
31 |
32 | dexOptions {
33 | maxProcessCount 8
34 | javaMaxHeapSize "2g"
35 | preDexLibraries true
36 | }
37 |
38 | buildFeatures {
39 | viewBinding = true
40 | }
41 |
42 | lintOptions {
43 | abortOnError false
44 | }
45 | }
46 |
47 | dependencies {
48 | implementation 'com.github.maplibre:maplibre-navigation-android:3.0.0'
49 | implementation(dependenciesList.mapLibre) {
50 | exclude group: 'com.mapbox.mapboxsdk', module: 'mapbox-sdk-geojson'
51 | exclude group: 'com.mapbox.mapboxsdk', module: 'mapbox-sdk-turf'
52 | }
53 |
54 | // Support libraries
55 | implementation dependenciesList.androidxAppcompat
56 | implementation dependenciesList.materialDesign
57 | implementation dependenciesList.androidxRecyclerView
58 | implementation dependenciesList.androidxConstraintLayout
59 | implementation dependenciesList.androidxCardView
60 | implementation dependenciesList.lifecycleExtensions
61 |
62 | implementation dependenciesList.gmsLocation
63 |
64 | // Logging
65 | implementation dependenciesList.timber
66 |
67 | // Butter Knife
68 | implementation dependenciesList.butterknife
69 | annotationProcessor dependenciesList.butterknifeProcessor
70 | implementation dependenciesList.androidxAppcompat
71 | implementation dependenciesList.androidxConstraintLayout
72 |
73 | // Leak Canary
74 | debugImplementation dependenciesList.leakCanaryDebug
75 |
76 | // Unit Testing
77 | testImplementation dependenciesList.junit
78 | testImplementation dependenciesList.mockito
79 |
80 | // Instrumentation testing
81 | androidTestImplementation dependenciesList.testRules
82 | androidTestImplementation(dependenciesList.testEspressoCore, {
83 | exclude group: 'com.android.support', module: 'support-annotations'
84 | })
85 | implementation dependenciesList.androidxCore
86 | implementation dependenciesList.kotlinstdlib
87 |
88 | // Separate dependencies of the app that don't need to be in the public dependencies API
89 | implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1"
90 | implementation 'androidx.multidex:multidex:2.0.1'
91 | }
92 |
93 | apply from: "${rootDir}/gradle/developer-config.gradle"
94 | apply from: "${rootDir}/gradle/checkstyle.gradle"
95 | apply from: "${rootDir}/gradle/dependency-updates.gradle"
96 | repositories {
97 | mavenCentral()
98 | }
99 |
--------------------------------------------------------------------------------
/localization.md:
--------------------------------------------------------------------------------
1 | ## Spoken instructions
2 |
3 | Turn instructions are announced in the user interface language when turn instructions are available in that language. Otherwise, if turn instructions are unavailable in that language, they are announced in English instead. To have instructions announced in a language other than the user interface language, set the `NavigationRoute.Builder#language` property when calculating the route with which to start navigation.
4 |
5 | Turn instructions are primarily designed to be announced by either the Mapbox Voice API (powered by [Amazon Polly](https://docs.aws.amazon.com/polly/latest/dg/SupportedLanguage.html)) or [TextToSpeech](https://developer.android.com/reference/android/speech/tts/TextToSpeech). By default, this SDK uses the Mapbox Voice API, which requires an Internet connection at various points along the route. If the Voice API lacks support for the turn instruction language or there is no Internet connection, TextToSpeech announces the instructions instead.
6 |
7 | By default, distances are given in the predominant measurement system of the system region, which may not necessarily be the same region in which the user is traveling. To override the measurement system used in spoken instructions, set the `MapboxNavigationOptions.Builder#unitType` property when calculating the route with which to start navigation.
8 |
9 | The upcoming road or ramp destination is named according to the local or national language. In some regions, the name may be given in multiple languages.
10 |
11 | ## Supported languages
12 |
13 | The table below lists the languages that are supported for user interface elements and for spoken instructions.
14 |
15 | | Language | User interface | [Spoken instructions][apidoc] | Remarks
16 | |------------|:--------------:|:-----------------------------:|--------
17 | | Bengali | ✅ | —
18 | | Burmese | ✅ | ✅ | Depends on the device; may require third-party text-to-speech
19 | | Chinese | - | ✅ Mandarin | Depends on the device; may require third-party text-to-speech
20 | | Czech | ✅ | -
21 | | Danish | ✅ | ✅
22 | | English | ✅ | ✅
23 | | Esperanto | — | ✅
24 | | Finnish | — | ✅ | Depends on the device; may require third-party text-to-speech
25 | | French | ✅ | ✅
26 | | German | ✅ | ✅
27 | | Hebrew | ✅ | ✅ | Depends on the device; may require third-party text-to-speech
28 | | Indonesian | — | ✅ | Depends on the device; may require third-party text-to-speech
29 | | Italian | ✅ | ✅
30 | | Korean | ✅ | ✅
31 | | Norwegian | — | ✅
32 | | Polish | — | ✅
33 | | Portuguese | ✅ | ✅
34 | | Romanian | — | ✅
35 | | Russian | ✅ | ✅
36 | | Spanish | ✅ | ✅
37 | | Swedish | ✅ | ✅
38 | | Turkish | — | ✅
39 | | Ukrainian | ✅ | ✅ | Depends on the device; may require third-party text-to-speech
40 | | Vietnamese | ✅ | ✅ | Depends on the device; may require third-party text-to-speech
41 |
42 | **Please note:** For languages marked with `Depends on the device; may require third-party text-to-speech`, instructions are provided by the SDK, but we cannot guarantee the given device will have the appropriate `TextToSpeech` speech engine installed to pronounce these instructions correctly.
43 |
44 | ## Contributing
45 |
46 | See the [contributing guide](https://github.com/mapbox/mapbox-navigation-ios/blob/master/CONTRIBUTING.md#adding-or-updating-a-localization) for instructions on adding a new localization or improving an existing localization.
47 |
48 | [apidoc]: https://www.mapbox.com/api-documentation/#instructions-languages
49 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Maplibre Navigation SDK for Android
3 |
4 | Mock Navigation
5 | Mock a navigation session using a mock location engine.
6 |
7 | Navigation UI
8 | Showcase a Navigation UI session. Optional with simulation.
9 |
10 | Snap to route
11 | Use snap to route option to show smoother location updates.
12 |
13 | Off route detection
14 | Uses the Route Utils class to determine if a users off route.
15 |
16 | Reroute
17 | Test the reroute function inside the navigation SDK
18 |
19 | Navigation Map Route
20 | Shows different styles using NavigationMapRoute
21 |
22 | Navigation Launcher
23 | Drop-in UI experience
24 |
25 | End Navigation
26 | Shows how to end navigation using NavigationView
27 |
28 | Dual Navigation Map
29 | Shows how to add NavigationView and MapView in the same layout
30 |
31 | Waypoint Navigation
32 | Navigation with waypoints between destinations
33 |
34 | Embedded Navigation
35 | Navigation in a view which contains other views
36 |
37 | NavigationView implemented with Fragment
38 | NavigationView implemented with Fragment
39 |
40 | MapboxNavigation with UI components
41 | MapboxNavigation with UI components
42 |
43 | Settings
44 | Simulate Route
45 | Language
46 | Unit Type
47 | Route Profile
48 |
49 | unit_type
50 | simulate_route
51 | language
52 | route_profile
53 | default_for_device
54 | default_for_device
55 | current_night_mode
56 |
57 | Current route is not available
58 | Please select a longer route
59 | Valid route not found.
60 | Long press map to place waypoint
61 |
62 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/testapp/NavigationViewOrientationTest.java:
--------------------------------------------------------------------------------
1 | package testapp;
2 |
3 | import android.content.res.Configuration;
4 | import androidx.test.espresso.ViewAction;
5 |
6 | import com.mapbox.services.android.navigation.testapp.R;
7 | import com.mapbox.services.android.navigation.ui.v5.map.NavigationMapboxMap;
8 |
9 | import org.junit.Test;
10 |
11 | import testapp.activity.BaseNavigationActivityTest;
12 |
13 | import static androidx.test.espresso.Espresso.onView;
14 | import static androidx.test.espresso.action.ViewActions.click;
15 | import static androidx.test.espresso.action.ViewActions.swipeUp;
16 | import static androidx.test.espresso.assertion.ViewAssertions.matches;
17 | import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
18 | import static androidx.test.espresso.matcher.ViewMatchers.isRoot;
19 | import static androidx.test.espresso.matcher.ViewMatchers.withId;
20 | import static junit.framework.Assert.assertFalse;
21 | import static testapp.action.OrientationChangeAction.orientationLandscape;
22 | import static testapp.action.OrientationChangeAction.orientationPortrait;
23 |
24 | public class NavigationViewOrientationTest extends BaseNavigationActivityTest {
25 |
26 | @Override
27 | protected Class getActivityClass() {
28 | return NavigationViewOrientationTest.class;
29 | }
30 |
31 | @Test
32 | public void onOrientationLandscape_navigationContinuesRunning() {
33 | if (checkOrientation(Configuration.ORIENTATION_LANDSCAPE)) {
34 | return;
35 | }
36 | validateTestSetup();
37 |
38 | changeOrientation(orientationLandscape());
39 | }
40 |
41 | @Test
42 | public void onOrientationPortrait_navigationContinuesRunning() {
43 | if (checkOrientation(Configuration.ORIENTATION_PORTRAIT)) {
44 | return;
45 | }
46 | validateTestSetup();
47 |
48 | changeOrientation(orientationPortrait());
49 | }
50 |
51 | @Test
52 | public void onOrientationChange_recenterBtnStateIsRestore() {
53 | if (checkOrientation(Configuration.ORIENTATION_LANDSCAPE)) {
54 | return;
55 | }
56 | validateTestSetup();
57 |
58 | onView(withId(R.id.routeOverviewBtn)).perform(click());
59 | changeOrientation(orientationLandscape());
60 | onView(withId(R.id.recenterBtn)).check(matches(isDisplayed()));
61 | }
62 |
63 | @Test
64 | public void onOrientationChange_cameraTrackingIsRestore() {
65 | if (checkOrientation(Configuration.ORIENTATION_LANDSCAPE)) {
66 | return;
67 | }
68 | validateTestSetup();
69 |
70 | onView(withId(R.id.navigationMapView)).perform(swipeUp());
71 | changeOrientation(orientationLandscape());
72 |
73 | NavigationMapboxMap navigationMapboxMap = getNavigationView().retrieveNavigationMapboxMap();
74 | boolean isTrackingEnabled = navigationMapboxMap.retrieveCamera().isTrackingEnabled();
75 | assertFalse(isTrackingEnabled);
76 | }
77 |
78 | @Test
79 | public void onOrientationChange_waynameVisibilityIsRestored() {
80 | if (checkOrientation(Configuration.ORIENTATION_LANDSCAPE)) {
81 | return;
82 | }
83 | validateTestSetup();
84 |
85 | onView(withId(R.id.navigationMapView)).perform(swipeUp());
86 | changeOrientation(orientationLandscape());
87 |
88 | NavigationMapboxMap navigationMapboxMap = getNavigationView().retrieveNavigationMapboxMap();
89 | // boolean isWaynameVisible = navigationMapboxMap.isWaynameVisible();
90 | // assertFalse(isWaynameVisible);
91 | }
92 |
93 | // TODO create test rule for this to conditionally ignore
94 | private boolean checkOrientation(int testedOrientation) {
95 | int orientation = getNavigationView().getContext().getResources().getConfiguration().orientation;
96 | return orientation == testedOrientation;
97 | }
98 |
99 | private void changeOrientation(ViewAction newOrientation) {
100 | onView(isRoot()).perform(newOrientation);
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_navigation_ui.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
34 |
35 |
36 |
51 |
52 |
59 |
60 |
69 |
70 |
71 |
72 |
73 |
87 |
88 |
89 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mapbox/services/android/navigation/testapp/CustomNavigationNotification.java:
--------------------------------------------------------------------------------
1 | package com.mapbox.services.android.navigation.testapp;
2 |
3 | import android.app.Notification;
4 | import android.app.NotificationChannel;
5 | import android.app.NotificationManager;
6 | import android.app.PendingIntent;
7 | import android.content.BroadcastReceiver;
8 | import android.content.Context;
9 | import android.content.Intent;
10 | import android.content.IntentFilter;
11 | import android.graphics.Color;
12 | import android.os.Build;
13 |
14 | import androidx.annotation.RequiresApi;
15 | import androidx.core.app.NotificationCompat;
16 |
17 | import com.mapbox.services.android.navigation.v5.navigation.notification.NavigationNotification;
18 | import com.mapbox.services.android.navigation.v5.routeprogress.RouteProgress;
19 |
20 | import static com.mapbox.services.android.navigation.v5.navigation.NavigationConstants.NAVIGATION_NOTIFICATION_CHANNEL;
21 |
22 | public class CustomNavigationNotification implements NavigationNotification {
23 |
24 | private static final int CUSTOM_NOTIFICATION_ID = 91234821;
25 | private static final String STOP_NAVIGATION_ACTION = "stop_navigation_action";
26 |
27 | private final Notification customNotification;
28 | private final NotificationCompat.Builder customNotificationBuilder;
29 | private final NotificationManager notificationManager;
30 | private BroadcastReceiver stopNavigationReceiver;
31 | private int numberOfUpdates;
32 |
33 | public CustomNavigationNotification(Context applicationContext) {
34 | notificationManager = (NotificationManager) applicationContext.getSystemService(Context.NOTIFICATION_SERVICE);
35 |
36 | customNotificationBuilder = new NotificationCompat.Builder(applicationContext, NAVIGATION_NOTIFICATION_CHANNEL)
37 | .setSmallIcon(R.drawable.ic_navigation)
38 | .setContentTitle("Custom Navigation Notification")
39 | .setContentText("Display your own content here!")
40 | .setContentIntent(createPendingStopIntent(applicationContext));
41 |
42 | customNotification = customNotificationBuilder.build();
43 | }
44 |
45 | @Override
46 | public Notification getNotification() {
47 | return customNotification;
48 | }
49 |
50 | @Override
51 | public int getNotificationId() {
52 | return CUSTOM_NOTIFICATION_ID;
53 | }
54 |
55 | @Override
56 | public void updateNotification(RouteProgress routeProgress) {
57 | // Update the builder with a new number of updates
58 | customNotificationBuilder.setContentText("Number of updates: " + numberOfUpdates++);
59 |
60 | notificationManager.notify(CUSTOM_NOTIFICATION_ID, customNotificationBuilder.build());
61 | }
62 |
63 | @Override
64 | public void onNavigationStopped(Context context) {
65 | context.unregisterReceiver(stopNavigationReceiver);
66 | notificationManager.cancel(CUSTOM_NOTIFICATION_ID);
67 | }
68 |
69 | public void register(BroadcastReceiver stopNavigationReceiver, Context applicationContext) {
70 | this.stopNavigationReceiver = stopNavigationReceiver;
71 | applicationContext.registerReceiver(stopNavigationReceiver, new IntentFilter(STOP_NAVIGATION_ACTION));
72 | }
73 |
74 | private PendingIntent createPendingStopIntent(Context context) {
75 | Intent stopNavigationIntent = new Intent(STOP_NAVIGATION_ACTION);
76 | return PendingIntent.getBroadcast(context, 0, stopNavigationIntent, PendingIntent.FLAG_IMMUTABLE);
77 | }
78 |
79 | @RequiresApi(Build.VERSION_CODES.O)
80 | public void createNotificationChannel(Context context) {
81 | NotificationChannel chan = new NotificationChannel(NAVIGATION_NOTIFICATION_CHANNEL, "CustomNavigationNotification", NotificationManager.IMPORTANCE_NONE);
82 | chan.setLightColor(Color.BLUE);
83 | chan.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
84 | NotificationManager service = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
85 | if (service != null) {
86 | service.createNotificationChannel(chan);
87 | }
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_mock_navigation.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
35 |
36 |
48 |
49 |
61 |
62 |
76 |
77 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/gradle/mvn-push-android.gradle:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 Chris Banes
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | plugins {
17 | id 'maven-publish'
18 | }
19 | apply plugin: 'signing'
20 |
21 | def isReleaseBuild() {
22 | return !VERSION_NAME.contains("SNAPSHOT")
23 | }
24 |
25 | def isLocalBuild() {
26 | if (System.getenv('IS_LOCAL_DEVELOPMENT') != null) {
27 | return System.getenv('IS_LOCAL_DEVELOPMENT').toBoolean()
28 | }
29 | return true
30 | }
31 |
32 | def getReleaseRepositoryUrl() {
33 | return hasProperty('RELEASE_REPOSITORY_URL') ? RELEASE_REPOSITORY_URL
34 | : "https://oss.sonatype.org/service/local/staging/deploy/maven2/"
35 | }
36 |
37 | def getSnapshotRepositoryUrl() {
38 | return hasProperty('SNAPSHOT_REPOSITORY_URL') ? SNAPSHOT_REPOSITORY_URL
39 | : "https://oss.sonatype.org/content/repositories/snapshots/"
40 | }
41 |
42 | def obtainMavenLocalUrl() {
43 | return getRepositories().mavenLocal().getUrl()
44 | }
45 |
46 | def getRepositoryUsername() {
47 | return hasProperty('NEXUS_USERNAME') ? NEXUS_USERNAME : ""
48 | }
49 |
50 | def getRepositoryPassword() {
51 | return hasProperty('NEXUS_PASSWORD') ? NEXUS_PASSWORD : ""
52 | }
53 |
54 | afterEvaluate { project ->
55 | uploadArchives {
56 | repositories {
57 | mavenDeployer {
58 | beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }
59 |
60 | pom.groupId = GROUP
61 | pom.artifactId = POM_ARTIFACT_ID
62 | pom.version = VERSION_NAME
63 |
64 | if (isLocalBuild()) {
65 | repository(url: obtainMavenLocalUrl())
66 | } else {
67 | repository(url: getReleaseRepositoryUrl()) {
68 | authentication(userName: getRepositoryUsername(), password: getRepositoryPassword())
69 | }
70 | snapshotRepository(url: getSnapshotRepositoryUrl()) {
71 | authentication(userName: getRepositoryUsername(), password: getRepositoryPassword())
72 | }
73 | }
74 |
75 | pom.project {
76 | name POM_NAME
77 | packaging POM_PACKAGING
78 | description POM_DESCRIPTION
79 | url POM_URL
80 |
81 | scm {
82 | url POM_SCM_URL
83 | connection POM_SCM_CONNECTION
84 | developerConnection POM_SCM_DEV_CONNECTION
85 | }
86 |
87 | licenses {
88 | license {
89 | name POM_LICENCE_NAME
90 | url POM_LICENCE_URL
91 | distribution POM_LICENCE_DIST
92 | }
93 | }
94 |
95 | developers {
96 | developer {
97 | id POM_DEVELOPER_ID
98 | name POM_DEVELOPER_NAME
99 | }
100 | }
101 | }
102 | }
103 | }
104 | }
105 |
106 | signing {
107 | required { isReleaseBuild() && gradle.taskGraph.hasTask("uploadArchives") }
108 | sign configurations.archives
109 | }
110 |
111 | task androidJavadocs(type: Javadoc) {
112 | failOnError false
113 | source = android.sourceSets.main.java.srcDirs
114 | classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
115 | }
116 |
117 | task androidJavadocsJar(type: Jar, dependsOn: androidJavadocs) {
118 | classifier = 'javadoc'
119 | from androidJavadocs.destinationDir
120 | }
121 |
122 | task androidSourcesJar(type: Jar) {
123 | classifier = 'sources'
124 | from android.sourceSets.main.java.sourceFiles
125 | }
126 |
127 | artifacts {
128 | archives androidSourcesJar
129 | archives androidJavadocsJar
130 | }
131 | }
132 |
133 | // See: https://github.com/chrisbanes/gradle-mvn-push/issues/43#issuecomment-84140513
134 | afterEvaluate { project ->
135 | android.libraryVariants.all { variant ->
136 | tasks.androidJavadocs.doFirst {
137 | classpath += files(variant.javaCompile.classpath.files)
138 | }
139 | }
140 | }
141 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/testapp/utils/OnNavigationReadyIdlingResource.java:
--------------------------------------------------------------------------------
1 | package testapp.utils;
2 |
3 | import android.app.Activity;
4 | import android.content.Context;
5 | import android.content.SharedPreferences;
6 | import android.preference.PreferenceManager;
7 | import androidx.annotation.NonNull;
8 | import androidx.test.espresso.IdlingResource;
9 |
10 | import com.google.gson.GsonBuilder;
11 | import com.mapbox.api.directions.v5.DirectionsAdapterFactory;
12 | import com.mapbox.api.directions.v5.models.DirectionsResponse;
13 | import com.mapbox.api.directions.v5.models.DirectionsRoute;
14 | import com.mapbox.geojson.Point;
15 | import com.mapbox.services.android.navigation.testapp.R;
16 | import com.mapbox.services.android.navigation.ui.v5.NavigationView;
17 | import com.mapbox.services.android.navigation.ui.v5.NavigationViewOptions;
18 | import com.mapbox.services.android.navigation.ui.v5.OnNavigationReadyCallback;
19 | import com.mapbox.services.android.navigation.ui.v5.route.NavigationRoute;
20 |
21 | import java.lang.reflect.Field;
22 |
23 | import retrofit2.Call;
24 | import retrofit2.Callback;
25 | import retrofit2.Response;
26 |
27 | public class OnNavigationReadyIdlingResource implements IdlingResource, Callback,
28 | OnNavigationReadyCallback {
29 |
30 | private static final String NAVIGATION_VIEW = "navigationView";
31 | private static final String TEST_ROUTE_JSON = "test_route_json";
32 | private static final int FIRST_ROUTE = 0;
33 | private boolean isNavigationReady;
34 | private NavigationView navigationView;
35 | private DirectionsRoute testRoute;
36 | private ResourceCallback resourceCallback;
37 | private SharedPreferences preferences;
38 |
39 | public OnNavigationReadyIdlingResource(Activity activity) {
40 | try {
41 | Field field = activity.getClass().getDeclaredField(NAVIGATION_VIEW);
42 | field.setAccessible(true);
43 | navigationView = (NavigationView) field.get(activity);
44 | preferences = PreferenceManager.getDefaultSharedPreferences(activity);
45 | fetchRoute(activity);
46 | } catch (Exception err) {
47 | throw new RuntimeException(err);
48 | }
49 | }
50 |
51 | @Override
52 | public String getName() {
53 | return getClass().getSimpleName();
54 | }
55 |
56 | @Override
57 | public boolean isIdleNow() {
58 | return isNavigationReady;
59 | }
60 |
61 | @Override
62 | public void registerIdleTransitionCallback(ResourceCallback resourceCallback) {
63 | this.resourceCallback = resourceCallback;
64 | }
65 |
66 | public NavigationView getNavigationView() {
67 | return navigationView;
68 | }
69 |
70 | @Override
71 | public void onResponse(@NonNull Call call, @NonNull Response response) {
72 | testRoute = response.body().routes().get(FIRST_ROUTE);
73 | storeRouteForRotation(testRoute);
74 | navigationView.initialize(this);
75 | }
76 |
77 | @Override
78 | public void onFailure(@NonNull Call call, @NonNull Throwable throwable) {
79 | throw new RuntimeException(throwable);
80 | }
81 |
82 | @Override
83 | public void onNavigationReady(boolean isRunning) {
84 | navigationView.startNavigation(buildTestNavigationViewOptions());
85 | transitionToIdle();
86 | }
87 |
88 | private void fetchRoute(Context context) {
89 | Point origin = Point.fromLngLat(-77.033987, 38.900123);
90 | Point destination = Point.fromLngLat(-77.044818, 38.848942);
91 | NavigationRoute.builder(context)
92 | .accessToken(context.getString(R.string.mapbox_access_token))
93 | .origin(origin)
94 | .destination(destination)
95 | .build().getRoute(this);
96 | }
97 |
98 | private void storeRouteForRotation(DirectionsRoute route) {
99 | SharedPreferences.Editor editor = preferences.edit();
100 | String testRouteJson = new GsonBuilder()
101 | .registerTypeAdapterFactory(DirectionsAdapterFactory.create()).create().toJson(route);
102 | editor.putString(TEST_ROUTE_JSON, testRouteJson);
103 | editor.apply();
104 | }
105 |
106 | private NavigationViewOptions buildTestNavigationViewOptions() {
107 | return NavigationViewOptions.builder()
108 | .directionsRoute(com.mapbox.services.android.navigation.v5.models.DirectionsRoute.fromJson(testRoute.toJson()))
109 | .shouldSimulateRoute(true)
110 | .build();
111 | }
112 |
113 | private void transitionToIdle() {
114 | isNavigationReady = true;
115 | if (resourceCallback != null) {
116 | resourceCallback.onTransitionToIdle();
117 | }
118 | }
119 | }
120 |
--------------------------------------------------------------------------------
/circle.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 |
3 | workflows:
4 | version: 2
5 | default:
6 | jobs:
7 | - build
8 | - release
9 | jobs:
10 | build:
11 | working_directory: ~/code
12 | docker:
13 | - image: mbgl/61abee1674:android-ndk-r18
14 | environment:
15 | JVM_OPTS: -Xmx3200m
16 | BUILDTYPE: Debug
17 | IS_LOCAL_DEVELOPMENT: false
18 | steps:
19 | - checkout
20 | - restore_cache:
21 | key: jars-{{ checksum "build.gradle" }}-{{ checksum "app/build.gradle" }}
22 | - run:
23 | name: Download Dependencies
24 | command: ./gradlew androidDependencies
25 | - save_cache:
26 | paths:
27 | - ~/.gradle
28 | key: jars-{{ checksum "build.gradle" }}-{{ checksum "app/build.gradle" }}
29 | - run:
30 | name: Check Java code style
31 | command: make checkstyle
32 | - run:
33 | name: Build release to test ProGuard rules
34 | command: ./gradlew app:assembleRelease
35 | - run:
36 | name: Build Test Application APK
37 | command: |
38 | ./gradlew accessToken
39 | ./gradlew app:assembleDebug
40 | # - run:
41 | # name: Build Instrumentation Test APK
42 | # command: |
43 | # ./gradlew app:assembleAndroidTest
44 | - run:
45 | name: Log in to Google Cloud Platform
46 | shell: /bin/bash -euo pipefail
47 | command: |
48 | echo "${GCLOUD_SERVICE_ACCOUNT_JSON}" > secret.json
49 | gcloud auth activate-service-account --key-file secret.json --project mapbox-navigation-android
50 | rm secret.json
51 | # - run:
52 | # name: Run instrumentation tests on Firebase
53 | # no_output_timeout: 1200
54 | # shell: /bin/bash -euo pipefail
55 | # command: |
56 | # gcloud firebase test android run --type instrumentation \
57 | # --app app/build/outputs/apk/debug/app-debug.apk \
58 | # --test app/build/outputs/apk/androidTest/debug/app-debug-androidTest.apk \
59 | # --device model=hammerhead,version=21,locale=en,orientation=portrait \
60 | # --device model=athene,version=23,locale=fr,orientation=landscape \
61 | # --device model=sailfish,version=26,locale=es,orientation=portrait \
62 | # --device model=walleye,version=28,locale=de,orientation=landscape \
63 | # --timeout 5m
64 | - run:
65 | name: Run robo test on Firebase
66 | no_output_timeout: 1200
67 | shell: /bin/bash -euo pipefail
68 | command: |
69 | gcloud firebase test android run --type robo \
70 | --app app/build/outputs/apk/debug/app-debug.apk \
71 | --device-ids shamu \
72 | --os-version-ids 22 \
73 | --locales en \
74 | --orientations portrait \
75 | --timeout 5m
76 | - run:
77 | name: Update Transifex
78 | command: |
79 | if [ "${CIRCLE_BRANCH}" == "${DEPLOY_BRANCH}" ]; then
80 | pip install transifex-client
81 | echo $'[https://www.transifex.com]\nhostname = https://www.transifex.com\nusername = '"${TRANSIFEX_USER}"$'\npassword = '"${TRANSIFEX_API_TOKEN}"$'\ntoken = '""$'\n' > ~/.transifexrc
82 | tx push -s
83 | else
84 | echo "Skipping push to Transifex"
85 | fi
86 | - store_artifacts:
87 | path: app/build/reports
88 | destination: reports
89 | - store_test_results:
90 | path: app/build/test-results
91 |
92 | # ------------------------------------------------------------------------------
93 | release:
94 | branch:
95 | only:
96 | - master
97 | docker:
98 | - image: mbgl/61abee1674:android-ndk-r18
99 | working_directory: ~/code
100 | environment:
101 | BUILDTYPE: Release
102 | IS_LOCAL_DEVELOPMENT: false
103 | steps:
104 | - checkout
105 | - run:
106 | name: Generate Maven credentials
107 | shell: /bin/bash -euo pipefail
108 | command: |
109 | aws s3 cp s3://mapbox/android/signing-credentials/secring.gpg secring.gpg
110 | echo "NEXUS_USERNAME=$PUBLISH_NEXUS_USERNAME
111 | NEXUS_PASSWORD=$PUBLISH_NEXUS_PASSWORD
112 | signing.keyId=$SIGNING_KEYID
113 | signing.password=$SIGNING_PASSWORD
114 | signing.secretKeyRingFile=../secring.gpg" >> gradle.properties
115 | - run:
116 | name: Build Navigation SDK
117 | command: make build-release
118 | - deploy:
119 | name: Publish Navigation SDK To Maven Central
120 | command: |
121 | if [ "${CIRCLE_BRANCH}" == "master" ]; then
122 | make publish ;
123 | fi
124 | - store_artifacts:
125 | path: app/build/reports
126 | destination: reports
--------------------------------------------------------------------------------
/app/src/main/java/com/mapbox/services/android/navigation/testapp/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.mapbox.services.android.navigation.testapp;
2 |
3 | import android.content.Intent;
4 | import android.os.Bundle;
5 | import android.view.LayoutInflater;
6 | import android.view.View;
7 | import android.view.ViewGroup;
8 | import android.widget.TextView;
9 | import android.widget.Toast;
10 |
11 | import androidx.annotation.NonNull;
12 | import androidx.appcompat.app.AppCompatActivity;
13 | import androidx.recyclerview.widget.LinearLayoutManager;
14 | import androidx.recyclerview.widget.RecyclerView;
15 |
16 | import com.mapbox.mapboxsdk.location.permissions.PermissionsListener;
17 | import com.mapbox.mapboxsdk.location.permissions.PermissionsManager;
18 |
19 | import java.util.ArrayList;
20 | import java.util.List;
21 |
22 | public class MainActivity extends AppCompatActivity implements PermissionsListener {
23 | private RecyclerView recyclerView;
24 | private PermissionsManager permissionsManager;
25 | private ArrayList list = new ArrayList<>();
26 |
27 | @Override
28 | protected void onCreate(Bundle savedInstanceState) {
29 | super.onCreate(savedInstanceState);
30 | setContentView(R.layout.activity_main);
31 |
32 | // RecyclerView
33 | recyclerView = findViewById(R.id.recycler_view);
34 | recyclerView.setHasFixedSize(true);
35 |
36 | // Use a linear layout manager
37 | RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this);
38 | recyclerView.setLayoutManager(layoutManager);
39 |
40 | // Specify an adapter
41 | list.add(new SampleItem(
42 | getString(R.string.title_mock_navigation),
43 | getString(R.string.description_mock_navigation),
44 | MockNavigationActivity.class
45 | ));
46 | list.add(new SampleItem(
47 | getString(R.string.title_navigation_ui),
48 | getString(R.string.description_navigation_ui),
49 | NavigationUIActivity.class
50 | ));
51 | list.add(new SampleItem(
52 | getString(R.string.title_snap_to_route),
53 | getString(R.string.description_snap_to_route),
54 | SnapToRouteNavigationActivity.class
55 | ));
56 | RecyclerView.Adapter adapter = new MainAdapter(list);
57 | recyclerView.setAdapter(adapter);
58 |
59 | // Check for location permission
60 | permissionsManager = new PermissionsManager(this);
61 | if (!PermissionsManager.areLocationPermissionsGranted(this)) {
62 | recyclerView.setEnabled(false);
63 | permissionsManager.requestLocationPermissions(this);
64 | }
65 | }
66 |
67 | @Override
68 | public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
69 | @NonNull int[] grantResults) {
70 | super.onRequestPermissionsResult(requestCode, permissions, grantResults);
71 | permissionsManager.onRequestPermissionsResult(requestCode, permissions, grantResults);
72 | }
73 |
74 | @Override
75 | public void onExplanationNeeded(List permissionsToExplain) {
76 | Toast.makeText(this, "This app needs location permissions in order to show its functionality.",
77 | Toast.LENGTH_LONG).show();
78 | }
79 |
80 | @Override
81 | public void onPermissionResult(boolean granted) {
82 | if (granted) {
83 | recyclerView.setEnabled(true);
84 | } else {
85 | Toast.makeText(this, "You didn't grant location permissions.",
86 | Toast.LENGTH_LONG).show();
87 | }
88 | }
89 |
90 | /*
91 | * Recycler view
92 | */
93 |
94 | private class MainAdapter extends RecyclerView.Adapter {
95 |
96 | private List samples;
97 |
98 | class ViewHolder extends RecyclerView.ViewHolder {
99 |
100 | private TextView nameView;
101 | private TextView descriptionView;
102 |
103 | ViewHolder(View view) {
104 | super(view);
105 | nameView = view.findViewById(R.id.nameView);
106 | descriptionView = view.findViewById(R.id.descriptionView);
107 | }
108 | }
109 |
110 | MainAdapter(List samples) {
111 | this.samples = samples;
112 | }
113 |
114 | @NonNull
115 | @Override
116 | public MainAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
117 | View view = LayoutInflater
118 | .from(parent.getContext())
119 | .inflate(R.layout.item_main_feature, parent, false);
120 |
121 | view.setOnClickListener(clickedView -> {
122 | int position = recyclerView.getChildLayoutPosition(clickedView);
123 | Intent intent = new Intent(clickedView.getContext(), samples.get(position).getActivity());
124 | startActivity(intent);
125 | });
126 |
127 | return new ViewHolder(view);
128 | }
129 |
130 | @Override
131 | public void onBindViewHolder(@NonNull MainAdapter.ViewHolder holder, int position) {
132 | holder.nameView.setText(samples.get(position).getName());
133 | holder.descriptionView.setText(samples.get(position).getDescription());
134 | }
135 |
136 | @Override
137 | public int getItemCount() {
138 | return samples.size();
139 | }
140 | }
141 | }
142 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | #
4 | # Copyright 2015 the original author or authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 |
19 | ##############################################################################
20 | ##
21 | ## Gradle start up script for UN*X
22 | ##
23 | ##############################################################################
24 |
25 | # Attempt to set APP_HOME
26 | # Resolve links: $0 may be a link
27 | PRG="$0"
28 | # Need this for relative symlinks.
29 | while [ -h "$PRG" ] ; do
30 | ls=`ls -ld "$PRG"`
31 | link=`expr "$ls" : '.*-> \(.*\)$'`
32 | if expr "$link" : '/.*' > /dev/null; then
33 | PRG="$link"
34 | else
35 | PRG=`dirname "$PRG"`"/$link"
36 | fi
37 | done
38 | SAVED="`pwd`"
39 | cd "`dirname \"$PRG\"`/" >/dev/null
40 | APP_HOME="`pwd -P`"
41 | cd "$SAVED" >/dev/null
42 |
43 | APP_NAME="Gradle"
44 | APP_BASE_NAME=`basename "$0"`
45 |
46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
48 |
49 | # Use the maximum available, or set MAX_FD != -1 to use that value.
50 | MAX_FD="maximum"
51 |
52 | warn () {
53 | echo "$*"
54 | }
55 |
56 | die () {
57 | echo
58 | echo "$*"
59 | echo
60 | exit 1
61 | }
62 |
63 | # OS specific support (must be 'true' or 'false').
64 | cygwin=false
65 | msys=false
66 | darwin=false
67 | nonstop=false
68 | case "`uname`" in
69 | CYGWIN* )
70 | cygwin=true
71 | ;;
72 | Darwin* )
73 | darwin=true
74 | ;;
75 | MINGW* )
76 | msys=true
77 | ;;
78 | NONSTOP* )
79 | nonstop=true
80 | ;;
81 | esac
82 |
83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
84 |
85 |
86 | # Determine the Java command to use to start the JVM.
87 | if [ -n "$JAVA_HOME" ] ; then
88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
89 | # IBM's JDK on AIX uses strange locations for the executables
90 | JAVACMD="$JAVA_HOME/jre/sh/java"
91 | else
92 | JAVACMD="$JAVA_HOME/bin/java"
93 | fi
94 | if [ ! -x "$JAVACMD" ] ; then
95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
96 |
97 | Please set the JAVA_HOME variable in your environment to match the
98 | location of your Java installation."
99 | fi
100 | else
101 | JAVACMD="java"
102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
103 |
104 | Please set the JAVA_HOME variable in your environment to match the
105 | location of your Java installation."
106 | fi
107 |
108 | # Increase the maximum file descriptors if we can.
109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
110 | MAX_FD_LIMIT=`ulimit -H -n`
111 | if [ $? -eq 0 ] ; then
112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
113 | MAX_FD="$MAX_FD_LIMIT"
114 | fi
115 | ulimit -n $MAX_FD
116 | if [ $? -ne 0 ] ; then
117 | warn "Could not set maximum file descriptor limit: $MAX_FD"
118 | fi
119 | else
120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
121 | fi
122 | fi
123 |
124 | # For Darwin, add options to specify how the application appears in the dock
125 | if $darwin; then
126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
127 | fi
128 |
129 | # For Cygwin or MSYS, switch paths to Windows format before running java
130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
133 |
134 | JAVACMD=`cygpath --unix "$JAVACMD"`
135 |
136 | # We build the pattern for arguments to be converted via cygpath
137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
138 | SEP=""
139 | for dir in $ROOTDIRSRAW ; do
140 | ROOTDIRS="$ROOTDIRS$SEP$dir"
141 | SEP="|"
142 | done
143 | OURCYGPATTERN="(^($ROOTDIRS))"
144 | # Add a user-defined pattern to the cygpath arguments
145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
147 | fi
148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
149 | i=0
150 | for arg in "$@" ; do
151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
153 |
154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
156 | else
157 | eval `echo args$i`="\"$arg\""
158 | fi
159 | i=`expr $i + 1`
160 | done
161 | case $i in
162 | 0) set -- ;;
163 | 1) set -- "$args0" ;;
164 | 2) set -- "$args0" "$args1" ;;
165 | 3) set -- "$args0" "$args1" "$args2" ;;
166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
172 | esac
173 | fi
174 |
175 | # Escape application args
176 | save () {
177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
178 | echo " "
179 | }
180 | APP_ARGS=`save "$@"`
181 |
182 | # Collect all arguments for the java command, following the shell quoting and substitution rules
183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
184 |
185 | exec "$JAVACMD" "$@"
186 |
--------------------------------------------------------------------------------
/gradle/dependencies.gradle:
--------------------------------------------------------------------------------
1 | ext {
2 |
3 | androidVersions = [
4 | minSdkVersion : 21,
5 | targetSdkVersion : 33,
6 | compileSdkVersion: 33,
7 | buildToolsVersion: '33.0.1',
8 | kotlinVersion : '1.7.20'
9 | ]
10 |
11 | version = [
12 | mapLibreVersion : '10.0.2',
13 | mapLibreService : '5.9.0',
14 | mapLibreTurf : '5.9.0',
15 | mapLibreAnnotations : '1.0.0',
16 | annotation : '1.7.0',
17 | autoValue : '1.10.4',
18 | autoValueGson : '1.3.1',
19 | junit : '4.13.2',
20 | androidxCoreVersion : '1.9.0',
21 | appcompatVersion : '1.6.1',
22 | cardViewVersion : '1.0.0',
23 | androidxAnnotationVersion : '1.6.0',
24 | constraintLayoutVersion : '2.1.4',
25 | materialVersion : '1.7.0',
26 | recyclerViewVersion : '1.3.1',
27 | mockito : '4.9.0',
28 | hamcrest : '2.0.0.0',
29 | errorprone : '2.22.0',
30 | butterknife : '10.2.3',
31 | leakCanaryVersion : '2.12',
32 | timber : '5.0.1',
33 | testRunnerVersion : '1.0.1',
34 | espressoVersion : '3.5.1',
35 | spoonRunner : '1.6.2',
36 | commonsIO : '2.14.0',
37 | robolectric : '4.10.3',
38 | lifecycle : '1.1.1',
39 | lifecycleVersion : '2.2.0',
40 | picasso : '2.71828',
41 | gmsLocation : '21.0.1',
42 | testRulesVersion : '1.5.0',
43 | jsonVersion : '20230618'
44 | ]
45 |
46 | pluginVersion = [
47 | checkstyle : '8.2',
48 | pmd : '5.8.1',
49 | errorprone : '2.0.2',
50 | coveralls : '2.8.1',
51 | spotbugs : '1.3',
52 | gradle : '7.4.2',
53 | kotlinGradle : '1.9.10',
54 | dependencyGraph : '0.3.0',
55 | dependencyUpdates: '0.44.0',
56 | ]
57 |
58 | dependenciesList = [
59 | // maplibre
60 | mapLibre : "org.maplibre.gl:android-sdk:${version.mapLibreVersion}",
61 | mapLibreServices : "org.maplibre.gl:android-sdk-services:${version.mapLibreService}",
62 | mapLibreTurf : "org.maplibre.gl:android-sdk-turf:${version.mapLibreTurf}",
63 | mapLibreAnnotations : "org.maplibre.gl:android-plugin-annotation-v9:${version.mapLibreAnnotations}",
64 |
65 | // AutoValue
66 | autoValue : "com.google.auto.value:auto-value:${version.autoValue}",
67 | autoValueAnnotations : "com.google.auto.value:auto-value-annotations:${version.autoValue}",
68 | autoValueGson : "com.ryanharter.auto.value:auto-value-gson:${version.autoValueGson}",
69 |
70 | // butterknife
71 | butterknife : "com.jakewharton:butterknife:${version.butterknife}",
72 | butterknifeProcessor : "com.jakewharton:butterknife-compiler:${version.butterknife}",
73 |
74 | // support
75 | androidxAppcompat : "androidx.appcompat:appcompat:${version.appcompatVersion}",
76 | androidxCore : "androidx.core:core-ktx:${version.androidxCoreVersion}",
77 | androidxAnnotation : "androidx.annotation:annotation:1.6.0",
78 | materialDesign : "com.google.android.material:material:${version.materialVersion}",
79 | androidxRecyclerView : "androidx.recyclerview:recyclerview:${version.recyclerViewVersion}",
80 | androidxCardView : "androidx.cardview:cardview:${version.cardViewVersion}",
81 | androidxConstraintLayout: "androidx.constraintlayout:constraintlayout:${version.constraintLayoutVersion}",
82 | kotlinstdlib : "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${androidVersions.kotlinVersion}",
83 | supportAnnotation : "androidx.annotation:annotation:${version.annotation}",
84 |
85 | // architecture
86 | lifecycleExtensions : "androidx.lifecycle:lifecycle-extensions:${version.lifecycleVersion}",
87 | lifecycleCompiler : "androidx.lifecycle:lifecycle-compiler:${version.lifecycleVersion}",
88 |
89 | // square crew
90 | timber : "com.jakewharton.timber:timber:${version.timber}",
91 | picasso : "com.squareup.picasso:picasso:${version.picasso}",
92 | leakCanaryDebug : "com.squareup.leakcanary:leakcanary-android:${version.leakCanaryVersion}",
93 | leakCanaryRelease : "com.squareup.leakcanary:leakcanary-android-no-op:${version.leakCanaryVersion}",
94 | leakCanaryTest : "com.squareup.leakcanary:leakcanary-android-no-op:${version.leakCanaryVersion}",
95 |
96 | // instrumentation test
97 | testSpoonRunner : "com.squareup.spoon:spoon-client:${version.spoonRunner}",
98 | testRunner : "com.android.support.test:runner:${version.testRunnerVersion}",
99 | testRules : "androidx.test:rules:${version.testRulesVersion}",
100 | testEspressoCore : "androidx.test.espresso:espresso-core:${version.espressoVersion}",
101 | testEspressoIntents : "com.android.support.test.espresso:espresso-intents:${version.espressoVersion}",
102 |
103 | // unit test
104 | junit : "junit:junit:${version.junit}",
105 | mockito : "org.mockito:mockito-core:${version.mockito}",
106 | hamcrest : "org.hamcrest:hamcrest-junit:${version.hamcrest}",
107 | commonsIO : "commons-io:commons-io:${version.commonsIO}",
108 | robolectric : "org.robolectric:robolectric:${version.robolectric}",
109 | json : "org.json:json:${version.jsonVersion}",
110 |
111 | // play services
112 | gmsLocation : "com.google.android.gms:play-services-location:${version.gmsLocation}",
113 | errorprone : "com.google.errorprone:error_prone_core:${version.errorprone}"
114 | ]
115 |
116 | pluginDependencies = [
117 | gradle : "com.android.tools.build:gradle:${pluginVersion.gradle}",
118 | checkstyle : "com.puppycrawl.tools:checkstyle:${pluginVersion.checkstyle}",
119 | spotbugs : "gradle.plugin.com.github.spotbugs:gradlePlugin:${pluginVersion.spotbugs}",
120 | coveralls : "org.kt3k.gradle.plugin:coveralls-gradle-plugin:${pluginVersion.coveralls}",
121 | errorprone : "net.ltgt.gradle:gradle-errorprone-plugin:${pluginVersion.errorprone}",
122 | dependencyGraph : "com.vanniktech:gradle-dependency-graph-generator-plugin:${pluginVersion.dependencyGraph}",
123 | dependencyUpdates : "com.github.ben-manes:gradle-versions-plugin:${pluginVersion.dependencyUpdates}",
124 | kotlinGradle : "org.jetbrains.kotlin:kotlin-gradle-plugin:${androidVersions.kotlinVersion}",
125 | ]
126 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/mapbox/services/android/navigation/testapp/SnapToRouteNavigationActivity.kt:
--------------------------------------------------------------------------------
1 | package com.mapbox.services.android.navigation.testapp
2 |
3 | import android.location.Location
4 | import android.os.Bundle
5 | import androidx.appcompat.app.AppCompatActivity
6 | import com.mapbox.api.directions.v5.models.DirectionsResponse
7 | import com.mapbox.geojson.Point
8 | import com.mapbox.mapboxsdk.location.LocationComponent
9 | import com.mapbox.mapboxsdk.location.LocationComponentActivationOptions
10 | import com.mapbox.mapboxsdk.location.OnLocationCameraTransitionListener
11 | import com.mapbox.mapboxsdk.location.modes.CameraMode
12 | import com.mapbox.mapboxsdk.location.modes.RenderMode
13 | import com.mapbox.mapboxsdk.maps.MapboxMap
14 | import com.mapbox.mapboxsdk.maps.OnMapReadyCallback
15 | import com.mapbox.mapboxsdk.maps.Style
16 | import com.mapbox.services.android.navigation.testapp.databinding.ActivitySnapToRouteNavigationBinding
17 | import com.mapbox.services.android.navigation.ui.v5.route.NavigationRoute
18 | import com.mapbox.services.android.navigation.v5.location.replay.ReplayRouteLocationEngine
19 | import com.mapbox.services.android.navigation.v5.milestone.*
20 | import com.mapbox.services.android.navigation.v5.models.DirectionsRoute
21 | import com.mapbox.services.android.navigation.v5.navigation.*
22 | import com.mapbox.services.android.navigation.v5.routeprogress.ProgressChangeListener
23 | import com.mapbox.services.android.navigation.v5.routeprogress.RouteProgress
24 | import com.mapbox.services.android.navigation.v5.snap.SnapToRoute
25 | import okhttp3.Request
26 | import retrofit2.Call
27 | import retrofit2.Callback
28 | import retrofit2.Response
29 | import timber.log.Timber
30 |
31 | /**
32 | * This activity shows you simulated navigation with enabled route snapping.
33 | *
34 | * You need to do the following steps to enable route snapping:
35 | * 1. Disable default location engine by set [LocationComponentActivationOptions.useDefaultLocationEngine] to false.
36 | * 2. Get snapped location from [ProgressChangeListener] callback and set it to [LocationComponent] by [LocationComponent.forceLocationUpdate] method.
37 | * 3. Activate route snapping by set [MapboxNavigationOptions.snapToRoute] to true.
38 | *
39 | * By default [SnapToRoute] is used. If you want to use your own snapping logic, you can set with [MapboxNavigation.setSnapEngine] for your own implementation.
40 | */
41 | class SnapToRouteNavigationActivity : AppCompatActivity(), OnMapReadyCallback,
42 | ProgressChangeListener {
43 |
44 | private lateinit var binding: ActivitySnapToRouteNavigationBinding
45 | private lateinit var mapboxMap: MapboxMap
46 | private var locationEngine: ReplayRouteLocationEngine = ReplayRouteLocationEngine()
47 | private lateinit var navigation: MapboxNavigation
48 | private var route: DirectionsRoute? = null
49 | private var navigationMapRoute: NavigationMapRoute? = null
50 |
51 | override fun onCreate(savedInstanceState: Bundle?) {
52 | super.onCreate(savedInstanceState)
53 |
54 | binding = ActivitySnapToRouteNavigationBinding.inflate(layoutInflater)
55 | setContentView(binding.root)
56 |
57 | navigation = MapboxNavigation(
58 | this, MapboxNavigationOptions.builder()
59 | .snapToRoute(true)
60 | .build()
61 | ).apply {
62 | snapEngine
63 | addProgressChangeListener(this@SnapToRouteNavigationActivity)
64 | }
65 |
66 | binding.mapView.apply {
67 | onCreate(savedInstanceState)
68 | getMapAsync(this@SnapToRouteNavigationActivity)
69 | }
70 |
71 | binding.btnFollow.setOnClickListener {
72 | followLocation()
73 | }
74 | }
75 |
76 | private var locationComponent: LocationComponent? = null
77 |
78 | override fun onMapReady(mapboxMap: MapboxMap) {
79 | this.mapboxMap = mapboxMap
80 | mapboxMap.setStyle(Style.Builder().fromUri(getString(R.string.map_style_light))) { style ->
81 | enableLocationComponent(style)
82 | }
83 |
84 | navigationMapRoute = NavigationMapRoute(navigation, binding.mapView, mapboxMap)
85 | calculateRouteAndStartNavigation()
86 | }
87 |
88 | @SuppressWarnings("MissingPermission")
89 | private fun enableLocationComponent(style: Style) {
90 | locationComponent = mapboxMap.locationComponent
91 | mapboxMap.locationComponent.activateLocationComponent(
92 | LocationComponentActivationOptions.builder(
93 | this,
94 | style,
95 | )
96 | .useDefaultLocationEngine(false)
97 | .build()
98 | )
99 |
100 | followLocation()
101 |
102 | mapboxMap.locationComponent.isLocationComponentEnabled = true
103 | }
104 |
105 | private fun followLocation() {
106 | if (!mapboxMap.locationComponent.isLocationComponentActivated) {
107 | return
108 | }
109 |
110 | mapboxMap.locationComponent.renderMode = RenderMode.GPS
111 | mapboxMap.locationComponent.setCameraMode(
112 | CameraMode.TRACKING_GPS,
113 | object :
114 | OnLocationCameraTransitionListener {
115 | override fun onLocationCameraTransitionFinished(cameraMode: Int) {
116 | mapboxMap.locationComponent.zoomWhileTracking(17.0)
117 | mapboxMap.locationComponent.tiltWhileTracking(60.0)
118 | }
119 |
120 | override fun onLocationCameraTransitionCanceled(cameraMode: Int) {}
121 | }
122 | )
123 | }
124 |
125 | private fun calculateRouteAndStartNavigation() {
126 | val navigationRouteBuilder = NavigationRoute.builder(this).apply {
127 | this.accessToken(getString(R.string.mapbox_access_token))
128 | this.origin(Point.fromLngLat(9.7536318, 52.3717979))
129 | this.addWaypoint(Point.fromLngLat(9.741052, 52.360496))
130 | this.destination(Point.fromLngLat(9.756259, 52.342620))
131 | this.voiceUnits(com.mapbox.services.android.navigation.v5.models.DirectionsCriteria.METRIC)
132 | this.alternatives(true)
133 | this.baseUrl(getString(R.string.base_url))
134 | }
135 |
136 | navigationRouteBuilder.build().getRoute(object : Callback {
137 | override fun onResponse(
138 | call: Call,
139 | response: Response,
140 | ) {
141 | Timber.d("Url: %s", (call.request() as Request).url.toString())
142 | response.body()?.let { responseBody ->
143 | if (responseBody.routes().isNotEmpty()) {
144 | val maplibreResponse = com.mapbox.services.android.navigation.v5.models.DirectionsResponse.fromJson(responseBody.toJson());
145 | val directionsRoute = maplibreResponse.routes().first()
146 | this@SnapToRouteNavigationActivity.route = directionsRoute
147 | navigationMapRoute?.addRoutes(maplibreResponse.routes())
148 |
149 | startNavigation()
150 | }
151 | }
152 | }
153 |
154 | override fun onFailure(call: Call, throwable: Throwable) {
155 | Timber.e(throwable, "onFailure: navigation.getRoute()")
156 | }
157 | })
158 | }
159 |
160 | fun startNavigation() {
161 | route?.let { route ->
162 | locationEngine.also { locationEngine ->
163 | locationEngine.assign(route)
164 | navigation.locationEngine = locationEngine
165 | navigation.startNavigation(route)
166 | }
167 | }
168 | }
169 |
170 | override fun onProgressChange(location: Location, routeProgress: RouteProgress) {
171 | // Update own location with the snapped location
172 | locationComponent?.forceLocationUpdate(location)
173 | }
174 |
175 | override fun onResume() {
176 | super.onResume()
177 | binding.mapView.onResume()
178 | }
179 |
180 | override fun onPause() {
181 | super.onPause()
182 | binding.mapView.onPause()
183 | }
184 |
185 | override fun onStart() {
186 | super.onStart()
187 | binding.mapView.onStart()
188 | }
189 |
190 | override fun onStop() {
191 | super.onStop()
192 | binding.mapView.onStop()
193 | }
194 |
195 | override fun onLowMemory() {
196 | super.onLowMemory()
197 | binding.mapView.onLowMemory()
198 | }
199 |
200 | override fun onDestroy() {
201 | super.onDestroy()
202 | navigation.onDestroy()
203 | binding.mapView.onDestroy()
204 | }
205 |
206 | }
207 |
--------------------------------------------------------------------------------
/scripts/release.py:
--------------------------------------------------------------------------------
1 | '''
2 | Utility to schedule Navigation SDK builds on CircleCI.
3 |
4 | Examples:
5 |
6 | - Publish a snapshot from master (release.py uses the current branch)
7 |
8 | $ git branch
9 | * master
10 | 1234-fix-crash
11 | $ python release.py --stage snapshot
12 |
13 | - Publish a snapshot from a feature branch (same as before, just switch branchs with git):
14 |
15 | $ git branch
16 | master
17 | * 1234-fix-crash
18 | $ python release.py --stage snapshot
19 |
20 | - Publish a beta from a pre-release branch:
21 |
22 | $ git branch
23 | master
24 | * release-android-420-beta1
25 | $ python release.py --stage beta --version 2.0.0-beta.1
26 |
27 | - Publish a beta from a release branch:
28 |
29 | $ git branch
30 | master
31 | * release-android-420
32 | $ python release.py --stage final --version 2.0.0
33 |
34 | TODO:
35 |
36 | - Add a flag to wait until the release has been built (CircleCI) and published (Maven).
37 |
38 | '''
39 |
40 | import click
41 | import json
42 | import os
43 | import requests
44 | import subprocess
45 |
46 | # Three stages, from less stable to more stable
47 | ALLOWED_STAGES = ['snapshot', 'beta', 'final']
48 |
49 | # Get the version from GRADLE_PROPERTIES_PATH below
50 | CURRENT_VERSION_TAG = 'current'
51 |
52 | # You can add your API token onhttps://circleci.com/account/api
53 | CIRCLECI_API_TOKEN_ENV_VAR = 'CIRCLECI_API_TOKEN'
54 |
55 | # In the future we might want to consider alpha, or rc.
56 | ALLOWED_PRE_RELEASE = ['beta']
57 |
58 | # We get the default version from here
59 | GRADLE_PROPERTIES_PATH = '../gradle.properties'
60 | GRADLE_TOKEN = 'VERSION_NAME='
61 |
62 | # Circle CI
63 | # Triggers a new build, returns a summary of the build
64 | URL_CIRCLECI = 'https://circleci.com/api/v1.1/project/github/mapbox/mapbox-gl-native/tree/' # + :branch
65 |
66 | # We support three parameters: stage, branch, and version
67 | @click.command()
68 | @click.option('--stage', default=ALLOWED_STAGES[0], type=click.Choice(ALLOWED_STAGES), prompt='Set stage', help='The release stage.')
69 | @click.option('--version', default=CURRENT_VERSION_TAG, prompt='Set version', help='The version you want to publish. E.g: 2.0.0-SNAPSHOT, 2.0.0-beta.1, or 2.0.0. If you set the version to "%s", the script will default to the current SNAPSHOT version.' % CURRENT_VERSION_TAG)
70 | def release(stage, version):
71 | # Validate params
72 | final_stage = validate_stage(stage=stage)
73 | final_branch = validate_branch(stage=final_stage)
74 | final_version = validate_version(stage=final_stage, branch=final_branch, version=version)
75 |
76 | # Get user confirmation
77 | click.echo('\n===== Build information =====')
78 | click.echo('- Stage: %s' % final_stage)
79 | click.echo('- Branch: %s' % final_branch)
80 | click.echo('- Version: %s' % final_version)
81 | click.confirm('\nDoes it look right?', abort=True)
82 |
83 | # Proceed
84 | if (final_stage == 'snapshot'):
85 | publish_snapshot(branch=final_branch, version=final_version)
86 | elif (final_stage == 'beta'):
87 | publish_beta(branch=final_branch, version=final_version)
88 | elif (final_stage == 'final'):
89 | publish_final(branch=final_branch, version=final_version)
90 |
91 | def validate_stage(stage):
92 | if stage not in ALLOWED_STAGES:
93 | abort_with_message('Invalid stage: %s' % stage)
94 | return stage
95 |
96 | def validate_branch(stage):
97 | branch = git_get_current_branch()
98 | if not branch:
99 | abort_with_message('The current folder is not a git repository.')
100 | if branch == 'master' and stage != 'snapshot':
101 | abort_with_message('You need to swtich to a release branch for a beta or a final release.')
102 | return branch
103 |
104 | def validate_version(stage, branch, version):
105 | if stage == 'snapshot' and branch == 'master' and version != CURRENT_VERSION_TAG:
106 | abort_with_message('You cannot specify a custom version if you are building a snapshot from master.')
107 |
108 | if not version or version == CURRENT_VERSION_TAG:
109 | version = get_current_version(file_path=GRADLE_PROPERTIES_PATH, file_var=GRADLE_TOKEN)
110 |
111 | if stage == 'snapshot':
112 | if not 'SNAPSHOT' in version:
113 | abort_with_message('Version should contain the word SNAPSHOT: %s' % version)
114 | elif stage == 'beta':
115 | if not ALLOWED_PRE_RELEASE[0] in version:
116 | abort_with_message('Version should contain the word %s: %s' % (ALLOWED_PRE_RELEASE[0], version))
117 | elif stage == 'final':
118 | if not version or 'SNAPSHOT' in version or ALLOWED_PRE_RELEASE[0] in version:
119 | abort_with_message('Version cannot be empty, or contain the words SNAPSHOT or %s: %s' % (ALLOWED_PRE_RELEASE[0], version))
120 |
121 | return version
122 |
123 | def publish_snapshot(branch, version):
124 | click.echo('Publishing snapshot for branch: %s (version: %s).' % (branch, version))
125 | if branch != 'master':
126 | dirty_gradle = update_current_version(file_path=GRADLE_PROPERTIES_PATH, file_var=GRADLE_TOKEN, version=version)
127 | if dirty_gradle:
128 | git_add(path=GRADLE_PROPERTIES_PATH)
129 | git_commit_and_push(branch=branch, version=version)
130 | do_circleci_request(branch=branch)
131 |
132 | def publish_beta(branch, version):
133 | click.echo('Publishing beta from branch: %s (version: %s).' % (branch, version))
134 | dirty_gradle = update_current_version(file_path=GRADLE_PROPERTIES_PATH, file_var=GRADLE_TOKEN, version=version)
135 | if dirty_gradle:
136 | git_add(path=GRADLE_PROPERTIES_PATH)
137 | git_commit_and_push(branch=branch, version=version)
138 | do_circleci_request(branch=branch)
139 |
140 | def publish_final(branch, version):
141 | click.echo('Publishing final release from branch: %s (version: %s).' % (branch, version))
142 | dirty_gradle = update_current_version(file_path=GRADLE_PROPERTIES_PATH, file_var=GRADLE_TOKEN, version=version)
143 | if dirty_gradle:
144 | git_add(path=GRADLE_PROPERTIES_PATH)
145 | git_commit_and_push(branch=branch, version=version)
146 | do_circleci_request(branch=branch)
147 |
148 | #
149 | # Utils
150 | #
151 |
152 | def abort_with_message(message):
153 | click.echo(message)
154 | click.get_current_context().abort()
155 |
156 | def execute_call(command):
157 | click.echo('Executing: %s' % command)
158 | result = subprocess.call(command, shell=True)
159 | if result != 0:
160 | abort_with_message('Command failed: %s' % command)
161 |
162 | #
163 | # CircleCI
164 | #
165 |
166 | def get_circleci_api_token():
167 | circleci_api_token = os.environ.get(CIRCLECI_API_TOKEN_ENV_VAR)
168 | if not circleci_api_token:
169 | abort_with_message('You need to set the CIRCLECI_API_TOKEN environment variable.')
170 | click.echo('Found CircleCI API token.')
171 | return circleci_api_token
172 |
173 | def do_circleci_request(branch):
174 | url = URL_CIRCLECI + branch
175 | params = {'circle-token': get_circleci_api_token()}
176 | click.echo('CircleCI request to %s (params: %s)' % (url, json.dumps(params)))
177 | click.confirm('\nDo you want to start a build?', abort=True)
178 |
179 | r = requests.post(url, params=params)
180 | click.echo('- CircleCI response code: %s' % r.status_code)
181 |
182 | #
183 | # Git
184 | #
185 |
186 | def git_get_current_branch():
187 | return subprocess.check_output('git symbolic-ref --short HEAD'.split(' ')).strip()
188 |
189 | def git_add(path):
190 | execute_call(command='git add %s' % path)
191 |
192 | def git_commit_and_push(branch, version):
193 | message = '[android] [auto] Update properties to version %s in preparation for build.' % version
194 | commands = [
195 | 'git commit -m "%s"' % message,
196 | 'git push -u origin %s' % branch]
197 | for command in commands:
198 | execute_call(command=command)
199 |
200 | #
201 | # Read and update properties files
202 | #
203 |
204 | def get_current_version(file_path, file_var):
205 | click.echo('Getting current version from %s.' % file_path)
206 | with open(file_path, 'r') as f:
207 | for line in f:
208 | if line.startswith(file_var):
209 | version_name = line[len(file_var):].strip()
210 | click.echo('Current version is %s.' % version_name)
211 | return version_name
212 | return None
213 |
214 | def update_current_version(file_path, file_var, version):
215 | dirty = False
216 | click.echo('Updating file to version %s: %s.' % (version, file_path))
217 | with open(file_path, 'r') as f:
218 | file_lines = f.readlines()
219 | for line_number in range(len(file_lines)):
220 | if file_lines[line_number].startswith(file_var):
221 | content_old = file_lines[line_number]
222 | content_new = '%s%s\n' % (file_var, version)
223 | if (content_old != content_new):
224 | click.echo('%s -> %s' % (content_old.strip(), content_new.strip()))
225 | file_lines[line_number] = content_new
226 | dirty = True
227 | if dirty:
228 | with open(file_path, 'w') as f:
229 | f.writelines(file_lines)
230 | else:
231 | click.echo('File already has the right version.')
232 | return dirty
233 |
234 | if __name__ == '__main__':
235 | release()
236 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mapbox/services/android/navigation/testapp/NavigationUIActivity.kt:
--------------------------------------------------------------------------------
1 | package com.mapbox.services.android.navigation.testapp
2 |
3 | import android.annotation.SuppressLint
4 | import android.os.Bundle
5 | import android.view.View
6 | import android.widget.Toast
7 | import androidx.appcompat.app.AppCompatActivity
8 | import com.google.android.material.snackbar.Snackbar
9 | import com.mapbox.api.directions.v5.DirectionsCriteria
10 | import com.mapbox.api.directions.v5.models.DirectionsResponse
11 | import com.mapbox.geojson.Point
12 | import com.mapbox.mapboxsdk.annotations.MarkerOptions
13 | import com.mapbox.mapboxsdk.camera.CameraPosition
14 | import com.mapbox.mapboxsdk.geometry.LatLng
15 | import com.mapbox.mapboxsdk.location.LocationComponent
16 | import com.mapbox.mapboxsdk.location.LocationComponentActivationOptions
17 | import com.mapbox.mapboxsdk.location.modes.CameraMode
18 | import com.mapbox.mapboxsdk.location.modes.RenderMode
19 | import com.mapbox.mapboxsdk.maps.MapboxMap
20 | import com.mapbox.mapboxsdk.maps.OnMapReadyCallback
21 | import com.mapbox.mapboxsdk.maps.Style
22 | import com.mapbox.services.android.navigation.testapp.databinding.ActivityNavigationUiBinding
23 | import com.mapbox.services.android.navigation.ui.v5.NavigationLauncher
24 | import com.mapbox.services.android.navigation.ui.v5.NavigationLauncherOptions
25 | import com.mapbox.services.android.navigation.ui.v5.route.NavigationRoute
26 | import com.mapbox.services.android.navigation.v5.milestone.*
27 | import com.mapbox.services.android.navigation.v5.models.DirectionsRoute
28 | import com.mapbox.services.android.navigation.v5.navigation.*
29 | import com.mapbox.turf.TurfConstants
30 | import com.mapbox.turf.TurfMeasurement
31 | import okhttp3.Request
32 | import retrofit2.Call
33 | import retrofit2.Callback
34 | import retrofit2.Response
35 | import timber.log.Timber
36 |
37 | class NavigationUIActivity :
38 | AppCompatActivity(),
39 | OnMapReadyCallback,
40 | MapboxMap.OnMapClickListener {
41 | private lateinit var mapboxMap: MapboxMap
42 |
43 | // Navigation related variables
44 | private var route: DirectionsRoute? = null
45 | private var navigationMapRoute: NavigationMapRoute? = null
46 | private var destination: Point? = null
47 | private var waypoint: Point? = null
48 | private var locationComponent: LocationComponent? = null
49 |
50 | private lateinit var binding: ActivityNavigationUiBinding
51 |
52 | private var simulateRoute = false
53 |
54 | @SuppressLint("MissingPermission")
55 | override fun onCreate(savedInstanceState: Bundle?) {
56 | super.onCreate(savedInstanceState)
57 |
58 | if (BuildConfig.DEBUG) {
59 | Timber.plant(Timber.DebugTree())
60 | }
61 |
62 | binding = ActivityNavigationUiBinding.inflate(layoutInflater)
63 | setContentView(binding.root)
64 | binding.mapView.apply {
65 | onCreate(savedInstanceState)
66 | getMapAsync(this@NavigationUIActivity)
67 | }
68 |
69 | binding.startRouteButton.setOnClickListener {
70 | route?.let { route ->
71 | val userLocation = mapboxMap.locationComponent.lastKnownLocation ?: return@let
72 |
73 | val options = NavigationLauncherOptions.builder()
74 | .directionsRoute(route)
75 | .shouldSimulateRoute(simulateRoute)
76 | .initialMapCameraPosition(CameraPosition.Builder().target(LatLng(userLocation.latitude, userLocation.longitude)).build())
77 | .lightThemeResId(R.style.TestNavigationViewLight)
78 | .darkThemeResId(R.style.TestNavigationViewDark)
79 | .build()
80 | NavigationLauncher.startNavigation(this@NavigationUIActivity, options)
81 | }
82 | }
83 |
84 | binding.simulateRouteSwitch.setOnCheckedChangeListener { _, checked ->
85 | simulateRoute = checked
86 | }
87 |
88 |
89 | binding.clearPoints.setOnClickListener {
90 | if (::mapboxMap.isInitialized) {
91 | mapboxMap.markers.forEach {
92 | mapboxMap.removeMarker(it)
93 | }
94 | }
95 | destination = null
96 | waypoint = null
97 | it.visibility = View.GONE
98 | binding.startRouteLayout.visibility = View.GONE
99 |
100 | navigationMapRoute?.removeRoute()
101 | }
102 | }
103 |
104 | override fun onMapReady(mapboxMap: MapboxMap) {
105 | this.mapboxMap = mapboxMap
106 | mapboxMap.setStyle(Style.Builder().fromUri(getString(R.string.map_style_light))) { style ->
107 | enableLocationComponent(style)
108 | }
109 |
110 | navigationMapRoute = NavigationMapRoute(
111 | binding.mapView,
112 | mapboxMap
113 | )
114 |
115 | mapboxMap.addOnMapClickListener(this)
116 | Snackbar.make(
117 | findViewById(R.id.container),
118 | "Tap map to place waypoint",
119 | Snackbar.LENGTH_LONG,
120 | ).show()
121 | }
122 |
123 | @SuppressWarnings("MissingPermission")
124 | private fun enableLocationComponent(style: Style) {
125 | // Get an instance of the component
126 | locationComponent = mapboxMap.locationComponent
127 |
128 | locationComponent?.let {
129 | // Activate with a built LocationComponentActivationOptions object
130 | it.activateLocationComponent(
131 | LocationComponentActivationOptions.builder(this, style).build(),
132 | )
133 |
134 | // Enable to make component visible
135 | it.isLocationComponentEnabled = true
136 |
137 | // Set the component's camera mode
138 | it.cameraMode = CameraMode.TRACKING_GPS_NORTH
139 |
140 | // Set the component's render mode
141 | it.renderMode = RenderMode.NORMAL
142 | }
143 | }
144 |
145 | override fun onMapClick(point: LatLng): Boolean {
146 | var addMarker = true
147 | when {
148 | destination == null -> destination = Point.fromLngLat(point.longitude, point.latitude)
149 | waypoint == null -> waypoint = Point.fromLngLat(point.longitude, point.latitude)
150 | else -> {
151 | Toast.makeText(this, "Only 2 waypoints supported", Toast.LENGTH_LONG).show()
152 | addMarker = false
153 | }
154 | }
155 |
156 | if (addMarker) {
157 | mapboxMap.addMarker(MarkerOptions().position(point))
158 | binding.clearPoints.visibility = View.VISIBLE
159 | }
160 | calculateRoute()
161 | return true
162 | }
163 |
164 | private fun calculateRoute() {
165 | binding.startRouteLayout.visibility = View.GONE
166 | val userLocation = mapboxMap.locationComponent.lastKnownLocation // LatLng(51.43224,14.241285)
167 | val destination = destination
168 | if (userLocation == null) {
169 | Toast.makeText(this, "calculateRoute: User location is null, therefore, origin can't be set.", Toast.LENGTH_LONG).show()
170 | return
171 | }
172 |
173 | if (destination == null) {
174 | return
175 | }
176 |
177 | val origin = Point.fromLngLat(userLocation.longitude, userLocation.latitude)
178 | if (TurfMeasurement.distance(origin, destination, TurfConstants.UNIT_METERS) < 50) {
179 | binding.startRouteLayout.visibility = View.GONE
180 | return
181 | }
182 |
183 | val navigationRouteBuilder = NavigationRoute.builder(this).apply {
184 | this.accessToken(getString(R.string.mapbox_access_token))
185 | this.origin(origin)
186 | this.destination(destination)
187 | this.voiceUnits(DirectionsCriteria.METRIC)
188 | this.alternatives(true)
189 | this.user("gh")
190 | this.profile("car")
191 | this.baseUrl(getString(R.string.base_url))
192 | }
193 |
194 | navigationRouteBuilder.build().getRoute(object : Callback {
195 | override fun onResponse(
196 | call: Call,
197 | response: Response,
198 | ) {
199 | Timber.d("Url: %s", (call.request() as Request).url.toString())
200 | response.body()?.let { response ->
201 | if (response.routes().isNotEmpty()) {
202 | val maplibreResponse = com.mapbox.services.android.navigation.v5.models.DirectionsResponse.fromJson(response.toJson());
203 | this@NavigationUIActivity.route = maplibreResponse.routes().first()
204 | navigationMapRoute?.addRoutes(maplibreResponse.routes())
205 | binding.startRouteLayout.visibility = View.VISIBLE
206 | }
207 | }
208 |
209 | }
210 |
211 | override fun onFailure(call: Call, throwable: Throwable) {
212 | Timber.e(throwable, "onFailure: navigation.getRoute()")
213 | }
214 | })
215 | }
216 |
217 | override fun onResume() {
218 | super.onResume()
219 | binding.mapView.onResume()
220 | }
221 |
222 | override fun onPause() {
223 | super.onPause()
224 | binding.mapView.onPause()
225 | }
226 |
227 | override fun onStart() {
228 | super.onStart()
229 | binding.mapView.onStart()
230 | }
231 |
232 | override fun onStop() {
233 | super.onStop()
234 | binding.mapView.onStop()
235 | }
236 |
237 | override fun onLowMemory() {
238 | super.onLowMemory()
239 | binding.mapView.onLowMemory()
240 | }
241 |
242 | override fun onDestroy() {
243 | super.onDestroy()
244 | if (::mapboxMap.isInitialized) {
245 | mapboxMap.removeOnMapClickListener(this)
246 | }
247 | binding.mapView.onDestroy()
248 | }
249 |
250 | override fun onSaveInstanceState(outState: Bundle) {
251 | super.onSaveInstanceState(outState)
252 | binding.mapView.onSaveInstanceState(outState)
253 | }
254 | }
255 |
--------------------------------------------------------------------------------
/app/src/main/assets/reroute.json:
--------------------------------------------------------------------------------
1 | {
2 | "locations": [{
3 | "lng": 11.579233823791801,
4 | "horizontalAccuracy": 40,
5 | "course": 277.0355517432898,
6 | "verticalAccuracy": 10,
7 | "speed": 14.704089336389941,
8 | "lat": 48.1776966801359,
9 | "altitude": 0,
10 | "timestamp": "2018-06-25T18:16:11.005+0000"
11 | }, {
12 | "lng": 11.579037109773616,
13 | "horizontalAccuracy": 40,
14 | "course": 277.3048420107052,
15 | "verticalAccuracy": 10,
16 | "speed": 14.704089336389941,
17 | "lat": 48.17771306903845,
18 | "altitude": 0,
19 | "timestamp": "2018-06-25T18:16:12.026+0000"
20 | }, {
21 | "lng": 11.578840471720559,
22 | "horizontalAccuracy": 40,
23 | "course": 277.30469546363236,
24 | "verticalAccuracy": 10,
25 | "speed": 14.704089336389941,
26 | "lat": 48.17772987732808,
27 | "altitude": 0,
28 | "timestamp": "2018-06-25T18:16:13.038+0000"
29 | }, {
30 | "lng": 11.578643833538571,
31 | "horizontalAccuracy": 40,
32 | "course": 277.3045489263966,
33 | "verticalAccuracy": 10,
34 | "speed": 14.704089336389941,
35 | "lat": 48.17774668528237,
36 | "altitude": 0,
37 | "timestamp": "2018-06-25T18:16:14.064+0000"
38 | }, {
39 | "lng": 11.578447195227648,
40 | "horizontalAccuracy": 40,
41 | "course": 277.30440238753647,
42 | "verticalAccuracy": 10,
43 | "speed": 14.704089336389941,
44 | "lat": 48.1777634929013,
45 | "altitude": 0,
46 | "timestamp": "2018-06-25T18:16:15.072+0000"
47 | }, {
48 | "lng": 11.578250556787797,
49 | "horizontalAccuracy": 40,
50 | "course": 277.30425584242937,
51 | "verticalAccuracy": 10,
52 | "speed": 14.704089336389941,
53 | "lat": 48.177780300184864,
54 | "altitude": 0,
55 | "timestamp": "2018-06-25T18:16:16.084+0000"
56 | }, {
57 | "lng": 11.57805391821902,
58 | "horizontalAccuracy": 40,
59 | "course": 277.30410931764175,
60 | "verticalAccuracy": 10,
61 | "speed": 14.704089336389941,
62 | "lat": 48.17779710713307,
63 | "altitude": 0,
64 | "timestamp": "2018-06-25T18:16:17.099+0000"
65 | }, {
66 | "lng": 11.577857279521318,
67 | "horizontalAccuracy": 40,
68 | "course": 277.3039627829298,
69 | "verticalAccuracy": 10,
70 | "speed": 14.706585219942085,
71 | "lat": 48.17781391374592,
72 | "altitude": 0,
73 | "timestamp": "2018-06-25T18:16:18.125+0000"
74 | }, {
75 | "lng": 11.577660607317055,
76 | "horizontalAccuracy": 40,
77 | "course": 277.3038162095172,
78 | "verticalAccuracy": 10,
79 | "speed": 14.706585219942085,
80 | "lat": 48.1778307228761,
81 | "altitude": 0,
82 | "timestamp": "2018-06-25T18:16:19.152+0000"
83 | }, {
84 | "lng": 11.577463934983832,
85 | "horizontalAccuracy": 40,
86 | "course": 277.3036696400822,
87 | "verticalAccuracy": 10,
88 | "speed": 14.706585219942085,
89 | "lat": 48.17784753167082,
90 | "altitude": 0,
91 | "timestamp": "2018-06-25T18:16:20.165+0000"
92 | }, {
93 | "lng": 11.577267262521646,
94 | "horizontalAccuracy": 40,
95 | "course": 277.3035230828386,
96 | "verticalAccuracy": 10,
97 | "speed": 14.706585219942085,
98 | "lat": 48.17786434013005,
99 | "altitude": 0,
100 | "timestamp": "2018-06-25T18:16:21.175+0000"
101 | }, {
102 | "lng": 11.577070589930504,
103 | "horizontalAccuracy": 40,
104 | "course": 277.3033765175093,
105 | "verticalAccuracy": 10,
106 | "speed": 14.706585219942085,
107 | "lat": 48.17788114825381,
108 | "altitude": 0,
109 | "timestamp": "2018-06-25T18:16:22.195+0000"
110 | }, {
111 | "lng": 11.574359352291717,
112 | "horizontalAccuracy": 48,
113 | "course": 268.312124335552,
114 | "verticalAccuracy": 78.20085144042969,
115 | "speed": 17.91221046447754,
116 | "lat": 48.177918933802175,
117 | "altitude": 48.968618182176954,
118 | "timestamp": "2018-06-25T18:16:22.994+0000"
119 | }, {
120 | "lng": 11.576873917210403,
121 | "horizontalAccuracy": 40,
122 | "course": 278.450736782001,
123 | "verticalAccuracy": 10,
124 | "speed": 14.706585219942085,
125 | "lat": 48.177897956042095,
126 | "altitude": 0,
127 | "timestamp": "2018-06-25T18:16:23.214+0000"
128 | }, {
129 | "lng": 11.574522629071382,
130 | "horizontalAccuracy": 48,
131 | "course": 264.0482831235232,
132 | "verticalAccuracy": 46.24095916748047,
133 | "speed": 17.91221046447754,
134 | "lat": 48.17801775561044,
135 | "altitude": 145.58279171356196,
136 | "timestamp": "2018-06-25T18:16:23.994+0000"
137 | }, {
138 | "lng": 11.574331268061316,
139 | "horizontalAccuracy": 48,
140 | "course": 268.1751927030716,
141 | "verticalAccuracy": 32.8426399230957,
142 | "speed": 15.196555137634277,
143 | "lat": 48.17804684917256,
144 | "altitude": 221.20309180182414,
145 | "timestamp": "2018-06-25T18:16:24.994+0000"
146 | }, {
147 | "lng": 11.56516,
148 | "horizontalAccuracy": 40,
149 | "course": 0,
150 | "verticalAccuracy": 10,
151 | "speed": 30,
152 | "lat": 48.17766000000002,
153 | "altitude": 0,
154 | "timestamp": "2018-06-25T18:16:25.487+0000"
155 | }, {
156 | "lng": 11.574178106389212,
157 | "horizontalAccuracy": 48,
158 | "course": 270.8357153093317,
159 | "verticalAccuracy": 26.84093475341797,
160 | "speed": 14.339875221252441,
161 | "lat": 48.178080277991555,
162 | "altitude": 280.8462253177666,
163 | "timestamp": "2018-06-25T18:16:25.994+0000"
164 | }, {
165 | "lng": 11.574008059553593,
166 | "horizontalAccuracy": 32,
167 | "course": 270.5562786100081,
168 | "verticalAccuracy": 22.006803512573242,
169 | "speed": 13.635870933532715,
170 | "lat": 48.17809862228263,
171 | "altitude": 328.0323720022608,
172 | "timestamp": "2018-06-25T18:16:26.994+0000"
173 | }, {
174 | "lng": 11.57386211241843,
175 | "horizontalAccuracy": 32,
176 | "course": 270.3645415396275,
177 | "verticalAccuracy": 18.102466583251953,
178 | "speed": 8.865394592285156,
179 | "lat": 48.17810865942336,
180 | "altitude": 365.45081994813916,
181 | "timestamp": "2018-06-25T18:16:27.994+0000"
182 | }, {
183 | "lng": 11.57376567902112,
184 | "horizontalAccuracy": 32,
185 | "course": 270.5847741592254,
186 | "verticalAccuracy": 14.9990873336792,
187 | "speed": 8.865394592285156,
188 | "lat": 48.17811604817344,
189 | "altitude": 395.29102788875264,
190 | "timestamp": "2018-06-25T18:16:28.996+0000"
191 | }, {
192 | "lng": 11.573712332853994,
193 | "horizontalAccuracy": 32,
194 | "course": 268.90924679355123,
195 | "verticalAccuracy": 12.552094459533691,
196 | "speed": 6.171590328216553,
197 | "lat": 48.17812282827704,
198 | "altitude": 419.11699633027285,
199 | "timestamp": "2018-06-25T18:16:29.996+0000"
200 | }, {
201 | "lng": 11.57367408373014,
202 | "horizontalAccuracy": 32,
203 | "course": 267.3676457771227,
204 | "verticalAccuracy": 10.65554141998291,
205 | "speed": 4.660297870635986,
206 | "lat": 48.17812949968013,
207 | "altitude": 438.10093661880165,
208 | "timestamp": "2018-06-25T18:16:30.997+0000"
209 | }, {
210 | "lng": 11.573650791666006,
211 | "horizontalAccuracy": 32,
212 | "course": 265.38418616290767,
213 | "verticalAccuracy": 9.199372291564941,
214 | "speed": 1.1029866933822632,
215 | "lat": 48.17813414073155,
216 | "altitude": 453.3387505254847,
217 | "timestamp": "2018-06-25T18:16:31.997+0000"
218 | }, {
219 | "lng": 11.573651032411707,
220 | "horizontalAccuracy": 32,
221 | "course": 264.96953903877454,
222 | "verticalAccuracy": 8.089214324951172,
223 | "speed": 0.24953123927116394,
224 | "lat": 48.178135350891466,
225 | "altitude": 465.50988790699057,
226 | "timestamp": "2018-06-25T18:16:32.997+0000"
227 | }, {
228 | "lng": 11.57366355967202,
229 | "horizontalAccuracy": 16,
230 | "course": 264.6807313199097,
231 | "verticalAccuracy": 7.259465217590332,
232 | "speed": 0.08760471642017365,
233 | "lat": 48.17813549408713,
234 | "altitude": 475.2478246602212,
235 | "timestamp": "2018-06-25T18:16:33.997+0000"
236 | }, {
237 | "lng": 11.573666459152962,
238 | "horizontalAccuracy": 16,
239 | "course": 264.40372616793064,
240 | "verticalAccuracy": 6.654788017272949,
241 | "speed": 0.06893076002597809,
242 | "lat": 48.178135725029186,
243 | "altitude": 483.0984814692704,
244 | "timestamp": "2018-06-25T18:16:34.997+0000"
245 | }, {
246 | "lng": 11.573665270949899,
247 | "horizontalAccuracy": 16,
248 | "course": 264.0772704463607,
249 | "verticalAccuracy": 6.2912917137146,
250 | "speed": 0.04840405657887459,
251 | "lat": 48.17813554458974,
252 | "altitude": 489.4621804169076,
253 | "timestamp": "2018-06-25T18:16:35.998+0000"
254 | }, {
255 | "lng": 11.57366498578763,
256 | "horizontalAccuracy": 16,
257 | "course": 262.7757095981231,
258 | "verticalAccuracy": 6.068527698516846,
259 | "speed": 0.538252055644989,
260 | "lat": 48.17813584106783,
261 | "altitude": 494.632077626026,
262 | "timestamp": "2018-06-25T18:16:36.998+0000"
263 | }, {
264 | "lng": 11.57365252827095,
265 | "horizontalAccuracy": 16,
266 | "course": 264.68313554649757,
267 | "verticalAccuracy": 5.916316509246826,
268 | "speed": 0.538252055644989,
269 | "lat": 48.178129500360306,
270 | "altitude": 498.6311698715431,
271 | "timestamp": "2018-06-25T18:16:37.998+0000"
272 | }, {
273 | "lng": 11.573622826101186,
274 | "horizontalAccuracy": 16,
275 | "course": 262.68096121395666,
276 | "verticalAccuracy": 5.802955627441406,
277 | "speed": 1.4058953523635864,
278 | "lat": 48.178127452657506,
279 | "altitude": 501.79815496262916,
280 | "timestamp": "2018-06-25T18:16:38.998+0000"
281 | }, {
282 | "lng": 11.573593990589218,
283 | "horizontalAccuracy": 16,
284 | "course": 261.5483246042718,
285 | "verticalAccuracy": 5.709236145019531,
286 | "speed": 2.158074378967285,
287 | "lat": 48.17812510064344,
288 | "altitude": 504.3031565362038,
289 | "timestamp": "2018-06-25T18:16:39.998+0000"
290 | }, {
291 | "lng": 11.573570600866708,
292 | "horizontalAccuracy": 16,
293 | "course": 262.657110193375,
294 | "verticalAccuracy": 5.625188827514648,
295 | "speed": 2.158074378967285,
296 | "lat": 48.17812390326735,
297 | "altitude": 506.29452861168886,
298 | "timestamp": "2018-06-25T18:16:40.998+0000"
299 | }, {
300 | "lng": 11.573544222281482,
301 | "horizontalAccuracy": 16,
302 | "course": 262.5914037735595,
303 | "verticalAccuracy": 5.543359279632568,
304 | "speed": 2.087489366531372,
305 | "lat": 48.178122375982795,
306 | "altitude": 507.8819353829481,
307 | "timestamp": "2018-06-25T18:16:41.998+0000"
308 | }, {
309 | "lng": 11.573522864491215,
310 | "horizontalAccuracy": 16,
311 | "course": 263.9457756444597,
312 | "verticalAccuracy": 5.4844794273376465,
313 | "speed": 1.5718590021133423,
314 | "lat": 48.17812073885602,
315 | "altitude": 509.1104736675136,
316 | "timestamp": "2018-06-25T18:16:42.998+0000"
317 | }, {
318 | "lng": 11.573514355033776,
319 | "horizontalAccuracy": 16,
320 | "course": 260.36009025474306,
321 | "verticalAccuracy": 5.441601753234863,
322 | "speed": 0.6080191135406494,
323 | "lat": 48.178121038726324,
324 | "altitude": 510.08266092409417,
325 | "timestamp": "2018-06-25T18:16:43.998+0000"
326 | }, {
327 | "lng": 11.573509069339542,
328 | "horizontalAccuracy": 16,
329 | "course": 258.3632707905115,
330 | "verticalAccuracy": 5.428653240203857,
331 | "speed": 0.057707976549863815,
332 | "lat": 48.17812058973181,
333 | "altitude": 510.8631459842678,
334 | "timestamp": "2018-06-25T18:16:44.998+0000"
335 | }, {
336 | "lng": 11.573520048732512,
337 | "horizontalAccuracy": 16,
338 | "course": 257.633642662614,
339 | "verticalAccuracy": 5.434919357299805,
340 | "speed": 0.005837027449160814,
341 | "lat": 48.178126701948436,
342 | "altitude": 511.493896722867,
343 | "timestamp": "2018-06-25T18:16:45.998+0000"
344 | }, {
345 | "lng": 11.573521553454881,
346 | "horizontalAccuracy": 16,
347 | "course": 257.14487432560793,
348 | "verticalAccuracy": 5.454024791717529,
349 | "speed": 0.015429791994392872,
350 | "lat": 48.17812728496367,
351 | "altitude": 511.9823615713549,
352 | "timestamp": "2018-06-25T18:16:46.999+0000"
353 | }],
354 | "route": "https://api.mapbox.com/directions/v5/mapbox/driving-traffic/11.579233823791801,48.1776966801359;11.573521553454881,48.17812728496367.json?access_token=pk.eyJ1IjoibWFwYm94LW5hdmlnYXRpb24iLCJhIjoiY2plZzkxZnl4MW9tZDMzb2R2ZXlkeHlhbCJ9.L1c9Wo-gk6d3cR3oi1n9SQ&steps=true&overview=full&geometries=geojson"
355 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/mapbox/services/android/navigation/testapp/MockNavigationActivity.kt:
--------------------------------------------------------------------------------
1 | package com.mapbox.services.android.navigation.testapp
2 |
3 | import android.annotation.SuppressLint
4 | import android.content.BroadcastReceiver
5 | import android.content.Context
6 | import android.content.Intent
7 | import android.location.Location
8 | import android.os.Build
9 | import android.os.Bundle
10 | import android.view.View
11 | import android.widget.Toast
12 | import androidx.appcompat.app.AppCompatActivity
13 | import com.google.android.material.snackbar.Snackbar
14 | import com.mapbox.api.directions.v5.DirectionsCriteria.METRIC
15 | import com.mapbox.api.directions.v5.models.DirectionsResponse
16 | import com.mapbox.geojson.Point
17 | import com.mapbox.mapboxsdk.annotations.MarkerOptions
18 | import com.mapbox.mapboxsdk.camera.CameraUpdateFactory
19 | import com.mapbox.mapboxsdk.geometry.LatLng
20 | import com.mapbox.mapboxsdk.location.LocationComponent
21 | import com.mapbox.mapboxsdk.location.LocationComponentActivationOptions
22 | import com.mapbox.mapboxsdk.location.modes.CameraMode
23 | import com.mapbox.mapboxsdk.location.modes.RenderMode
24 | import com.mapbox.mapboxsdk.maps.MapboxMap
25 | import com.mapbox.mapboxsdk.maps.OnMapReadyCallback
26 | import com.mapbox.mapboxsdk.maps.Style
27 | import com.mapbox.services.android.navigation.testapp.databinding.ActivityMockNavigationBinding
28 | import com.mapbox.services.android.navigation.ui.v5.route.NavigationRoute
29 | import com.mapbox.services.android.navigation.v5.instruction.Instruction
30 | import com.mapbox.services.android.navigation.v5.location.replay.ReplayRouteLocationEngine
31 | import com.mapbox.services.android.navigation.v5.milestone.*
32 | import com.mapbox.services.android.navigation.v5.models.DirectionsRoute
33 | import com.mapbox.services.android.navigation.v5.navigation.*
34 | import com.mapbox.services.android.navigation.v5.offroute.OffRouteListener
35 | import com.mapbox.services.android.navigation.v5.routeprogress.ProgressChangeListener
36 | import com.mapbox.services.android.navigation.v5.routeprogress.RouteProgress
37 | import com.mapbox.turf.TurfConstants
38 | import com.mapbox.turf.TurfMeasurement
39 | import okhttp3.Request
40 | import retrofit2.Call
41 | import retrofit2.Callback
42 | import retrofit2.Response
43 | import timber.log.Timber
44 | import java.lang.ref.WeakReference
45 |
46 | class MockNavigationActivity :
47 | AppCompatActivity(),
48 | OnMapReadyCallback,
49 | MapboxMap.OnMapClickListener,
50 | ProgressChangeListener,
51 | NavigationEventListener,
52 | MilestoneEventListener,
53 | OffRouteListener {
54 | private val BEGIN_ROUTE_MILESTONE = 1001
55 | private lateinit var mapboxMap: MapboxMap
56 |
57 | // Navigation related variables
58 | private var locationEngine: ReplayRouteLocationEngine = ReplayRouteLocationEngine()
59 | private lateinit var navigation: MapboxNavigation
60 | private var route: DirectionsRoute? = null
61 | private var navigationMapRoute: NavigationMapRoute? = null
62 | private var destination: Point? = null
63 | private var waypoint: Point? = null
64 | private var locationComponent: LocationComponent? = null
65 |
66 | private lateinit var binding: ActivityMockNavigationBinding
67 |
68 | @SuppressLint("MissingPermission")
69 | override fun onCreate(savedInstanceState: Bundle?) {
70 | super.onCreate(savedInstanceState)
71 | binding = ActivityMockNavigationBinding.inflate(layoutInflater)
72 | setContentView(binding.root)
73 | binding.mapView.apply {
74 | onCreate(savedInstanceState)
75 | getMapAsync(this@MockNavigationActivity)
76 | }
77 |
78 | val context = applicationContext
79 | val customNotification = CustomNavigationNotification(context)
80 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
81 | customNotification.createNotificationChannel(this)
82 | }
83 | val options = MapboxNavigationOptions.builder()
84 | .navigationNotification(customNotification)
85 | .build()
86 |
87 | navigation = MapboxNavigation(this, options)
88 |
89 | navigation.addMilestone(
90 | RouteMilestone.Builder()
91 | .setIdentifier(BEGIN_ROUTE_MILESTONE)
92 | .setInstruction(BeginRouteInstruction())
93 | .setTrigger(
94 | Trigger.all(
95 | Trigger.lt(TriggerProperty.STEP_INDEX, 3),
96 | Trigger.gt(TriggerProperty.STEP_DISTANCE_TOTAL_METERS, 200),
97 | Trigger.gte(TriggerProperty.STEP_DISTANCE_TRAVELED_METERS, 75),
98 | ),
99 | ).build(),
100 | )
101 | customNotification.register(MyBroadcastReceiver(navigation), context)
102 |
103 | binding.startRouteButton.setOnClickListener {
104 | route?.let { route ->
105 | binding.startRouteButton.visibility = View.INVISIBLE
106 |
107 | // Attach all of our navigation listeners.
108 | navigation.apply {
109 | addNavigationEventListener(this@MockNavigationActivity)
110 | addProgressChangeListener(this@MockNavigationActivity)
111 | addMilestoneEventListener(this@MockNavigationActivity)
112 | addOffRouteListener(this@MockNavigationActivity)
113 | }
114 |
115 | locationEngine.also {
116 | it.assign(route)
117 | navigation.locationEngine = it
118 | navigation.startNavigation(route)
119 | if (::mapboxMap.isInitialized) {
120 | mapboxMap.removeOnMapClickListener(this)
121 | }
122 | }
123 | }
124 | }
125 |
126 | binding.newLocationFab.setOnClickListener {
127 | newOrigin()
128 | }
129 |
130 | binding.clearPoints.setOnClickListener {
131 | if (::mapboxMap.isInitialized) {
132 | mapboxMap.markers.forEach {
133 | mapboxMap.removeMarker(it)
134 | }
135 | }
136 | destination = null
137 | waypoint = null
138 | it.visibility = View.GONE
139 |
140 | navigationMapRoute?.removeRoute()
141 | }
142 | }
143 |
144 | override fun onMapReady(mapboxMap: MapboxMap) {
145 | this.mapboxMap = mapboxMap
146 | mapboxMap.setStyle(Style.Builder().fromUri(getString(R.string.map_style_light))) { style ->
147 | enableLocationComponent(style)
148 | }
149 |
150 | navigationMapRoute = NavigationMapRoute(navigation, binding.mapView, mapboxMap)
151 |
152 | mapboxMap.addOnMapClickListener(this)
153 | Snackbar.make(
154 | findViewById(R.id.container),
155 | "Tap map to place waypoint",
156 | Snackbar.LENGTH_LONG,
157 | ).show()
158 |
159 | newOrigin()
160 | }
161 |
162 | @SuppressWarnings("MissingPermission")
163 | private fun enableLocationComponent(style: Style) {
164 | // Get an instance of the component
165 | locationComponent = mapboxMap.locationComponent
166 |
167 | locationComponent?.let {
168 | // Activate with a built LocationComponentActivationOptions object
169 | it.activateLocationComponent(
170 | LocationComponentActivationOptions.builder(this, style).build(),
171 | )
172 |
173 | // Enable to make component visible
174 | it.isLocationComponentEnabled = true
175 |
176 | // Set the component's camera mode
177 | it.cameraMode = CameraMode.TRACKING
178 |
179 | // Set the component's render mode
180 | it.renderMode = RenderMode.GPS
181 |
182 | it.locationEngine = locationEngine
183 | }
184 | }
185 |
186 | override fun onMapClick(point: LatLng): Boolean {
187 | var addMarker = true
188 | when {
189 | destination == null -> destination = Point.fromLngLat(point.longitude, point.latitude)
190 | waypoint == null -> waypoint = Point.fromLngLat(point.longitude, point.latitude)
191 | else -> {
192 | Toast.makeText(this, "Only 2 waypoints supported", Toast.LENGTH_LONG).show()
193 | addMarker = false
194 | }
195 | }
196 |
197 | if (addMarker) {
198 | mapboxMap.addMarker(MarkerOptions().position(point))
199 | }
200 | binding.clearPoints.visibility = View.VISIBLE
201 |
202 | binding.startRouteButton.visibility = View.VISIBLE
203 | calculateRoute()
204 | return true
205 | }
206 |
207 | private fun calculateRoute() {
208 | val userLocation = locationEngine.lastLocation
209 | val destination = destination
210 | if (userLocation == null) {
211 | Timber.d("calculateRoute: User location is null, therefore, origin can't be set.")
212 | return
213 | }
214 |
215 | if (destination == null) {
216 | return
217 | }
218 |
219 | val origin = Point.fromLngLat(userLocation.longitude, userLocation.latitude)
220 | if (TurfMeasurement.distance(origin, destination, TurfConstants.UNIT_METERS) < 50) {
221 | binding.startRouteButton.visibility = View.GONE
222 | return
223 | }
224 |
225 | val navigationRouteBuilder = NavigationRoute.builder(this).apply {
226 | this.accessToken(getString(R.string.mapbox_access_token))
227 | this.origin(origin)
228 | this.destination(destination)
229 | this.voiceUnits(METRIC)
230 | this.alternatives(true)
231 | this.user("gh")
232 | this.profile("car")
233 | this.baseUrl(getString(R.string.base_url))
234 | }
235 |
236 | navigationRouteBuilder.build().getRoute(object : Callback {
237 | override fun onResponse(
238 | call: Call,
239 | response: Response,
240 | ) {
241 | Timber.d("Url: %s", (call.request() as Request).url.toString())
242 | response.body()?.let { response ->
243 | if (response.routes().isNotEmpty()) {
244 | val maplibreResponse = com.mapbox.services.android.navigation.v5.models.DirectionsResponse.fromJson(response.toJson());
245 | val directionsRoute = DirectionsRoute.fromJson(maplibreResponse.routes().first().toJson())
246 | this@MockNavigationActivity.route = directionsRoute
247 | navigationMapRoute?.addRoutes(maplibreResponse.routes())
248 | }
249 | }
250 | }
251 |
252 | override fun onFailure(call: Call, throwable: Throwable) {
253 | Timber.e(throwable, "onFailure: navigation.getRoute()")
254 | }
255 | })
256 | }
257 |
258 | override fun onProgressChange(location: Location?, routeProgress: RouteProgress?) {
259 | }
260 |
261 | override fun onRunning(running: Boolean) {
262 | }
263 |
264 | override fun onMilestoneEvent(
265 | routeProgress: RouteProgress?,
266 | instruction: String?,
267 | milestone: Milestone?,
268 | ) {
269 | }
270 |
271 | override fun userOffRoute(location: Location?) {
272 | }
273 |
274 | private class BeginRouteInstruction : Instruction() {
275 |
276 | override fun buildInstruction(routeProgress: RouteProgress): String {
277 | return "Have a safe trip!"
278 | }
279 | }
280 |
281 | override fun onResume() {
282 | super.onResume()
283 | binding.mapView.onResume()
284 | }
285 |
286 | override fun onPause() {
287 | super.onPause()
288 | binding.mapView.onPause()
289 | }
290 |
291 | override fun onStart() {
292 | super.onStart()
293 | binding.mapView.onStart()
294 | }
295 |
296 | override fun onStop() {
297 | super.onStop()
298 | binding.mapView.onStop()
299 | }
300 |
301 | override fun onLowMemory() {
302 | super.onLowMemory()
303 | binding.mapView.onLowMemory()
304 | }
305 |
306 | override fun onDestroy() {
307 | super.onDestroy()
308 | navigation.onDestroy()
309 | if (::mapboxMap.isInitialized) {
310 | mapboxMap.removeOnMapClickListener(this)
311 | }
312 | binding.mapView.onDestroy()
313 | }
314 |
315 | override fun onSaveInstanceState(outState: Bundle) {
316 | super.onSaveInstanceState(outState)
317 | binding.mapView.onSaveInstanceState(outState)
318 | }
319 |
320 | private class MyBroadcastReceiver internal constructor(navigation: MapboxNavigation) :
321 | BroadcastReceiver() {
322 | private val weakNavigation: WeakReference = WeakReference(navigation)
323 |
324 | override fun onReceive(context: Context, intent: Intent) {
325 | weakNavigation.get()?.stopNavigation()
326 | }
327 | }
328 |
329 | private fun newOrigin() {
330 | mapboxMap.let {
331 | val latLng = LatLng(52.039176, 5.550339)
332 | locationEngine.assignLastLocation(
333 | Point.fromLngLat(latLng.longitude, latLng.latitude),
334 | )
335 | it.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng, 12.0))
336 | }
337 | }
338 | }
339 |
--------------------------------------------------------------------------------
/config/checkstyle/checkstyle.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
68 |
69 |
70 |
74 |
75 |
76 |
78 |
79 |
80 |
84 |
85 |
86 |
87 |
89 |
90 |
91 |
95 |
96 |
97 |
99 |
100 |
101 |
105 |
106 |
107 |
109 |
110 |
111 |
115 |
116 |
117 |
119 |
120 |
121 |
122 |
123 |
124 |
126 |
127 |
128 |
132 |
133 |
134 |
135 |
136 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
172 |
173 |
174 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
259 |
260 |
261 |
262 |
263 |
264 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
279 |
280 |
281 |
285 |
286 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
312 |
313 |
314 |
315 |
316 |
317 |
319 |
321 |
322 |
323 |
324 |
325 |
327 |
329 |
331 |
333 |
334 |
335 |
336 |
337 |
338 |
339 |
340 |
341 |
342 |
343 |
344 |
345 |
349 |
350 |
351 |
352 |
353 |
354 |
356 |
357 |
358 |
359 |
360 |
361 |
366 |
367 |
368 |
369 |
370 |
371 |
373 |
374 |
375 |
378 |
379 |
380 |
381 |
382 |
383 |
384 |
388 |
389 |
390 |
391 |
392 |
393 |
394 |
395 |
396 |
397 |
398 |
399 |
400 |
401 |
402 |
403 |
404 |
405 |
406 |
407 |
408 |
409 |
410 |
411 |
412 |
413 |
414 |
415 |
416 |
417 |
418 |
419 |
420 |
424 |
425 |
426 |
430 |
431 |
432 |
433 |
434 |
435 |
436 |
437 |
438 |
439 |
440 |
441 |
442 |
443 |
444 |
445 |
446 |
447 |
448 |
449 |
450 |
451 |
452 |
453 |
454 |
456 |
457 |
458 |
459 |
460 |
461 |
462 |
463 |
464 |
465 |
466 |
467 |
468 |
469 |
470 |
471 |
472 |
473 |
474 |
475 |
476 |
477 |
478 |
479 |
480 |
481 |
485 |
486 |
487 |
488 |
489 |
490 |
491 |
492 |
493 |
494 |
495 |
496 |
497 |
498 |
499 |
500 |
501 |
507 |
508 |
509 |
513 |
514 |
515 |
516 |
517 |
518 |
519 |
520 |
521 |
522 |
523 |
524 |
525 |
526 |
527 |
528 |
529 |
530 |
531 |
532 |
533 |
534 |
535 |
536 |
537 |
538 |
539 |
540 |
541 |
542 |
543 |
544 |
545 |
546 |
547 |
548 |
549 |
550 |
551 |
--------------------------------------------------------------------------------