Skip to content

Commit

Permalink
Adasis example activity
Browse files Browse the repository at this point in the history
  • Loading branch information
DzmitryFomchyn committed Jan 16, 2024
1 parent b2301f6 commit 08b55d3
Show file tree
Hide file tree
Showing 6 changed files with 365 additions and 11 deletions.
6 changes: 6 additions & 0 deletions examples/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,12 @@
android:label="@string/title_multileg_route">
</activity>

<activity
android:name=".AdasisActivity"
android:label="@string/title_adasis"
android:screenOrientation="portrait">
</activity>

<activity
android:name="com.mapbox.navigation.examples.MainActivity"
android:exported="true">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import androidx.recyclerview.widget.LinearLayoutManager
import com.mapbox.android.core.permissions.PermissionsListener
import com.mapbox.common.LogConfiguration
import com.mapbox.common.LoggingLevel
import com.mapbox.navigation.examples.core.AdasisActivity
import com.mapbox.navigation.examples.core.IndependentRouteGenerationActivity
import com.mapbox.navigation.examples.core.MapboxBuildingHighlightActivity
import com.mapbox.navigation.examples.core.MapboxCustomStyleActivity
Expand Down Expand Up @@ -143,6 +144,11 @@ class MainActivity : AppCompatActivity(), PermissionsListener {
getString(R.string.description_draw_utility),
RouteDrawingActivity::class.java
),
SampleItem(
getString(R.string.title_adasis),
getString(R.string.description_adasis),
AdasisActivity::class.java
)
)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,319 @@
package com.mapbox.navigation.examples.core

import android.annotation.SuppressLint
import android.location.Location
import android.os.Bundle
import android.util.Log
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import com.mapbox.api.directions.v5.models.DirectionsRoute
import com.mapbox.api.directions.v5.models.RouteOptions
import com.mapbox.geojson.Point
import com.mapbox.maps.CameraOptions
import com.mapbox.maps.EdgeInsets
import com.mapbox.maps.MapboxMap
import com.mapbox.maps.Style
import com.mapbox.maps.plugin.animation.CameraAnimationsPlugin
import com.mapbox.maps.plugin.animation.MapAnimationOptions
import com.mapbox.maps.plugin.animation.camera
import com.mapbox.maps.plugin.gestures.gestures
import com.mapbox.maps.plugin.locationcomponent.LocationComponentPlugin
import com.mapbox.maps.plugin.locationcomponent.location
import com.mapbox.navigation.base.ExperimentalPreviewMapboxNavigationAPI
import com.mapbox.navigation.base.extensions.applyDefaultNavigationOptions
import com.mapbox.navigation.base.extensions.applyLanguageAndVoiceUnitOptions
import com.mapbox.navigation.base.options.NavigationOptions
import com.mapbox.navigation.base.route.NavigationRoute
import com.mapbox.navigation.base.route.NavigationRouterCallback
import com.mapbox.navigation.base.route.RouterFailure
import com.mapbox.navigation.base.route.RouterOrigin
import com.mapbox.navigation.core.MapboxNavigation
import com.mapbox.navigation.core.MapboxNavigationProvider
import com.mapbox.navigation.core.adasis.AdasisConfig
import com.mapbox.navigation.core.directions.session.RoutesObserver
import com.mapbox.navigation.core.replay.MapboxReplayer
import com.mapbox.navigation.core.replay.ReplayLocationEngine
import com.mapbox.navigation.core.replay.route.ReplayProgressObserver
import com.mapbox.navigation.core.replay.route.ReplayRouteMapper
import com.mapbox.navigation.core.trip.session.LocationMatcherResult
import com.mapbox.navigation.core.trip.session.LocationObserver
import com.mapbox.navigation.core.trip.session.RouteProgressObserver
import com.mapbox.navigation.examples.core.databinding.LayoutActivityAdasisBinding
import com.mapbox.navigation.examples.core.waypoints.WaypointsController
import com.mapbox.navigation.ui.maps.location.NavigationLocationProvider
import com.mapbox.navigation.ui.maps.route.arrow.api.MapboxRouteArrowApi
import com.mapbox.navigation.ui.maps.route.arrow.api.MapboxRouteArrowView
import com.mapbox.navigation.ui.maps.route.arrow.model.RouteArrowOptions
import com.mapbox.navigation.ui.maps.route.line.MapboxRouteLineApiExtensions.setNavigationRoutes
import com.mapbox.navigation.ui.maps.route.line.api.MapboxRouteLineApi
import com.mapbox.navigation.ui.maps.route.line.api.MapboxRouteLineView
import com.mapbox.navigation.ui.maps.route.line.model.MapboxRouteLineOptions
import com.mapbox.navigation.ui.maps.route.line.model.RouteLineResources
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch

class AdasisActivity : AppCompatActivity() {

private lateinit var mapboxMap: MapboxMap
private lateinit var mapCamera: CameraAnimationsPlugin
private lateinit var mapboxNavigation: MapboxNavigation
private lateinit var binding: LayoutActivityAdasisBinding
private lateinit var locationComponent: LocationComponentPlugin
private var isNavigating = false

private val mapboxReplayer = MapboxReplayer()
private val navigationLocationProvider = NavigationLocationProvider()
private val waypointsController = WaypointsController()

private val routeLineResources: RouteLineResources by lazy {
RouteLineResources.Builder().build()
}

private val options: MapboxRouteLineOptions by lazy {
MapboxRouteLineOptions.Builder(this)
.withRouteLineResources(routeLineResources)
.withRouteLineBelowLayerId("road-label")
.build()
}

private val routeLineView by lazy {
MapboxRouteLineView(options)
}

private val routeLineApi: MapboxRouteLineApi by lazy {
MapboxRouteLineApi(options)
}

private val routeArrowApi: MapboxRouteArrowApi by lazy {
MapboxRouteArrowApi()
}

private val routeArrowView: MapboxRouteArrowView by lazy {
MapboxRouteArrowView(RouteArrowOptions.Builder(this).build())
}

private val replayProgressObserver = ReplayProgressObserver(mapboxReplayer)

private val routeProgressObserver = RouteProgressObserver { routeProgress ->
routeArrowApi.addUpcomingManeuverArrow(routeProgress).apply {
routeArrowView.renderManeuverUpdate(mapboxMap.getStyle()!!, this)
}
}

private val locationObserver = object : LocationObserver {
override fun onNewRawLocation(rawLocation: Location) {}
override fun onNewLocationMatcherResult(locationMatcherResult: LocationMatcherResult) {
navigationLocationProvider.changePosition(
locationMatcherResult.enhancedLocation,
locationMatcherResult.keyPoints,
)
if (isNavigating) {
updateCamera(locationMatcherResult.enhancedLocation)
}
}
}

private val routesObserver = RoutesObserver { result ->
if (result.navigationRoutes.isNotEmpty()) {
CoroutineScope(Dispatchers.Main).launch {
routeLineApi.setNavigationRoutes(result.navigationRoutes).apply {
routeLineView.renderRouteDrawData(mapboxMap.getStyle()!!, this)
}
}
isNavigating = true
startSimulation(result.navigationRoutes[0].directionsRoute)
}
}

private var adasisMessagesLog: String = "Received adasis messages:\n"
private var numberOfMessages = 1

private fun init() {
initNavigation()
initStyle()
}

@SuppressLint("MissingPermission")
private fun initNavigation() {
mapboxNavigation = MapboxNavigationProvider.create(
NavigationOptions.Builder(this@AdasisActivity)
.accessToken(getMapboxAccessTokenFromResources())
.locationEngine(ReplayLocationEngine(mapboxReplayer))
.build()
)
mapboxNavigation.registerLocationObserver(object : LocationObserver {
override fun onNewRawLocation(rawLocation: Location) {
updateCamera(rawLocation)
navigationLocationProvider.changePosition(
rawLocation,
)
mapboxNavigation.unregisterLocationObserver(this)
}

override fun onNewLocationMatcherResult(
locationMatcherResult: LocationMatcherResult,
) {
//
}
})
mapboxNavigation.startTripSession()
mapboxReplayer.pushRealLocation(this, 0.0)
mapboxReplayer.play()
}

@SuppressLint("MissingPermission")
private fun initStyle() {
mapboxMap.loadStyleUri(Style.MAPBOX_STREETS) { style ->
routeLineView.initializeLayers(style)
binding.mapView.gestures.addOnMapLongClickListener { point ->
val currentLocation = navigationLocationProvider.lastLocation
if (currentLocation != null) {
waypointsController.add(point)
val origin = Point.fromLngLat(
currentLocation.longitude,
currentLocation.latitude
)
findRoute(origin)
}
false
}
}
}

@SuppressLint("DiscouragedApi")
private fun getMapboxAccessTokenFromResources(): String {
return getString(
resources.getIdentifier("mapbox_access_token", "string", packageName)
)
}

private fun getMapCamera(): CameraAnimationsPlugin {
return binding.mapView.camera
}

@SuppressLint("MissingPermission")
private fun startSimulation(route: DirectionsRoute) {
mapboxReplayer.stop()
mapboxReplayer.clearEvents()
mapboxReplayer.pushRealLocation(this, 0.0)
val replayEvents = ReplayRouteMapper().mapDirectionsRouteGeometry(route)
mapboxReplayer.pushEvents(replayEvents)
mapboxReplayer.seekTo(replayEvents.first())
mapboxReplayer.play()
}

private fun updateCamera(location: Location) {
val mapAnimationOptionsBuilder = MapAnimationOptions.Builder()
mapAnimationOptionsBuilder.duration(1500L)
mapCamera.easeTo(
CameraOptions.Builder()
.center(Point.fromLngLat(location.longitude, location.latitude))
.bearing(location.bearing.toDouble())
.pitch(45.0)
.zoom(17.0)
.padding(EdgeInsets(1000.0, 0.0, 0.0, 0.0))
.build(),
mapAnimationOptionsBuilder.build()
)
}

private fun findRoute(origin: Point) {
val coordinates = waypointsController.coordinates(origin)
val routeOptions = RouteOptions.builder()
.applyDefaultNavigationOptions()
.applyLanguageAndVoiceUnitOptions(this)
.coordinatesList(coordinates)
.layersList(
ArrayList<Int?>(coordinates.size).apply {
add(mapboxNavigation.getZLevel())
repeat(coordinates.size - 1) { add(null) }
},
)
.build()

mapboxNavigation.requestRoutes(
routeOptions,
object : NavigationRouterCallback {
override fun onRoutesReady(
routes: List<NavigationRoute>,
routerOrigin: RouterOrigin,
) {
mapboxNavigation.setNavigationRoutes(routes)
}

override fun onFailure(reasons: List<RouterFailure>, routeOptions: RouteOptions) {
// no impl
}

override fun onCanceled(routeOptions: RouteOptions, routerOrigin: RouterOrigin) {
// no impl
}
}
)
}

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

binding = LayoutActivityAdasisBinding.inflate(layoutInflater)
setContentView(binding.root)

mapboxMap = binding.mapView.getMapboxMap()
binding.adasisMsgLog.text = adasisMessagesLog

locationComponent = binding.mapView.location.apply {
setLocationProvider(navigationLocationProvider)
enabled = true
}
mapCamera = getMapCamera()

init()
}

@OptIn(ExperimentalPreviewMapboxNavigationAPI::class)
override fun onStart() {
super.onStart()
if (::mapboxNavigation.isInitialized) {
mapboxNavigation.registerRoutesObserver(routesObserver)
mapboxNavigation.registerLocationObserver(locationObserver)
mapboxNavigation.registerRouteProgressObserver(routeProgressObserver)
mapboxNavigation.registerRouteProgressObserver(replayProgressObserver)

mapboxNavigation.setAdasisMessageCallback(
AdasisConfig.Builder().build()
) { messageBuffer, context ->
this@AdasisActivity.runOnUiThread {
// TODO decode buffer and print data
adasisMessagesLog += "${numberOfMessages++}: ${messageBuffer.size} bytes\n"
binding.adasisMsgLog.text = adasisMessagesLog
binding.scrollContainer.fullScroll(View.FOCUS_DOWN)

Log.d(TAG, "Adasis message: $messageBuffer, context: $context")
}
}
}
}

@OptIn(ExperimentalPreviewMapboxNavigationAPI::class)
override fun onStop() {
super.onStop()
mapboxNavigation.unregisterRoutesObserver(routesObserver)
mapboxNavigation.unregisterLocationObserver(locationObserver)
mapboxNavigation.unregisterRouteProgressObserver(routeProgressObserver)
mapboxNavigation.unregisterRouteProgressObserver(replayProgressObserver)
mapboxNavigation.resetAdasisMessageCallback()
}

override fun onDestroy() {
super.onDestroy()
routeLineApi.cancel()
routeLineView.cancel()
mapboxReplayer.finish()
mapboxNavigation.onDestroy()
}

private companion object {
val TAG = AdasisActivity::class.simpleName
}
}
Loading

0 comments on commit 08b55d3

Please sign in to comment.