@jadamsbit/react-native-mapbox-navigation 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.gitattributes +1 -0
- package/CONTRIBUTING.md +11 -0
- package/LICENSE +21 -0
- package/README.md +357 -0
- package/android/.gradle/7.3.3/checksums/checksums.lock +0 -0
- package/android/.gradle/7.3.3/checksums/md5-checksums.bin +0 -0
- package/android/.gradle/7.3.3/checksums/sha1-checksums.bin +0 -0
- package/android/.gradle/7.3.3/dependencies-accessors/dependencies-accessors.lock +0 -0
- package/android/.gradle/7.3.3/dependencies-accessors/gc.properties +0 -0
- package/android/.gradle/7.3.3/executionHistory/executionHistory.lock +0 -0
- package/android/.gradle/7.3.3/fileChanges/last-build.bin +0 -0
- package/android/.gradle/7.3.3/fileHashes/fileHashes.lock +0 -0
- package/android/.gradle/7.3.3/gc.properties +0 -0
- package/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
- package/android/.gradle/buildOutputCleanup/cache.properties +2 -0
- package/android/.gradle/vcs-1/gc.properties +0 -0
- package/android/README.md +14 -0
- package/android/build.gradle +99 -0
- package/android/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/android/gradle/wrapper/gradle-wrapper.properties +7 -0
- package/android/gradle.properties +4 -0
- package/android/gradlew +244 -0
- package/android/gradlew.bat +92 -0
- package/android/src/main/AndroidManifest.xml +4 -0
- package/android/src/main/java/com/jadamsbit/mapboxnavigation/MapboxNavigationManager.kt +122 -0
- package/android/src/main/java/com/jadamsbit/mapboxnavigation/MapboxNavigationPackage.kt +16 -0
- package/android/src/main/java/com/jadamsbit/mapboxnavigation/MapboxNavigationView.kt +794 -0
- package/android/src/main/res/layout/navigation_view.xml +84 -0
- package/android/src/main/res/values/styles.xml +15 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +12 -0
- package/dist/typings.d.ts +40 -0
- package/dist/typings.js +1 -0
- package/example/.buckconfig +6 -0
- package/example/.eslintrc.js +4 -0
- package/example/.flowconfig +65 -0
- package/example/.prettierrc.js +7 -0
- package/example/.watchmanconfig +1 -0
- package/example/App.js +51 -0
- package/example/Gemfile +6 -0
- package/example/Gemfile.lock +100 -0
- package/example/NavigationComponent.js +56 -0
- package/example/__tests__/App-test.js +14 -0
- package/example/_bundle/config +2 -0
- package/example/_ruby-version +1 -0
- package/example/android/.gradle/8.2/checksums/checksums.lock +0 -0
- package/example/android/.gradle/8.2/fileChanges/last-build.bin +0 -0
- package/example/android/.gradle/8.2/fileHashes/fileHashes.lock +0 -0
- package/example/android/.gradle/8.2/gc.properties +0 -0
- package/example/android/.gradle/vcs-1/gc.properties +0 -0
- package/example/android/app/_BUCK +55 -0
- package/example/android/app/build.gradle +232 -0
- package/example/android/app/build_defs.bzl +19 -0
- package/example/android/app/debug.keystore +0 -0
- package/example/android/app/proguard-rules.pro +10 -0
- package/example/android/app/src/debug/AndroidManifest.xml +13 -0
- package/example/android/app/src/debug/java/com/basicapp/ReactNativeFlipper.java +72 -0
- package/example/android/app/src/main/AndroidManifest.xml +30 -0
- package/example/android/app/src/main/java/com/basicapp/MainActivity.java +15 -0
- package/example/android/app/src/main/java/com/basicapp/MainApplication.java +81 -0
- package/example/android/app/src/main/res/drawable/rn_edit_text_material.xml +36 -0
- package/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png +0 -0
- package/example/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png +0 -0
- package/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png +0 -0
- package/example/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png +0 -0
- package/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png +0 -0
- package/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png +0 -0
- package/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png +0 -0
- package/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png +0 -0
- package/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png +0 -0
- package/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png +0 -0
- package/example/android/app/src/main/res/values/strings.xml +3 -0
- package/example/android/app/src/main/res/values/styles.xml +9 -0
- package/example/android/build.gradle +55 -0
- package/example/android/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/example/android/gradle/wrapper/gradle-wrapper.properties +5 -0
- package/example/android/gradle.properties +35 -0
- package/example/android/gradlew +185 -0
- package/example/android/gradlew.bat +89 -0
- package/example/android/settings.gradle +6 -0
- package/example/app.json +4 -0
- package/example/babel.config.js +24 -0
- package/example/index.js +9 -0
- package/example/ios/BasicApp/AppDelegate.h +8 -0
- package/example/ios/BasicApp/AppDelegate.m +62 -0
- package/example/ios/BasicApp/Images.xcassets/AppIcon.appiconset/Contents.json +38 -0
- package/example/ios/BasicApp/Images.xcassets/Contents.json +6 -0
- package/example/ios/BasicApp/Info.plist +62 -0
- package/example/ios/BasicApp/LaunchScreen.storyboard +47 -0
- package/example/ios/BasicApp/main.m +9 -0
- package/example/ios/BasicApp-Bridging-Header.h +4 -0
- package/example/ios/BasicApp.xcodeproj/project.pbxproj +690 -0
- package/example/ios/BasicApp.xcodeproj/xcshareddata/xcschemes/BasicApp.xcscheme +88 -0
- package/example/ios/BasicApp.xcworkspace/contents.xcworkspacedata +10 -0
- package/example/ios/BasicApp.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
- package/example/ios/BasicAppTests/BasicAppTests.m +65 -0
- package/example/ios/BasicAppTests/Info.plist +24 -0
- package/example/ios/BridgeHeader.swift +8 -0
- package/example/ios/Podfile +44 -0
- package/example/ios/Podfile.lock +473 -0
- package/example/metro.config.js +45 -0
- package/example/package.json +31 -0
- package/img/bridging-header.png +0 -0
- package/img/build-setting-linking.png +0 -0
- package/img/build-setting-path.png +0 -0
- package/ios/MapboxNavigation-Bridging-Header.h +3 -0
- package/ios/MapboxNavigation.xcodeproj/project.pbxproj +290 -0
- package/ios/MapboxNavigation.xcworkspace/contents.xcworkspacedata +7 -0
- package/ios/MapboxNavigation.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
- package/ios/MapboxNavigationManager.m +20 -0
- package/ios/MapboxNavigationManager.swift +10 -0
- package/ios/MapboxNavigationView.swift +163 -0
- package/package.json +33 -0
- package/react-native-mapbox-navigation.podspec +51 -0
- package/src/index.tsx +21 -0
- package/src/typings.ts +43 -0
- package/tsconfig.json +14 -0
|
@@ -0,0 +1,794 @@
|
|
|
1
|
+
package com.jadamsbit.mapboxnavigation
|
|
2
|
+
|
|
3
|
+
import android.annotation.SuppressLint
|
|
4
|
+
import android.content.res.Configuration
|
|
5
|
+
import android.content.res.Resources
|
|
6
|
+
import android.location.Location
|
|
7
|
+
import android.location.LocationManager
|
|
8
|
+
import android.view.LayoutInflater
|
|
9
|
+
import android.view.View
|
|
10
|
+
import android.widget.FrameLayout
|
|
11
|
+
import android.widget.Toast
|
|
12
|
+
import androidx.core.content.ContextCompat
|
|
13
|
+
import com.facebook.react.bridge.Arguments
|
|
14
|
+
import com.facebook.react.uimanager.ThemedReactContext
|
|
15
|
+
import com.mapbox.api.directions.v5.models.DirectionsRoute
|
|
16
|
+
import com.mapbox.api.directions.v5.models.RouteOptions
|
|
17
|
+
import com.mapbox.bindgen.Expected
|
|
18
|
+
import com.mapbox.geojson.Point
|
|
19
|
+
import com.mapbox.maps.EdgeInsets
|
|
20
|
+
import com.mapbox.maps.MapView
|
|
21
|
+
import com.mapbox.maps.MapboxMap
|
|
22
|
+
import com.mapbox.maps.Style
|
|
23
|
+
import com.mapbox.maps.plugin.LocationPuck2D
|
|
24
|
+
import com.mapbox.maps.plugin.animation.camera
|
|
25
|
+
import com.mapbox.maps.plugin.locationcomponent.location
|
|
26
|
+
import com.mapbox.navigation.base.TimeFormat
|
|
27
|
+
import com.mapbox.navigation.base.extensions.applyDefaultNavigationOptions
|
|
28
|
+
import com.mapbox.navigation.base.extensions.applyLanguageAndVoiceUnitOptions
|
|
29
|
+
import com.mapbox.navigation.base.options.NavigationOptions
|
|
30
|
+
import com.mapbox.navigation.base.route.RouterCallback
|
|
31
|
+
import com.mapbox.navigation.base.route.RouterFailure
|
|
32
|
+
import com.mapbox.navigation.base.route.RouterOrigin
|
|
33
|
+
import com.mapbox.navigation.core.MapboxNavigation
|
|
34
|
+
import com.mapbox.navigation.core.MapboxNavigationProvider
|
|
35
|
+
import com.mapbox.navigation.core.directions.session.RoutesObserver
|
|
36
|
+
import com.mapbox.navigation.core.formatter.MapboxDistanceFormatter
|
|
37
|
+
import com.mapbox.navigation.core.replay.MapboxReplayer
|
|
38
|
+
import com.mapbox.navigation.core.replay.ReplayLocationEngine
|
|
39
|
+
import com.mapbox.navigation.core.replay.route.ReplayProgressObserver
|
|
40
|
+
import com.mapbox.navigation.core.replay.route.ReplayRouteMapper
|
|
41
|
+
import com.mapbox.navigation.core.trip.session.LocationMatcherResult
|
|
42
|
+
import com.mapbox.navigation.core.trip.session.LocationObserver
|
|
43
|
+
import com.mapbox.navigation.core.trip.session.RouteProgressObserver
|
|
44
|
+
import com.mapbox.navigation.core.trip.session.VoiceInstructionsObserver
|
|
45
|
+
import com.jadamsbit.mapboxnavigation.databinding.NavigationViewBinding
|
|
46
|
+
import com.mapbox.api.directions.v5.DirectionsCriteria
|
|
47
|
+
import com.mapbox.navigation.base.trip.model.RouteLegProgress
|
|
48
|
+
import com.mapbox.navigation.base.trip.model.RouteProgress
|
|
49
|
+
import com.mapbox.navigation.core.arrival.ArrivalObserver
|
|
50
|
+
import com.mapbox.navigation.ui.base.util.MapboxNavigationConsumer
|
|
51
|
+
import com.mapbox.navigation.ui.maneuver.api.MapboxManeuverApi
|
|
52
|
+
import com.mapbox.navigation.ui.maneuver.view.MapboxManeuverView
|
|
53
|
+
import com.mapbox.navigation.ui.maps.camera.NavigationCamera
|
|
54
|
+
import com.mapbox.navigation.ui.maps.camera.data.MapboxNavigationViewportDataSource
|
|
55
|
+
import com.mapbox.navigation.ui.maps.camera.lifecycle.NavigationBasicGesturesHandler
|
|
56
|
+
import com.mapbox.navigation.ui.maps.camera.state.NavigationCameraState
|
|
57
|
+
import com.mapbox.navigation.ui.maps.camera.transition.NavigationCameraTransitionOptions
|
|
58
|
+
import com.mapbox.navigation.ui.maps.location.NavigationLocationProvider
|
|
59
|
+
import com.mapbox.navigation.ui.maps.route.arrow.api.MapboxRouteArrowApi
|
|
60
|
+
import com.mapbox.navigation.ui.maps.route.arrow.api.MapboxRouteArrowView
|
|
61
|
+
import com.mapbox.navigation.ui.maps.route.arrow.model.RouteArrowOptions
|
|
62
|
+
import com.mapbox.navigation.ui.maps.route.line.api.MapboxRouteLineApi
|
|
63
|
+
import com.mapbox.navigation.ui.maps.route.line.api.MapboxRouteLineView
|
|
64
|
+
import com.mapbox.navigation.ui.maps.route.line.model.MapboxRouteLineOptions
|
|
65
|
+
import com.mapbox.navigation.ui.maps.route.line.model.RouteLine
|
|
66
|
+
import com.mapbox.navigation.ui.tripprogress.api.MapboxTripProgressApi
|
|
67
|
+
import com.mapbox.navigation.ui.tripprogress.model.DistanceRemainingFormatter
|
|
68
|
+
import com.mapbox.navigation.ui.tripprogress.model.EstimatedTimeToArrivalFormatter
|
|
69
|
+
import com.mapbox.navigation.ui.tripprogress.model.PercentDistanceTraveledFormatter
|
|
70
|
+
import com.mapbox.navigation.ui.tripprogress.model.TimeRemainingFormatter
|
|
71
|
+
import com.mapbox.navigation.ui.tripprogress.model.TripProgressUpdateFormatter
|
|
72
|
+
import com.mapbox.navigation.ui.tripprogress.view.MapboxTripProgressView
|
|
73
|
+
import com.mapbox.navigation.ui.voice.api.MapboxSpeechApi
|
|
74
|
+
import com.mapbox.navigation.ui.voice.api.MapboxVoiceInstructionsPlayer
|
|
75
|
+
import com.mapbox.navigation.ui.voice.model.SpeechAnnouncement
|
|
76
|
+
import com.mapbox.navigation.ui.voice.model.SpeechError
|
|
77
|
+
import com.mapbox.navigation.ui.voice.model.SpeechValue
|
|
78
|
+
import com.mapbox.navigation.ui.voice.model.SpeechVolume
|
|
79
|
+
import java.util.Locale
|
|
80
|
+
import com.facebook.react.uimanager.events.RCTEventEmitter
|
|
81
|
+
|
|
82
|
+
class MapboxNavigationView(private val context: ThemedReactContext, private val accessToken: String?) :
|
|
83
|
+
FrameLayout(context.baseContext) {
|
|
84
|
+
|
|
85
|
+
private companion object {
|
|
86
|
+
private const val BUTTON_ANIMATION_DURATION = 1500L
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
private var origin: Point? = null
|
|
90
|
+
private var waypoints: List<Point>? = null
|
|
91
|
+
private var destination: Point? = null
|
|
92
|
+
private var shouldSimulateRoute = false
|
|
93
|
+
private var showsEndOfRouteFeedback = false
|
|
94
|
+
private var maxHeight: Double? = null
|
|
95
|
+
private var maxWidth: Double? = null
|
|
96
|
+
/**
|
|
97
|
+
* Debug tool used to play, pause and seek route progress events that can be used to produce mocked location updates along the route.
|
|
98
|
+
*/
|
|
99
|
+
private val mapboxReplayer = MapboxReplayer()
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Debug tool that mocks location updates with an input from the [mapboxReplayer].
|
|
103
|
+
*/
|
|
104
|
+
private val replayLocationEngine = ReplayLocationEngine(mapboxReplayer)
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Debug observer that makes sure the replayer has always an up-to-date information to generate mock updates.
|
|
108
|
+
*/
|
|
109
|
+
private val replayProgressObserver = ReplayProgressObserver(mapboxReplayer)
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Bindings to the example layout.
|
|
113
|
+
*/
|
|
114
|
+
private var binding: NavigationViewBinding =
|
|
115
|
+
NavigationViewBinding.inflate(LayoutInflater.from(context), this, true)
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Mapbox Maps entry point obtained from the [MapView].
|
|
119
|
+
* You need to get a new reference to this object whenever the [MapView] is recreated.
|
|
120
|
+
*/
|
|
121
|
+
private lateinit var mapboxMap: MapboxMap
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Mapbox Navigation entry point. There should only be one instance of this object for the app.
|
|
125
|
+
* You can use [MapboxNavigationProvider] to help create and obtain that instance.
|
|
126
|
+
*/
|
|
127
|
+
private lateinit var mapboxNavigation: MapboxNavigation
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Used to execute camera transitions based on the data generated by the [viewportDataSource].
|
|
131
|
+
* This includes transitions from route overview to route following and continuously updating the camera as the location changes.
|
|
132
|
+
*/
|
|
133
|
+
private lateinit var navigationCamera: NavigationCamera
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Produces the camera frames based on the location and routing data for the [navigationCamera] to execute.
|
|
137
|
+
*/
|
|
138
|
+
private lateinit var viewportDataSource: MapboxNavigationViewportDataSource
|
|
139
|
+
|
|
140
|
+
/*
|
|
141
|
+
* Below are generated camera padding values to ensure that the route fits well on screen while
|
|
142
|
+
* other elements are overlaid on top of the map (including instruction view, buttons, etc.)
|
|
143
|
+
*/
|
|
144
|
+
private val pixelDensity = Resources.getSystem().displayMetrics.density
|
|
145
|
+
private val overviewPadding: EdgeInsets by lazy {
|
|
146
|
+
EdgeInsets(
|
|
147
|
+
140.0 * pixelDensity,
|
|
148
|
+
40.0 * pixelDensity,
|
|
149
|
+
120.0 * pixelDensity,
|
|
150
|
+
40.0 * pixelDensity
|
|
151
|
+
)
|
|
152
|
+
}
|
|
153
|
+
private val landscapeOverviewPadding: EdgeInsets by lazy {
|
|
154
|
+
EdgeInsets(
|
|
155
|
+
30.0 * pixelDensity,
|
|
156
|
+
380.0 * pixelDensity,
|
|
157
|
+
110.0 * pixelDensity,
|
|
158
|
+
20.0 * pixelDensity
|
|
159
|
+
)
|
|
160
|
+
}
|
|
161
|
+
private val followingPadding: EdgeInsets by lazy {
|
|
162
|
+
EdgeInsets(
|
|
163
|
+
180.0 * pixelDensity,
|
|
164
|
+
40.0 * pixelDensity,
|
|
165
|
+
150.0 * pixelDensity,
|
|
166
|
+
40.0 * pixelDensity
|
|
167
|
+
)
|
|
168
|
+
}
|
|
169
|
+
private val landscapeFollowingPadding: EdgeInsets by lazy {
|
|
170
|
+
EdgeInsets(
|
|
171
|
+
30.0 * pixelDensity,
|
|
172
|
+
380.0 * pixelDensity,
|
|
173
|
+
110.0 * pixelDensity,
|
|
174
|
+
40.0 * pixelDensity
|
|
175
|
+
)
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Generates updates for the [MapboxManeuverView] to display the upcoming maneuver instructions
|
|
180
|
+
* and remaining distance to the maneuver point.
|
|
181
|
+
*/
|
|
182
|
+
private lateinit var maneuverApi: MapboxManeuverApi
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Generates updates for the [MapboxTripProgressView] that include remaining time and distance to the destination.
|
|
186
|
+
*/
|
|
187
|
+
private lateinit var tripProgressApi: MapboxTripProgressApi
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Generates updates for the [routeLineView] with the geometries and properties of the routes that should be drawn on the map.
|
|
191
|
+
*/
|
|
192
|
+
private lateinit var routeLineApi: MapboxRouteLineApi
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Draws route lines on the map based on the data from the [routeLineApi]
|
|
196
|
+
*/
|
|
197
|
+
private lateinit var routeLineView: MapboxRouteLineView
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Generates updates for the [routeArrowView] with the geometries and properties of maneuver arrows that should be drawn on the map.
|
|
201
|
+
*/
|
|
202
|
+
private val routeArrowApi: MapboxRouteArrowApi = MapboxRouteArrowApi()
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Draws maneuver arrows on the map based on the data [routeArrowApi].
|
|
206
|
+
*/
|
|
207
|
+
private lateinit var routeArrowView: MapboxRouteArrowView
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Stores and updates the state of whether the voice instructions should be played as they come or muted.
|
|
211
|
+
*/
|
|
212
|
+
private var isVoiceInstructionsMuted = false
|
|
213
|
+
set(value) {
|
|
214
|
+
field = value
|
|
215
|
+
if (value) {
|
|
216
|
+
binding.soundButton.muteAndExtend(BUTTON_ANIMATION_DURATION)
|
|
217
|
+
voiceInstructionsPlayer.volume(SpeechVolume(0f))
|
|
218
|
+
} else {
|
|
219
|
+
binding.soundButton.unmuteAndExtend(BUTTON_ANIMATION_DURATION)
|
|
220
|
+
voiceInstructionsPlayer.volume(SpeechVolume(1f))
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Extracts message that should be communicated to the driver about the upcoming maneuver.
|
|
226
|
+
* When possible, downloads a synthesized audio file that can be played back to the driver.
|
|
227
|
+
*/
|
|
228
|
+
private lateinit var speechApi: MapboxSpeechApi
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Plays the synthesized audio files with upcoming maneuver instructions
|
|
232
|
+
* or uses an on-device Text-To-Speech engine to communicate the message to the driver.
|
|
233
|
+
*/
|
|
234
|
+
private lateinit var voiceInstructionsPlayer: MapboxVoiceInstructionsPlayer
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Observes when a new voice instruction should be played.
|
|
238
|
+
*/
|
|
239
|
+
private val voiceInstructionsObserver = VoiceInstructionsObserver { voiceInstructions ->
|
|
240
|
+
speechApi.generate(voiceInstructions, speechCallback)
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Based on whether the synthesized audio file is available, the callback plays the file
|
|
245
|
+
* or uses the fall back which is played back using the on-device Text-To-Speech engine.
|
|
246
|
+
*/
|
|
247
|
+
private val speechCallback =
|
|
248
|
+
MapboxNavigationConsumer<Expected<SpeechError, SpeechValue>> { expected ->
|
|
249
|
+
expected.fold(
|
|
250
|
+
{ error ->
|
|
251
|
+
// play the instruction via fallback text-to-speech engine
|
|
252
|
+
voiceInstructionsPlayer.play(
|
|
253
|
+
error.fallback,
|
|
254
|
+
voiceInstructionsPlayerCallback
|
|
255
|
+
)
|
|
256
|
+
},
|
|
257
|
+
{ value ->
|
|
258
|
+
// play the sound file from the external generator
|
|
259
|
+
voiceInstructionsPlayer.play(
|
|
260
|
+
value.announcement,
|
|
261
|
+
voiceInstructionsPlayerCallback
|
|
262
|
+
)
|
|
263
|
+
}
|
|
264
|
+
)
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* When a synthesized audio file was downloaded, this callback cleans up the disk after it was played.
|
|
269
|
+
*/
|
|
270
|
+
private val voiceInstructionsPlayerCallback =
|
|
271
|
+
MapboxNavigationConsumer<SpeechAnnouncement> { value ->
|
|
272
|
+
// remove already consumed file to free-up space
|
|
273
|
+
speechApi.clean(value)
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* [NavigationLocationProvider] is a utility class that helps to provide location updates generated by the Navigation SDK
|
|
278
|
+
* to the Maps SDK in order to update the user location indicator on the map.
|
|
279
|
+
*/
|
|
280
|
+
private val navigationLocationProvider = NavigationLocationProvider()
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Gets notified with location updates.
|
|
284
|
+
*
|
|
285
|
+
* Exposes raw updates coming directly from the location services
|
|
286
|
+
* and the updates enhanced by the Navigation SDK (cleaned up and matched to the road).
|
|
287
|
+
*/
|
|
288
|
+
private val locationObserver = object : LocationObserver {
|
|
289
|
+
override fun onNewRawLocation(rawLocation: Location) {
|
|
290
|
+
// not handled
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
override fun onNewLocationMatcherResult(locationMatcherResult: LocationMatcherResult) {
|
|
294
|
+
val enhancedLocation = locationMatcherResult.enhancedLocation
|
|
295
|
+
// update location puck's position on the map
|
|
296
|
+
navigationLocationProvider.changePosition(
|
|
297
|
+
location = enhancedLocation,
|
|
298
|
+
keyPoints = locationMatcherResult.keyPoints,
|
|
299
|
+
)
|
|
300
|
+
|
|
301
|
+
// update camera position to account for new location
|
|
302
|
+
viewportDataSource.onLocationChanged(enhancedLocation)
|
|
303
|
+
viewportDataSource.evaluate()
|
|
304
|
+
|
|
305
|
+
val event = Arguments.createMap()
|
|
306
|
+
event.putDouble("longitude", enhancedLocation.longitude)
|
|
307
|
+
event.putDouble("latitude", enhancedLocation.latitude)
|
|
308
|
+
context
|
|
309
|
+
.getJSModule(RCTEventEmitter::class.java)
|
|
310
|
+
.receiveEvent(id, "onLocationChange", event)
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* Gets notified with progress along the currently active route.
|
|
316
|
+
*/
|
|
317
|
+
private val routeProgressObserver = RouteProgressObserver { routeProgress ->
|
|
318
|
+
// update the camera position to account for the progressed fragment of the route
|
|
319
|
+
viewportDataSource.onRouteProgressChanged(routeProgress)
|
|
320
|
+
viewportDataSource.evaluate()
|
|
321
|
+
|
|
322
|
+
// draw the upcoming maneuver arrow on the map
|
|
323
|
+
val style = mapboxMap.getStyle()
|
|
324
|
+
if (style != null) {
|
|
325
|
+
val maneuverArrowResult = routeArrowApi.addUpcomingManeuverArrow(routeProgress)
|
|
326
|
+
routeArrowView.renderManeuverUpdate(style, maneuverArrowResult)
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// update top banner with maneuver instructions
|
|
330
|
+
val maneuvers = maneuverApi.getManeuvers(routeProgress)
|
|
331
|
+
maneuvers.fold(
|
|
332
|
+
{ error ->
|
|
333
|
+
Toast.makeText(
|
|
334
|
+
context,
|
|
335
|
+
error.errorMessage,
|
|
336
|
+
Toast.LENGTH_SHORT
|
|
337
|
+
).show()
|
|
338
|
+
},
|
|
339
|
+
{
|
|
340
|
+
binding.maneuverView.visibility = View.VISIBLE
|
|
341
|
+
binding.maneuverView.updatePrimaryManeuverTextAppearance(R.style.PrimaryManeuverTextAppearance)
|
|
342
|
+
binding.maneuverView.updateSecondaryManeuverTextAppearance(R.style.ManeuverTextAppearance)
|
|
343
|
+
binding.maneuverView.updateSubManeuverTextAppearance(R.style.ManeuverTextAppearance)
|
|
344
|
+
binding.maneuverView.updateStepDistanceTextAppearance(R.style.StepDistanceRemainingAppearance)
|
|
345
|
+
binding.maneuverView.renderManeuvers(maneuvers)
|
|
346
|
+
}
|
|
347
|
+
)
|
|
348
|
+
|
|
349
|
+
// update bottom trip progress summary
|
|
350
|
+
binding.tripProgressView.render(
|
|
351
|
+
tripProgressApi.getTripProgress(routeProgress)
|
|
352
|
+
)
|
|
353
|
+
|
|
354
|
+
val event = Arguments.createMap()
|
|
355
|
+
event.putDouble("distanceTraveled", routeProgress.distanceTraveled.toDouble())
|
|
356
|
+
event.putDouble("durationRemaining", routeProgress.durationRemaining.toDouble())
|
|
357
|
+
event.putDouble("fractionTraveled", routeProgress.fractionTraveled.toDouble())
|
|
358
|
+
event.putDouble("distanceRemaining", routeProgress.distanceRemaining.toDouble())
|
|
359
|
+
context
|
|
360
|
+
.getJSModule(RCTEventEmitter::class.java)
|
|
361
|
+
.receiveEvent(id, "onRouteProgressChange", event)
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* Gets notified whenever the tracked routes change.
|
|
366
|
+
*
|
|
367
|
+
* A change can mean:
|
|
368
|
+
* - routes get changed with [MapboxNavigation.setRoutes]
|
|
369
|
+
* - routes annotations get refreshed (for example, congestion annotation that indicate the live traffic along the route)
|
|
370
|
+
* - driver got off route and a reroute was executed
|
|
371
|
+
*/
|
|
372
|
+
private val routesObserver = RoutesObserver { routeUpdateResult ->
|
|
373
|
+
if (routeUpdateResult.routes.isNotEmpty()) {
|
|
374
|
+
// generate route geometries asynchronously and render them
|
|
375
|
+
val routeLines = routeUpdateResult.routes.map { RouteLine(it, null) }
|
|
376
|
+
|
|
377
|
+
routeLineApi.setRoutes(
|
|
378
|
+
routeLines
|
|
379
|
+
) { value ->
|
|
380
|
+
mapboxMap.getStyle()?.apply {
|
|
381
|
+
routeLineView.renderRouteDrawData(this, value)
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
// update the camera position to account for the new route
|
|
386
|
+
viewportDataSource.onRouteChanged(routeUpdateResult.routes.first())
|
|
387
|
+
viewportDataSource.evaluate()
|
|
388
|
+
} else {
|
|
389
|
+
// remove the route line and route arrow from the map
|
|
390
|
+
val style = mapboxMap.getStyle()
|
|
391
|
+
if (style != null) {
|
|
392
|
+
routeLineApi.clearRouteLine { value ->
|
|
393
|
+
routeLineView.renderClearRouteLineValue(
|
|
394
|
+
style,
|
|
395
|
+
value
|
|
396
|
+
)
|
|
397
|
+
}
|
|
398
|
+
routeArrowView.render(style, routeArrowApi.clearArrows())
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
// remove the route reference from camera position evaluations
|
|
402
|
+
viewportDataSource.clearRouteData()
|
|
403
|
+
viewportDataSource.evaluate()
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
private val arrivalObserver = object : ArrivalObserver {
|
|
408
|
+
|
|
409
|
+
override fun onWaypointArrival(routeProgress: RouteProgress) {
|
|
410
|
+
// do something when the user arrives at a waypoint
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
override fun onNextRouteLegStart(routeLegProgress: RouteLegProgress) {
|
|
414
|
+
// do something when the user starts a new leg
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
override fun onFinalDestinationArrival(routeProgress: RouteProgress) {
|
|
418
|
+
val event = Arguments.createMap()
|
|
419
|
+
event.putString("onArrive", "")
|
|
420
|
+
context
|
|
421
|
+
.getJSModule(RCTEventEmitter::class.java)
|
|
422
|
+
.receiveEvent(id, "onRouteProgressChange", event)
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
|
|
427
|
+
override fun onAttachedToWindow() {
|
|
428
|
+
super.onAttachedToWindow()
|
|
429
|
+
onCreate()
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
override fun requestLayout() {
|
|
433
|
+
super.requestLayout()
|
|
434
|
+
post(measureAndLayout)
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
private val measureAndLayout = Runnable {
|
|
438
|
+
measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
|
|
439
|
+
MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY))
|
|
440
|
+
layout(left, top, right, bottom)
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
private fun setCameraPositionToOrigin() {
|
|
444
|
+
val startingLocation = Location(LocationManager.GPS_PROVIDER)
|
|
445
|
+
startingLocation.latitude = origin!!.latitude()
|
|
446
|
+
startingLocation.longitude = origin!!.longitude()
|
|
447
|
+
viewportDataSource.onLocationChanged(startingLocation)
|
|
448
|
+
|
|
449
|
+
navigationCamera.requestNavigationCameraToFollowing(
|
|
450
|
+
stateTransitionOptions = NavigationCameraTransitionOptions.Builder()
|
|
451
|
+
.maxDuration(0) // instant transition
|
|
452
|
+
.build()
|
|
453
|
+
)
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
@SuppressLint("MissingPermission")
|
|
457
|
+
fun onCreate() {
|
|
458
|
+
if (accessToken == null) {
|
|
459
|
+
sendErrorToReact("Mapbox access token is not set")
|
|
460
|
+
return
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
if (origin == null || destination == null) {
|
|
464
|
+
sendErrorToReact("origin and destination are required")
|
|
465
|
+
return
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
mapboxMap = binding.mapView.getMapboxMap()
|
|
469
|
+
|
|
470
|
+
// initialize the location puck
|
|
471
|
+
binding.mapView.location.apply {
|
|
472
|
+
this.locationPuck = LocationPuck2D(
|
|
473
|
+
bearingImage = ContextCompat.getDrawable(
|
|
474
|
+
context,
|
|
475
|
+
R.drawable.mapbox_navigation_puck_icon
|
|
476
|
+
)
|
|
477
|
+
)
|
|
478
|
+
setLocationProvider(navigationLocationProvider)
|
|
479
|
+
enabled = true
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
// initialize Mapbox Navigation
|
|
483
|
+
mapboxNavigation = if (MapboxNavigationProvider.isCreated()) {
|
|
484
|
+
MapboxNavigationProvider.retrieve()
|
|
485
|
+
} else if (shouldSimulateRoute) {
|
|
486
|
+
MapboxNavigationProvider.create(
|
|
487
|
+
NavigationOptions.Builder(context)
|
|
488
|
+
.accessToken(accessToken)
|
|
489
|
+
.locationEngine(replayLocationEngine)
|
|
490
|
+
.build()
|
|
491
|
+
)
|
|
492
|
+
} else {
|
|
493
|
+
MapboxNavigationProvider.create(
|
|
494
|
+
NavigationOptions.Builder(context)
|
|
495
|
+
.accessToken(accessToken)
|
|
496
|
+
.build()
|
|
497
|
+
)
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
// initialize Navigation Camera
|
|
501
|
+
viewportDataSource = MapboxNavigationViewportDataSource(mapboxMap)
|
|
502
|
+
|
|
503
|
+
navigationCamera = NavigationCamera(
|
|
504
|
+
mapboxMap,
|
|
505
|
+
binding.mapView.camera,
|
|
506
|
+
viewportDataSource
|
|
507
|
+
)
|
|
508
|
+
// set the animations lifecycle listener to ensure the NavigationCamera stops
|
|
509
|
+
// automatically following the user location when the map is interacted with
|
|
510
|
+
binding.mapView.camera.addCameraAnimationsLifecycleListener(
|
|
511
|
+
NavigationBasicGesturesHandler(navigationCamera)
|
|
512
|
+
)
|
|
513
|
+
navigationCamera.registerNavigationCameraStateChangeObserver { navigationCameraState ->
|
|
514
|
+
// shows/hide the recenter button depending on the camera state
|
|
515
|
+
when (navigationCameraState) {
|
|
516
|
+
NavigationCameraState.TRANSITION_TO_FOLLOWING,
|
|
517
|
+
NavigationCameraState.FOLLOWING -> binding.recenter.visibility = View.INVISIBLE
|
|
518
|
+
NavigationCameraState.TRANSITION_TO_OVERVIEW,
|
|
519
|
+
NavigationCameraState.OVERVIEW,
|
|
520
|
+
NavigationCameraState.IDLE -> binding.recenter.visibility = View.VISIBLE
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
// set the padding values depending on screen orientation and visible view layout
|
|
524
|
+
if (this.resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE) {
|
|
525
|
+
viewportDataSource.overviewPadding = landscapeOverviewPadding
|
|
526
|
+
} else {
|
|
527
|
+
viewportDataSource.overviewPadding = overviewPadding
|
|
528
|
+
}
|
|
529
|
+
if (this.resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE) {
|
|
530
|
+
viewportDataSource.followingPadding = landscapeFollowingPadding
|
|
531
|
+
} else {
|
|
532
|
+
viewportDataSource.followingPadding = followingPadding
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
// make sure to use the same DistanceFormatterOptions across different features
|
|
536
|
+
val distanceFormatterOptions = mapboxNavigation.navigationOptions.distanceFormatterOptions
|
|
537
|
+
|
|
538
|
+
// initialize maneuver api that feeds the data to the top banner maneuver view
|
|
539
|
+
maneuverApi = MapboxManeuverApi(
|
|
540
|
+
MapboxDistanceFormatter(distanceFormatterOptions)
|
|
541
|
+
)
|
|
542
|
+
|
|
543
|
+
// initialize bottom progress view
|
|
544
|
+
tripProgressApi = MapboxTripProgressApi(
|
|
545
|
+
TripProgressUpdateFormatter.Builder(context)
|
|
546
|
+
.distanceRemainingFormatter(
|
|
547
|
+
DistanceRemainingFormatter(distanceFormatterOptions)
|
|
548
|
+
)
|
|
549
|
+
.timeRemainingFormatter(
|
|
550
|
+
TimeRemainingFormatter(context)
|
|
551
|
+
)
|
|
552
|
+
.percentRouteTraveledFormatter(
|
|
553
|
+
PercentDistanceTraveledFormatter()
|
|
554
|
+
)
|
|
555
|
+
.estimatedTimeToArrivalFormatter(
|
|
556
|
+
EstimatedTimeToArrivalFormatter(context, TimeFormat.NONE_SPECIFIED)
|
|
557
|
+
)
|
|
558
|
+
.build()
|
|
559
|
+
)
|
|
560
|
+
|
|
561
|
+
// initialize voice instructions api and the voice instruction player
|
|
562
|
+
speechApi = MapboxSpeechApi(
|
|
563
|
+
context,
|
|
564
|
+
accessToken,
|
|
565
|
+
Locale.US.language
|
|
566
|
+
)
|
|
567
|
+
voiceInstructionsPlayer = MapboxVoiceInstructionsPlayer(
|
|
568
|
+
context,
|
|
569
|
+
accessToken,
|
|
570
|
+
Locale.US.language
|
|
571
|
+
)
|
|
572
|
+
|
|
573
|
+
// initialize route line, the withRouteLineBelowLayerId is specified to place
|
|
574
|
+
// the route line below road labels layer on the map
|
|
575
|
+
// the value of this option will depend on the style that you are using
|
|
576
|
+
// and under which layer the route line should be placed on the map layers stack
|
|
577
|
+
val mapboxRouteLineOptions = MapboxRouteLineOptions.Builder(context)
|
|
578
|
+
.withRouteLineBelowLayerId("road-label")
|
|
579
|
+
.build()
|
|
580
|
+
routeLineApi = MapboxRouteLineApi(mapboxRouteLineOptions)
|
|
581
|
+
routeLineView = MapboxRouteLineView(mapboxRouteLineOptions)
|
|
582
|
+
|
|
583
|
+
// initialize maneuver arrow view to draw arrows on the map
|
|
584
|
+
val routeArrowOptions = RouteArrowOptions.Builder(context).build()
|
|
585
|
+
routeArrowView = MapboxRouteArrowView(routeArrowOptions)
|
|
586
|
+
|
|
587
|
+
setCameraPositionToOrigin()
|
|
588
|
+
// load map style
|
|
589
|
+
mapboxMap.loadStyleUri(
|
|
590
|
+
Style.MAPBOX_STREETS
|
|
591
|
+
)
|
|
592
|
+
|
|
593
|
+
// initialize view interactions
|
|
594
|
+
binding.stop.setOnClickListener {
|
|
595
|
+
// clearRouteAndStopNavigation() // TODO: figure out how we want to address this since a user cannot reinitialize a route once it is canceled.
|
|
596
|
+
val event = Arguments.createMap()
|
|
597
|
+
event.putString("onCancelNavigation", "Navigation Closed")
|
|
598
|
+
context
|
|
599
|
+
.getJSModule(RCTEventEmitter::class.java)
|
|
600
|
+
.receiveEvent(id, "onCancelNavigation", event)
|
|
601
|
+
}
|
|
602
|
+
binding.recenter.setOnClickListener {
|
|
603
|
+
navigationCamera.requestNavigationCameraToFollowing()
|
|
604
|
+
binding.routeOverview.showTextAndExtend(BUTTON_ANIMATION_DURATION)
|
|
605
|
+
}
|
|
606
|
+
binding.routeOverview.setOnClickListener {
|
|
607
|
+
navigationCamera.requestNavigationCameraToOverview()
|
|
608
|
+
binding.recenter.showTextAndExtend(BUTTON_ANIMATION_DURATION)
|
|
609
|
+
}
|
|
610
|
+
binding.soundButton.setOnClickListener {
|
|
611
|
+
// mute/unmute voice instructions
|
|
612
|
+
isVoiceInstructionsMuted = !isVoiceInstructionsMuted
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
// set initial sounds button state
|
|
616
|
+
binding.soundButton.unmute()
|
|
617
|
+
|
|
618
|
+
// start the trip session to being receiving location updates in free drive
|
|
619
|
+
// and later when a route is set also receiving route progress updates
|
|
620
|
+
mapboxNavigation.startTripSession()
|
|
621
|
+
startRoute()
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
private fun startRoute() {
|
|
625
|
+
// register event listeners
|
|
626
|
+
mapboxNavigation.registerRoutesObserver(routesObserver)
|
|
627
|
+
mapboxNavigation.registerArrivalObserver(arrivalObserver)
|
|
628
|
+
mapboxNavigation.registerRouteProgressObserver(routeProgressObserver)
|
|
629
|
+
mapboxNavigation.registerLocationObserver(locationObserver)
|
|
630
|
+
mapboxNavigation.registerVoiceInstructionsObserver(voiceInstructionsObserver)
|
|
631
|
+
mapboxNavigation.registerRouteProgressObserver(replayProgressObserver)
|
|
632
|
+
|
|
633
|
+
// Create a list of coordinates that includes origin, destination, and waypoints
|
|
634
|
+
val coordinatesList = mutableListOf<Point>()
|
|
635
|
+
this.origin?.let { coordinatesList.add(it) }
|
|
636
|
+
this.waypoints?.let { coordinatesList.addAll(it) }
|
|
637
|
+
this.destination?.let { coordinatesList.add(it) }
|
|
638
|
+
|
|
639
|
+
findRoute(coordinatesList)
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
override fun onDetachedFromWindow() {
|
|
643
|
+
super.onDetachedFromWindow()
|
|
644
|
+
mapboxNavigation.unregisterRoutesObserver(routesObserver)
|
|
645
|
+
mapboxNavigation.unregisterRouteProgressObserver(routeProgressObserver)
|
|
646
|
+
mapboxNavigation.unregisterLocationObserver(locationObserver)
|
|
647
|
+
mapboxNavigation.unregisterVoiceInstructionsObserver(voiceInstructionsObserver)
|
|
648
|
+
mapboxNavigation.unregisterRouteProgressObserver(replayProgressObserver)
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
private fun onDestroy() {
|
|
652
|
+
MapboxNavigationProvider.destroy()
|
|
653
|
+
mapboxReplayer.finish()
|
|
654
|
+
maneuverApi.cancel()
|
|
655
|
+
routeLineApi.cancel()
|
|
656
|
+
routeLineView.cancel()
|
|
657
|
+
speechApi.cancel()
|
|
658
|
+
voiceInstructionsPlayer.shutdown()
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
private fun findRoute(coordinates: List<Point>) {
|
|
662
|
+
try {
|
|
663
|
+
val routeOptionsBuilder = RouteOptions.builder()
|
|
664
|
+
.applyDefaultNavigationOptions()
|
|
665
|
+
.applyLanguageAndVoiceUnitOptions(context)
|
|
666
|
+
.coordinatesList(coordinates)
|
|
667
|
+
.profile(DirectionsCriteria.PROFILE_DRIVING)
|
|
668
|
+
.steps(true)
|
|
669
|
+
|
|
670
|
+
maxHeight?.let { routeOptionsBuilder.maxHeight(it) }
|
|
671
|
+
maxWidth?.let { routeOptionsBuilder.maxWidth(it) }
|
|
672
|
+
|
|
673
|
+
val routeOptions = routeOptionsBuilder.build()
|
|
674
|
+
|
|
675
|
+
mapboxNavigation.requestRoutes(
|
|
676
|
+
routeOptions,
|
|
677
|
+
object : RouterCallback {
|
|
678
|
+
override fun onRoutesReady(
|
|
679
|
+
routes: List<DirectionsRoute>,
|
|
680
|
+
routerOrigin: RouterOrigin
|
|
681
|
+
) {
|
|
682
|
+
setRouteAndStartNavigation(routes)
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
override fun onFailure(
|
|
686
|
+
reasons: List<RouterFailure>,
|
|
687
|
+
routeOptions: RouteOptions
|
|
688
|
+
) {
|
|
689
|
+
sendErrorToReact("Error finding route $reasons")
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
override fun onCanceled(routeOptions: RouteOptions, routerOrigin: RouterOrigin) {
|
|
693
|
+
// no impl
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
)
|
|
697
|
+
} catch (ex: Exception) {
|
|
698
|
+
sendErrorToReact(ex.toString())
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
private fun sendErrorToReact(error: String?) {
|
|
704
|
+
val event = Arguments.createMap()
|
|
705
|
+
event.putString("error", error)
|
|
706
|
+
context
|
|
707
|
+
.getJSModule(RCTEventEmitter::class.java)
|
|
708
|
+
.receiveEvent(id, "onError", event)
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
private fun setRouteAndStartNavigation(routes: List<DirectionsRoute>) {
|
|
712
|
+
if (routes.isEmpty()) {
|
|
713
|
+
sendErrorToReact("No route found")
|
|
714
|
+
return;
|
|
715
|
+
}
|
|
716
|
+
// set routes, where the first route in the list is the primary route that
|
|
717
|
+
// will be used for active guidance
|
|
718
|
+
mapboxNavigation.setRoutes(routes)
|
|
719
|
+
|
|
720
|
+
// start location simulation along the primary route
|
|
721
|
+
if (shouldSimulateRoute) {
|
|
722
|
+
startSimulation(routes.first())
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
// show UI elements
|
|
726
|
+
binding.soundButton.visibility = View.VISIBLE
|
|
727
|
+
binding.routeOverview.visibility = View.VISIBLE
|
|
728
|
+
binding.tripProgressCard.visibility = View.VISIBLE
|
|
729
|
+
|
|
730
|
+
// move the camera to overview when new route is available
|
|
731
|
+
navigationCamera.requestNavigationCameraToFollowing()
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
private fun clearRouteAndStopNavigation() {
|
|
735
|
+
// clear
|
|
736
|
+
mapboxNavigation.setRoutes(listOf())
|
|
737
|
+
|
|
738
|
+
// stop simulation
|
|
739
|
+
mapboxReplayer.stop()
|
|
740
|
+
|
|
741
|
+
// hide UI elements
|
|
742
|
+
binding.soundButton.visibility = View.INVISIBLE
|
|
743
|
+
binding.maneuverView.visibility = View.INVISIBLE
|
|
744
|
+
binding.routeOverview.visibility = View.INVISIBLE
|
|
745
|
+
binding.tripProgressCard.visibility = View.INVISIBLE
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
private fun startSimulation(route: DirectionsRoute) {
|
|
749
|
+
mapboxReplayer.run {
|
|
750
|
+
stop()
|
|
751
|
+
clearEvents()
|
|
752
|
+
val replayEvents = ReplayRouteMapper().mapDirectionsRouteGeometry(route)
|
|
753
|
+
pushEvents(replayEvents)
|
|
754
|
+
seekTo(replayEvents.first())
|
|
755
|
+
play()
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
fun onDropViewInstance() {
|
|
760
|
+
this.onDestroy()
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
fun setOrigin(origin: Point?) {
|
|
764
|
+
this.origin = origin
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
fun setWaypoints(waypoints: List<Point>) {
|
|
768
|
+
this.waypoints = waypoints
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
fun setDestination(destination: Point?) {
|
|
772
|
+
this.destination = destination
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
fun setShouldSimulateRoute(shouldSimulateRoute: Boolean) {
|
|
776
|
+
this.shouldSimulateRoute = shouldSimulateRoute
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
fun setShowsEndOfRouteFeedback(showsEndOfRouteFeedback: Boolean) {
|
|
780
|
+
this.showsEndOfRouteFeedback = showsEndOfRouteFeedback
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
fun setMute(mute: Boolean) {
|
|
784
|
+
this.isVoiceInstructionsMuted = mute
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
fun setMaxHeight(maxHeight: Double?) {
|
|
788
|
+
this.maxHeight = maxHeight
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
fun setMaxWidth(maxWidth: Double?) {
|
|
792
|
+
this.maxWidth = maxWidth
|
|
793
|
+
}
|
|
794
|
+
}
|