Skip to content

Commit

Permalink
Working utils for voice and banner instructions
Browse files Browse the repository at this point in the history
  • Loading branch information
danesfeder committed Apr 16, 2018
1 parent 6bdf90f commit 77cb3ed
Show file tree
Hide file tree
Showing 3 changed files with 121 additions and 96 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,17 @@
import android.content.Context;
import android.support.annotation.Nullable;

import com.mapbox.api.directions.v5.models.BannerInstructions;
import com.mapbox.api.directions.v5.models.BannerText;
import com.mapbox.api.directions.v5.models.LegStep;
import com.mapbox.services.android.navigation.v5.navigation.NavigationUnitType;
import com.mapbox.services.android.navigation.v5.routeprogress.RouteLegProgress;
import com.mapbox.services.android.navigation.v5.routeprogress.RouteProgress;

import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

public class InstructionModel {
import static com.mapbox.services.android.navigation.v5.utils.RouteUtils.findCurrentBannerText;

private static final int ONE_INSTRUCTION_INDEX = 1;
public class InstructionModel {

private BannerText primaryBannerText;
private BannerText secondaryBannerText;
Expand Down Expand Up @@ -71,37 +68,15 @@ private void extractStepInstructions(RouteProgress progress) {
LegStep upComingStep = legProgress.upComingStep();
int stepDistanceRemaining = (int) legProgress.currentStepProgress().distanceRemaining();

primaryBannerText = findBannerText(currentStep, stepDistanceRemaining, true);
secondaryBannerText = findBannerText(currentStep, stepDistanceRemaining, false);
thenBannerText = findBannerText(upComingStep, stepDistanceRemaining, true);
primaryBannerText = findCurrentBannerText(currentStep, stepDistanceRemaining, true);
secondaryBannerText = findCurrentBannerText(currentStep, stepDistanceRemaining, false);

if (primaryBannerText != null && primaryBannerText.degrees() != null) {
roundaboutAngle = primaryBannerText.degrees().floatValue();
if (upComingStep != null) {
thenBannerText = findCurrentBannerText(upComingStep, upComingStep.distance(), true);
}
}

@Nullable
private static BannerText findBannerText(LegStep step, final double stepDistanceRemaining, boolean findPrimary) {
if (step != null && hasInstructions(step.bannerInstructions())) {
List<BannerInstructions> instructions = new ArrayList<>(step.bannerInstructions());
for (int i = 0; i < instructions.size(); i++) {
double distanceAlongGeometry = instructions.get(i).distanceAlongGeometry();
if (distanceAlongGeometry < stepDistanceRemaining) {
instructions.remove(i);
}
}
int instructionIndex = instructions.size() - 1;
BannerInstructions currentInstructions = instructions.get(instructionIndex);
return retrievePrimaryOrSecondaryBannerText(findPrimary, currentInstructions);
if (primaryBannerText != null && primaryBannerText.degrees() != null) {
roundaboutAngle = primaryBannerText.degrees().floatValue();
}
return null;
}

private static boolean hasInstructions(List<BannerInstructions> bannerInstructions) {
return bannerInstructions != null && !bannerInstructions.isEmpty();
}

private static BannerText retrievePrimaryOrSecondaryBannerText(boolean findPrimary, BannerInstructions instruction) {
return findPrimary ? instruction.primary() : instruction.secondary();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,12 @@
import com.mapbox.services.android.navigation.v5.navigation.VoiceInstructionLoader;
import com.mapbox.services.android.navigation.v5.routeprogress.RouteProgress;

import java.util.List;
import static com.mapbox.services.android.navigation.v5.utils.RouteUtils.findCurrentVoiceInstructions;

public class VoiceInstructionMilestone extends Milestone {

private String announcement;
private String ssmlAnnouncement;
private VoiceInstructions instructions;
private DirectionsRoute currentRoute;
private LegStep currentStep;
private List<VoiceInstructions> stepVoiceInstructions;

VoiceInstructionMilestone(Builder builder) {
super(builder);
Expand All @@ -24,22 +21,13 @@ public class VoiceInstructionMilestone extends Milestone {
@Override
public boolean isOccurring(RouteProgress previousRouteProgress, RouteProgress routeProgress) {
if (isNewRoute(routeProgress)) {
clearInstructionList();
cacheInstructions(routeProgress, true);
}

if (shouldAddInstructions(routeProgress)) {
stepVoiceInstructions = routeProgress.currentLegProgress().currentStep().voiceInstructions();
}

for (VoiceInstructions voice : stepVoiceInstructions) {
if (shouldBeVoiced(routeProgress, voice)) {
cacheInstructions(routeProgress, false);
announcement = voice.announcement();
ssmlAnnouncement = voice.ssmlAnnouncement();
stepVoiceInstructions.remove(voice);
return true;
}
LegStep currentStep = routeProgress.currentLegProgress().currentStep();
double stepDistanceRemaining = routeProgress.currentLegProgress().currentStepProgress().distanceRemaining();
VoiceInstructions instructions = findCurrentVoiceInstructions(currentStep, stepDistanceRemaining);
if (shouldBeVoiced(instructions, stepDistanceRemaining)) {
return updateInstructions(routeProgress, instructions);
}
return false;
}
Expand All @@ -49,7 +37,10 @@ public Instruction getInstruction() {
return new Instruction() {
@Override
public String buildInstruction(RouteProgress routeProgress) {
return announcement;
if (instructions == null) {
return routeProgress.currentLegProgress().currentStep().name();
}
return instructions.announcement();
}
};
}
Expand All @@ -64,7 +55,10 @@ public String buildInstruction(RouteProgress routeProgress) {
* @since 0.8.0
*/
public String getSsmlAnnouncement() {
return ssmlAnnouncement;
if (instructions == null) {
return "";
}
return instructions.ssmlAnnouncement();
}

/**
Expand All @@ -76,40 +70,10 @@ public String getSsmlAnnouncement() {
* @since 0.12.0
*/
public String getAnnouncement() {
return announcement;
}

/**
* Check if a new set of step instructions should be set.
*
* @param routeProgress the current route progress
* @return true if new instructions should be added to the list, false if not
*/
private boolean shouldAddInstructions(RouteProgress routeProgress) {
return newStep(routeProgress) || stepVoiceInstructions == null;
}

/**
* Called when adding new instructions to the list.
* <p>
* Make sure old announcements are not called (can happen in reroute scenarios).
*/
private void clearInstructionList() {
if (stepVoiceInstructions != null && !stepVoiceInstructions.isEmpty()) {
stepVoiceInstructions.clear();
if (instructions == null) {
return "";
}
}

/**
* Looks to see if we have a new step.
*
* @param routeProgress provides updated step information
* @return true if new step, false if not
*/
private boolean newStep(RouteProgress routeProgress) {
boolean newStep = currentStep == null || !currentStep.equals(routeProgress.currentLegProgress().currentStep());
currentStep = routeProgress.currentLegProgress().currentStep();
return newStep;
return instructions.announcement();
}

/**
Expand All @@ -125,22 +89,30 @@ private boolean isNewRoute(RouteProgress routeProgress) {
}

/**
* Uses the current step distance remaining to check against voice instruction distance.
* Checks if the current instructions are different from the instructions
* determined by the step distance remaining.
*
* @param routeProgress the current route progress
* @param voice a given voice instruction from the list of step instructions
* @param instructions the current voice instructions from the list of step instructions
* @param stepDistanceRemaining the current step distance remaining
* @return true if time to voice the announcement, false if not
*/
private boolean shouldBeVoiced(RouteProgress routeProgress, VoiceInstructions voice) {
return voice.distanceAlongGeometry()
>= routeProgress.currentLegProgress().currentStepProgress().distanceRemaining();
private boolean shouldBeVoiced(VoiceInstructions instructions, double stepDistanceRemaining) {
boolean isNewInstruction = this.instructions == null || !this.instructions.equals(instructions);
boolean isValidNewInstruction = instructions != null && isNewInstruction;
return isValidNewInstruction && instructions.distanceAlongGeometry() >= stepDistanceRemaining;
}

private boolean updateInstructions(RouteProgress routeProgress, VoiceInstructions instructions) {
cacheInstructions(routeProgress, false);
this.instructions = instructions;
return true;
}

/**
* Caches the instructions in the VoiceInstructionLoader if it has been initialized
*
* @param routeProgress containing the instructions
* @param isFirst whether it's the first routeProgress of the route
* @param isFirst whether it's the first routeProgress of the route
*/
private void cacheInstructions(RouteProgress routeProgress, boolean isFirst) {
VoiceInstructionLoader voiceInstructionLoader = VoiceInstructionLoader.getInstance();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,12 @@
import android.text.TextUtils;

import com.mapbox.api.directions.v5.DirectionsCriteria;
import com.mapbox.api.directions.v5.models.BannerInstructions;
import com.mapbox.api.directions.v5.models.BannerText;
import com.mapbox.api.directions.v5.models.DirectionsRoute;
import com.mapbox.api.directions.v5.models.LegStep;
import com.mapbox.api.directions.v5.models.RouteLeg;
import com.mapbox.api.directions.v5.models.VoiceInstructions;
import com.mapbox.geojson.Point;
import com.mapbox.services.android.navigation.v5.routeprogress.RouteProgress;

Expand Down Expand Up @@ -108,9 +112,7 @@ public static List<Point> calculateRemainingWaypoints(RouteProgress routeProgres
if (routeProgress.directionsRoute().routeOptions() == null) {
return null;
}

List<Point> coordinates = new ArrayList<>(routeProgress.directionsRoute().routeOptions().coordinates());

if (coordinates.size() < routeProgress.remainingWaypoints()) {
return null;
}
Expand Down Expand Up @@ -150,6 +152,62 @@ public static boolean isValidRouteProfile(String routeProfile) {
return !TextUtils.isEmpty(routeProfile) && VALID_PROFILES.contains(routeProfile);
}

/**
* This method returns the current {@link BannerText} based on the step distance
* remaining.
* <p>
* When called, this is the banner text that should be shown at the given point along the route.
*
* @param step holding the current banner instructions
* @param stepDistanceRemaining to determine progress along the step
* @param findPrimary if the primary or secondary BannerText should be retrieved
* @return current BannerText based on step distance remaining
* @since 0.13.0
*/
@Nullable
public static BannerText findCurrentBannerText(LegStep step, double stepDistanceRemaining, boolean findPrimary) {
if (isValidStep(step)) {
List<BannerInstructions> instructions = new ArrayList<>(step.bannerInstructions());
for (int i = 0; i < instructions.size(); i++) {
double distanceAlongGeometry = instructions.get(i).distanceAlongGeometry();
if (distanceAlongGeometry < stepDistanceRemaining) {
instructions.remove(i);
}
}
int instructionIndex = checkValidIndex(instructions);
BannerInstructions currentInstructions = instructions.get(instructionIndex);
return retrievePrimaryOrSecondaryBannerText(findPrimary, currentInstructions);
}
return null;
}

/**
* This method returns the current {@link VoiceInstructions} based on the step distance
* remaining.
*
* @param step holding the current banner instructions
* @param stepDistanceRemaining to determine progress along the step
* @return current voice instructions based on step distance remaining
* @since 0.13.0
*/
@Nullable
public static VoiceInstructions findCurrentVoiceInstructions(LegStep step, double stepDistanceRemaining) {
if (isValidStep(step)) {
List<VoiceInstructions> instructions = new ArrayList<>(step.voiceInstructions());
for (int i = 0; i < instructions.size(); i++) {
double distanceAlongGeometry = instructions.get(i).distanceAlongGeometry();
if (distanceAlongGeometry < stepDistanceRemaining) {
instructions.remove(i);
}
}
int instructionIndex = checkValidIndex(instructions);
if (instructions.size() > 0) {
return instructions.get(instructionIndex);
}
}
return null;
}

private static boolean upcomingStepIsArrival(@NonNull RouteProgress routeProgress) {
return routeProgress.currentLegProgress().upComingStep() != null
&& routeProgress.currentLegProgress().upComingStep().maneuver().type().contains(STEP_MANEUVER_TYPE_ARRIVE);
Expand All @@ -158,4 +216,24 @@ private static boolean upcomingStepIsArrival(@NonNull RouteProgress routeProgres
private static boolean currentStepIsArrival(@NonNull RouteProgress routeProgress) {
return routeProgress.currentLegProgress().currentStep().maneuver().type().contains(STEP_MANEUVER_TYPE_ARRIVE);
}

private static boolean isValidStep(LegStep step) {
return step != null && hasInstructions(step.bannerInstructions());
}

private static <T> boolean hasInstructions(List<T> instructions) {
return instructions != null && !instructions.isEmpty();
}

private static <T> int checkValidIndex(List<T> instructions) {
int instructionIndex = instructions.size() - 1;
if (instructionIndex < 0) {
instructionIndex = 0;
}
return instructionIndex;
}

private static BannerText retrievePrimaryOrSecondaryBannerText(boolean findPrimary, BannerInstructions instruction) {
return findPrimary ? instruction.primary() : instruction.secondary();
}
}

0 comments on commit 77cb3ed

Please sign in to comment.