Garmin/app/src/main/java/eu/ztsh/garmin/mapbox/MapControl.kt
2024-09-21 00:22:53 +02:00

189 lines
7.5 KiB
Kotlin

/*
* Garmin HUD Companion Application
* Copyright (C) 2022 Piotr Dec / ztsh.eu
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package eu.ztsh.garmin.mapbox
import android.content.res.Configuration
import android.content.res.Resources
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import com.mapbox.geojson.Point
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.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 eu.ztsh.garmin.MainActivity
import eu.ztsh.garmin.UI
import eu.ztsh.garmin.mock.ReplayResources
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 navigationStatusControl = NavigationStatusControl()
val tripControl = TripControl(this, TripMode.GPS)
// 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
private val searchControl = SearchControl(this, ui)
fun init() {
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
}
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 routeToPoint(point: Point) {
routeControl.findRoute(point)
}
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
}
tripControl.initLocation()
}
fun mapboxNavigation(): MapboxNavigation {
return (context as MainActivity).mapboxNavigation
}
override fun onAttached(mapboxNavigation: MapboxNavigation) {
mapboxNavigation.registerRoutesObserver(routesObserver)
mapboxNavigation.registerLocationObserver(locationObserver)
mapboxNavigation.registerRouteProgressObserver(routeProgressObserver)
mapboxNavigation.registerVoiceInstructionsObserver(voiceInstructionsObserver)
navigationStatusControl.registerObserver(searchControl)
tripControl.onAttached(mapboxNavigation)
}
override fun onDetached(mapboxNavigation: MapboxNavigation) {
mapboxNavigation.unregisterRoutesObserver(routesObserver)
mapboxNavigation.unregisterLocationObserver(locationObserver)
mapboxNavigation.unregisterRouteProgressObserver(routeProgressObserver)
mapboxNavigation.unregisterVoiceInstructionsObserver(voiceInstructionsObserver)
navigationStatusControl.unregisterObserver(searchControl)
tripControl.onDetached(mapboxNavigation)
}
fun onDestroy() {
routeControl.cancel()
voiceControl.cancel()
}
companion object {
const val TAG = "MAPCTRL"
}
}