diff --git a/app/build.gradle b/app/build.gradle index a37a97c0..8c6d7f81 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -69,7 +69,7 @@ android { dependencies { // Mapbox Navigation SDK - implementation "com.mapbox.navigation:android:2.8.0-alpha.2" + implementation "com.mapbox.navigation:android:2.8.0-alpha.3" implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.5.31" implementation "androidx.core:core-ktx:1.7.0" implementation "com.google.android.material:material:1.5.0" diff --git a/app/src/main/java/com/mapbox/navigation/examples/MainActivity.kt b/app/src/main/java/com/mapbox/navigation/examples/MainActivity.kt index e3337daa..c528d6bf 100644 --- a/app/src/main/java/com/mapbox/navigation/examples/MainActivity.kt +++ b/app/src/main/java/com/mapbox/navigation/examples/MainActivity.kt @@ -13,6 +13,7 @@ import androidx.recyclerview.widget.LinearLayoutManager import com.mapbox.android.core.permissions.PermissionsListener import com.mapbox.android.core.permissions.PermissionsManager import com.mapbox.android.core.permissions.PermissionsManager.areLocationPermissionsGranted +import com.mapbox.navigation.core.lifecycle.MapboxNavigationApp import com.mapbox.navigation.examples.databinding.ActivityMainBinding class MainActivity : AppCompatActivity(), PermissionsListener { @@ -28,6 +29,9 @@ class MainActivity : AppCompatActivity(), PermissionsListener { return } + // Each example needs to call MapboxNavigationApp.setup. + MapboxNavigationApp.disable() + binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) diff --git a/app/src/main/java/com/mapbox/navigation/examples/alternative/ShowAlternativeRoutesActivity.kt b/app/src/main/java/com/mapbox/navigation/examples/alternative/ShowAlternativeRoutesActivity.kt index 49d324c2..865b6363 100644 --- a/app/src/main/java/com/mapbox/navigation/examples/alternative/ShowAlternativeRoutesActivity.kt +++ b/app/src/main/java/com/mapbox/navigation/examples/alternative/ShowAlternativeRoutesActivity.kt @@ -254,7 +254,7 @@ class ShowAlternativeRoutesActivity : AppCompatActivity() { } } - val navigationResumedObserver = object : MapboxNavigationObserver { + private val navigationResumedObserver = object : MapboxNavigationObserver { override fun onAttached(mapboxNavigation: MapboxNavigation) { mapboxNavigation.registerLocationObserver(locationObserver) mapboxNavigation.registerRouteProgressObserver(replayProgressObserver) @@ -274,7 +274,7 @@ class ShowAlternativeRoutesActivity : AppCompatActivity() { init { // You can setup MapboxNavigation at any part of the app lifecycle. - MapboxNavigationApp.setup( + MapboxNavigationApp.setup { NavigationOptions.Builder(this) .accessToken(getString(R.string.mapbox_access_token)) .locationEngine(ReplayLocationEngine(mapboxReplayer)) @@ -284,25 +284,7 @@ class ShowAlternativeRoutesActivity : AppCompatActivity() { .build() ) .build() - ).attach(this) - - lifecycle.addObserver(object : DefaultLifecycleObserver { - override fun onCreate(owner: LifecycleOwner) { - MapboxNavigationApp.registerObserver(navigationCreatedObserver) - } - - override fun onResume(owner: LifecycleOwner) { - MapboxNavigationApp.registerObserver(navigationResumedObserver) - } - - override fun onPause(owner: LifecycleOwner) { - MapboxNavigationApp.unregisterObserver(navigationResumedObserver) - } - - override fun onDestroy(owner: LifecycleOwner) { - MapboxNavigationApp.unregisterObserver(navigationCreatedObserver) - } - }) + }.attach(this) } override fun onCreate(savedInstanceState: Bundle?) { @@ -322,11 +304,23 @@ class ShowAlternativeRoutesActivity : AppCompatActivity() { findRoute(originPoint, destinationPoint) } + MapboxNavigationApp.registerObserver(navigationCreatedObserver) replayOriginLocation() } + override fun onResume() { + super.onResume() + MapboxNavigationApp.registerObserver(navigationResumedObserver) + } + + override fun onPause() { + super.onPause() + MapboxNavigationApp.unregisterObserver(navigationResumedObserver) + } + override fun onDestroy() { super.onDestroy() + MapboxNavigationApp.unregisterObserver(navigationCreatedObserver) routeLineApi.cancel() routeLineView.cancel() mapboxReplayer.finish() diff --git a/app/src/main/java/com/mapbox/navigation/examples/junctions/ShowJunctionsActivity.kt b/app/src/main/java/com/mapbox/navigation/examples/junctions/ShowJunctionsActivity.kt index 1ede8d7f..e35c6a2c 100644 --- a/app/src/main/java/com/mapbox/navigation/examples/junctions/ShowJunctionsActivity.kt +++ b/app/src/main/java/com/mapbox/navigation/examples/junctions/ShowJunctionsActivity.kt @@ -5,6 +5,8 @@ import android.location.Location import android.os.Bundle import android.view.View.GONE import androidx.appcompat.app.AppCompatActivity +import androidx.lifecycle.DefaultLifecycleObserver +import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.lifecycleScope import com.mapbox.api.directions.v5.models.DirectionsRoute import com.mapbox.bindgen.Expected @@ -21,8 +23,10 @@ import com.mapbox.navigation.base.options.NavigationOptions import com.mapbox.navigation.base.route.NavigationRoute import com.mapbox.navigation.base.route.toNavigationRoute import com.mapbox.navigation.core.MapboxNavigation -import com.mapbox.navigation.core.MapboxNavigationProvider 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.lifecycle.NavigationOptionsProvider import com.mapbox.navigation.core.replay.MapboxReplayer import com.mapbox.navigation.core.replay.ReplayLocationEngine import com.mapbox.navigation.core.replay.route.ReplayProgressObserver @@ -30,6 +34,7 @@ import com.mapbox.navigation.core.replay.route.ReplayRouteMapper import com.mapbox.navigation.core.trip.session.BannerInstructionsObserver 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.R import com.mapbox.navigation.examples.databinding.MapboxActivityShowJunctionsBinding import com.mapbox.navigation.ui.base.util.MapboxNavigationConsumer @@ -59,7 +64,6 @@ import kotlinx.coroutines.launch class ShowJunctionsActivity : AppCompatActivity() { private lateinit var mapboxMap: MapboxMap - private lateinit var mapboxNavigation: MapboxNavigation private lateinit var binding: MapboxActivityShowJunctionsBinding private lateinit var locationComponent: LocationComponentPlugin @@ -139,28 +143,39 @@ class ShowJunctionsActivity : AppCompatActivity() { junctionApi.generateJunction(bannerInstructions, junctionCallback) } - private fun init() { - initNavigation() - initStyle() + @SuppressLint("MissingPermission") + private val sessionStarter = object : MapboxNavigationObserver { + override fun onAttached(mapboxNavigation: MapboxNavigation) { + mapboxNavigation.startTripSession() + } + + override fun onDetached(mapboxNavigation: MapboxNavigation) { + mapboxNavigation.stopTripSession() + } } - @SuppressLint("MissingPermission") - private fun initNavigation() { - mapboxNavigation = MapboxNavigationProvider.create( - NavigationOptions.Builder(this) - .accessToken(getString(R.string.mapbox_access_token)) - .locationEngine(ReplayLocationEngine(mapboxReplayer)) - .build() - ) - mapboxNavigation.startTripSession() + init { + mapboxNavigationInstaller() + .onCreated(sessionStarter) + .onStarted( + mapboxLocationObserver(locationObserver), + mapboxRoutesObserver(routesObserver), + mapboxRouteProgressObserver(replayProgressObserver), + mapboxBannerInstructionsObserver(bannerInstructionsObserver), + ) + .install { + NavigationOptions.Builder(this) + .accessToken(getString(R.string.mapbox_access_token)) + .locationEngine(ReplayLocationEngine(mapboxReplayer)) + .build() + } } - @SuppressLint("MissingPermission") - private fun initStyle() { + private fun init() { mapboxMap.loadStyleUri(Style.MAPBOX_STREETS) { style -> routeLineView.initializeLayers(style) binding.actionButton.setOnClickListener { - mapboxNavigation.setNavigationRoutes(listOf(route)) + MapboxNavigationApp.current()?.setNavigationRoutes(listOf(route)) binding.actionButton.visibility = GONE } } @@ -204,28 +219,114 @@ class ShowJunctionsActivity : AppCompatActivity() { init() } - override fun onStart() { - super.onStart() - mapboxNavigation.registerRoutesObserver(routesObserver) - mapboxNavigation.registerLocationObserver(locationObserver) - mapboxNavigation.registerRouteProgressObserver(replayProgressObserver) - mapboxNavigation.registerBannerInstructionsObserver(bannerInstructionsObserver) - } - - override fun onStop() { - super.onStop() - mapboxNavigation.unregisterRoutesObserver(routesObserver) - mapboxNavigation.unregisterLocationObserver(locationObserver) - mapboxNavigation.unregisterRouteProgressObserver(replayProgressObserver) - mapboxNavigation.unregisterBannerInstructionsObserver(bannerInstructionsObserver) - } - override fun onDestroy() { super.onDestroy() routeLineApi.cancel() routeLineView.cancel() junctionApi.cancelAll() mapboxReplayer.finish() - mapboxNavigation.onDestroy() + } +} + +fun AppCompatActivity.mapboxNavigationInstaller() = MapboxNavigationActivityInstaller(this) + +fun mapboxLocationObserver(locationObserver: LocationObserver) : MapboxNavigationObserver { + return object : MapboxNavigationObserver { + override fun onAttached(mapboxNavigation: MapboxNavigation) { + mapboxNavigation.registerLocationObserver(locationObserver) + } + + override fun onDetached(mapboxNavigation: MapboxNavigation) { + mapboxNavigation.unregisterLocationObserver(locationObserver) + } + } +} + +fun mapboxRoutesObserver(routesObserver: RoutesObserver) : MapboxNavigationObserver { + return object : MapboxNavigationObserver { + override fun onAttached(mapboxNavigation: MapboxNavigation) { + mapboxNavigation.registerRoutesObserver(routesObserver) + } + + override fun onDetached(mapboxNavigation: MapboxNavigation) { + mapboxNavigation.unregisterRoutesObserver(routesObserver) + } + } +} + +fun mapboxBannerInstructionsObserver(bannerInstructionsObserver: BannerInstructionsObserver) : MapboxNavigationObserver { + return object : MapboxNavigationObserver { + override fun onAttached(mapboxNavigation: MapboxNavigation) { + mapboxNavigation.registerBannerInstructionsObserver(bannerInstructionsObserver) + } + + override fun onDetached(mapboxNavigation: MapboxNavigation) { + mapboxNavigation.unregisterBannerInstructionsObserver(bannerInstructionsObserver) + } + } +} + +fun mapboxRouteProgressObserver(routeProgressObserver: RouteProgressObserver) : MapboxNavigationObserver { + return object : MapboxNavigationObserver { + override fun onAttached(mapboxNavigation: MapboxNavigation) { + mapboxNavigation.registerRouteProgressObserver(routeProgressObserver) + } + + override fun onDetached(mapboxNavigation: MapboxNavigation) { + mapboxNavigation.unregisterRouteProgressObserver(routeProgressObserver) + } + } +} + +class MapboxNavigationActivityInstaller( + val activity: AppCompatActivity +) { + private val onCreated = mutableSetOf() + private val onStarted = mutableSetOf() + private val onResumed = mutableSetOf() + + fun onCreated(vararg observers: MapboxNavigationObserver) = apply { + onCreated.addAll(observers) + } + + fun onStarted(vararg observers: MapboxNavigationObserver) = apply { + onStarted.addAll(observers) + } + + fun onResumed(vararg observers: MapboxNavigationObserver) = apply { + onResumed.addAll(observers) + } + + fun install( + navigationOptionsProvider: NavigationOptionsProvider + ) { + MapboxNavigationApp.attach(activity) + activity.lifecycle.addObserver(object : DefaultLifecycleObserver { + override fun onCreate(owner: LifecycleOwner) { + val navigationOptions = navigationOptionsProvider.createNavigationOptions() + MapboxNavigationApp.setup(navigationOptions) + onCreated.forEach { MapboxNavigationApp.registerObserver(it) } + } + + override fun onStart(owner: LifecycleOwner) { + onStarted.forEach { MapboxNavigationApp.registerObserver(it) } + } + + override fun onResume(owner: LifecycleOwner) { + onResumed.forEach { MapboxNavigationApp.registerObserver(it) } + } + + override fun onPause(owner: LifecycleOwner) { + onResumed.reversed().forEach { MapboxNavigationApp.unregisterObserver(it) } + } + + override fun onStop(owner: LifecycleOwner) { + onStarted.reversed().forEach { MapboxNavigationApp.unregisterObserver(it) } + } + + override fun onDestroy(owner: LifecycleOwner) { + onCreated.reversed().forEach { MapboxNavigationApp.unregisterObserver(it) } + } + }) } } diff --git a/app/src/main/java/com/mapbox/navigation/examples/location/ShowCurrentLocationActivity.kt b/app/src/main/java/com/mapbox/navigation/examples/location/ShowCurrentLocationActivity.kt index 1e635982..f5b632bd 100644 --- a/app/src/main/java/com/mapbox/navigation/examples/location/ShowCurrentLocationActivity.kt +++ b/app/src/main/java/com/mapbox/navigation/examples/location/ShowCurrentLocationActivity.kt @@ -4,6 +4,9 @@ import android.annotation.SuppressLint import android.location.Location import android.os.Bundle import androidx.appcompat.app.AppCompatActivity +import androidx.lifecycle.DefaultLifecycleObserver +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleOwner import com.mapbox.geojson.Point import com.mapbox.maps.CameraOptions import com.mapbox.maps.EdgeInsets @@ -16,6 +19,9 @@ 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.MapboxNavigationProvider +import com.mapbox.navigation.core.internal.extensions.attachCreated +import com.mapbox.navigation.core.lifecycle.MapboxNavigationApp +import com.mapbox.navigation.core.lifecycle.MapboxNavigationObserver import com.mapbox.navigation.core.trip.session.LocationMatcherResult import com.mapbox.navigation.core.trip.session.LocationObserver import com.mapbox.navigation.examples.R @@ -46,6 +52,7 @@ import com.mapbox.navigation.ui.maps.location.NavigationLocationProvider * - You should see a map view with the camera transitioning to your current location. * - A blue circular puck should be visible at your current location. */ +@SuppressLint("MissingPermission") class ShowCurrentLocationActivity : AppCompatActivity() { /** @@ -91,17 +98,25 @@ class ShowCurrentLocationActivity : AppCompatActivity() { */ private lateinit var mapboxMap: MapboxMap - /** - * Mapbox Navigation entry point. There should only be one instance of this object for the app. - * You can use [MapboxNavigationProvider] to help create and obtain that instance. - */ - private lateinit var mapboxNavigation: MapboxNavigation - /** * Bindings to the example layout. */ private lateinit var binding: MapboxActivityUserCurrentLocationBinding + init { + MapboxNavigationApp.setup { + NavigationOptions.Builder(this) + .accessToken(getString(R.string.mapbox_access_token)) + .build() + }.attach( + this, + onCreate = { startTripSession() }, + onResume = { registerLocationObserver(locationObserver) }, + onPause = { unregisterLocationObserver(locationObserver) }, + onDestroy = { stopTripSession() }, + ) + } + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -127,31 +142,6 @@ class ShowCurrentLocationActivity : AppCompatActivity() { enabled = true } - init() - } - - private fun init() { - initStyle() - initNavigation() - } - - @SuppressLint("MissingPermission") - private fun initNavigation() { - mapboxNavigation = MapboxNavigationProvider.create( - NavigationOptions.Builder(this) - .accessToken(getString(R.string.mapbox_access_token)) - .build() - ).apply { - // This is important to call as the [LocationProvider] will only start sending - // location updates when the trip session has started. - startTripSession() - // Register the location observer to listen to location updates received from the - // location provider - registerLocationObserver(locationObserver) - } - } - - private fun initStyle() { mapboxMap.loadStyleUri(Style.MAPBOX_STREETS) } @@ -169,12 +159,56 @@ class ShowCurrentLocationActivity : AppCompatActivity() { mapAnimationOptions ) } +} - override fun onDestroy() { - super.onDestroy() - // make sure to stop the trip session. In this case it is being called inside `onDestroy`. - mapboxNavigation.stopTripSession() - // make sure to unregister the observer you have registered. - mapboxNavigation.unregisterLocationObserver(locationObserver) - } +private fun MapboxNavigationApp.registerCallbacks( + onAttached: (MapboxNavigation.() -> Unit)? = null, + onDetached: (MapboxNavigation.() -> Unit)? = null, +) { + registerObserver(object : MapboxNavigationObserver { + override fun onAttached(mapboxNavigation: MapboxNavigation) { + onAttached?.invoke(mapboxNavigation) + } + + override fun onDetached(mapboxNavigation: MapboxNavigation) { + onDetached?.invoke(mapboxNavigation) + } + }) +} + +private fun MapboxNavigationApp.attach( + lifecycleOwner: LifecycleOwner, + onCreate: (MapboxNavigation.() -> Unit)? = null, + onStart: (MapboxNavigation.() -> Unit)? = null, + onResume: (MapboxNavigation.() -> Unit)? = null, + onPause: (MapboxNavigation.() -> Unit)? = null, + onStop: (MapboxNavigation.() -> Unit)? = null, + onDestroy: (MapboxNavigation.() -> Unit)? = null, +) { + attach(lifecycleOwner) + lifecycleOwner.lifecycle.addObserver(object : DefaultLifecycleObserver { + override fun onCreate(owner: LifecycleOwner) { + registerCallbacks(onAttached = onCreate) + } + + override fun onStart(owner: LifecycleOwner) { + registerCallbacks(onAttached = onStart) + } + + override fun onResume(owner: LifecycleOwner) { + registerCallbacks(onAttached = onResume) + } + + override fun onPause(owner: LifecycleOwner) { + registerCallbacks(onAttached = onPause) + } + + override fun onStop(owner: LifecycleOwner) { + registerCallbacks(onAttached = onStop) + } + + override fun onDestroy(owner: LifecycleOwner) { + registerCallbacks(onAttached = onDestroy) + } + }) }