Skip to content

Commit

Permalink
Create a delegate for MapboxNavigation
Browse files Browse the repository at this point in the history
  • Loading branch information
kmadsen committed Aug 30, 2022
1 parent 6567290 commit 254b936
Show file tree
Hide file tree
Showing 9 changed files with 616 additions and 115 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ Mapbox welcomes participation and contributions from everyone.

## Unreleased
#### Features
- Added `RequireMapboxNavigationDelegate` and `requireMapboxNavigation` to offer a simple way to use `MapboxNavigationApp`. [#6233](https://github.com/mapbox/mapbox-navigation-android/pull/6233)
#### Bug fixes and improvements
- Fixed an issue where portions of alternative routes that overlap with the primary route weren't hidden correctly, suffering from precision problems. [#6228](https://github.com/mapbox/mapbox-navigation-android/pull/6228)
- Fixed incorrect values in `AlternativeRouteInfo#duration` and `RouteProgress#durationRemaining`: now they rely on `route.leg.annotations.duration` if available, otherwise, `LegStep#duration` is used for calculations. [#6237](https://github.com/mapbox/mapbox-navigation-android/pull/6237)
Expand Down
9 changes: 9 additions & 0 deletions libnavigation-core/api/current.txt
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,15 @@ package com.mapbox.navigation.core.lifecycle {
method public com.mapbox.navigation.base.options.NavigationOptions createNavigationOptions();
}

public final class RequireMapboxNavigationDelegate implements kotlin.properties.ReadOnlyProperty<androidx.lifecycle.LifecycleOwner,com.mapbox.navigation.core.MapboxNavigation> {
ctor public RequireMapboxNavigationDelegate(com.mapbox.navigation.core.lifecycle.MapboxNavigationObserver? onCreatedObserver = null, com.mapbox.navigation.core.lifecycle.MapboxNavigationObserver? onStartedObserver = null, com.mapbox.navigation.core.lifecycle.MapboxNavigationObserver? onResumedObserver = null, kotlin.jvm.functions.Function0<kotlin.Unit>? onInitialize = null);
method public com.mapbox.navigation.core.MapboxNavigation getValue(androidx.lifecycle.LifecycleOwner thisRef, kotlin.reflect.KProperty<?> property);
}

public final class RequireMapboxNavigationDelegateKt {
method public static com.mapbox.navigation.core.lifecycle.RequireMapboxNavigationDelegate requireMapboxNavigation(com.mapbox.navigation.core.lifecycle.MapboxNavigationObserver? onCreatedObserver = null, com.mapbox.navigation.core.lifecycle.MapboxNavigationObserver? onStartedObserver = null, com.mapbox.navigation.core.lifecycle.MapboxNavigationObserver? onResumedObserver = null, kotlin.jvm.functions.Function0<kotlin.Unit>? onInitialize = null);
}

}

package com.mapbox.navigation.core.navigator {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ internal class MapboxNavigationOwner {
attached = false
services.forEach { it.onDetached(mapboxNavigation!!) }
MapboxNavigationProvider.destroy()
logI("disabled ${services.size} observers", LOG_CATEGORY)
}
}

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

import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import com.mapbox.navigation.core.MapboxNavigation
import kotlin.properties.ReadOnlyProperty
import kotlin.reflect.KProperty

/**
* Extension function to make it simple to create the [RequireMapboxNavigationDelegate]. Below are
* a couple examples of how you may use the delegate.
*
* Default can be used when [MapboxNavigationApp] is setup elsewhere.
* ```
* val mapboxNavigation by requireMapboxNavigation()
* ```
*
* Initialize the [MapboxNavigationApp] when you are ready to use it
* ```
* val mapboxNavigation by requireMapboxNavigation {
* MapboxNavigationApp.setup(..)
* }
* ```
*
* Register subscriptions and setup MapboxNavigationApp
* ```
* private val mapboxNavigation by requireMapboxNavigation(
* onResumedObserver = object : MapboxNavigationObserver {
* override fun onAttached(mapboxNavigation: MapboxNavigation) {
* mapboxNavigation.registerLocationObserver(locationObserver)
* mapboxNavigation.registerRoutesObserver(routesObserver)
* }
* override fun onDetached(mapboxNavigation: MapboxNavigation) {
* mapboxNavigation.unregisterLocationObserver(locationObserver)
* mapboxNavigation.unregisterRoutesObserver(routesObserver)
* }
* }
* ) {
* MapboxNavigationApp.setup(
* NavigationOptions.Builder(this)
* .accessToken(accessToken)
* .build()
* )
* }
* ```
*
* @see [RequireMapboxNavigationDelegate] for more details.
*/
fun requireMapboxNavigation(
onCreatedObserver: MapboxNavigationObserver? = null,
onStartedObserver: MapboxNavigationObserver? = null,
onResumedObserver: MapboxNavigationObserver? = null,
onInitialize: (() -> Unit)? = null,
) = RequireMapboxNavigationDelegate(
onCreatedObserver = onCreatedObserver,
onStartedObserver = onStartedObserver,
onResumedObserver = onResumedObserver,
onInitialize = onInitialize
)

/**
* Attaches a [LifecycleOwner] to [MapboxNavigationApp] and provides access to [MapboxNavigation].
*
* You can choose to call [MapboxNavigationApp.setup] in the [onInitialize]. You can also setup in
* the onCreate calls, or any call that happens before this delegate is accessed. The delegate will
* crash if the app is not setup and an attached has been created.
*
* You can use the observers parameter to setup any subscriptions. This is important because the
* [MapboxNavigation] instance can be re-created with [MapboxNavigationApp.disable], or if all
* [MapboxNavigationApp.attach] lifecycles are destroyed.
*
* @param onCreatedObserver registered to the [Lifecycle.State.CREATED] lifecycle
* @param onStartedObserver registered to the [Lifecycle.State.STARTED] lifecycle
* @param onResumedObserver registered to the [Lifecycle.State.RESUMED] lifecycle
* @param onInitialize called when the property is read for the first time
*/
class RequireMapboxNavigationDelegate(
private val onCreatedObserver: MapboxNavigationObserver? = null,
private val onStartedObserver: MapboxNavigationObserver? = null,
private val onResumedObserver: MapboxNavigationObserver? = null,
private val onInitialize: (() -> Unit)? = null
) : ReadOnlyProperty<LifecycleOwner, MapboxNavigation> {

private lateinit var lifecycleOwner: LifecycleOwner

private val lifecycleObserver = object : DefaultLifecycleObserver {
override fun onCreate(owner: LifecycleOwner) {
onCreatedObserver?.let { MapboxNavigationApp.registerObserver(it) }
}

override fun onDestroy(owner: LifecycleOwner) {
onCreatedObserver?.let { MapboxNavigationApp.unregisterObserver(it) }
}

override fun onStart(owner: LifecycleOwner) {
onStartedObserver?.let { MapboxNavigationApp.registerObserver(it) }
}

override fun onStop(owner: LifecycleOwner) {
onStartedObserver?.let { MapboxNavigationApp.unregisterObserver(it) }
}

override fun onResume(owner: LifecycleOwner) {
onResumedObserver?.let { MapboxNavigationApp.registerObserver(it) }
}

override fun onPause(owner: LifecycleOwner) {
onResumedObserver?.let { MapboxNavigationApp.unregisterObserver(it) }
}
}

/**
* Returns an instance of [MapboxNavigation], the first retrieval will attach the [thisRef]
* to [MapboxNavigationApp.attach]. If [MapboxNavigationApp.isSetup] is false after all
* observers and initializers, this property getter will crash.
*
* @param thisRef - the [LifecycleOwner] that needs access to [MapboxNavigation].
* @param property - ignored
*/
override fun getValue(thisRef: LifecycleOwner, property: KProperty<*>): MapboxNavigation {
if (!this::lifecycleOwner.isInitialized) {
onInitialize?.invoke()
this.lifecycleOwner = thisRef
MapboxNavigationApp.attach(lifecycleOwner)
lifecycleOwner.lifecycle.addObserver(lifecycleObserver)
}
val mapboxNavigation = MapboxNavigationApp.current()
checkNotNull(mapboxNavigation) {
"MapboxNavigation cannot be null. Ensure that MapboxNavigationApp is setup and an" +
" attached lifecycle is at least CREATED."
}
return mapboxNavigation
}
}
Loading

0 comments on commit 254b936

Please sign in to comment.