feat!: Application outline

This commit is contained in:
Piotr Dec 2024-07-23 00:55:59 +02:00
parent 80dfa6ab4e
commit 01fbf32042
Signed by: stawros
GPG key ID: F89F27AD8F881A91
9 changed files with 1440 additions and 190 deletions

View file

@ -1,102 +1,153 @@
package eu.ztsh.garmin.mapbox
import android.content.res.Configuration
import android.content.res.Resources
import android.util.Log
import com.mapbox.api.directions.v5.models.RouteOptions
import com.mapbox.maps.EdgeInsets
import com.mapbox.maps.MapView
import com.mapbox.maps.Style
import com.mapbox.maps.plugin.gestures.gestures
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import com.mapbox.maps.ImageHolder
import com.mapbox.maps.plugin.LocationPuck2D
import com.mapbox.maps.plugin.animation.camera
import com.mapbox.maps.plugin.locationcomponent.location
import com.mapbox.maps.plugin.viewport.data.FollowPuckViewportStateOptions
import com.mapbox.maps.plugin.viewport.state.FollowPuckViewportState
import com.mapbox.maps.plugin.viewport.viewport
import com.mapbox.navigation.base.extensions.applyDefaultNavigationOptions
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.base.options.NavigationOptions
import com.mapbox.navigation.core.MapboxNavigation
import com.mapbox.navigation.core.directions.session.RoutesObserver
import com.mapbox.navigation.core.lifecycle.MapboxNavigationApp
import com.mapbox.navigation.core.lifecycle.MapboxNavigationObserver
import com.mapbox.navigation.core.trip.session.LocationObserver
import com.mapbox.navigation.core.trip.session.RouteProgressObserver
import com.mapbox.navigation.core.trip.session.VoiceInstructionsObserver
import com.mapbox.navigation.ui.maps.camera.NavigationCamera
import com.mapbox.navigation.ui.maps.camera.data.MapboxNavigationViewportDataSource
import com.mapbox.navigation.ui.maps.camera.lifecycle.NavigationBasicGesturesHandler
import com.mapbox.navigation.ui.maps.camera.state.NavigationCameraState
import com.mapbox.navigation.ui.maps.location.NavigationLocationProvider
import com.mapbox.navigation.utils.internal.toPoint
import eu.ztsh.garmin.MainActivity
import eu.ztsh.garmin.UI
import eu.ztsh.garmin.mock.ReplayResources
class MapControl(val mapView: MapView, private val resources: Resources) {
class MapControl(
val context: AppCompatActivity,
val ui: UI,
private val resources: Resources
) : MapboxNavigationObserver {
/**
* Used to execute camera transitions based on the data generated by the [viewportDataSource].
* This includes transitions from route overview to route following and continuously updating the camera as the location changes.
*/
lateinit var navigationCamera: NavigationCamera
/**
* Produces the camera frames based on the location and routing data for the [navigationCamera] to execute.
*/
lateinit var viewportDataSource: MapboxNavigationViewportDataSource
/**
* [NavigationLocationProvider] is a utility class that helps to provide location updates generated by the Navigation SDK
* to the Maps SDK in order to update the user location indicator on the map.
*/
val navigationLocationProvider = NavigationLocationProvider()
val routesRequestCallback = object : NavigationRouterCallback {
override fun onRoutesReady(routes: List<NavigationRoute>, @RouterOrigin routerOrigin: String) {
MapboxNavigationApp.current()?.setNavigationRoutes(routes)
}
override fun onFailure(reasons: List<RouterFailure>, routeOptions: RouteOptions) {
Log.e(TAG, "onFailure: ")
}
override fun onCanceled(routeOptions: RouteOptions, @RouterOrigin routerOrigin: String) {
Log.w(TAG, "onCanceled: ")
}
}
val replay = ReplayResources(this)
// Observers
private lateinit var routeControl: RouteControl
private lateinit var voiceControl: VoiceControl
private lateinit var routesObserver: RoutesObserver
private lateinit var locationObserver: LocationObserver
private lateinit var routeProgressObserver: RouteProgressObserver
private lateinit var voiceInstructionsObserver: VoiceInstructionsObserver
fun init() {
mapView.mapboxMap.loadStyle(Style.TRAFFIC_DAY) // TODO: base on sun position
viewportDataSource = MapboxNavigationViewportDataSource(ui.mapView.mapboxMap)
if (this.resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE) {
viewportDataSource.overviewPadding = UI.landscapeOverviewPadding
} else {
viewportDataSource.overviewPadding = UI.overviewPadding
}
if (this.resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE) {
viewportDataSource.followingPadding = UI.landscapeFollowingPadding
} else {
viewportDataSource.followingPadding = UI.followingPadding
}
mapView.location.apply {
// locationProvider = this.getLocationProvider()
// setLocationProvider(navigationLocationProvider)
navigationCamera = NavigationCamera(
ui.mapView.mapboxMap,
ui.mapView.camera,
viewportDataSource
)
// set the animations lifecycle listener to ensure the NavigationCamera stops
// automatically following the user location when the map is interacted with
ui.mapView.camera.addCameraAnimationsLifecycleListener(
NavigationBasicGesturesHandler(navigationCamera)
)
navigationCamera.registerNavigationCameraStateChangeObserver { navigationCameraState ->
// shows/hide the recenter button depending on the camera state
when (navigationCameraState) {
NavigationCameraState.TRANSITION_TO_FOLLOWING,
NavigationCameraState.FOLLOWING -> ui.recenter.visibility = View.INVISIBLE
NavigationCameraState.TRANSITION_TO_OVERVIEW,
NavigationCameraState.OVERVIEW,
NavigationCameraState.IDLE -> ui.recenter.visibility = View.VISIBLE
}
}
routeControl = RouteControl(this, ui, context)
voiceControl = VoiceControl(ui, context)
routesObserver = routeControl.routesObserver
locationObserver = LocationObserver(this)
routeProgressObserver = routeControl.routeProgressObserver
voiceInstructionsObserver = voiceControl.voiceInstructionsObserver
}
fun initNavigation() {
MapboxNavigationApp.setup(
NavigationOptions.Builder(context)
.build()
)
// initialize location puck
ui.mapView.location.apply {
setLocationProvider(navigationLocationProvider)
this.locationPuck = LocationPuck2D(
bearingImage = ImageHolder.Companion.from(
com.mapbox.navigation.ui.maps.R.drawable.mapbox_navigation_puck_icon
)
)
puckBearingEnabled = true
enabled = true
}
follow(true)
setGestures(mapView)
replay.replayOriginLocation()
}
fun follow(immediately: Boolean = false) {
mapView.viewport.apply {
// transition to followPuckViewportState with default transition
val followPuckViewportState: FollowPuckViewportState = this.makeFollowPuckViewportState(
FollowPuckViewportStateOptions.Builder()
// .bearing(FollowPuckViewportStateBearing.Constant(0.0))
.padding(EdgeInsets(200.0 * resources.displayMetrics.density, 0.0, 0.0, 0.0))
.build()
)
if (immediately) {
val immediateTransition = this.makeImmediateViewportTransition()
this.transitionTo(followPuckViewportState, immediateTransition) { success ->
Log.d(TAG, "follow: $success")
}
} else {
this.transitionTo(followPuckViewportState) { success ->
Log.d(TAG, "follow: $success")
}
}
}
fun mapboxNavigation(): MapboxNavigation {
return (context as MainActivity).mapboxNavigation
}
private fun setGestures(mapView: MapView) {
mapView.gestures.apply {
addOnMapClickListener { point ->
mapView.location.isLocatedAt(point) { isPuckLocatedAtPoint ->
if (isPuckLocatedAtPoint) {
follow()
}
}
true
}
addOnMapLongClickListener { point ->
MapboxNavigationApp.current()?.requestRoutes(
RouteOptions.builder()
.applyDefaultNavigationOptions()
.coordinatesList(mutableListOf(navigationLocationProvider.lastLocation!!.toPoint(), point))
.build(),
routesRequestCallback
)
true
}
}
override fun onAttached(mapboxNavigation: MapboxNavigation) {
mapboxNavigation.registerRoutesObserver(routesObserver)
mapboxNavigation.registerLocationObserver(locationObserver)
mapboxNavigation.registerRouteProgressObserver(routeProgressObserver)
mapboxNavigation.registerVoiceInstructionsObserver(voiceInstructionsObserver)
replay.onAttached(mapboxNavigation)
}
override fun onDetached(mapboxNavigation: MapboxNavigation) {
mapboxNavigation.unregisterRoutesObserver(routesObserver)
mapboxNavigation.unregisterLocationObserver(locationObserver)
mapboxNavigation.unregisterRouteProgressObserver(routeProgressObserver)
mapboxNavigation.unregisterVoiceInstructionsObserver(voiceInstructionsObserver)
replay.onDetached(mapboxNavigation)
}
fun onDestroy() {
routeControl.cancel()
voiceControl.cancel()
}
companion object {