189 lines
7.5 KiB
Kotlin
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"
|
|
|
|
}
|
|
}
|