Refactoring of the js voice guidance

This commit is contained in:
PaulStets 2018-08-21 15:07:30 +03:00
parent 3dc93e3c15
commit cf5b44cbf1
7 changed files with 254 additions and 593 deletions

View file

@ -21,6 +21,7 @@ import net.osmand.IndexConstants;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.activities.OsmandActionBarActivity;
import net.osmand.plus.routing.data.StreetName;
import net.osmand.plus.voice.AbstractPrologCommandPlayer;
import net.osmand.plus.voice.JSCommandBuilder;
import net.osmand.plus.voice.JSMediaCommandPlayerImpl;
@ -134,148 +135,84 @@ public class TestVoiceActivity extends OsmandActionBarActivity {
private String getVoiceSystemInfo() {
String v ="";
v += " \u25CF App profile: " + ((OsmandApplication) getApplication()).getSettings().APPLICATION_MODE.get().getStringKey();
v += " \u25CF App profile: " + ((OsmandApplication) getApplication()).getSettings().APPLICATION_MODE.get().getStringKey();
if (((OsmandApplication) getApplication()).getSettings().AUDIO_STREAM_GUIDANCE.get() == 3) {
v += "\n \u25CF Voice guidance output: Media/music audio";
v += "\n \u25CF Voice guidance output: Media/music audio";
} else if (((OsmandApplication) getApplication()).getSettings().AUDIO_STREAM_GUIDANCE.get() == 5) {
v += "\n \u25CF Voice guidance output: Notification audio";
v += "\n \u25CF Voice guidance output: Notification audio";
} else if (((OsmandApplication) getApplication()).getSettings().AUDIO_STREAM_GUIDANCE.get() == 0) {
v += "\n \u25CF Voice guidance output: Phone call audio";
v += "\n \u25CF Voice guidance output: Phone call audio";
} else {
v += "\n \u25CF Voice guidance output: " + ((OsmandApplication) getApplication()).getSettings().AUDIO_STREAM_GUIDANCE.get();
v += "\n \u25CF Voice guidance output: " + ((OsmandApplication) getApplication()).getSettings().AUDIO_STREAM_GUIDANCE.get();
}
v += "\n \u25CF OsmAnd voice: " + osmandVoice;
v += "\n \u25CF OsmAnd voice language: " + osmandVoiceLang;
v += "\n \u25CF OsmAnd voice: " + osmandVoice;
v += "\n \u25CF OsmAnd voice language: " + osmandVoiceLang;
if (AbstractPrologCommandPlayer.getCurrentVersion() > 99) {
v += "\n \u25CF Voice language availability: " + TTSCommandPlayerImpl.getTtsVoiceStatus();
v += "\n \u25CF Voice actually used: " + TTSCommandPlayerImpl.getTtsVoiceUsed();
v += "\n \u25CF Voice language availability: " + TTSCommandPlayerImpl.getTtsVoiceStatus();
v += "\n \u25CF Voice actually used: " + TTSCommandPlayerImpl.getTtsVoiceUsed();
} else {
v += "\n \u25CF Voice language availability: Recorded voice";
v += "\n \u25CF Voice actually used: Recorded voice";
v += "\n \u25CF Voice language availability: Recorded voice";
v += "\n \u25CF Voice actually used: Recorded voice";
}
if (((OsmandApplication) getApplication()).getSettings().AUDIO_STREAM_GUIDANCE.get() == 0) {
v += "\n \u25CF BT SCO: " + AbstractPrologCommandPlayer.btScoInit;
v += "\n \u25CF BT SCO: " + AbstractPrologCommandPlayer.btScoInit;
} else {
v += "\n \u25CF BT SCO: The current app profile is not set to use 'Phone call audio'.";
v += "\n \u25CF BT SCO: The current app profile is not set to use 'Phone call audio'.";
}
v += "\n \u25CF Phone call audio delay: " + ((OsmandApplication) getApplication()).getSettings().BT_SCO_DELAY.get() + "\u00A0ms";
v += "\n \u25CF Phone call audio delay: " + ((OsmandApplication) getApplication()).getSettings().BT_SCO_DELAY.get() + "\u00A0ms";
return v;
}
private Term street(CommandPlayer p, String name) {
return street(p, name, "", "", "");
}
private Term street(CommandPlayer p, String name, String ref) {
return street(p, name, ref, "", "");
}
private Term street(CommandPlayer p, String name, String ref, String dest) {
return street(p, name, ref, dest, "");
}
private Term getTermString(String s) {
if(!Algorithms.isEmpty(s)) {
return new Struct(s);
}
return new Struct("");
}
private Term street(CommandPlayer p, String name, String ref, String destName, String currentName) {
// Pass all test strings through our character replacement method
ref = VoiceRouter.getSpeakablePointName(ref);
name = VoiceRouter.getSpeakablePointName(name);
destName = VoiceRouter.getSpeakablePointName(destName);
currentName = VoiceRouter.getSpeakablePointName(currentName);
if(p.supportsStructuredStreetNames()) {
Struct next = new Struct(new Term[] { getTermString(ref),
getTermString(name),
getTermString(destName) });
Term current = new Struct("");
if (currentName.length() > 0) {
current = new Struct(new Term[] { getTermString(""),
getTermString(currentName),
getTermString("") });
}
Struct voice = new Struct("voice", next, current );
return voice;
}
return new Struct(name);
}
private void addButtons(final LinearLayout ll, CommandPlayer p) {
boolean isJS = p instanceof JSTTSCommandPlayerImpl || p instanceof JSMediaCommandPlayerImpl;
addButton(ll, "Route calculated and number tests:", builder(p));
addButton(ll, "\u25BA (1.1) New route calculated, 150m, 230sec (00:03:50)", !isJS ? builder(p).newRouteCalculated(150, 230) : jsBuilder(p).newRouteCalculated(150, 230));
addButton(ll, "\u25BA (1.2) New route calculated, 1350m, 3680sec (01:01:20)", !isJS ? builder(p).newRouteCalculated(1350, 3680) : jsBuilder(p).newRouteCalculated(1350, 3680));
addButton(ll, "\u25BA (1.3) New route calculated 3700m, 7320sec (02:02)", !isJS ? builder(p).newRouteCalculated(3700, 7320) : jsBuilder(p).newRouteCalculated(3700, 7320));
addButton(ll, "\u25BA (1.4) New route calculated 9100m, 10980sec (03:03)", !isJS ? builder(p).newRouteCalculated(9100, 10980) : jsBuilder(p).newRouteCalculated(9100, 10980));
addButton(ll, "\u25BA (2.1) Route recalculated 11500m, 18600sec (05:10)", !isJS ? builder(p).routeRecalculated(11500, 18600) : jsBuilder(p).routeRecalculated(11500, 18600));
addButton(ll, "\u25BA (2.2) Route recalculated 19633m, 26700sec (07:25)", !isJS ? builder(p).routeRecalculated(19633, 26700) : jsBuilder(p).routeRecalculated(19633, 26700));
addButton(ll, "\u25BA (2.3) Route recalculated 89750m, 55800sec (15:30)", !isJS ? builder(p).routeRecalculated(89750, 55800) : jsBuilder(p).routeRecalculated(89750, 55800));
addButton(ll, "\u25BA (2.4) Route recalculated 125900m, 92700sec (25:45)", !isJS ? builder(p).routeRecalculated(125900, 92700) : jsBuilder(p).routeRecalculated(125900, 92700));
addButton(ll, "\u25BA (1.1) New route calculated, 150m, 230sec (00:03:50)", builder(p).newRouteCalculated(150, 230));
addButton(ll, "\u25BA (1.2) New route calculated, 1350m, 3680sec (01:01:20)", builder(p).newRouteCalculated(1350, 3680));
addButton(ll, "\u25BA (1.3) New route calculated 3700m, 7320sec (02:02)", builder(p).newRouteCalculated(3700, 7320));
addButton(ll, "\u25BA (1.4) New route calculated 9100m, 10980sec (03:03)", builder(p).newRouteCalculated(9100, 10980));
addButton(ll, "\u25BA (2.1) Route recalculated 11500m, 18600sec (05:10)", builder(p).routeRecalculated(11500, 18600));
addButton(ll, "\u25BA (2.2) Route recalculated 19633m, 26700sec (07:25)", builder(p).routeRecalculated(19633, 26700) );
addButton(ll, "\u25BA (2.3) Route recalculated 89750m, 55800sec (15:30)", builder(p).routeRecalculated(89750, 55800) );
addButton(ll, "\u25BA (2.4) Route recalculated 125900m, 92700sec (25:45)", builder(p).routeRecalculated(125900, 92700) );
addButton(ll, "All turn types: prepareTurn, makeTurnIn, turn:", builder(p));
addButton(ll, "\u25BA (3.1) After 1520m turn slightly left", !isJS ? builder(p).prepareTurn(AbstractPrologCommandPlayer.A_LEFT_SL, 1520, street(p, "")) :
jsBuilder(p).prepareTurn(AbstractPrologCommandPlayer.A_LEFT_SL, 1520, jsStreet(p, "")));
addButton(ll, "\u25BA (3.2) In 450m turn sharply left onto 'Hauptstra"+"\u00df"+"e', then bear right", !isJS ? builder(p).turn(AbstractPrologCommandPlayer.A_LEFT_SH, 450, street(p, "Hauptstraße")).then().bearRight(street(p, "")) :
jsBuilder(p).turn(AbstractPrologCommandPlayer.A_LEFT_SH, 450, jsStreet(p, "Hauptstraße")).then().bearRight(jsStreet(p, "")));
addButton(ll, "\u25BA (3.3) Turn left, then in 100m turn slightly right", !isJS ? builder(p).turn(AbstractPrologCommandPlayer.A_LEFT, street(p, "")).then().turn(AbstractPrologCommandPlayer.A_RIGHT_SL, 100, street(p, "")) :
jsBuilder(p).turn(AbstractPrologCommandPlayer.A_LEFT, jsStreet(p, "")).then().turn(AbstractPrologCommandPlayer.A_RIGHT_SL, 100, jsStreet(p, "")));
addButton(ll, "\u25BA (3.4) After 3100m turn right onto 'SR 80' toward 'Rome'", !isJS ? builder(p).prepareTurn(AbstractPrologCommandPlayer.A_RIGHT, 3100, street(p, "", "SR 80", "Rome")) :
jsBuilder(p).prepareTurn(AbstractPrologCommandPlayer.A_RIGHT, 3100, jsStreet(p, "", "SR 80", "Rome")));
addButton(ll, "\u25BA (3.5) In 370m turn slightly right onto 'Route 23' 'Main Street', then bear left", !isJS ? builder(p).turn(AbstractPrologCommandPlayer.A_RIGHT_SL, 370, street(p, "Main Street", "Route 23")).then().bearLeft(street(p, "")) :
jsBuilder(p).turn(AbstractPrologCommandPlayer.A_RIGHT_SL, 370, jsStreet(p, "Main jsStreet", "Route 23")).then().bearLeft(jsStreet(p, "")));
addButton(ll, "\u25BA (3.6) Turn sharply right onto 'Dr.-Quinn-Stra"+"\u00df"+"e'", !isJS ? builder(p).turn(AbstractPrologCommandPlayer.A_RIGHT_SH, street(p, "Dr.-Quinn-Straße")) :
jsBuilder(p).turn(AbstractPrologCommandPlayer.A_RIGHT_SH, jsStreet(p, "Dr.-Quinn-Straße")));
addButton(ll, "\u25BA (3.1) After 1520m turn slightly left", builder(p).prepareTurn(AbstractPrologCommandPlayer.A_LEFT_SL, 1520, street(p, "")));
addButton(ll, "\u25BA (3.2) In 450m turn sharply left onto 'Hauptstra"+"\u00df"+"e', then bear right", builder(p).turn(AbstractPrologCommandPlayer.A_LEFT_SH, 450, street(p, "Hauptstraße")).then().bearRight(street(p, "")));
addButton(ll, "\u25BA (3.3) Turn left, then in 100m turn slightly right", builder(p).turn(AbstractPrologCommandPlayer.A_LEFT, street(p, "")).then().turn(AbstractPrologCommandPlayer.A_RIGHT_SL, 100, street(p, "")));
addButton(ll, "\u25BA (3.4) After 3100m turn right onto 'SR 80' toward 'Rome'", builder(p).prepareTurn(AbstractPrologCommandPlayer.A_RIGHT, 3100, street(p, "", "SR 80", "Rome")));
addButton(ll, "\u25BA (3.5) In 370m turn slightly right onto 'Route 23' 'Main Street', then bear left", builder(p).turn(AbstractPrologCommandPlayer.A_RIGHT_SL, 370, street(p, "Main Street", "Route 23")).then().bearLeft(street(p, "")));
addButton(ll, "\u25BA (3.6) Turn sharply right onto 'Dr.-Quinn-Stra"+"\u00df"+"e'", builder(p).turn(AbstractPrologCommandPlayer.A_RIGHT_SH, street(p, "Dr.-Quinn-Straße")));
addButton(ll, "Keep left/right: prepareTurn, makeTurnIn, turn:", builder(p));
addButton(ll, "\u25BA (4.1) After 1810m keep left ' '", !isJS ? builder(p).prepareTurn(AbstractPrologCommandPlayer.A_LEFT_KEEP, 1810, street(p, "")) :
jsBuilder(p).prepareTurn(AbstractPrologCommandPlayer.A_LEFT_KEEP, 1810, jsStreet(p, "")));
addButton(ll, "\u25BA (4.2) In 400m keep left ' ' then in 80m keep right onto 'A1'", !isJS ? builder(p).turn(AbstractPrologCommandPlayer.A_LEFT_KEEP, 400, street(p, "")).then().turn(AbstractPrologCommandPlayer.A_RIGHT_KEEP, 80, street(p,"", "A1")) :
jsBuilder(p).turn(AbstractPrologCommandPlayer.A_LEFT_KEEP, 400, jsStreet(p, "")).then().turn(AbstractPrologCommandPlayer.A_RIGHT_KEEP, 80, jsStreet(p,"", "A1")));
addButton(ll, "\u25BA (4.3) Keep right on 'Highway 60'", !isJS ? builder(p).turn(AbstractPrologCommandPlayer.A_RIGHT_KEEP, street(p, "Highway 60", "", "", "Highway 60")) :
jsBuilder(p).turn(AbstractPrologCommandPlayer.A_RIGHT_KEEP, jsStreet(p, "Highway 60", "", "", "Highway 60")));
addButton(ll, "\u25BA (4.4) Turn left onto 'Broadway', then in 100m keep right and arrive at your destination 'Town Hall'", !isJS ?
addButton(ll, "\u25BA (4.1) After 1810m keep left ' '", builder(p).prepareTurn(AbstractPrologCommandPlayer.A_LEFT_KEEP, 1810, street(p, "")));
addButton(ll, "\u25BA (4.2) In 400m keep left ' ' then in 80m keep right onto 'A1'", builder(p).turn(AbstractPrologCommandPlayer.A_LEFT_KEEP, 400, street(p, "")).then().turn(AbstractPrologCommandPlayer.A_RIGHT_KEEP, 80, street(p,"", "A1")));
addButton(ll, "\u25BA (4.3) Keep right on 'Highway 60'", builder(p).turn(AbstractPrologCommandPlayer.A_RIGHT_KEEP, street(p, "Highway 60", "", "", "Highway 60")));
addButton(ll, "\u25BA (4.4) Turn left onto 'Broadway', then in 100m keep right and arrive at your destination 'Town Hall'",
builder(p).turn(AbstractPrologCommandPlayer.A_LEFT, street(p, "Broadway"))
.then().turn(AbstractPrologCommandPlayer.A_RIGHT_KEEP, 100, street(p, "")).andArriveAtDestination("Town Hall") :
jsBuilder(p).turn(AbstractPrologCommandPlayer.A_LEFT, jsStreet(p, "Broadway"))
.then().turn(AbstractPrologCommandPlayer.A_RIGHT_KEEP, 100, jsStreet(p, "")).andArriveAtDestination("Town Hall"));
.then().turn(AbstractPrologCommandPlayer.A_RIGHT_KEEP, 100, street(p, "")).andArriveAtDestination("Town Hall"));
addButton(ll, "Roundabouts: prepareTurn, makeTurnIn, turn:", builder(p));
addButton(ll, "\u25BA (5.1) After 1250m enter a roundabout", !isJS ? builder(p).prepareRoundAbout(1250, 3, street(p,"", "I 15", "Los Angeles")) :
jsBuilder(p).prepareRoundAbout(1250, 3, jsStreet(p,"", "I 15", "Los Angeles")));
addButton(ll, "\u25BA (5.2) In 450m enter the roundabout and take the 1st exit onto 'I 15' toward 'Los Angeles'", !isJS ? builder(p).roundAbout(450, 0, 1, street(p,"", "I 15", "Los Angeles")) :
jsBuilder(p).roundAbout(450, 0, 1, jsStreet(p,"", "I 15", "Los Angeles")));
addButton(ll, "\u25BA (5.3) Roundabout: Take the 2nd exit onto 'Highway 60'", !isJS ? builder(p).roundAbout(0, 2, street(p, "Highway 60")) :
jsBuilder(p).roundAbout(0, 2, jsStreet(p, "Highway 60")));
addButton(ll, "\u25BA (5.1) After 1250m enter a roundabout", builder(p).prepareRoundAbout(1250, 3, street(p,"", "I 15", "Los Angeles")));
addButton(ll, "\u25BA (5.2) In 450m enter the roundabout and take the 1st exit onto 'I 15' toward 'Los Angeles'", builder(p).roundAbout(450, 0, 1, street(p,"", "I 15", "Los Angeles")));
addButton(ll, "\u25BA (5.3) Roundabout: Take the 2nd exit onto 'Highway 60'", builder(p).roundAbout(0, 2, street(p, "Highway 60")));
addButton(ll, "U-turns: prepareTurn, makeTurnIn, turn, when possible:", builder(p));
addButton(ll, "\u25BA (6.1) After 640m make a U-turn", !isJS ? builder(p).prepareMakeUT(640, street(p, "")) :
jsBuilder(p).prepareMakeUT(640, jsStreet(p, "")));
addButton(ll, "\u25BA (6.2) In 400m make a U-turn", !isJS ? builder(p).makeUT(400, street(p, "")) :
jsBuilder(p).makeUT(400, jsStreet(p, "")));
addButton(ll, "\u25BA (6.3) Make a U-turn on 'Riviera'", !isJS ? builder(p).makeUT(street(p, "Riviera", "", "", "Riviera")) :
jsBuilder(p).makeUT(jsStreet(p, "Riviera", "", "", "Riviera")));
addButton(ll, "\u25BA (6.1) After 640m make a U-turn", builder(p).prepareMakeUT(640, street(p, "")));
addButton(ll, "\u25BA (6.2) In 400m make a U-turn", builder(p).makeUT(400, street(p, "")));
addButton(ll, "\u25BA (6.3) Make a U-turn on 'Riviera'", builder(p).makeUT(street(p, "Riviera", "", "", "Riviera")));
addButton(ll, "\u25BA (6.4) When possible, make a U-turn", builder(p).makeUTwp());
addButton(ll, "Go straight, follow the road, approaching:", builder(p));
addButton(ll, "\u25BA (7.1) Straight ahead", builder(p).goAhead());
addButton(ll, "\u25BA (7.2) Continue for 2350m to ' '", !isJS ? builder(p).goAhead(2350, street(p, "")) :
jsBuilder(p).goAhead(2350, jsStreet(p, "")));
addButton(ll, "\u25BA (7.3) Continue for 360m to 'Broadway' and arrive at your intermediate destination ' '", !isJS ? builder(p).goAhead(360, street(p,"Broadway")).andArriveAtIntermediatePoint("") :
jsBuilder(p).goAhead(360, jsStreet(p,"Broadway")).andArriveAtIntermediatePoint(""));
addButton(ll, "\u25BA (7.4) Continue for 800m to 'Dr Martin Luther King Jr Boulevard' and arrive at your destination ' '", !isJS ? builder(p).goAhead(800, street(p,"", "Dr Martin Luther King Jr Boulevard")).andArriveAtDestination("") :
jsBuilder(p).goAhead(800, jsStreet(p,"", "Dr Martin Luther King Jr Boulevard")).andArriveAtDestination(""));
addButton(ll, "\u25BA (7.5) Continue for 200m and pass GPX waypoint 'Trailhead'", !isJS ? builder(p).goAhead(200, null).andArriveAtWayPoint("Trailhead") : jsBuilder(p).goAhead(200, new HashMap<String, String>()).andArriveAtWayPoint("Trailhead"));
addButton(ll, "\u25BA (7.6) Continue for 400m and pass favorite 'Brewery'", !isJS ? builder(p).goAhead(400, null).andArriveAtFavorite("Brewery") : jsBuilder(p).goAhead(400, new HashMap<String, String>()).andArriveAtFavorite("Brewery"));
addButton(ll, "\u25BA (7.7) Continue for 600m and pass POI 'Museum'", !isJS ? builder(p).goAhead(600, null).andArriveAtPoi("Museum") : jsBuilder(p).goAhead(600, new HashMap<String, String>()).andArriveAtPoi("Museum"));
addButton(ll, "\u25BA (7.2) Continue for 2350m to ' '", builder(p).goAhead(2350, street(p)));
addButton(ll, "\u25BA (7.3) Continue for 360m to 'Broadway' and arrive at your intermediate destination ' '", builder(p).goAhead(360, street(p,"Broadway")).andArriveAtIntermediatePoint(""));
addButton(ll, "\u25BA (7.4) Continue for 800m to 'Dr Martin Luther King Jr Boulevard' and arrive at your destination ' '", builder(p).goAhead(800, street(p,"", "Dr Martin Luther King Jr Boulevard")).andArriveAtDestination(""));
addButton(ll, "\u25BA (7.5) Continue for 200m and pass GPX waypoint 'Trailhead'", builder(p).goAhead(200, new StreetName()).andArriveAtWayPoint("Trailhead") );
addButton(ll, "\u25BA (7.6) Continue for 400m and pass favorite 'Brewery'", builder(p).goAhead(400, new StreetName()).andArriveAtFavorite("Brewery") );
addButton(ll, "\u25BA (7.7) Continue for 600m and pass POI 'Museum'", builder(p).goAhead(600, new StreetName()).andArriveAtPoi("Museum") );
addButton(ll, "Arriving and passing points:", builder(p));
addButton(ll, "\u25BA (8.1) Arrive at your destination 'Home'", builder(p).arrivedAtDestination("Home"));
@ -307,10 +244,10 @@ public class TestVoiceActivity extends OsmandActionBarActivity {
ll.forceLayout();
}
private Map<String, String> jsStreet(CommandPlayer p, String... args) {
private StreetName street(CommandPlayer p, String... args) {
Map<String, String> res = new HashMap<>();
if (!p.supportsStructuredStreetNames()) {
return res;
return new StreetName();
}
String[] streetNames = new String[]{"toRef", "toStreetName", "toDest", "fromRef", "fromStreetName", "fromDest"};
for (int i = 0; i < args.length; i++) {
@ -321,17 +258,13 @@ public class TestVoiceActivity extends OsmandActionBarActivity {
res.put(streetName, "");
}
}
return res;
return new StreetName(res);
}
private CommandBuilder builder(CommandPlayer p){
return p.newCommandBuilder();
}
private JSCommandBuilder jsBuilder(CommandPlayer p) {
return (JSCommandBuilder) p.newCommandBuilder();
}
public void addButton(ViewGroup layout, final String description, final CommandBuilder builder){
final Button button = new Button(this);
button.setGravity(Gravity.LEFT);
@ -385,9 +318,9 @@ public class TestVoiceActivity extends OsmandActionBarActivity {
public boolean onOptionsItemSelected(MenuItem item) {
int itemId = item.getItemId();
switch (itemId) {
case android.R.id.home:
finish();
return true;
case android.R.id.home:
finish();
return true;
}
return false;
}

View file

@ -1,330 +0,0 @@
package net.osmand.plus.routing;
import net.osmand.Location;
import net.osmand.binary.RouteDataObject;
import net.osmand.plus.OsmandSettings;
import net.osmand.plus.voice.CommandBuilder;
import net.osmand.plus.voice.JSCommandBuilder;
import net.osmand.router.RouteSegmentResult;
import net.osmand.router.TurnType;
import java.util.HashMap;
import java.util.Map;
public class JSVoiceRouter extends VoiceRouter {
public JSVoiceRouter(RoutingHelper router, OsmandSettings settings) {
super(router, settings);
}
public Map<String, String> getSpeakableJSStreetName(RouteSegmentResult currentSegment, RouteDirectionInfo i, boolean includeDest) {
Map<String, String> result = new HashMap<>();
if (i == null || !router.getSettings().SPEAK_STREET_NAMES.get()) {
return result;
}
if (player != null && player.supportsStructuredStreetNames()) {
// Issue 2377: Play Dest here only if not already previously announced, to avoid repetition
if (includeDest == true) {
result.put("toRef", getNonNullString(getSpeakablePointName(i.getRef())));
result.put("toStreetName", getNonNullString(getSpeakablePointName(i.getStreetName())));
result.put("toDest", getNonNullString(getSpeakablePointName(i.getDestinationName())));
} else {
result.put("toRef", getNonNullString(getSpeakablePointName(i.getRef())));
result.put("toStreetName", getNonNullString(getSpeakablePointName(i.getStreetName())));
result.put("toDest", "");
}
if (currentSegment != null) {
// Issue 2377: Play Dest here only if not already previously announced, to avoid repetition
if (includeDest == true) {
RouteDataObject obj = currentSegment.getObject();
result.put("fromRef", getNonNullString(getSpeakablePointName(obj.getRef(settings.MAP_PREFERRED_LOCALE.get(),
settings.MAP_TRANSLITERATE_NAMES.get(), currentSegment.isForwardDirection()))));
result.put("fromStreetName", getNonNullString(getSpeakablePointName(obj.getName(settings.MAP_PREFERRED_LOCALE.get(),
settings.MAP_TRANSLITERATE_NAMES.get()))));
result.put("fromDest", getNonNullString(getSpeakablePointName(obj.getDestinationName(settings.MAP_PREFERRED_LOCALE.get(),
settings.MAP_TRANSLITERATE_NAMES.get(), currentSegment.isForwardDirection()))));
} else {
RouteDataObject obj = currentSegment.getObject();
result.put("fromRef", getNonNullString(getSpeakablePointName(obj.getRef(settings.MAP_PREFERRED_LOCALE.get(),
settings.MAP_TRANSLITERATE_NAMES.get(), currentSegment.isForwardDirection()))));
result.put("fromStreetName", getNonNullString(getSpeakablePointName(obj.getName(settings.MAP_PREFERRED_LOCALE.get(),
settings.MAP_TRANSLITERATE_NAMES.get()))));
result.put("fromDest", "");
}
}
} else {
result.put("toRef", getNonNullString(getSpeakablePointName(i.getRef())));
result.put("toStreetName", getNonNullString(getSpeakablePointName(i.getStreetName())));
result.put("toDest", "");
}
return result;
}
private String getNonNullString(String speakablePointName) {
return speakablePointName == null ? "" : speakablePointName;
}
/**
* Updates status of voice guidance
* @param currentLocation
*/
@Override
protected void updateStatus(Location currentLocation, boolean repeat) {
// Directly after turn: goAhead (dist), unless:
// < PREPARE_LONG_DISTANCE (e.g. 3500m): playPrepareTurn (-not played any more-)
// < PREPARE_DISTANCE (e.g. 1500m): playPrepareTurn ("Turn after ...")
// < TURN_IN_DISTANCE (e.g. 390m or 30sec): playMakeTurnIn ("Turn in ...")
// < TURN_DISTANCE (e.g. 50m or 7sec): playMakeTurn ("Turn ...")
float speed = DEFAULT_SPEED;
if (currentLocation != null && currentLocation.hasSpeed()) {
speed = Math.max(currentLocation.getSpeed(), speed);
}
RouteCalculationResult.NextDirectionInfo nextInfo = router.getNextRouteDirectionInfo(new RouteCalculationResult.NextDirectionInfo(), true);
RouteSegmentResult currentSegment = router.getCurrentSegmentResult();
if (nextInfo == null || nextInfo.directionInfo == null) {
return;
}
int dist = nextInfo.distanceTo;
RouteDirectionInfo next = nextInfo.directionInfo;
// If routing is changed update status to unknown
if (next != nextRouteDirection) {
nextRouteDirection = next;
currentStatus = STATUS_UNKNOWN;
suppressDest = false;
playedAndArriveAtTarget = false;
announceBackOnRoute = false;
if (playGoAheadDist != -1) {
playGoAheadDist = 0;
}
}
if (!repeat) {
if (dist <= 0) {
return;
} else if (needsInforming()) {
playGoAhead(dist, getSpeakableJSStreetName(currentSegment, next, false));
return;
} else if (currentStatus == STATUS_TOLD) {
// nothing said possibly that's wrong case we should say before that
// however it should be checked manually ?
return;
}
}
if (currentStatus == STATUS_UNKNOWN) {
// Play "Continue for ..." if (1) after route calculation no other prompt is due, or (2) after a turn if next turn is more than PREPARE_LONG_DISTANCE away
if ((playGoAheadDist == -1) || (dist > PREPARE_LONG_DISTANCE)) {
playGoAheadDist = dist - 3 * TURN_DISTANCE;
}
}
RouteCalculationResult.NextDirectionInfo nextNextInfo = router.getNextRouteDirectionInfoAfter(nextInfo, new RouteCalculationResult.NextDirectionInfo(), true); //I think "true" is correct here, not "!repeat"
// Note: getNextRouteDirectionInfoAfter(nextInfo, x, y).distanceTo is distance from nextInfo, not from current position!
// STATUS_TURN = "Turn (now)"
if ((repeat || statusNotPassed(STATUS_TURN)) && isDistanceLess(speed, dist, TURN_DISTANCE, TURN_DEFAULT_SPEED)) {
if (nextNextInfo.distanceTo < TURN_IN_DISTANCE_END && nextNextInfo != null) {
playMakeTurn(currentSegment, next, nextNextInfo);
} else {
playMakeTurn(currentSegment, next, null);
}
if (!next.getTurnType().goAhead() && isTargetPoint(nextNextInfo)) { // !goAhead() avoids isolated "and arrive.." prompt, as goAhead() is not pronounced
if (nextNextInfo.distanceTo < TURN_IN_DISTANCE_END) {
// Issue #2865: Ensure a distance associated with the destination arrival is always announced, either here, or in subsequent "Turn in" prompt
// Distance fon non-straights already announced in "Turn (now)"'s nextnext code above
if ((nextNextInfo != null) && (nextNextInfo.directionInfo != null) && nextNextInfo.directionInfo.getTurnType().goAhead()) {
playThen();
playGoAhead(nextNextInfo.distanceTo, new HashMap<String, String>());
}
playAndArriveAtDestination(nextNextInfo);
} else if (nextNextInfo.distanceTo < 1.2f * TURN_IN_DISTANCE_END) {
// 1.2 is safety margin should the subsequent "Turn in" prompt not fit in amy more
playThen();
playGoAhead(nextNextInfo.distanceTo, new HashMap<String, String>());
playAndArriveAtDestination(nextNextInfo);
}
}
nextStatusAfter(STATUS_TURN);
// STATUS_TURN_IN = "Turn in ..."
} else if ((repeat || statusNotPassed(STATUS_TURN_IN)) && isDistanceLess(speed, dist, TURN_IN_DISTANCE, 0f)) {
if (repeat || dist >= TURN_IN_DISTANCE_END) {
if ((isDistanceLess(speed, nextNextInfo.distanceTo, TURN_DISTANCE, 0f) || nextNextInfo.distanceTo < TURN_IN_DISTANCE_END) &&
nextNextInfo != null) {
playMakeTurnIn(currentSegment, next, dist - (int) btScoDelayDistance, nextNextInfo.directionInfo);
} else {
playMakeTurnIn(currentSegment, next, dist - (int) btScoDelayDistance, null);
}
playGoAndArriveAtDestination(repeat, nextInfo, currentSegment);
}
nextStatusAfter(STATUS_TURN_IN);
// STATUS_PREPARE = "Turn after ..."
} else if ((repeat || statusNotPassed(STATUS_PREPARE)) && (dist <= PREPARE_DISTANCE)) {
if (repeat || dist >= PREPARE_DISTANCE_END) {
if (!repeat && (next.getTurnType().keepLeft() || next.getTurnType().keepRight())) {
// Do not play prepare for keep left/right
} else {
playPrepareTurn(currentSegment, next, dist);
playGoAndArriveAtDestination(repeat, nextInfo, currentSegment);
}
}
nextStatusAfter(STATUS_PREPARE);
// STATUS_LONG_PREPARE = also "Turn after ...", we skip this now, users said this is obsolete
} else if ((repeat || statusNotPassed(STATUS_LONG_PREPARE)) && (dist <= PREPARE_LONG_DISTANCE)) {
if (repeat || dist >= PREPARE_LONG_DISTANCE_END) {
playPrepareTurn(currentSegment, next, dist);
playGoAndArriveAtDestination(repeat, nextInfo, currentSegment);
}
nextStatusAfter(STATUS_LONG_PREPARE);
// STATUS_UNKNOWN = "Continue for ..." if (1) after route calculation no other prompt is due, or (2) after a turn if next turn is more than PREPARE_LONG_DISTANCE away
} else if (statusNotPassed(STATUS_UNKNOWN)) {
// Strange how we get here but
nextStatusAfter(STATUS_UNKNOWN);
} else if (repeat || (statusNotPassed(STATUS_PREPARE) && dist < playGoAheadDist)) {
playGoAheadDist = 0;
playGoAhead(dist, getSpeakableJSStreetName(currentSegment, next, false));
}
}
private void playPrepareTurn(RouteSegmentResult currentSegment, RouteDirectionInfo next, int dist) {
JSCommandBuilder play = (JSCommandBuilder) getNewCommandPlayerToPlay();
if (play != null) {
String tParam = getTurnType(next.getTurnType());
if (tParam != null) {
notifyOnVoiceMessage();
play.prepareTurn(tParam, dist, getSpeakableJSStreetName(currentSegment, next, true)).play();
} else if (next.getTurnType().isRoundAbout()) {
notifyOnVoiceMessage();
play.prepareRoundAbout(dist, next.getTurnType().getExitOut(), getSpeakableJSStreetName(currentSegment, next, true)).play();
} else if (next.getTurnType().getValue() == TurnType.TU || next.getTurnType().getValue() == TurnType.TRU) {
notifyOnVoiceMessage();
play.prepareMakeUT(dist, getSpeakableJSStreetName(currentSegment, next, true)).play();
}
}
}
private void playMakeTurnIn(RouteSegmentResult currentSegment, RouteDirectionInfo next, int dist, RouteDirectionInfo pronounceNextNext) {
JSCommandBuilder play = (JSCommandBuilder) getNewCommandPlayerToPlay();
if (play != null) {
String tParam = getTurnType(next.getTurnType());
boolean isPlay = true;
if (tParam != null) {
play.turn(tParam, dist, getSpeakableJSStreetName(currentSegment, next, true));
suppressDest = true;
} else if (next.getTurnType().isRoundAbout()) {
play.roundAbout(dist, next.getTurnType().getTurnAngle(), next.getTurnType().getExitOut(), getSpeakableJSStreetName(currentSegment, next, true));
// Other than in prepareTurn, in prepareRoundabout we do not announce destination, so we can repeat it one more time
suppressDest = false;
} else if (next.getTurnType().getValue() == TurnType.TU || next.getTurnType().getValue() == TurnType.TRU) {
play.makeUT(dist, getSpeakableJSStreetName(currentSegment, next, true));
suppressDest = true;
} else {
isPlay = false;
}
// 'then keep' preparation for next after next. (Also announces an interim straight segment, which is not pronounced above.)
if (pronounceNextNext != null) {
TurnType t = pronounceNextNext.getTurnType();
isPlay = true;
if (t.getValue() != TurnType.C && next.getTurnType().getValue() == TurnType.C) {
play.goAhead(dist, getSpeakableJSStreetName(currentSegment, next, true));
}
if (t.getValue() == TurnType.TL || t.getValue() == TurnType.TSHL || t.getValue() == TurnType.TSLL
|| t.getValue() == TurnType.TU || t.getValue() == TurnType.KL ) {
play.then().bearLeft(getSpeakableJSStreetName(currentSegment, next, false));
} else if (t.getValue() == TurnType.TR || t.getValue() == TurnType.TSHR || t.getValue() == TurnType.TSLR
|| t.getValue() == TurnType.TRU || t.getValue() == TurnType.KR) {
play.then().bearRight(getSpeakableJSStreetName(currentSegment, next, false));
}
}
if (isPlay) {
notifyOnVoiceMessage();
play.play();
}
}
}
private void playGoAhead(int dist, Map<String, String> streetName) {
CommandBuilder play = getNewCommandPlayerToPlay();
JSCommandBuilder playJs = (JSCommandBuilder) play;
if (play != null) {
notifyOnVoiceMessage();
playJs.goAhead(dist, streetName).play();
}
}
private void playMakeTurn(RouteSegmentResult currentSegment, RouteDirectionInfo next, RouteCalculationResult.NextDirectionInfo nextNextInfo) {
JSCommandBuilder play = (JSCommandBuilder) getNewCommandPlayerToPlay();
if (play != null) {
String tParam = getTurnType(next.getTurnType());
boolean isplay = true;
if (tParam != null) {
play.turn(tParam, getSpeakableJSStreetName(currentSegment, next, !suppressDest));
} else if (next.getTurnType().isRoundAbout()) {
play.roundAbout(next.getTurnType().getTurnAngle(), next.getTurnType().getExitOut(), getSpeakableJSStreetName(currentSegment, next, !suppressDest));
} else if (next.getTurnType().getValue() == TurnType.TU || next.getTurnType().getValue() == TurnType.TRU) {
play.makeUT(getSpeakableJSStreetName(currentSegment, next, !suppressDest));
// Do not announce goAheads
//} else if (next.getTurnType().getValue() == TurnType.C)) {
// play.goAhead();
} else {
isplay = false;
}
// Add turn after next
if ((nextNextInfo != null) && (nextNextInfo.directionInfo != null)) {
// This case only needed should we want a prompt at the end of straight segments (equivalent of makeTurn) when nextNextInfo should be announced again there.
if (nextNextInfo.directionInfo.getTurnType().getValue() != TurnType.C && next.getTurnType().getValue() == TurnType.C) {
play.goAhead();
isplay = true;
}
String t2Param = getTurnType(nextNextInfo.directionInfo.getTurnType());
if (t2Param != null) {
if (isplay) {
play.then();
play.turn(t2Param, nextNextInfo.distanceTo, new HashMap<String, String>());
}
} else if (nextNextInfo.directionInfo.getTurnType().isRoundAbout()) {
if (isplay) {
play.then();
play.roundAbout(nextNextInfo.distanceTo, nextNextInfo.directionInfo.getTurnType().getTurnAngle(),
nextNextInfo.directionInfo.getTurnType().getExitOut(), new HashMap<String, String>());
}
} else if (nextNextInfo.directionInfo.getTurnType().getValue() == TurnType.TU) {
if (isplay) {
play.then();
play.makeUT(nextNextInfo.distanceTo, new HashMap<String, String>());
}
}
}
if (isplay) {
notifyOnVoiceMessage();
play.play();
}
}
}
private void playGoAndArriveAtDestination(boolean repeat, RouteCalculationResult.NextDirectionInfo nextInfo, RouteSegmentResult currentSegment) {
RouteDirectionInfo next = nextInfo.directionInfo;
if (isTargetPoint(nextInfo) && (!playedAndArriveAtTarget || repeat)) {
if (next.getTurnType().goAhead()) {
playGoAhead(nextInfo.distanceTo, getSpeakableJSStreetName(currentSegment, next, false));
playAndArriveAtDestination(nextInfo);
playedAndArriveAtTarget = true;
} else if (nextInfo.distanceTo <= 2 * TURN_IN_DISTANCE) {
playAndArriveAtDestination(nextInfo);
playedAndArriveAtTarget = true;
}
}
}
}

View file

@ -97,9 +97,7 @@ public class RoutingHelper {
public RoutingHelper(OsmandApplication context){
this.app = context;
settings = context.getSettings();
boolean useJS = settings.USE_JS_VOICE_GUIDANCE.get();
voiceRouter = useJS ? new JSVoiceRouter(this, settings)
: new VoiceRouter(this, settings);
voiceRouter = new VoiceRouter(this, settings);
provider = new RouteProvider();
setAppMode(settings.APPLICATION_MODE.get());
}

View file

@ -2,7 +2,9 @@ package net.osmand.plus.routing;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import net.osmand.Location;
@ -13,6 +15,7 @@ import net.osmand.plus.OsmandSettings;
import net.osmand.plus.helpers.WaypointHelper.LocationPointWrapper;
import net.osmand.plus.routing.AlarmInfo.AlarmInfoType;
import net.osmand.plus.routing.RouteCalculationResult.NextDirectionInfo;
import net.osmand.plus.routing.data.StreetName;
import net.osmand.plus.voice.AbstractPrologCommandPlayer;
import net.osmand.plus.voice.CommandBuilder;
import net.osmand.plus.voice.CommandPlayer;
@ -28,48 +31,51 @@ import android.media.SoundPool;
public class VoiceRouter {
private static final int STATUS_UTWP_TOLD = -1;
static final int STATUS_UNKNOWN = 0;
static final int STATUS_LONG_PREPARE = 1;
static final int STATUS_PREPARE = 2;
static final int STATUS_TURN_IN = 3;
static final int STATUS_TURN = 4;
static final int STATUS_TOLD = 5;
private static final int STATUS_UNKNOWN = 0;
private static final int STATUS_LONG_PREPARE = 1;
private static final int STATUS_PREPARE = 2;
private static final int STATUS_TURN_IN = 3;
private static final int STATUS_TURN = 4;
private static final int STATUS_TOLD = 5;
public static final String TO_REF = "toRef";
public static final String TO_STREET_NAME = "toStreetName";
public static final String TO_DEST = "toDest";
public static final String FROM_REF = "fromRef";
public static final String FROM_STREET_NAME = "fromStreetName";
public static final String FROM_DEST = "fromDest";
protected final RoutingHelper router;
protected static CommandPlayer player;
protected final OsmandSettings settings;
private static boolean mute = false;
static int currentStatus = STATUS_UNKNOWN;
static boolean playedAndArriveAtTarget = false;
static float playGoAheadDist = 0;
private static int currentStatus = STATUS_UNKNOWN;
private static boolean playedAndArriveAtTarget = false;
private static float playGoAheadDist = 0;
private static long lastAnnouncedSpeedLimit = 0;
private static long waitAnnouncedSpeedLimit = 0;
private static long lastAnnouncedOffRoute = 0;
private static long waitAnnouncedOffRoute = 0;
static boolean suppressDest = false;
static boolean announceBackOnRoute = false;
private static boolean suppressDest = false;
private static boolean announceBackOnRoute = false;
// private static long lastTimeRouteRecalcAnnounced = 0;
// Remember when last announcement was made
private static long lastAnnouncement = 0;
// Default speed to have comfortable announcements (Speed in m/s)
protected float DEFAULT_SPEED = 12;
protected float TURN_DEFAULT_SPEED = 5;
private float DEFAULT_SPEED = 12;
private float TURN_DEFAULT_SPEED = 5;
protected int PREPARE_LONG_DISTANCE = 0;
protected int PREPARE_LONG_DISTANCE_END = 0;
private int PREPARE_LONG_DISTANCE = 0;
private int PREPARE_LONG_DISTANCE_END = 0;
protected int PREPARE_DISTANCE = 0;
protected int PREPARE_DISTANCE_END = 0;
protected int TURN_IN_DISTANCE = 0;
protected int TURN_IN_DISTANCE_END = 0;
protected int TURN_DISTANCE = 0;
private int PREPARE_DISTANCE_END = 0;
private int TURN_IN_DISTANCE = 0;
private int TURN_IN_DISTANCE_END = 0;
private int TURN_DISTANCE = 0;
protected static VoiceCommandPending pendingCommand = null;
static RouteDirectionInfo nextRouteDirection;
private Term empty;
private boolean useJS;
private static VoiceCommandPending pendingCommand = null;
private static RouteDirectionInfo nextRouteDirection;
public interface VoiceMessageListener {
void onVoiceMessage();
@ -77,17 +83,15 @@ public class VoiceRouter {
private ConcurrentHashMap<VoiceMessageListener, Integer> voiceMessageListeners;
public VoiceRouter(RoutingHelper router, final OsmandSettings settings) {
VoiceRouter(RoutingHelper router, final OsmandSettings settings) {
this.router = router;
this.settings = settings;
useJS = settings.USE_JS_VOICE_GUIDANCE.get();
this.mute = settings.VOICE_MUTE.get();
empty = new Struct("");
mute = settings.VOICE_MUTE.get();
voiceMessageListeners = new ConcurrentHashMap<VoiceRouter.VoiceMessageListener, Integer>();
}
public void setPlayer(CommandPlayer player) {
this.player = player;
VoiceRouter.player = player;
if (pendingCommand != null && player != null) {
CommandBuilder newCommand = getNewCommandPlayerToPlay();
if (newCommand != null) {
@ -109,7 +113,7 @@ public class VoiceRouter {
return mute;
}
protected CommandBuilder getNewCommandPlayerToPlay() {
private CommandBuilder getNewCommandPlayerToPlay() {
if (player == null) {
return null;
}
@ -167,7 +171,7 @@ public class VoiceRouter {
}
}
double btScoDelayDistance = 0;
private double btScoDelayDistance = 0;
public boolean isDistanceLess(float currentSpeed, double dist, double etalon, float defSpeed) {
if (defSpeed <= 0) {
@ -204,7 +208,7 @@ public class VoiceRouter {
}
}
void nextStatusAfter(int previousStatus) {
private void nextStatusAfter(int previousStatus) {
//STATUS_UNKNOWN=0 -> STATUS_LONG_PREPARE=1 -> STATUS_PREPARE=2 -> STATUS_TURN_IN=3 -> STATUS_TURN=4 -> STATUS_TOLD=5
if (previousStatus != STATUS_TOLD) {
this.currentStatus = previousStatus + 1;
@ -213,7 +217,7 @@ public class VoiceRouter {
}
}
boolean statusNotPassed(int statusToCheck) {
private boolean statusNotPassed(int statusToCheck) {
return currentStatus <= statusToCheck;
}
@ -237,7 +241,7 @@ public class VoiceRouter {
public void announceBackOnRoute() {
CommandBuilder p = getNewCommandPlayerToPlay();
if (announceBackOnRoute == true) {
if (announceBackOnRoute) {
if (p != null) {
notifyOnVoiceMessage();
p.backOnRoute().play();
@ -398,14 +402,14 @@ public class VoiceRouter {
}
}
boolean isTargetPoint(NextDirectionInfo info) {
private boolean isTargetPoint(NextDirectionInfo info) {
boolean in = info != null && info.intermediatePoint;
boolean target = info == null || info.directionInfo == null
|| info.directionInfo.distance == 0;
return in || target;
}
boolean needsInforming() {
private boolean needsInforming() {
final Integer repeat = settings.KEEP_INFORMING.get();
if (repeat == null || repeat == 0) return false;
@ -485,13 +489,13 @@ public class VoiceRouter {
// Distance fon non-straights already announced in "Turn (now)"'s nextnext code above
if ((nextNextInfo != null) && (nextNextInfo.directionInfo != null) && nextNextInfo.directionInfo.getTurnType().goAhead()) {
playThen();
playGoAhead(nextNextInfo.distanceTo, empty);
playGoAhead(nextNextInfo.distanceTo, new StreetName());
}
playAndArriveAtDestination(nextNextInfo);
} else if (nextNextInfo.distanceTo < 1.2f * TURN_IN_DISTANCE_END) {
// 1.2 is safety margin should the subsequent "Turn in" prompt not fit in amy more
playThen();
playGoAhead(nextNextInfo.distanceTo, empty);
playGoAhead(nextNextInfo.distanceTo, new StreetName());
playAndArriveAtDestination(nextNextInfo);
}
}
@ -568,7 +572,7 @@ public class VoiceRouter {
}
}
private void playGoAhead(int dist, Term streetName) {
private void playGoAhead(int dist, StreetName streetName) {
CommandBuilder play = getNewCommandPlayerToPlay();
if (play != null) {
notifyOnVoiceMessage();
@ -576,57 +580,54 @@ public class VoiceRouter {
}
}
public Term getSpeakableStreetName(RouteSegmentResult currentSegment, RouteDirectionInfo i, boolean includeDest) {
private StreetName getSpeakableStreetName(RouteSegmentResult currentSegment, RouteDirectionInfo i, boolean includeDest) {
Map<String, String> result = new HashMap<>();
if (i == null || !router.getSettings().SPEAK_STREET_NAMES.get()) {
return empty;
return new StreetName(result);
}
if (player != null && player.supportsStructuredStreetNames()) {
Term next = empty;
// Issue 2377: Play Dest here only if not already previously announced, to avoid repetition
if (includeDest == true) {
next = new Struct(new Term[] { getTermString(getSpeakablePointName(i.getRef())),
getTermString(getSpeakablePointName(i.getStreetName())),
getTermString(getSpeakablePointName(i.getDestinationName())) });
result.put(TO_REF, getNonNullString(getSpeakablePointName(i.getRef())));
result.put(TO_STREET_NAME, getNonNullString(getSpeakablePointName(i.getStreetName())));
result.put(TO_DEST, getNonNullString(getSpeakablePointName(i.getDestinationName())));
} else {
next = new Struct(new Term[] { getTermString(getSpeakablePointName(i.getRef())),
getTermString(getSpeakablePointName(i.getStreetName())),
empty });
result.put(TO_REF, getNonNullString(getSpeakablePointName(i.getRef())));
result.put(TO_STREET_NAME, getNonNullString(getSpeakablePointName(i.getStreetName())));
result.put(TO_DEST, "");
}
Term current = empty;
if (currentSegment != null) {
// Issue 2377: Play Dest here only if not already previously announced, to avoid repetition
if (includeDest == true) {
RouteDataObject obj = currentSegment.getObject();
current = new Struct(new Term[] { getTermString(getSpeakablePointName(obj.getRef(settings.MAP_PREFERRED_LOCALE.get(),
settings.MAP_TRANSLITERATE_NAMES.get(), currentSegment.isForwardDirection()))),
getTermString(getSpeakablePointName(obj.getName(settings.MAP_PREFERRED_LOCALE.get(), settings.MAP_TRANSLITERATE_NAMES.get()))),
getTermString(getSpeakablePointName(obj.getDestinationName(settings.MAP_PREFERRED_LOCALE.get(),
settings.MAP_TRANSLITERATE_NAMES.get(), currentSegment.isForwardDirection()))) });
result.put(FROM_REF, getNonNullString(getSpeakablePointName(obj.getRef(settings.MAP_PREFERRED_LOCALE.get(),
settings.MAP_TRANSLITERATE_NAMES.get(), currentSegment.isForwardDirection()))));
result.put(FROM_STREET_NAME, getNonNullString(getSpeakablePointName(obj.getName(settings.MAP_PREFERRED_LOCALE.get(),
settings.MAP_TRANSLITERATE_NAMES.get()))));
result.put(FROM_DEST, getNonNullString(getSpeakablePointName(obj.getDestinationName(settings.MAP_PREFERRED_LOCALE.get(),
settings.MAP_TRANSLITERATE_NAMES.get(), currentSegment.isForwardDirection()))));
} else {
RouteDataObject obj = currentSegment.getObject();
current = new Struct(new Term[] { getTermString(getSpeakablePointName(obj.getRef(settings.MAP_PREFERRED_LOCALE.get(),
settings.MAP_TRANSLITERATE_NAMES.get(), currentSegment.isForwardDirection()))),
getTermString(getSpeakablePointName(obj.getName(settings.MAP_PREFERRED_LOCALE.get(),
settings.MAP_TRANSLITERATE_NAMES.get()))),
empty });
result.put(FROM_REF, getNonNullString(getSpeakablePointName(obj.getRef(settings.MAP_PREFERRED_LOCALE.get(),
settings.MAP_TRANSLITERATE_NAMES.get(), currentSegment.isForwardDirection()))));
result.put(FROM_STREET_NAME, getNonNullString(getSpeakablePointName(obj.getName(settings.MAP_PREFERRED_LOCALE.get(),
settings.MAP_TRANSLITERATE_NAMES.get()))));
result.put(FROM_DEST, "");
}
}
Struct voice = new Struct("voice", next, current );
return voice;
} else {
Term rf = getTermString(getSpeakablePointName(i.getRef()));
if (rf == empty) {
rf = getTermString(getSpeakablePointName(i.getStreetName()));
}
return rf;
result.put("toRef", getNonNullString(getSpeakablePointName(i.getRef())));
result.put(TO_STREET_NAME, getNonNullString(getSpeakablePointName(i.getStreetName())));
result.put(TO_DEST, "");
}
return new StreetName(result);
}
private Term getTermString(String s) {
if (!Algorithms.isEmpty(s)) {
return new Struct(s);
}
return empty;
private String getNonNullString(String speakablePointName) {
return speakablePointName == null ? "" : speakablePointName;
}
public static String getSpeakablePointName(String pn) {
@ -718,7 +719,7 @@ public class VoiceRouter {
}
}
void playAndArriveAtDestination(NextDirectionInfo info) {
private void playAndArriveAtDestination(NextDirectionInfo info) {
if (isTargetPoint(info)) {
String pointName = info == null ? "" : info.pointName;
CommandBuilder play = getNewCommandPlayerToPlay();
@ -763,17 +764,17 @@ public class VoiceRouter {
if (t2Param != null) {
if (isplay) {
play.then();
play.turn(t2Param, nextNextInfo.distanceTo, empty);
play.turn(t2Param, nextNextInfo.distanceTo, new StreetName());
}
} else if (nextNextInfo.directionInfo.getTurnType().isRoundAbout()) {
if (isplay) {
play.then();
play.roundAbout(nextNextInfo.distanceTo, nextNextInfo.directionInfo.getTurnType().getTurnAngle(), nextNextInfo.directionInfo.getTurnType().getExitOut(), empty);
play.roundAbout(nextNextInfo.distanceTo, nextNextInfo.directionInfo.getTurnType().getTurnAngle(), nextNextInfo.directionInfo.getTurnType().getExitOut(), new StreetName());
}
} else if (nextNextInfo.directionInfo.getTurnType().getValue() == TurnType.TU) {
if (isplay) {
play.then();
play.makeUT(nextNextInfo.distanceTo, empty);
play.makeUT(nextNextInfo.distanceTo, new StreetName());
}
}
}
@ -784,7 +785,7 @@ public class VoiceRouter {
}
}
String getTurnType(TurnType t) {
private String getTurnType(TurnType t) {
if (TurnType.TL == t.getValue()) {
return AbstractPrologCommandPlayer.A_LEFT;
} else if (TurnType.TSHL == t.getValue()) {

View file

@ -0,0 +1,56 @@
package net.osmand.plus.routing.data;
import net.osmand.plus.routing.VoiceRouter;
import net.osmand.util.Algorithms;
import java.util.HashMap;
import java.util.Map;
import alice.tuprolog.Struct;
import alice.tuprolog.Term;
public class StreetName {
private Map<String, String> names;
private static final Term empty = new Struct("");;
public StreetName(Map<String, String> data) {
this.names = data;
}
public StreetName() {
names = new HashMap<>();
}
public Map<String, String> toMap() {
return names;
}
public Term toTerm() {
if (names == null || names.isEmpty()) {
return empty;
}
if (names.size() > 3) {
Term next = new Struct(new Term[]{getTermString(names.get(VoiceRouter.TO_REF)),
getTermString(names.get(VoiceRouter.TO_STREET_NAME)),
getTermString(names.get(VoiceRouter.TO_DEST))});
Term current = new Struct(new Term[]{getTermString(names.get(VoiceRouter.FROM_REF)),
getTermString(names.get(VoiceRouter.FROM_STREET_NAME)),
getTermString(names.get(VoiceRouter.FROM_DEST))});
return new Struct("voice", next, current);
} else {
Term rf = getTermString(names.get(VoiceRouter.TO_REF));
if (rf == empty) {
rf = getTermString(names.get(VoiceRouter.TO_STREET_NAME));
}
return rf;
}
}
private Term getTermString(String s) {
if (!Algorithms.isEmpty(s)) {
return new Struct(s);
}
return empty;
}
}

View file

@ -6,6 +6,7 @@ import java.util.List;
import net.osmand.PlatformUtil;
import net.osmand.plus.R;
import net.osmand.plus.routing.data.StreetName;
import org.apache.commons.logging.Log;
@ -41,32 +42,32 @@ public class CommandBuilder {
protected static final String C_ATTENTION = "attention"; //$NON-NLS-1$
protected static final String C_OFF_ROUTE = "off_route"; //$NON-NLS-1$
protected static final String C_BACK_ON_ROUTE ="back_on_route"; //$NON-NLS-1$
protected static final String C_BEAR_LEFT = "bear_left"; //$NON-NLS-1$
protected static final String C_BEAR_RIGHT = "bear_right"; //$NON-NLS-1$
protected static final String C_ROUTE_RECALC = "route_recalc"; //$NON-NLS-1$
protected static final String C_ROUTE_NEW_CALC = "route_new_calc"; //$NON-NLS-1$
protected static final String C_LOCATION_LOST = "location_lost"; //$NON-NLS-1$
protected static final String C_LOCATION_RECOVERED = "location_recovered"; //$NON-NLS-1$
/**
*
*
*/
protected final CommandPlayer commandPlayer;
protected boolean alreadyExecuted = false;
private List<Struct> listStruct = new ArrayList<Struct>();
public CommandBuilder(CommandPlayer commandPlayer){
this.commandPlayer = commandPlayer;
}
private void checkState() {
if(alreadyExecuted){
throw new IllegalArgumentException();
}
}
private CommandBuilder addCommand(String name, Object... args){
Struct struct = prepareStruct(name, args);
listStruct.add(struct);
@ -80,6 +81,8 @@ public class CommandBuilder {
Object o = args[i];
if(o instanceof Term){
list[i] = (Term) o;
} else if (o instanceof StreetName){
list[i] = ((StreetName)o).toTerm();
} else if(o instanceof java.lang.Number){
if(o instanceof java.lang.Double){
list[i] = new alice.tuprolog.Double((Double) o);
@ -103,7 +106,7 @@ public class CommandBuilder {
}
return struct;
}
private CommandBuilder alt(Struct... s1) {
if (s1.length == 1) {
listStruct.add(s1[0]);
@ -112,32 +115,31 @@ public class CommandBuilder {
}
return this;
}
public CommandBuilder goAhead(){
return addCommand(C_GO_AHEAD);
}
public CommandBuilder goAhead(double dist, Term streetName){
public CommandBuilder goAhead(double dist, StreetName streetName){
return alt(prepareStruct(C_GO_AHEAD, dist, streetName), prepareStruct(C_GO_AHEAD, dist));
}
public CommandBuilder makeUTwp(){
return addCommand(C_MAKE_UTWP);
}
public CommandBuilder makeUT(Term streetName){
public CommandBuilder makeUT(StreetName streetName){
return alt(prepareStruct(C_MAKE_UT, streetName), prepareStruct(C_MAKE_UT));
}
public CommandBuilder speedAlarm(int maxSpeed, float speed){
return addCommand(C_SPEAD_ALARM, maxSpeed, speed);
}
public CommandBuilder attention(String type){
return addCommand(C_ATTENTION, type);
}
public CommandBuilder offRoute(double dist){
return addCommand(C_OFF_ROUTE, dist);
}
@ -145,50 +147,49 @@ public class CommandBuilder {
public CommandBuilder backOnRoute(){
return addCommand(C_BACK_ON_ROUTE);
}
public CommandBuilder makeUT(double dist, Term streetName){
public CommandBuilder makeUT(double dist, StreetName streetName){
return alt(prepareStruct(C_MAKE_UT, dist, streetName), prepareStruct(C_MAKE_UT, dist));
}
public CommandBuilder prepareMakeUT(double dist, Term streetName){
public CommandBuilder prepareMakeUT(double dist, StreetName streetName){
return alt(prepareStruct(C_PREPARE_MAKE_UT, dist, streetName), prepareStruct(C_PREPARE_MAKE_UT, dist));
}
public CommandBuilder turn(String param, Term streetName) {
public CommandBuilder turn(String param, StreetName streetName) {
return alt(prepareStruct(C_TURN, param, streetName), prepareStruct(C_TURN, param));
}
public CommandBuilder turn(String param, double dist, Term streetName){
public CommandBuilder turn(String param, double dist, StreetName streetName){
return alt(prepareStruct(C_TURN, param, dist, streetName), prepareStruct(C_TURN, param, dist));
}
/**
*
*
* @param param A_LEFT, A_RIGHT, ...
* @param dist
* @return
*/
public CommandBuilder prepareTurn(String param, double dist, Term streetName){
public CommandBuilder prepareTurn(String param, double dist, StreetName streetName){
return alt(prepareStruct(C_PREPARE_TURN, param, dist, streetName), prepareStruct(C_PREPARE_TURN, param, dist));
}
public CommandBuilder prepareRoundAbout(double dist, int exit, Term streetName){
public CommandBuilder prepareRoundAbout(double dist, int exit, StreetName streetName){
return alt(prepareStruct(C_PREPARE_ROUNDABOUT, dist, exit, streetName), prepareStruct(C_PREPARE_ROUNDABOUT, dist));
}
public CommandBuilder roundAbout(double dist, double angle, int exit, Term streetName){
public CommandBuilder roundAbout(double dist, double angle, int exit, StreetName streetName){
return alt(prepareStruct(C_ROUNDABOUT, dist, angle, exit, streetName), prepareStruct(C_ROUNDABOUT, dist, angle, exit));
}
public CommandBuilder roundAbout(double angle, int exit, Term streetName) {
public CommandBuilder roundAbout(double angle, int exit, StreetName streetName) {
return alt(prepareStruct(C_ROUNDABOUT, angle, exit, streetName), prepareStruct(C_ROUNDABOUT, angle, exit));
}
public CommandBuilder andArriveAtDestination(String name){
return alt(prepareStruct(C_AND_ARRIVE_DESTINATION, name), prepareStruct(C_AND_ARRIVE_DESTINATION));
}
public CommandBuilder arrivedAtDestination(String name){
return alt(prepareStruct(C_REACHED_DESTINATION, name), prepareStruct(C_REACHED_DESTINATION));
}
@ -224,31 +225,31 @@ public class CommandBuilder {
public CommandBuilder arrivedAtPoi(String name) {
return addCommand(C_REACHED_POI, name);
}
public CommandBuilder bearLeft(Term streetName){
public CommandBuilder bearLeft(StreetName streetName){
return alt(prepareStruct(C_BEAR_LEFT, streetName), prepareStruct(C_BEAR_LEFT));
}
public CommandBuilder bearRight(Term streetName){
public CommandBuilder bearRight(StreetName streetName){
return alt(prepareStruct(C_BEAR_RIGHT, streetName), prepareStruct(C_BEAR_RIGHT));
}
public CommandBuilder then(){
return addCommand(C_THEN);
}
public CommandBuilder gpsLocationLost() {
return addCommand(C_LOCATION_LOST);
}
public CommandBuilder gpsLocationRecover() {
return addCommand(C_LOCATION_RECOVERED);
}
public CommandBuilder newRouteCalculated(double dist, int time){
return alt(prepareStruct(C_ROUTE_NEW_CALC, dist, time), prepareStruct(C_ROUTE_NEW_CALC, dist));
}
public CommandBuilder routeRecalculated(double dist, int time){
return alt(prepareStruct(C_ROUTE_RECALC, dist, time), prepareStruct(C_ROUTE_RECALC, dist));
}
@ -256,8 +257,8 @@ public class CommandBuilder {
public void play(){
this.commandPlayer.playCommands(this);
}
protected List<String> execute(){
alreadyExecuted = true;
return this.commandPlayer.execute(listStruct);

View file

@ -1,6 +1,7 @@
package net.osmand.plus.voice;
import net.osmand.PlatformUtil;
import net.osmand.plus.routing.data.StreetName;
import org.apache.commons.logging.Log;
import org.json.JSONObject;
@ -40,8 +41,8 @@ public class JSCommandBuilder extends CommandBuilder {
this.jsScope = jsScope;
}
private Object convertStreetName(Map<String, String> streetName) {
return NativeJSON.parse(jsContext, jsScope, new JSONObject(streetName).toString(),
private Object convertStreetName(StreetName streetName) {
return NativeJSON.parse(jsContext, jsScope, new JSONObject(streetName.toMap()).toString(),
new NullCallable());
}
@ -70,18 +71,19 @@ public class JSCommandBuilder extends CommandBuilder {
}
public JSCommandBuilder goAhead(){
return goAhead(-1, new HashMap<String, String>());
return goAhead(-1, new StreetName());
}
public JSCommandBuilder goAhead(double dist, Map<String, String> streetName){
public JSCommandBuilder goAhead(double dist, StreetName streetName){
return addCommand(C_GO_AHEAD, dist, convertStreetName(streetName));
}
@Override
public JSCommandBuilder makeUTwp(){
return makeUT(new HashMap<String, String>());
return makeUT(new StreetName());
}
public JSCommandBuilder makeUT(Map<String, String> streetName){
public JSCommandBuilder makeUT(StreetName streetName){
return makeUT(-1, streetName);
}
@Override
@ -101,20 +103,20 @@ public class JSCommandBuilder extends CommandBuilder {
return addCommand(C_BACK_ON_ROUTE);
}
public JSCommandBuilder makeUT(double dist, Map<String,String> streetName){
public JSCommandBuilder makeUT(double dist, StreetName streetName){
return addCommand(C_MAKE_UT, dist, convertStreetName(streetName));
}
public JSCommandBuilder prepareMakeUT(double dist, Map<String, String> streetName){
public JSCommandBuilder prepareMakeUT(double dist, StreetName streetName){
return addCommand(C_PREPARE_MAKE_UT, dist, convertStreetName(streetName));
}
public JSCommandBuilder turn(String param, Map<String, String> streetName) {
public JSCommandBuilder turn(String param, StreetName streetName) {
return turn(param, -1, streetName);
}
public JSCommandBuilder turn(String param, double dist, Map<String, String> streetName) {
public JSCommandBuilder turn(String param, double dist, StreetName streetName) {
return addCommand(C_TURN, param, dist, convertStreetName(streetName));
}
@ -124,19 +126,19 @@ public class JSCommandBuilder extends CommandBuilder {
* @param dist
* @return
*/
public JSCommandBuilder prepareTurn(String param, double dist, Map<String, String> streetName){
public JSCommandBuilder prepareTurn(String param, double dist, StreetName streetName){
return addCommand(C_PREPARE_TURN, param, dist, convertStreetName(streetName));
}
public JSCommandBuilder prepareRoundAbout(double dist, int exit, Map<String, String> streetName){
public JSCommandBuilder prepareRoundAbout(double dist, int exit, StreetName streetName){
return addCommand(C_PREPARE_ROUNDABOUT, dist, exit, convertStreetName(streetName));
}
public JSCommandBuilder roundAbout(double dist, double angle, int exit, Map<String, String> streetName){
public JSCommandBuilder roundAbout(double dist, double angle, int exit, StreetName streetName){
return addCommand(C_ROUNDABOUT, dist, angle, exit, convertStreetName(streetName));
}
public JSCommandBuilder roundAbout(double angle, int exit, Map<String, String> streetName) {
public JSCommandBuilder roundAbout(double angle, int exit, StreetName streetName) {
return roundAbout(-1, angle, exit, streetName);
}
@Override
@ -180,11 +182,11 @@ public class JSCommandBuilder extends CommandBuilder {
return addCommand(C_REACHED_POI, name);
}
public JSCommandBuilder bearLeft(Map<String,String> streetName){
public JSCommandBuilder bearLeft(StreetName streetName){
return addCommand(C_BEAR_LEFT, convertStreetName(streetName));
}
public JSCommandBuilder bearRight(Map<String, String> streetName){
public JSCommandBuilder bearRight(StreetName streetName){
return addCommand(C_BEAR_RIGHT, convertStreetName(streetName));
}