mapbox / mapbox-navigation-ios

Turn-by-turn navigation logic and UI in Swift on iOS
https://docs.mapbox.com/ios/navigation/
Other
863 stars 313 forks source link

Ask the user whether to proactively reroute #2740

Open 1ec5 opened 4 years ago

1ec5 commented 4 years ago

As long as Router.reroutesProactively is set to true, RouteController or LegacyRouteController automatically reroutes the user when it finds a faster route (subject to some heuristics around the time remaining to the destination). However, some applications may want to give the user the opportunity to accept or reject the new route, since the existing route is still valid.

NavigationViewController should optionally present a transient prompt upon receiving a faster route and reroute or stay on the current route based on the user’s choice. In CarPlay, the same UI can be implemented as a CPNavigationAlert with a duration. Both UIs would depend on new RouterDelegate.router(_:shouldProactivelyRerouteFrom:to:) and NavigationServiceDelegate.navigationService(_:shouldProactivelyRerouteFrom:to:) methods, which a custom UI could use to independently implement this prompt.

At the point where we set the new route, we currently only check a hard-coded heuristic, but this is a good opportunity to call RouterDelegate.router(_:shouldProactivelyRerouteFrom:to:) and perhaps also MapboxNavigationService.router(_:shouldRerouteFrom:):

https://github.com/mapbox/mapbox-navigation-ios/blob/0f00c9d3e36791b479e0a72e7937c37c1c089d16/MapboxCoreNavigation/Router.swift#L221-L223 https://github.com/mapbox/mapbox-navigation-ios/blob/0f00c9d3e36791b479e0a72e7937c37c1c089d16/MapboxCoreNavigation/RouteController.swift#L247-L248

We could implement these delegate methods as a first step before implementing any new UI.

There isn’t a perfect analogue on Android, but apparently an Android application can implement a callback similar to NavigationViewController.navigationService(_:didRerouteAlong:at:proactive:); the difference is that the Android application is responsible for setting the new route, whereas on iOS the SDK takes care of setting the new route automatically.

/cc @mapbox/navigation-ios

1ec5 commented 4 years ago

As a workaround, an application using NavigationViewController can implement the prompt described above by setting Router.reroutesProactively to false:

let router = navigationViewController.navigationService.router
router.reroutesProactively = false

then reimplementing much of the logic in InternalRouter.checkForFasterRoute(from:routeProgress:). Most likely, the application’s reimplementation can be a lot simpler than what’s in MapboxCoreNavigation, especially if the application doesn’t use alternative routes or silent waypoints (that is, all the waypoints separate legs, which is the default). Here’s a broad outline:

1ec5 commented 4 years ago

We could implement these delegate methods as a first step before implementing any new UI.

Adding NavigationServiceDelegate.navigationService(_:shouldProactivelyRerouteFrom:to:) and NavigationViewController.navigationViewController(_:shouldProactivelyRerouteFrom:to:) methods would be very simple on our side. Then the workaround would become much simpler, for example:

extension MyViewController: NavigationViewControllerDelegate {
    func navigationViewController(_ navigationViewController: NavigationViewController, shouldProactivelyRerouteFrom currentRoute: Route, to proposedRoute: Route) {
        presentProactiveReroutingPrompt(for: proposedRoute)
        return false
    }

    @IBAction func didAcceptProposedRoute(_ sender: Any) {
        guard let promptViewController = sender as? ProactiveReroutingPromptViewController else { return }
        navigationViewController.navigationService.indexedRoute = (promptViewController.proposedRoute, 0)
    }
}
1ec5 commented 2 years ago

Fixed in #4229.

1ec5 commented 2 years ago

Oh, actually, #4229 adds the underlying functionality but we still need default UI for this.