Skip to content

Commit

Permalink
[WIP] add periodic refresh (every 5 minutes) functionality to update …
Browse files Browse the repository at this point in the history
…traffic and etas on a regular basis when in navigation
  • Loading branch information
Guardiola31337 committed Apr 1, 2019
1 parent 8dd2fae commit 4c5b556
Show file tree
Hide file tree
Showing 9 changed files with 292 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ public class MapboxNavigation implements ServiceConnection {
private final String accessToken;
private Context applicationContext;
private boolean isBound;
private RouteRefresher routeRefresher;

static {
NavigationLibraryLoader.load();
Expand Down Expand Up @@ -845,6 +846,11 @@ LocationEngineRequest retrieveLocationEngineRequest() {
return locationEngineRequest;
}

@Nullable
RouteRefresher retrieveRouteRefresher() {
return routeRefresher;
}

private void initializeForTest() {
// Initialize event dispatcher and add internal listeners
navigationEventDispatcher = new NavigationEventDispatcher();
Expand Down Expand Up @@ -926,6 +932,7 @@ private LocationEngineRequest obtainLocationEngineRequest() {
private void startNavigationWith(@NonNull DirectionsRoute directionsRoute, DirectionsRouteType routeType) {
ValidationUtils.validDirectionsRoute(directionsRoute, options.defaultMilestonesEnabled());
this.directionsRoute = directionsRoute;
routeRefresher = new RouteRefresher(this, new RouteRefresh(accessToken), 5 * 60 * 1000);
mapboxNavigator.updateRoute(directionsRoute, routeType);
if (!isBound) {
navigationTelemetry.startSession(directionsRoute, locationEngine);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -680,7 +680,8 @@ public NavigationRoute build() {
.voiceInstructions(true)
.bannerInstructions(true)
.roundaboutExits(true)
.eventListener(eventListener);
.eventListener(eventListener)
.enableRefresh(true);
return new NavigationRoute(directionsBuilder.build());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,17 @@ private void process() {
MapboxNavigationOptions options = navigation.options();
DirectionsRoute route = navigation.getRoute();

NavigationStatus status = mapboxNavigator.retrieveStatus(new Date(),
Date date = new Date();
NavigationStatus status = mapboxNavigator.retrieveStatus(date,
options.navigationLocationEngineIntervalLagInMilliseconds());
status = checkForNewLegIndex(mapboxNavigator, route, status, options.enableAutoIncrementLegIndex());
RouteProgress routeProgress = routeProcessor.buildNewRouteProgress(mapboxNavigator, status, route);

RouteRefresher routeRefresher = navigation.retrieveRouteRefresher();
if (routeRefresher != null && routeRefresher.check(date)) {
routeRefresher.refresh(routeProgress);
}

NavigationEngineFactory engineFactory = navigation.retrieveEngineFactory();
final boolean userOffRoute = isUserOffRoute(options, status, rawLocation, routeProgress, engineFactory);
final Location snappedLocation = findSnappedLocation(status, rawLocation, routeProgress, engineFactory);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,40 +4,77 @@
import com.mapbox.api.directionsrefresh.v1.MapboxDirectionsRefresh;
import com.mapbox.services.android.navigation.v5.routeprogress.RouteProgress;

import timber.log.Timber;

/**
* This class allows the developer to interact with the Directions Refresh API, receiving updated
* annotations for a route previously requested with the enableRefresh flag.
*/
public final class RouteRefresh {
private final RefreshCallback refreshCallback;
private RefreshCallback refreshCallback;
private final String accessToken;

/**
* Creates a {@link RouteRefresh} object which calls the {@link RefreshCallback} with updated
* routes.
*
* @param accessToken mapbox access token
* @param accessToken mapbox access token
* @param refreshCallback to call with updated routes
* @deprecated use {@link RouteRefresh(String)} instead
*/
@Deprecated
public RouteRefresh(String accessToken, RefreshCallback refreshCallback) {
this.accessToken = accessToken;
this.refreshCallback = refreshCallback;
}

/**
* Creates a {@link RouteRefresh} object.
*
* @param accessToken mapbox access token
*/
public RouteRefresh(String accessToken) {
this.accessToken = accessToken;
}

/**
* Refreshes the {@link DirectionsRoute} included in the {@link RouteProgress} and returns it
* to the callback that was originally passed in. The client will then have to update their
* {@link DirectionsRoute} with the {@link com.mapbox.api.directions.v5.models.LegAnnotation}s
* returned in this response. The leg annotations start at the current leg index of the
* {@link RouteProgress}
* <p>
* Note that if {@link RefreshCallback} is not passed in {@link RouteRefresh(String, RefreshCallback)} this call
* will be ignored.
* </p>
*
* @param routeProgress to refresh via the route and current leg index
* @deprecated use {@link RouteRefresh#refresh(RouteProgress, RefreshCallback)} instead
*/
@Deprecated
public void refresh(RouteProgress routeProgress) {
refresh(routeProgress.directionsRoute(), routeProgress.legIndex());
if (refreshCallback == null) {
Timber.e("RefreshCallback cannot be null.");
return;
}
refresh(routeProgress.directionsRoute(), routeProgress.legIndex(), refreshCallback);
}

/**
* Refreshes the {@link DirectionsRoute} included in the {@link RouteProgress} and returns it
* to the callback that was originally passed in. The client will then have to update their
* {@link DirectionsRoute} with the {@link com.mapbox.api.directions.v5.models.LegAnnotation}s
* returned in this response. The leg annotations start at the current leg index of the
* {@link RouteProgress}
*
* @param routeProgress to refresh via the route and current leg index
* @param refreshCallback to call with updated routes
*/
public void refresh(RouteProgress routeProgress, RefreshCallback refreshCallback) {
refresh(routeProgress.directionsRoute(), routeProgress.legIndex(), refreshCallback);
}

private void refresh(final DirectionsRoute directionsRoute, final int legIndex) {
private void refresh(final DirectionsRoute directionsRoute, final int legIndex, RefreshCallback refreshCallback) {
MapboxDirectionsRefresh.builder()
.requestId(directionsRoute.routeOptions().requestUuid())
.routeIndex(Integer.valueOf(directionsRoute.routeIndex()))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@ class RouteRefreshCallback implements Callback<DirectionsRefreshResponse> {
private final int legIndex;
private final RefreshCallback refreshCallback;

RouteRefreshCallback(DirectionsRoute directionsRoute,
int legIndex, RefreshCallback refreshCallback) {
RouteRefreshCallback(DirectionsRoute directionsRoute, int legIndex, RefreshCallback refreshCallback) {
this(new RouteAnnotationUpdater(), directionsRoute, legIndex, refreshCallback);
}

Expand All @@ -31,13 +30,12 @@ public void onResponse(Call<DirectionsRefreshResponse> call, Response<Directions
if (response.body() == null || response.body().route() == null) {
refreshCallback.onError(new RefreshError(response.message()));
} else {
refreshCallback.onRefresh(routeAnnotationUpdater.update(directionsRoute,
response.body().route(), legIndex));
refreshCallback.onRefresh(routeAnnotationUpdater.update(directionsRoute, response.body().route(), legIndex));
}
}

@Override
public void onFailure(Call<DirectionsRefreshResponse> call, Throwable throwable) {
refreshCallback.onError(new RefreshError("There was a network error."));
refreshCallback.onError(new RefreshError(throwable.getMessage()));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.mapbox.services.android.navigation.v5.navigation;

import com.mapbox.services.android.navigation.v5.routeprogress.RouteProgress;

import java.util.Date;

class RouteRefresher {
private final RouteRefresh routeRefresh;
private final MapboxNavigation mapboxNavigation;
private final long refreshIntervalInMilliseconds;
private Date lastRefreshedDate;
private boolean isChecking;

RouteRefresher(MapboxNavigation mapboxNavigation, RouteRefresh routeRefresh, long refreshIntervalInMilliseconds) {
this.mapboxNavigation = mapboxNavigation;
this.routeRefresh = routeRefresh;
this.refreshIntervalInMilliseconds = refreshIntervalInMilliseconds;
this.lastRefreshedDate = new Date();
}

boolean check(Date currentDate) {
if (isChecking) {
return false;
}
long millisSinceLastRefresh = currentDate.getTime() - lastRefreshedDate.getTime();
return millisSinceLastRefresh > refreshIntervalInMilliseconds;
}

void refresh(RouteProgress routeProgress) {
updateIsChecking(true);
routeRefresh.refresh(routeProgress, new RouteRefresherCallback(mapboxNavigation, this));
}

void updateLastRefresh(Date date) {
lastRefreshedDate = date;
}

void updateIsChecking(boolean isChecking) {
this.isChecking = isChecking;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.mapbox.services.android.navigation.v5.navigation;

import com.mapbox.api.directions.v5.models.DirectionsRoute;

import java.util.Date;

import timber.log.Timber;

class RouteRefresherCallback implements RefreshCallback {
private final MapboxNavigation mapboxNavigation;
private final RouteRefresher routeRefresher;

RouteRefresherCallback(MapboxNavigation mapboxNavigation, RouteRefresher routeRefresher) {
this.mapboxNavigation = mapboxNavigation;
this.routeRefresher = routeRefresher;
}

@Override
public void onRefresh(DirectionsRoute directionsRoute) {
mapboxNavigation.startNavigation(directionsRoute, DirectionsRouteType.FRESH_ROUTE);
routeRefresher.updateLastRefresh(new Date());
routeRefresher.updateIsChecking(false);
}

@Override
public void onError(RefreshError error) {
Timber.w(error.getMessage());
routeRefresher.updateIsChecking(false);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package com.mapbox.services.android.navigation.v5.navigation;

import com.mapbox.api.directions.v5.models.DirectionsRoute;

import org.junit.Test;

import java.util.Date;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;

public class RouteRefresherCallbackTest {

@Test
public void checksStartNavigationWithRefreshedRouteIsCalledWhenOnRefresh() {
MapboxNavigation mockedMapboxNavigation = mock(MapboxNavigation.class);
RouteRefresher mockedRouteRefresher = mock(RouteRefresher.class);
RouteRefresherCallback theRouteRefresherCallback = new RouteRefresherCallback(mockedMapboxNavigation,
mockedRouteRefresher);
DirectionsRoute anyRoute = mock(DirectionsRoute.class);

theRouteRefresherCallback.onRefresh(anyRoute);

verify(mockedMapboxNavigation).startNavigation(eq(anyRoute), eq(DirectionsRouteType.FRESH_ROUTE));
}

@Test
public void checksUpdateLastRefreshDateIsCalledWhenOnRefresh() {
MapboxNavigation mockedMapboxNavigation = mock(MapboxNavigation.class);
RouteRefresher mockedRouteRefresher = mock(RouteRefresher.class);
RouteRefresherCallback theRouteRefresherCallback = new RouteRefresherCallback(mockedMapboxNavigation,
mockedRouteRefresher);
DirectionsRoute anyRoute = mock(DirectionsRoute.class);

theRouteRefresherCallback.onRefresh(anyRoute);

verify(mockedRouteRefresher).updateLastRefresh(any(Date.class));
}

@Test
public void checksUpdateIsNotCheckingAfterOnRefresh() {
MapboxNavigation mockedMapboxNavigation = mock(MapboxNavigation.class);
RouteRefresher mockedRouteRefresher = mock(RouteRefresher.class);
RouteRefresherCallback theRouteRefresherCallback = new RouteRefresherCallback(mockedMapboxNavigation,
mockedRouteRefresher);
DirectionsRoute anyRoute = mock(DirectionsRoute.class);

theRouteRefresherCallback.onRefresh(anyRoute);

verify(mockedRouteRefresher).updateIsChecking(eq(false));
}

@Test
public void checksUpdateIsNotCheckingIfOnError() {
MapboxNavigation mockedMapboxNavigation = mock(MapboxNavigation.class);
RouteRefresher mockedRouteRefresher = mock(RouteRefresher.class);
RouteRefresherCallback theRouteRefresherCallback = new RouteRefresherCallback(mockedMapboxNavigation,
mockedRouteRefresher);
RefreshError anyRefreshError = mock(RefreshError.class);

theRouteRefresherCallback.onError(anyRefreshError);

verify(mockedRouteRefresher).updateIsChecking(eq(false));
}
}
Loading

0 comments on commit 4c5b556

Please sign in to comment.