Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import android.content.res.Configuration;
import android.location.Location;
import android.os.Bundle;
import android.os.Environment;
import android.preference.PreferenceManager;
import android.support.annotation.IdRes;
import android.support.annotation.NonNull;
Expand Down Expand Up @@ -39,8 +40,11 @@
import com.mapbox.services.android.navigation.v5.routeprogress.ProgressChangeListener;
import com.mapbox.services.android.navigation.v5.routeprogress.RouteProgress;

import java.io.File;

import retrofit2.Call;
import retrofit2.Response;
import timber.log.Timber;

public class EmbeddedNavigationActivity extends AppCompatActivity implements OnNavigationReadyCallback,
NavigationListener, ProgressChangeListener, InstructionListListener, SpeechAnnouncementListener,
Expand Down Expand Up @@ -194,13 +198,29 @@ private void startNavigation(DirectionsRoute directionsRoute) {
.progressChangeListener(this)
.instructionListListener(this)
.speechAnnouncementListener(this)
.bannerInstructionsListener(this);
.bannerInstructionsListener(this)
.offlineRoutingTilesPath(obtainOfflineDirectory())
.offlineRoutingTilesVersion(obtainOfflineTileVersion());
setBottomSheetCallback(options);
setupNightModeFab();

navigationView.startNavigation(options.build());
}

private String obtainOfflineDirectory() {
File offline = Environment.getExternalStoragePublicDirectory("Offline");
if (!offline.exists()) {
Timber.d("Offline directory does not exist");
offline.mkdirs();
}
return offline.getAbsolutePath();
}

private String obtainOfflineTileVersion() {
return PreferenceManager.getDefaultSharedPreferences(this)
.getString(getString(R.string.offline_version_key), "");
}

private void fetchRoute() {
NavigationRoute.builder(this)
.accessToken(Mapbox.getAccessToken())
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package com.mapbox.services.android.navigation.ui.v5;

import android.annotation.SuppressLint;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;

import java.util.HashMap;

class ConnectivityStatusProvider {

private final Context context;
private final WifiNetworkChecker wifiNetworkChecker;
private final MobileNetworkChecker mobileNetworkChecker;

ConnectivityStatusProvider(Context applicationContext) {
this.context = applicationContext;
this.wifiNetworkChecker = new WifiNetworkChecker(new HashMap<Integer, Boolean>());
this.mobileNetworkChecker = new MobileNetworkChecker(new HashMap<Integer, Boolean>());
}

boolean isConnected() {
NetworkInfo info = getNetworkInfo(context);
return (info != null && info.isConnected());
}

boolean isConnectedFast() {
NetworkInfo info = getNetworkInfo(context);
int wifiLevel = getWifiLevel(context);
return (info != null
&& info.isConnected()
&& isConnectionFast(info.getType(), info.getSubtype(), wifiLevel));
}

@SuppressLint("MissingPermission")
private NetworkInfo getNetworkInfo(Context context) {
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
return cm.getActiveNetworkInfo();
}

@SuppressLint({"MissingPermission", "WifiManagerPotentialLeak"})
private int getWifiLevel(Context context) {
WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
int numberOfLevels = 5;
WifiInfo wifiInfo = wifiManager.getConnectionInfo();
return WifiManager.calculateSignalLevel(wifiInfo.getRssi(), numberOfLevels);
}

private boolean isConnectionFast(int type, int networkType, int wifiLevel) {
if (type == ConnectivityManager.TYPE_WIFI) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should be careful here because you could be connected to a Wi-Fi but that doesn't mean to have connectivity e.g. you could be connected to a hotspot and don't have connection until you log in.

I believe we should implement something similar as with mobile connectivity. Maybe 👀 Wi-Fi strength?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is good to think about as an improvement but can possibly be deferred.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added a wifi strength "checker" to address this

return wifiNetworkChecker.isFast(wifiLevel);
} else if (type == ConnectivityManager.TYPE_MOBILE) {
return mobileNetworkChecker.isFast(networkType);
} else {
return false;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.mapbox.services.android.navigation.ui.v5.route;
package com.mapbox.services.android.navigation.ui.v5;

import java.util.HashMap;
import java.util.Map;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package com.mapbox.services.android.navigation.ui.v5;

import android.support.annotation.NonNull;
import android.telephony.TelephonyManager;

import java.util.HashMap;

class MobileNetworkChecker {

private final HashMap<Integer, Boolean> statusMap;

MobileNetworkChecker(HashMap<Integer, Boolean> statusMap) {
this.statusMap = statusMap;
initialize(statusMap);
}

@NonNull
Boolean isFast(Integer networkType) {
Boolean isConnectionFast = statusMap.get(networkType);
if (isConnectionFast == null) {
isConnectionFast = false;
}
return isConnectionFast;
}

private void initialize(HashMap<Integer, Boolean> statusMap) {
statusMap.put(TelephonyManager.NETWORK_TYPE_1xRTT, false);
statusMap.put(TelephonyManager.NETWORK_TYPE_GPRS, false);
statusMap.put(TelephonyManager.NETWORK_TYPE_CDMA, false);
statusMap.put(TelephonyManager.NETWORK_TYPE_EDGE, false);
statusMap.put(TelephonyManager.NETWORK_TYPE_IDEN, false);
statusMap.put(TelephonyManager.NETWORK_TYPE_UNKNOWN, false);

statusMap.put(TelephonyManager.NETWORK_TYPE_EVDO_0, true);
statusMap.put(TelephonyManager.NETWORK_TYPE_EVDO_A, true);
statusMap.put(TelephonyManager.NETWORK_TYPE_HSDPA, true);
statusMap.put(TelephonyManager.NETWORK_TYPE_HSPA, true);
statusMap.put(TelephonyManager.NETWORK_TYPE_HSUPA, true);
statusMap.put(TelephonyManager.NETWORK_TYPE_UMTS, true);
statusMap.put(TelephonyManager.NETWORK_TYPE_EHRPD, true);
statusMap.put(TelephonyManager.NETWORK_TYPE_EVDO_B, true);
statusMap.put(TelephonyManager.NETWORK_TYPE_HSPAP, true);
statusMap.put(TelephonyManager.NETWORK_TYPE_LTE, true);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@
import android.arch.lifecycle.MutableLiveData;
import android.content.Context;
import android.location.Location;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.TextUtils;
Expand All @@ -21,9 +19,6 @@
import com.mapbox.services.android.navigation.ui.v5.feedback.FeedbackItem;
import com.mapbox.services.android.navigation.ui.v5.instruction.BannerInstructionModel;
import com.mapbox.services.android.navigation.ui.v5.instruction.InstructionModel;
import com.mapbox.services.android.navigation.ui.v5.route.OffRouteEvent;
import com.mapbox.services.android.navigation.ui.v5.route.ViewRouteFetcher;
import com.mapbox.services.android.navigation.ui.v5.route.ViewRouteListener;
import com.mapbox.services.android.navigation.ui.v5.summary.SummaryModel;
import com.mapbox.services.android.navigation.ui.v5.voice.NavigationSpeechPlayer;
import com.mapbox.services.android.navigation.ui.v5.voice.SpeechAnnouncement;
Expand All @@ -42,6 +37,7 @@
import com.mapbox.services.android.navigation.v5.navigation.metrics.FeedbackEvent;
import com.mapbox.services.android.navigation.v5.offroute.OffRouteListener;
import com.mapbox.services.android.navigation.v5.route.FasterRouteListener;
import com.mapbox.services.android.navigation.v5.route.RouteFetcher;
import com.mapbox.services.android.navigation.v5.routeprogress.ProgressChangeListener;
import com.mapbox.services.android.navigation.v5.routeprogress.RouteProgress;
import com.mapbox.services.android.navigation.v5.utils.DistanceFormatter;
Expand Down Expand Up @@ -69,14 +65,13 @@ public class NavigationViewModel extends AndroidViewModel {
private final MutableLiveData<Point> destination = new MutableLiveData<>();

private MapboxNavigation navigation;
private ViewRouteFetcher routeFetcher;
private NavigationViewRouter router;
private LocationEngineConductor locationEngineConductor;
private NavigationViewEventDispatcher navigationViewEventDispatcher;
private SpeechPlayer speechPlayer;
private VoiceInstructionLoader voiceInstructionLoader;
private VoiceInstructionCache voiceInstructionCache;
private int voiceInstructionsToAnnounce = 0;
private ConnectivityManager connectivityManager;
private RouteProgress routeProgress;
private String feedbackId;
private String screenshot;
Expand All @@ -93,9 +88,8 @@ public class NavigationViewModel extends AndroidViewModel {
public NavigationViewModel(Application application) {
super(application);
this.accessToken = Mapbox.getAccessToken();
initializeConnectivityManager(application);
initializeNavigationRouteEngine();
initializeNavigationLocationEngine();
initializeLocationEngine();
initializeRouter();
routeUtils = new RouteUtils();
localeUtils = new LocaleUtils();
}
Expand All @@ -121,7 +115,7 @@ public NavigationViewModel(Application application) {
public void onDestroy(boolean isChangingConfigurations) {
this.isChangingConfigurations = isChangingConfigurations;
if (!isChangingConfigurations) {
routeFetcher.onDestroy();
router.onDestroy();
endNavigation();
deactivateInstructionPlayer();
isRunning = false;
Expand Down Expand Up @@ -208,7 +202,7 @@ void initialize(NavigationViewOptions options) {
initializeVoiceInstructionCache();
initializeNavigationSpeechPlayer(options);
}
routeFetcher.extractRouteOptions(options);
router.extractRouteOptions(options);
}

void updateFeedbackScreenshot(String screenshot) {
Expand Down Expand Up @@ -264,15 +258,14 @@ MutableLiveData<Point> retrieveDestination() {
return destination;
}

private void initializeConnectivityManager(Application application) {
connectivityManager = (ConnectivityManager) application.getSystemService(Context.CONNECTIVITY_SERVICE);
private void initializeRouter() {
RouteFetcher onlineRouter = new RouteFetcher(getApplication(), accessToken);
Context applicationContext = getApplication().getApplicationContext();
ConnectivityStatusProvider connectivityStatus = new ConnectivityStatusProvider(applicationContext);
router = new NavigationViewRouter(onlineRouter, connectivityStatus, routeEngineListener);
}

private void initializeNavigationRouteEngine() {
routeFetcher = new ViewRouteFetcher(getApplication(), accessToken, routeEngineListener);
}

private void initializeNavigationLocationEngine() {
private void initializeLocationEngine() {
locationEngineConductor = new LocationEngineConductor();
}

Expand Down Expand Up @@ -365,7 +358,7 @@ private void addMilestones(NavigationViewOptions options) {
@Override
public void onProgressChange(Location location, RouteProgress routeProgress) {
NavigationViewModel.this.routeProgress = routeProgress;
routeFetcher.updateLocation(location);
router.updateLocation(location);
instructionModel.setValue(new InstructionModel(distanceFormatter, routeProgress));
summaryModel.setValue(new SummaryModel(getApplication(), distanceFormatter, routeProgress, timeFormatType));
navigationLocation.setValue(location);
Expand All @@ -376,11 +369,9 @@ public void onProgressChange(Location location, RouteProgress routeProgress) {
private OffRouteListener offRouteListener = new OffRouteListener() {
@Override
public void userOffRoute(Location location) {
if (hasNetworkConnection()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the offRouteListener only getting fired now when the device is online? This doesn't cause any issues?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Connectivity checks are now done in NavigationViewRouter with the ConnectivityStatusProvider, so this check was no longer necessary / would block the new logic.

speechPlayer.onOffRoute();
Point newOrigin = Point.fromLngLat(location.getLongitude(), location.getLatitude());
handleOffRouteEvent(newOrigin);
}
speechPlayer.onOffRoute();
Point newOrigin = Point.fromLngLat(location.getLongitude(), location.getLatitude());
handleOffRouteEvent(newOrigin);
}
};

Expand Down Expand Up @@ -469,15 +460,6 @@ private void updateBannerInstruction(RouteProgress routeProgress, Milestone mile
}
}

@SuppressWarnings( {"MissingPermission"})
private boolean hasNetworkConnection() {
if (connectivityManager == null) {
return false;
}
NetworkInfo activeNetwork = connectivityManager.getActiveNetworkInfo();
return activeNetwork != null && activeNetwork.isConnectedOrConnecting();
}

private void sendEventFeedback(FeedbackItem feedbackItem) {
if (navigationViewEventDispatcher != null) {
navigationViewEventDispatcher.onFeedbackSent(feedbackItem);
Expand All @@ -493,8 +475,7 @@ private void sendEventArrival(RouteProgress routeProgress) {
private void handleOffRouteEvent(Point newOrigin) {
if (navigationViewEventDispatcher != null && navigationViewEventDispatcher.allowRerouteFrom(newOrigin)) {
navigationViewEventDispatcher.onOffRoute(newOrigin);
OffRouteEvent event = new OffRouteEvent(newOrigin, routeProgress);
routeFetcher.fetchRouteFromOffRouteEvent(event);
router.findRouteFrom(routeProgress);
isOffRoute.setValue(true);
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package com.mapbox.services.android.navigation.ui.v5;

import com.mapbox.services.android.navigation.v5.navigation.MapboxOfflineRouter;
import com.mapbox.services.android.navigation.v5.navigation.NavigationRoute;
import com.mapbox.services.android.navigation.v5.navigation.OfflineRoute;

import timber.log.Timber;

class NavigationViewOfflineRouter {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have a lot of objects called routers, since this seems to only take care of making sure that the offline router is properly configured, can we try to name it to make that apparent?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure I completely follow regarding sole responsibility of configuration, findRouteWith is also finding new offline routes

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok I understand what you are saying. Can we call this a wrapper or something? Since it is acting mostly as a wrapper for the routers.


private final MapboxOfflineRouter offlineRouter;
private final NavigationViewRouter router;
private boolean isConfigured;
private String tileVersion;

NavigationViewOfflineRouter(MapboxOfflineRouter offlineRouter, NavigationViewRouter router) {
this.offlineRouter = offlineRouter;
this.router = router;
}

void configure(String tileVersion) {
if (!isConfigured || isNew(tileVersion)) {
offlineRouter.configure(tileVersion, new OfflineRouterConfiguredCallback(this));
}
this.tileVersion = tileVersion;
}

void setIsConfigured(boolean isConfigured) {
this.isConfigured = isConfigured;
}

boolean isConfigured() {
return isConfigured;
}

void findRouteWith(NavigationRoute.Builder builder) {
if (!isConfigured) {
Timber.e("Cannot find route - offline router is not configured");
return;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we give an error if not configured?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, good catch

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we throw an exception here? As it is, this would be a somewhat silent failure.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We actually won't call this method if this class isn't configured https://github.com/mapbox/mapbox-navigation-android/pull/1829/files#diff-29009b5750e50557cd5e8a7fd79a46f7R80. So we may not need this check at all?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, let's remove it altogether then.

}

OfflineRoute offlineRoute = OfflineRoute.builder(builder).build();
offlineRouter.findRoute(offlineRoute, new OfflineRouteFoundCallback(router));
}

private boolean isNew(String tileVersion) {
return !this.tileVersion.equals(tileVersion);
}
}
Loading