-
Notifications
You must be signed in to change notification settings - Fork 318
/
ReplayActivity.kt
230 lines (201 loc) · 8.9 KB
/
ReplayActivity.kt
1
2
3
4
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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
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
221
222
223
224
225
226
227
228
229
230
package com.mapbox.navigation.examples.core
import android.annotation.SuppressLint
import android.os.Bundle
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import com.google.android.material.snackbar.Snackbar
import com.google.android.material.snackbar.Snackbar.LENGTH_SHORT
import com.mapbox.android.core.location.LocationEngineCallback
import com.mapbox.android.core.location.LocationEngineProvider
import com.mapbox.android.core.location.LocationEngineResult
import com.mapbox.api.directions.v5.DirectionsCriteria
import com.mapbox.api.directions.v5.models.DirectionsRoute
import com.mapbox.api.directions.v5.models.RouteOptions
import com.mapbox.base.common.logger.model.Message
import com.mapbox.common.logger.MapboxLogger
import com.mapbox.mapboxsdk.camera.CameraUpdateFactory
import com.mapbox.mapboxsdk.location.modes.RenderMode
import com.mapbox.mapboxsdk.maps.MapboxMap
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback
import com.mapbox.mapboxsdk.maps.Style
import com.mapbox.navigation.base.internal.extensions.applyDefaultParams
import com.mapbox.navigation.base.internal.extensions.coordinates
import com.mapbox.navigation.core.MapboxNavigation
import com.mapbox.navigation.core.directions.session.RoutesRequestCallback
import com.mapbox.navigation.core.fasterroute.FasterRouteObserver
import com.mapbox.navigation.core.replay.MapboxReplayer
import com.mapbox.navigation.core.replay.ReplayLocationEngine
import com.mapbox.navigation.core.replay.route.ReplayRouteMapper
import com.mapbox.navigation.core.trip.session.TripSessionState
import com.mapbox.navigation.core.trip.session.TripSessionStateObserver
import com.mapbox.navigation.examples.R
import com.mapbox.navigation.examples.utils.Utils
import com.mapbox.navigation.examples.utils.extensions.toPoint
import com.mapbox.navigation.ui.camera.NavigationCamera
import com.mapbox.navigation.ui.map.NavigationMapboxMap
import com.mapbox.navigation.ui.map.NavigationMapboxMapInstanceState
import java.lang.ref.WeakReference
import kotlinx.android.synthetic.main.activity_replay_route_layout.*
/**
* This activity shows how to use the MapboxNavigation
* class with the Navigation SDK's [MapboxReplayer] and [ReplayLocationEngine].
*/
class ReplayActivity : AppCompatActivity(), OnMapReadyCallback {
private var mapboxMap: MapboxMap? = null
private var mapboxNavigation: MapboxNavigation? = null
private var navigationMapboxMap: NavigationMapboxMap? = null
private var mapInstanceState: NavigationMapboxMapInstanceState? = null
private val firstLocationCallback = FirstLocationCallback(this)
private val replayRouteMapper = ReplayRouteMapper()
private val mapboxReplayer = MapboxReplayer()
@SuppressLint("MissingPermission")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_replay_route_layout)
mapView.onCreate(savedInstanceState)
val mapboxNavigationOptions = MapboxNavigation
.defaultNavigationOptionsBuilder(this, Utils.getMapboxAccessToken(this))
.locationEngine(ReplayLocationEngine(mapboxReplayer))
.build()
mapboxNavigation = MapboxNavigation(mapboxNavigationOptions).apply {
registerTripSessionStateObserver(tripSessionStateObserver)
}
initListeners()
mapView.getMapAsync(this)
Snackbar.make(container, R.string.msg_long_press_map_to_place_waypoint, LENGTH_SHORT)
.show()
}
override fun onMapReady(mapboxMap: MapboxMap) {
this.mapboxMap = mapboxMap
mapboxMap.setStyle(Style.MAPBOX_STREETS) { style ->
mapboxMap.moveCamera(CameraUpdateFactory.zoomTo(15.0))
navigationMapboxMap = NavigationMapboxMap(mapView, mapboxMap, this, true)
mapInstanceState?.let { state ->
navigationMapboxMap?.restoreFrom(state)
}
initializeFirstLocation()
mapboxNavigation?.attachFasterRouteObserver(object : FasterRouteObserver {
override fun onFasterRoute(currentRoute: DirectionsRoute, alternatives: List<DirectionsRoute>, isAlternativeFaster: Boolean) {
navigationMapboxMap?.drawRoutes(alternatives)
mapboxNavigation?.setRoutes(alternatives)
}
})
}
mapboxMap.addOnMapLongClickListener { latLng ->
mapboxMap.locationComponent.lastKnownLocation?.let { originLocation ->
mapboxNavigation?.requestRoutes(
RouteOptions.builder().applyDefaultParams()
.accessToken(Utils.getMapboxAccessToken(applicationContext))
.coordinates(originLocation.toPoint(), null, latLng.toPoint())
.alternatives(true)
.profile(DirectionsCriteria.PROFILE_DRIVING_TRAFFIC)
.build(),
routesReqCallback
)
}
true
}
}
private fun initializeFirstLocation() {
// Center the map at current location. Using LocationEngineProvider because the
// replay engine won't have your last location.
LocationEngineProvider.getBestLocationEngine(this)
.getLastLocation(firstLocationCallback)
}
private val routesReqCallback = object : RoutesRequestCallback {
override fun onRoutesReady(routes: List<DirectionsRoute>) {
MapboxLogger.d(Message("route request success $routes"))
if (routes.isNotEmpty()) {
navigationMapboxMap?.drawRoutes(routes)
val replayEvents = replayRouteMapper.mapGeometry(routes[0].geometry()!!)
mapboxReplayer.pushEvents(replayEvents)
mapboxReplayer.seekTo(replayEvents.first())
startNavigation.visibility = View.VISIBLE
} else {
startNavigation.visibility = View.GONE
}
}
override fun onRoutesRequestFailure(throwable: Throwable, routeOptions: RouteOptions) {
MapboxLogger.e(
Message("Route request failure"),
throwable
)
}
override fun onRoutesRequestCanceled(routeOptions: RouteOptions) {
MapboxLogger.d(Message("route request canceled"))
}
}
@SuppressLint("MissingPermission")
fun initListeners() {
startNavigation.setOnClickListener {
updateCameraOnNavigationStateChange(true)
navigationMapboxMap?.addProgressChangeListener(mapboxNavigation!!)
if (mapboxNavigation?.getRoutes()?.isNotEmpty() == true) {
navigationMapboxMap?.startCamera(mapboxNavigation?.getRoutes()!![0])
}
mapboxNavigation?.startTripSession()
startNavigation.visibility = View.GONE
mapboxReplayer.play()
}
}
override fun onStart() {
super.onStart()
mapView.onStart()
}
public override fun onResume() {
super.onResume()
mapView.onResume()
}
public override fun onPause() {
super.onPause()
mapView.onPause()
}
override fun onStop() {
super.onStop()
mapView.onStop()
}
override fun onDestroy() {
super.onDestroy()
mapboxReplayer.finish()
mapboxNavigation?.unregisterTripSessionStateObserver(tripSessionStateObserver)
mapboxNavigation?.stopTripSession()
mapboxNavigation?.onDestroy()
mapView.onDestroy()
}
override fun onLowMemory() {
super.onLowMemory()
mapView.onLowMemory()
}
private fun updateCameraOnNavigationStateChange(
navigationStarted: Boolean
) {
navigationMapboxMap?.apply {
if (navigationStarted) {
updateCameraTrackingMode(NavigationCamera.NAVIGATION_TRACKING_MODE_GPS)
updateLocationLayerRenderMode(RenderMode.GPS)
} else {
updateCameraTrackingMode(NavigationCamera.NAVIGATION_TRACKING_MODE_NONE)
updateLocationLayerRenderMode(RenderMode.COMPASS)
}
}
}
private class FirstLocationCallback(activity: ReplayActivity) :
LocationEngineCallback<LocationEngineResult> {
private val activityRef = WeakReference(activity)
override fun onSuccess(result: LocationEngineResult?) {
result?.locations?.firstOrNull()?.let {
activityRef.get()?.mapboxMap?.locationComponent?.forceLocationUpdate(it)
}
}
override fun onFailure(exception: Exception) {
}
}
private val tripSessionStateObserver = object : TripSessionStateObserver {
override fun onSessionStateChanged(tripSessionState: TripSessionState) {
if (tripSessionState == TripSessionState.STOPPED) {
navigationMapboxMap?.removeRoute()
updateCameraOnNavigationStateChange(false)
}
}
}
}