Skip to content

Commit 33c9841

Browse files
committed
Create NavigationViewRouter timeout to unblock routing state
1 parent 807d5bf commit 33c9841

File tree

7 files changed

+175
-34
lines changed

7 files changed

+175
-34
lines changed

libandroid-navigation-ui/src/main/java/com/mapbox/services/android/navigation/ui/v5/NavigationViewRouter.java

Lines changed: 49 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import com.mapbox.services.android.navigation.v5.route.RouteListener;
1616
import com.mapbox.services.android.navigation.v5.routeprogress.RouteProgress;
1717

18+
import java.util.Date;
1819
import java.util.List;
1920

2021
class NavigationViewRouter implements RouteListener {
@@ -29,7 +30,7 @@ class NavigationViewRouter implements RouteListener {
2930
private RouteOptions routeOptions;
3031
private DirectionsRoute currentRoute;
3132
private Location location;
32-
private boolean isRouting;
33+
private RouteCallStatus callStatus;
3334

3435
NavigationViewRouter(RouteFetcher onlineRouter, ConnectivityStatusProvider connectivityStatus,
3536
ViewRouteListener listener) {
@@ -43,25 +44,28 @@ class NavigationViewRouter implements RouteListener {
4344
// Extra fields for testing purposes
4445
NavigationViewRouter(RouteFetcher onlineRouter, NavigationViewOfflineRouter offlineRouter,
4546
ConnectivityStatusProvider connectivityStatus, RouteComparator routeComparator,
46-
ViewRouteListener listener) {
47+
ViewRouteListener listener, RouteCallStatus callStatus) {
4748
this.onlineRouter = onlineRouter;
4849
this.offlineRouter = offlineRouter;
4950
this.connectivityStatus = connectivityStatus;
50-
this.listener = listener;
5151
this.routeComparator = routeComparator;
52+
this.listener = listener;
53+
this.callStatus = callStatus;
5254
onlineRouter.addRouteListener(this);
5355
}
5456

5557
@Override
5658
public void onResponseReceived(DirectionsResponse response, @Nullable RouteProgress routeProgress) {
57-
routeComparator.compare(response, currentRoute);
58-
isRouting = false;
59+
if (validRouteResponse(response)) {
60+
routeComparator.compare(response, currentRoute);
61+
}
62+
updateCallStatusReceived();
5963
}
6064

6165
@Override
6266
public void onErrorReceived(Throwable throwable) {
6367
onRequestError(throwable.getMessage());
64-
isRouting = false;
68+
updateCallStatusReceived();
6569
}
6670

6771
void extractRouteOptions(NavigationViewOptions options) {
@@ -70,19 +74,16 @@ void extractRouteOptions(NavigationViewOptions options) {
7074
}
7175

7276
void findRouteFrom(@Nullable RouteProgress routeProgress) {
73-
if (isRouting) {
77+
if (isRouting()) {
7478
return;
7579
}
7680
NavigationRoute.Builder builder = onlineRouter.buildRequestFrom(location, routeProgress);
7781
if (connectivityStatus.isConnectedFast()) {
78-
onlineRouter.findRouteWith(builder);
79-
isRouting = true;
82+
findOnlineRouteWith(builder);
8083
} else if (isOfflineConfigured()) {
81-
offlineRouter.findRouteWith(builder);
82-
isRouting = true;
84+
findOfflineRouteWith(builder);
8385
} else if (connectivityStatus.isConnected()) {
84-
onlineRouter.findRouteWith(builder);
85-
isRouting = true;
86+
findOnlineRouteWith(builder);
8687
}
8788
}
8889

@@ -95,6 +96,12 @@ void updateCurrentRoute(DirectionsRoute currentRoute) {
9596
listener.onRouteUpdate(currentRoute);
9697
}
9798

99+
void updateCallStatusReceived() {
100+
if (callStatus != null) {
101+
callStatus.setResponseReceived();
102+
}
103+
}
104+
98105
void onRequestError(String errorMessage) {
99106
listener.onRouteRequestError(errorMessage);
100107
}
@@ -104,6 +111,10 @@ void onDestroy() {
104111
onlineRouter.clearListeners();
105112
}
106113

114+
private boolean validRouteResponse(DirectionsResponse response) {
115+
return response != null && !response.routes().isEmpty();
116+
}
117+
107118
private void extractRouteFrom(NavigationViewOptions options) {
108119
DirectionsRoute route = options.directionsRoute();
109120
cacheRouteOptions(route.routeOptions());
@@ -115,6 +126,16 @@ private void cacheRouteOptions(RouteOptions routeOptions) {
115126
cacheRouteDestination();
116127
}
117128

129+
private void cacheRouteDestination() {
130+
boolean hasValidCoordinates = routeOptions != null && !routeOptions.coordinates().isEmpty();
131+
if (hasValidCoordinates) {
132+
List<Point> coordinates = routeOptions.coordinates();
133+
int destinationCoordinate = coordinates.size() - 1;
134+
Point destinationPoint = coordinates.get(destinationCoordinate);
135+
listener.onDestinationSet(destinationPoint);
136+
}
137+
}
138+
118139
private void initializeOfflineFrom(NavigationViewOptions options) {
119140
String offlinePath = options.offlineRoutingTilesPath();
120141
String offlineTilesVersion = options.offlineRoutingTilesVersion();
@@ -131,13 +152,21 @@ private boolean isOfflineConfigured() {
131152
return offlineRouter != null && offlineRouter.isConfigured();
132153
}
133154

134-
private void cacheRouteDestination() {
135-
boolean hasValidCoordinates = routeOptions != null && !routeOptions.coordinates().isEmpty();
136-
if (hasValidCoordinates) {
137-
List<Point> coordinates = routeOptions.coordinates();
138-
int destinationCoordinate = coordinates.size() - 1;
139-
Point destinationPoint = coordinates.get(destinationCoordinate);
140-
listener.onDestinationSet(destinationPoint);
155+
private void findOnlineRouteWith(NavigationRoute.Builder builder) {
156+
onlineRouter.cancelRouteCall();
157+
onlineRouter.findRouteWith(builder);
158+
callStatus = new RouteCallStatus(new Date());
159+
}
160+
161+
private void findOfflineRouteWith(NavigationRoute.Builder builder) {
162+
offlineRouter.findRouteWith(builder);
163+
callStatus = new RouteCallStatus(new Date());
164+
}
165+
166+
private boolean isRouting() {
167+
if (callStatus == null) {
168+
return false;
141169
}
170+
return callStatus.isRouting(new Date());
142171
}
143172
}

libandroid-navigation-ui/src/main/java/com/mapbox/services/android/navigation/ui/v5/OfflineRouteFoundCallback.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,12 @@ class OfflineRouteFoundCallback implements OnOfflineRouteFoundCallback {
1717
@Override
1818
public void onRouteFound(@NonNull DirectionsRoute offlineRoute) {
1919
router.updateCurrentRoute(offlineRoute);
20+
router.updateCallStatusReceived();
2021
}
2122

2223
@Override
2324
public void onError(@NonNull OfflineError error) {
2425
router.onRequestError(error.getMessage());
26+
router.updateCallStatusReceived();
2527
}
2628
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package com.mapbox.services.android.navigation.ui.v5;
2+
3+
import java.util.Date;
4+
5+
class RouteCallStatus {
6+
7+
private static final int FIVE_SECONDS_IN_MILLISECONDS = 5000;
8+
private boolean responseReceived;
9+
private final Date callDate;
10+
11+
RouteCallStatus(Date callDate) {
12+
this.callDate = callDate;
13+
}
14+
15+
void setResponseReceived() {
16+
this.responseReceived = true;
17+
}
18+
19+
boolean isRouting(Date currentDate) {
20+
if (responseReceived) {
21+
return false;
22+
}
23+
return diffInMilliseconds(callDate, currentDate) < FIVE_SECONDS_IN_MILLISECONDS;
24+
}
25+
26+
private long diffInMilliseconds(Date callDate, Date currentDate) {
27+
return currentDate.getTime() - callDate.getTime();
28+
}
29+
}

libandroid-navigation-ui/src/test/java/com/mapbox/services/android/navigation/ui/v5/NavigationViewRouterTest.java

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,8 @@ public void findRouteFrom_fastConnectionGoesToOnline() {
103103
null, // Null offline (simulate no data)
104104
status,
105105
mock(RouteComparator.class),
106-
mock(ViewRouteListener.class)
106+
mock(ViewRouteListener.class),
107+
mock(RouteCallStatus.class)
107108
);
108109
router.updateLocation(mock(Location.class));
109110

@@ -125,7 +126,8 @@ public void findRouteFrom_nullOfflineAndSlowConnectionGoesToOnline() {
125126
null, // Null offline (simulate no data)
126127
status,
127128
mock(RouteComparator.class),
128-
mock(ViewRouteListener.class)
129+
mock(ViewRouteListener.class),
130+
mock(RouteCallStatus.class)
129131
);
130132
router.updateLocation(mock(Location.class));
131133

@@ -148,7 +150,8 @@ public void findRouteFrom_slowConnectionGoesToOffline() {
148150
offlineRouter,
149151
status,
150152
mock(RouteComparator.class),
151-
mock(ViewRouteListener.class)
153+
mock(ViewRouteListener.class),
154+
mock(RouteCallStatus.class)
152155
);
153156
router.updateLocation(mock(Location.class));
154157

@@ -171,7 +174,8 @@ public void findRouteFrom_secondRequestIgnored() {
171174
offlineRouter,
172175
status,
173176
mock(RouteComparator.class),
174-
mock(ViewRouteListener.class)
177+
mock(ViewRouteListener.class),
178+
mock(RouteCallStatus.class)
175179
);
176180
router.updateLocation(mock(Location.class));
177181

@@ -189,7 +193,8 @@ public void onDestroy_clearsListeners() {
189193
mock(NavigationViewOfflineRouter.class),
190194
mock(ConnectivityStatusProvider.class),
191195
mock(RouteComparator.class),
192-
mock(ViewRouteListener.class)
196+
mock(ViewRouteListener.class),
197+
mock(RouteCallStatus.class)
193198
);
194199

195200
router.onDestroy();
@@ -205,7 +210,8 @@ public void onDestroy_cancelsOnlineRouteCall() {
205210
mock(NavigationViewOfflineRouter.class),
206211
mock(ConnectivityStatusProvider.class),
207212
mock(RouteComparator.class),
208-
mock(ViewRouteListener.class)
213+
mock(ViewRouteListener.class),
214+
mock(RouteCallStatus.class)
209215
);
210216

211217
router.onDestroy();
@@ -227,7 +233,8 @@ public void checksOfflineRouterIsConfiguredIfPathAndTilesVersionArePresent() thr
227233
offlineRouter,
228234
mock(ConnectivityStatusProvider.class),
229235
mock(RouteComparator.class),
230-
mock(ViewRouteListener.class)
236+
mock(ViewRouteListener.class),
237+
mock(RouteCallStatus.class)
231238
);
232239

233240
router.extractRouteOptions(options);
@@ -249,7 +256,8 @@ public void checksOfflineRouterIsNotConfiguredIfPathIsNull() throws Exception {
249256
offlineRouter,
250257
mock(ConnectivityStatusProvider.class),
251258
mock(RouteComparator.class),
252-
mock(ViewRouteListener.class)
259+
mock(ViewRouteListener.class),
260+
mock(RouteCallStatus.class)
253261
);
254262

255263
router.extractRouteOptions(options);
@@ -271,7 +279,8 @@ public void checksOfflineRouterIsNotConfiguredIfPathIsEmpty() throws Exception {
271279
offlineRouter,
272280
mock(ConnectivityStatusProvider.class),
273281
mock(RouteComparator.class),
274-
mock(ViewRouteListener.class)
282+
mock(ViewRouteListener.class),
283+
mock(RouteCallStatus.class)
275284
);
276285

277286
router.extractRouteOptions(options);
@@ -294,7 +303,8 @@ public void checksOfflineRouterIsNotConfiguredIfTilesVersionIsNull() throws Exce
294303
offlineRouter,
295304
mock(ConnectivityStatusProvider.class),
296305
mock(RouteComparator.class),
297-
mock(ViewRouteListener.class)
306+
mock(ViewRouteListener.class),
307+
mock(RouteCallStatus.class)
298308
);
299309

300310
router.extractRouteOptions(options);
@@ -317,7 +327,8 @@ public void checksOfflineRouterIsNotConfiguredIfTilesVersionIsEmpty() throws Exc
317327
offlineRouter,
318328
mock(ConnectivityStatusProvider.class),
319329
mock(RouteComparator.class),
320-
mock(ViewRouteListener.class)
330+
mock(ViewRouteListener.class),
331+
mock(RouteCallStatus.class)
321332
);
322333

323334
router.extractRouteOptions(options);

libandroid-navigation-ui/src/test/java/com/mapbox/services/android/navigation/ui/v5/OfflineRouteFoundCallbackTest.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,17 @@ public void onRouteFound_routerIsUpdated() {
2323
verify(router).updateCurrentRoute(offlineRoute);
2424
}
2525

26+
@Test
27+
public void onRouteFound_callStatusIsUpdated() {
28+
NavigationViewRouter router = mock(NavigationViewRouter.class);
29+
DirectionsRoute offlineRoute = mock(DirectionsRoute.class);
30+
OfflineRouteFoundCallback callback = new OfflineRouteFoundCallback(router);
31+
32+
callback.onRouteFound(offlineRoute);
33+
34+
verify(router).updateCallStatusReceived();
35+
}
36+
2637
@Test
2738
public void onError_routerReceivesErrorMessage() {
2839
NavigationViewRouter router = mock(NavigationViewRouter.class);
@@ -35,4 +46,17 @@ public void onError_routerReceivesErrorMessage() {
3546

3647
verify(router).onRequestError(eq(errorMessage));
3748
}
49+
50+
@Test
51+
public void onError_callStatusIsUpdated() {
52+
NavigationViewRouter router = mock(NavigationViewRouter.class);
53+
OfflineError error = mock(OfflineError.class);
54+
String errorMessage = "error message";
55+
when(error.getMessage()).thenReturn(errorMessage);
56+
OfflineRouteFoundCallback callback = new OfflineRouteFoundCallback(router);
57+
58+
callback.onError(error);
59+
60+
verify(router).updateCallStatusReceived();
61+
}
3862
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package com.mapbox.services.android.navigation.ui.v5;
2+
3+
import org.junit.Test;
4+
5+
import java.util.Date;
6+
7+
import static org.junit.Assert.assertFalse;
8+
import static org.junit.Assert.assertTrue;
9+
import static org.mockito.Mockito.mock;
10+
import static org.mockito.Mockito.when;
11+
12+
public class RouteCallStatusTest {
13+
14+
@Test
15+
public void setResponseReceived_isNoLongerRouting() {
16+
Date callDate = mock(Date.class);
17+
RouteCallStatus callStatus = new RouteCallStatus(callDate);
18+
19+
callStatus.setResponseReceived();
20+
21+
assertFalse(callStatus.isRouting(mock(Date.class)));
22+
}
23+
24+
@Test
25+
public void isRouting_returnsTrueUnderTwoSeconds() {
26+
Date callDate = mock(Date.class);
27+
when(callDate.getTime()).thenReturn(0L);
28+
Date currentDate = mock(Date.class);
29+
when((currentDate.getTime())).thenReturn(1000L);
30+
RouteCallStatus callStatus = new RouteCallStatus(callDate);
31+
32+
boolean isRouting = callStatus.isRouting(currentDate);
33+
34+
assertTrue(isRouting);
35+
}
36+
37+
@Test
38+
public void isRouting_returnsFalseOverFiveSeconds() {
39+
Date callDate = mock(Date.class);
40+
when(callDate.getTime()).thenReturn(0L);
41+
Date currentDate = mock(Date.class);
42+
when((currentDate.getTime())).thenReturn(5100L);
43+
RouteCallStatus callStatus = new RouteCallStatus(callDate);
44+
45+
boolean isRouting = callStatus.isRouting(currentDate);
46+
47+
assertFalse(isRouting);
48+
}
49+
}

libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/route/RouteFetcher.java

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -215,9 +215,6 @@ private boolean invalid(Context context, Location location, RouteProgress routeP
215215
private Callback<DirectionsResponse> directionsResponseCallback = new Callback<DirectionsResponse>() {
216216
@Override
217217
public void onResponse(@NonNull Call<DirectionsResponse> call, @NonNull Response<DirectionsResponse> response) {
218-
if (!response.isSuccessful()) {
219-
return;
220-
}
221218
updateListeners(response.body(), routeProgress);
222219
}
223220

0 commit comments

Comments
 (0)