implement voice navigation
git-svn-id: https://osmand.googlecode.com/svn/trunk@342 e29c36b1-1cfa-d876-8d93-3434fc2bb7b8
This commit is contained in:
parent
6245fc5388
commit
7a7f6ad6eb
10 changed files with 374 additions and 138 deletions
|
@ -22,11 +22,18 @@ public class ToDoConstants {
|
||||||
// Improvement : Show stops in the transport route on the map
|
// Improvement : Show stops in the transport route on the map
|
||||||
// Improvement : redesign poi selecting (show on map )
|
// Improvement : redesign poi selecting (show on map )
|
||||||
/// Better : improve zooming (better zoom out)
|
/// Better : improve zooming (better zoom out)
|
||||||
|
// Add menu mute for voice
|
||||||
// BUG with search area for poi/transport bounds region
|
// BUG with search area for poi/transport bounds region
|
||||||
|
// BUG with foot navigation (unavailable for cloudmade)
|
||||||
|
// BUG animated move more precise check final location
|
||||||
|
// BUG turn concatenation
|
||||||
|
/// BUG Settings for osm bug creator name (save)
|
||||||
|
// BUG 9
|
||||||
|
|
||||||
// 69. Add phone information to POI
|
// 69. Add phone information to POI
|
||||||
|
|
||||||
// Not clear if it is really needed
|
// Not clear if it is really needed
|
||||||
// 43. Enable poi filter by name (find lake by name or shop) - case sensitive search DB!
|
// 43. Enable poi filter by name (find lake by name or shop) - case sensitive search DB - make only search filter (on UI)!
|
||||||
// 45. Get clear <Use internet> settings. Move that setting on top settings screen.
|
// 45. Get clear <Use internet> settings. Move that setting on top settings screen.
|
||||||
// That setting should rule all activities that use internet. It should ask whenever internet is used
|
// That setting should rule all activities that use internet. It should ask whenever internet is used
|
||||||
// (would you like to use internet for that operation - if using internet is not checked).
|
// (would you like to use internet for that operation - if using internet is not checked).
|
||||||
|
@ -42,7 +49,6 @@ public class ToDoConstants {
|
||||||
|
|
||||||
// BUGS Android
|
// BUGS Android
|
||||||
|
|
||||||
|
|
||||||
// TODO swing
|
// TODO swing
|
||||||
// 9. Fix issues with big files (such as netherlands) - save memory (!) - very slow due to transport index !
|
// 9. Fix issues with big files (such as netherlands) - save memory (!) - very slow due to transport index !
|
||||||
// Current result : for big file (1 - task 60-80% time, 90% memory) (?)
|
// Current result : for big file (1 - task 60-80% time, 90% memory) (?)
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
package="com.osmand" android:versionName="0.2.2" android:versionCode="5">
|
package="com.osmand" android:versionName="0.2.3" android:versionCode="6">
|
||||||
<application android:icon="@drawable/icon" android:label="@string/app_name"
|
<application android:icon="@drawable/icon" android:label="@string/app_name"
|
||||||
android:debuggable="true" android:name=".activities.OsmandApplication" android:description="@string/app_description">
|
android:debuggable="false" android:name=".activities.OsmandApplication" android:description="@string/app_description">
|
||||||
<activity android:name=".activities.MainMenuActivity"
|
<activity android:name=".activities.MainMenuActivity"
|
||||||
android:label="@string/app_name">
|
android:label="@string/app_name">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
|
|
|
@ -828,7 +828,9 @@ public class MapActivity extends Activity implements IMapLocationListener, Senso
|
||||||
builder.setNeutralButton(R.string.route_about, new DialogInterface.OnClickListener(){
|
builder.setNeutralButton(R.string.route_about, new DialogInterface.OnClickListener(){
|
||||||
@Override
|
@Override
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
startActivity(new Intent(MapActivity.this, ShowRouteInfoActivity.class));
|
Intent intent = new Intent(MapActivity.this, ShowRouteInfoActivity.class);
|
||||||
|
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||||
|
startActivity(intent);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -836,7 +838,6 @@ public class MapActivity extends Activity implements IMapLocationListener, Senso
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
|
||||||
Location map = new Location("map"); //$NON-NLS-1$
|
Location map = new Location("map"); //$NON-NLS-1$
|
||||||
map.setLatitude(lat);
|
map.setLatitude(lat);
|
||||||
map.setLongitude(lon);
|
map.setLongitude(lon);
|
||||||
|
|
|
@ -504,16 +504,14 @@ public class RouteProvider {
|
||||||
} else {
|
} else {
|
||||||
caz = res.get(dirInfo.routePointOffset - 1).bearingTo(res.get(dirInfo.routePointOffset));
|
caz = res.get(dirInfo.routePointOffset - 1).bearingTo(res.get(dirInfo.routePointOffset));
|
||||||
}
|
}
|
||||||
float angle = caz - paz + 15;
|
float angle = caz - paz;
|
||||||
if(angle < 0){
|
if(angle < 0){
|
||||||
angle += 360;
|
angle += 360;
|
||||||
} else if(angle > 360){
|
} else if(angle > 360){
|
||||||
angle -= 360;
|
angle -= 360;
|
||||||
}
|
}
|
||||||
// that magic number helps to fix some errors for turn
|
// that magic number helps to fix some errors for turn
|
||||||
if(angle < 100){
|
angle += 75;
|
||||||
angle += 45;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(previous.turnType.getTurnAngle() < 0.5f){
|
if(previous.turnType.getTurnAngle() < 0.5f){
|
||||||
previous.turnType.setTurnAngle(angle);
|
previous.turnType.setTurnAngle(angle);
|
||||||
|
|
|
@ -34,8 +34,8 @@ public class RoutingHelper {
|
||||||
|
|
||||||
// Note always currentRoute > get(currentDirectionInfo).routeOffset,
|
// Note always currentRoute > get(currentDirectionInfo).routeOffset,
|
||||||
// but currentRoute <= get(currentDirectionInfo+1).routeOffset
|
// but currentRoute <= get(currentDirectionInfo+1).routeOffset
|
||||||
private int currentDirectionInfo = 0;
|
protected int currentDirectionInfo = 0;
|
||||||
private int currentRoute = 0;
|
protected int currentRoute = 0;
|
||||||
|
|
||||||
|
|
||||||
private LatLon finalLocation;
|
private LatLon finalLocation;
|
||||||
|
@ -47,6 +47,7 @@ public class RoutingHelper {
|
||||||
private ApplicationMode mode;
|
private ApplicationMode mode;
|
||||||
|
|
||||||
private RouteProvider provider = new RouteProvider();
|
private RouteProvider provider = new RouteProvider();
|
||||||
|
private VoiceRouter voiceRouter;
|
||||||
|
|
||||||
|
|
||||||
// TEST CODE
|
// TEST CODE
|
||||||
|
@ -66,11 +67,13 @@ public class RoutingHelper {
|
||||||
|
|
||||||
|
|
||||||
private RoutingHelper(){
|
private RoutingHelper(){
|
||||||
|
voiceRouter = new VoiceRouter(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static RoutingHelper INSTANCE = new RoutingHelper();
|
private static RoutingHelper INSTANCE = new RoutingHelper();
|
||||||
public static RoutingHelper getInstance(Activity ctx){
|
public static RoutingHelper getInstance(Activity ctx){
|
||||||
INSTANCE.activity = ctx;
|
INSTANCE.activity = ctx;
|
||||||
|
INSTANCE.voiceRouter.init(ctx);
|
||||||
return INSTANCE;
|
return INSTANCE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,6 +103,7 @@ public class RoutingHelper {
|
||||||
|
|
||||||
public void setAppMode(ApplicationMode mode){
|
public void setAppMode(ApplicationMode mode){
|
||||||
this.mode = mode;
|
this.mode = mode;
|
||||||
|
voiceRouter.updateAppMode();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ApplicationMode getAppMode() {
|
public ApplicationMode getAppMode() {
|
||||||
|
@ -115,12 +119,17 @@ public class RoutingHelper {
|
||||||
return finalLocation != null && lastFixedLocation != null;
|
return finalLocation != null && lastFixedLocation != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public VoiceRouter getVoiceRouter() {
|
||||||
|
return voiceRouter;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public boolean finishAtLocation(Location currentLocation) {
|
public boolean finishAtLocation(Location currentLocation) {
|
||||||
Location lastPoint = routeNodes.get(routeNodes.size() - 1);
|
Location lastPoint = routeNodes.get(routeNodes.size() - 1);
|
||||||
if(currentRoute > routeNodes.size() - 3 && currentLocation.distanceTo(lastPoint) < 60){
|
if(currentRoute > routeNodes.size() - 3 && currentLocation.distanceTo(lastPoint) < 60){
|
||||||
if(lastFixedLocation != null && lastFixedLocation.distanceTo(lastPoint) < 60){
|
if(lastFixedLocation != null && lastFixedLocation.distanceTo(lastPoint) < 60){
|
||||||
showMessage(activity.getString(R.string.arrived_at_destination));
|
showMessage(activity.getString(R.string.arrived_at_destination));
|
||||||
|
voiceRouter.arrivedDestinationPoint();
|
||||||
updateCurrentRoute(routeNodes.size() - 1);
|
updateCurrentRoute(routeNodes.size() - 1);
|
||||||
// clear final location to prevent all time showing message
|
// clear final location to prevent all time showing message
|
||||||
finalLocation = null;
|
finalLocation = null;
|
||||||
|
@ -286,6 +295,7 @@ public class RoutingHelper {
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
voiceRouter.updateStatus();
|
||||||
|
|
||||||
lastFixedLocation = currentLocation;
|
lastFixedLocation = currentLocation;
|
||||||
if(calculateRoute){
|
if(calculateRoute){
|
||||||
|
@ -299,6 +309,9 @@ public class RoutingHelper {
|
||||||
listDistance = res.getListDistance();
|
listDistance = res.getListDistance();
|
||||||
currentDirectionInfo = 0;
|
currentDirectionInfo = 0;
|
||||||
currentRoute = 0;
|
currentRoute = 0;
|
||||||
|
if(isFollowingMode){
|
||||||
|
voiceRouter.newRouteIsCalculated();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized int getLeftDistance(){
|
public synchronized int getLeftDistance(){
|
||||||
|
@ -327,6 +340,12 @@ public class RoutingHelper {
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
public RouteDirectionInfo getNextNextRouteDirectionInfo(){
|
||||||
|
if(directionInfo != null && currentDirectionInfo < directionInfo.size() - 2){
|
||||||
|
return directionInfo.get(currentDirectionInfo + 2);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
public List<RouteDirectionInfo> getRouteDirections(){
|
public List<RouteDirectionInfo> getRouteDirections(){
|
||||||
if(directionInfo != null && currentDirectionInfo < directionInfo.size()){
|
if(directionInfo != null && currentDirectionInfo < directionInfo.size()){
|
||||||
|
@ -510,10 +529,12 @@ public class RoutingHelper {
|
||||||
this.exitOut = exitOut;
|
this.exitOut = exitOut;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// calculated CW head rotation if previous direction to NORTH
|
||||||
public float getTurnAngle() {
|
public float getTurnAngle() {
|
||||||
return turnAngle;
|
return turnAngle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void setTurnAngle(float turnAngle) {
|
public void setTurnAngle(float turnAngle) {
|
||||||
this.turnAngle = turnAngle;
|
this.turnAngle = turnAngle;
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,8 +34,6 @@ import com.osmand.activities.RoutingHelper.RouteDirectionInfo;
|
||||||
import com.osmand.activities.RoutingHelper.TurnType;
|
import com.osmand.activities.RoutingHelper.TurnType;
|
||||||
import com.osmand.osm.MapUtils;
|
import com.osmand.osm.MapUtils;
|
||||||
import com.osmand.views.MapInfoLayer;
|
import com.osmand.views.MapInfoLayer;
|
||||||
import com.osmand.voice.CommandPlayer;
|
|
||||||
import com.osmand.voice.CommandPlayer.CommandBuilder;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -65,30 +63,6 @@ public class ShowRouteInfoActivity extends ListActivity {
|
||||||
public void onListItemClick(ListView parent, View v, int position, long id) {
|
public void onListItemClick(ListView parent, View v, int position, long id) {
|
||||||
RouteDirectionInfo item = ((RouteInfoAdapter)getListAdapter()).getItem(position - 1);
|
RouteDirectionInfo item = ((RouteInfoAdapter)getListAdapter()).getItem(position - 1);
|
||||||
Location loc = helper.getLocationFromRouteDirection(item);
|
Location loc = helper.getLocationFromRouteDirection(item);
|
||||||
CommandPlayer player = CommandPlayer.getInstance(this);
|
|
||||||
if(player != null){
|
|
||||||
CommandBuilder builder = player.newCommandBuilder();
|
|
||||||
if(item.turnType.getValue() == TurnType.C){
|
|
||||||
builder.goAhead(item.distance);
|
|
||||||
} else if(item.turnType.getValue() == TurnType.TU){
|
|
||||||
builder.makeUT(item.distance);
|
|
||||||
} else if(item.turnType.getValue() == TurnType.TL){
|
|
||||||
builder.turnLeft(item.distance);
|
|
||||||
} else if(item.turnType.getValue() == TurnType.TSLL) {
|
|
||||||
builder.turnSLLeft(item.distance);
|
|
||||||
} else if(item.turnType.getValue() == TurnType.TSHL) {
|
|
||||||
builder.turnSHLeft(item.distance);
|
|
||||||
} else if(item.turnType.getValue() == TurnType.TR){
|
|
||||||
builder.turnRight(item.distance);
|
|
||||||
} else if(item.turnType.getValue() == TurnType.TSLR) {
|
|
||||||
builder.turnSLRight(item.distance);
|
|
||||||
} else if(item.turnType.getValue() == TurnType.TSHR) {
|
|
||||||
builder.turnSHRight(item.distance);
|
|
||||||
} else if(item.turnType.isRoundAbout()) {
|
|
||||||
builder.roundAbout(item.distance, item.turnType.getExitOut());
|
|
||||||
}
|
|
||||||
builder.play();
|
|
||||||
}
|
|
||||||
if(loc != null){
|
if(loc != null){
|
||||||
OsmandSettings.setMapLocationToShow(this, loc.getLatitude(),loc.getLongitude());
|
OsmandSettings.setMapLocationToShow(this, loc.getLatitude(),loc.getLongitude());
|
||||||
startActivity(new Intent(this, MapActivity.class));
|
startActivity(new Intent(this, MapActivity.class));
|
||||||
|
|
230
OsmAnd/src/com/osmand/activities/VoiceRouter.java
Normal file
230
OsmAnd/src/com/osmand/activities/VoiceRouter.java
Normal file
|
@ -0,0 +1,230 @@
|
||||||
|
package com.osmand.activities;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
|
import com.osmand.OsmandSettings.ApplicationMode;
|
||||||
|
import com.osmand.activities.RoutingHelper.RouteDirectionInfo;
|
||||||
|
import com.osmand.activities.RoutingHelper.TurnType;
|
||||||
|
import com.osmand.voice.CommandPlayer;
|
||||||
|
import com.osmand.voice.CommandPlayer.CommandBuilder;
|
||||||
|
|
||||||
|
public class VoiceRouter {
|
||||||
|
|
||||||
|
private final RoutingHelper router;
|
||||||
|
private boolean mute = false;
|
||||||
|
private CommandPlayer player;
|
||||||
|
|
||||||
|
private int currentDirection = 0;
|
||||||
|
// 0 - unknown, 1 - notify prepare, 2 - notify to turn after , 3 - notify to turn
|
||||||
|
private int currentStatus = 0;
|
||||||
|
|
||||||
|
public VoiceRouter(RoutingHelper router){
|
||||||
|
this.router = router;
|
||||||
|
updateAppMode();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void init(Context ctx){
|
||||||
|
player = CommandPlayer.getInstance(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMute(boolean mute) {
|
||||||
|
this.mute = mute;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isMute() {
|
||||||
|
return mute;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected CommandBuilder getNewCommandPlayerToPlay(){
|
||||||
|
if(player == null || mute){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return player.newCommandBuilder();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected int PREPARE_DISTANCE = 0;
|
||||||
|
protected int TURN_IN_DISTANCE = 0;
|
||||||
|
protected int TURN_DISTANCE = 0;
|
||||||
|
|
||||||
|
public void updateAppMode(){
|
||||||
|
if(router.getAppMode() == ApplicationMode.PEDESTRIAN){
|
||||||
|
PREPARE_DISTANCE = 400;
|
||||||
|
TURN_IN_DISTANCE = 150;
|
||||||
|
TURN_DISTANCE = 20;
|
||||||
|
} else if(router.getAppMode() == ApplicationMode.BICYCLE){
|
||||||
|
PREPARE_DISTANCE = 550;
|
||||||
|
TURN_IN_DISTANCE = 200;
|
||||||
|
TURN_DISTANCE = 40;
|
||||||
|
} else {
|
||||||
|
PREPARE_DISTANCE = 800;
|
||||||
|
TURN_IN_DISTANCE = 300;
|
||||||
|
TURN_DISTANCE = 70;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
protected void updateStatus(){
|
||||||
|
// directly after turn (go - ahead dist)
|
||||||
|
// < 800m prepare
|
||||||
|
// < 200m turn in
|
||||||
|
// < 50m turn
|
||||||
|
if(currentDirection != router.currentDirectionInfo){
|
||||||
|
currentDirection = router.currentDirectionInfo;
|
||||||
|
currentStatus = 0;
|
||||||
|
}
|
||||||
|
RouteDirectionInfo next = router.getNextRouteDirectionInfo();
|
||||||
|
int dist = router.getDistanceToNextRouteDirection();
|
||||||
|
if(next == null && currentDirection > 0) {
|
||||||
|
if(currentStatus == 0){
|
||||||
|
CommandBuilder play = getNewCommandPlayerToPlay();
|
||||||
|
if(play != null){
|
||||||
|
play.goAhead(router.getLeftDistance()).andArriveAtDestination().play();
|
||||||
|
}
|
||||||
|
currentStatus = 1;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(dist == 0){
|
||||||
|
// nothing said possibly that's wrong case we should say before that
|
||||||
|
// however it should be checked manually !?
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
RouteDirectionInfo nextNext = router.getNextNextRouteDirectionInfo();
|
||||||
|
|
||||||
|
if(currentStatus == 0){
|
||||||
|
if(dist > PREPARE_DISTANCE){
|
||||||
|
CommandBuilder play = getNewCommandPlayerToPlay();
|
||||||
|
if(play != null){
|
||||||
|
play.goAhead(dist).play();
|
||||||
|
}
|
||||||
|
} else if (dist < TURN_IN_DISTANCE){
|
||||||
|
// should already told it
|
||||||
|
currentStatus = 3;
|
||||||
|
}
|
||||||
|
currentStatus = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if(currentStatus <= 3 && dist <= TURN_DISTANCE){
|
||||||
|
CommandBuilder play = getNewCommandPlayerToPlay();
|
||||||
|
if(play != null){
|
||||||
|
String tParam = getTurnType(next.turnType);
|
||||||
|
boolean isplay = true;
|
||||||
|
if(tParam != null){
|
||||||
|
play.turn(tParam);
|
||||||
|
} else if(next.turnType.isRoundAbout()){
|
||||||
|
play.roundAbout(next.turnType.getExitOut());
|
||||||
|
} else if(next.turnType.getValue().equals(TurnType.TU)){
|
||||||
|
play.makeUT();
|
||||||
|
} else if(next.turnType.getValue().equals(TurnType.C)){
|
||||||
|
play.goAhead();
|
||||||
|
} else {
|
||||||
|
isplay = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nextNext != null && next.distance <= TURN_IN_DISTANCE) {
|
||||||
|
isplay = true;
|
||||||
|
String t2Param = getTurnType(nextNext.turnType);
|
||||||
|
if (t2Param != null) {
|
||||||
|
play.then().turn(t2Param, next.distance);
|
||||||
|
} else if (nextNext.turnType.isRoundAbout()) {
|
||||||
|
play.then().roundAbout(next.distance, next.turnType.getExitOut());
|
||||||
|
} else if (nextNext.turnType.getValue().equals(TurnType.TU)) {
|
||||||
|
play.then().makeUT(next.distance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(isplay){
|
||||||
|
play.play();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
currentStatus = 4;
|
||||||
|
} else if(currentStatus <= 2 && dist <= TURN_IN_DISTANCE){
|
||||||
|
CommandBuilder play = getNewCommandPlayerToPlay();
|
||||||
|
if (play != null) {
|
||||||
|
String tParam = getTurnType(next.turnType);
|
||||||
|
boolean isPlay = true;
|
||||||
|
if (tParam != null) {
|
||||||
|
play.turn(tParam, dist);
|
||||||
|
} else if (next.turnType.isRoundAbout()) {
|
||||||
|
play.roundAbout(dist, next.turnType.getExitOut());
|
||||||
|
} else if (next.turnType.getValue().equals(TurnType.TU)) {
|
||||||
|
play.makeUT(dist);
|
||||||
|
} else {
|
||||||
|
isPlay = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nextNext != null && next.distance <= TURN_DISTANCE) {
|
||||||
|
TurnType t = nextNext.turnType;
|
||||||
|
isPlay = true;
|
||||||
|
if (next.turnType.getValue().equals(TurnType.C)) {
|
||||||
|
play.goAhead(dist);
|
||||||
|
}
|
||||||
|
if (TurnType.TL.equals(t.getValue()) || TurnType.TSHL.equals(t.getValue()) || TurnType.TSLL.equals(t.getValue())
|
||||||
|
|| TurnType.TU.equals(t.getValue())) {
|
||||||
|
play.then().bearLeft();
|
||||||
|
} else if (TurnType.TR.equals(t.getValue()) || TurnType.TSHR.equals(t.getValue()) || TurnType.TSLR.equals(t.getValue())) {
|
||||||
|
play.then().bearRight();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(isPlay){
|
||||||
|
play.play();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
currentStatus = 3;
|
||||||
|
} else if(currentStatus <= 1 && dist <= PREPARE_DISTANCE){
|
||||||
|
CommandBuilder play = getNewCommandPlayerToPlay();
|
||||||
|
if(play != null){
|
||||||
|
String tParam = getTurnType(next.turnType);
|
||||||
|
if(tParam != null){
|
||||||
|
play.prepareTurn(tParam, dist).play();
|
||||||
|
} else if(next.turnType.isRoundAbout()){
|
||||||
|
play.prepareRoundAbout(dist).play();
|
||||||
|
} else if(next.turnType.getValue().equals(TurnType.TU)){
|
||||||
|
play.prepareMakeUT(dist).play();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
currentStatus = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getTurnType(TurnType t){
|
||||||
|
if(TurnType.TL.equals(t.getValue())){
|
||||||
|
return CommandPlayer.A_LEFT;
|
||||||
|
} else if(TurnType.TSHL.equals(t.getValue())){
|
||||||
|
return CommandPlayer.A_LEFT_SH;
|
||||||
|
} else if(TurnType.TSLL.equals(t.getValue())){
|
||||||
|
return CommandPlayer.A_LEFT_SL;
|
||||||
|
} else if(TurnType.TR.equals(t.getValue())){
|
||||||
|
return CommandPlayer.A_RIGHT;
|
||||||
|
} else if(TurnType.TSHR.equals(t.getValue())){
|
||||||
|
return CommandPlayer.A_RIGHT_SH;
|
||||||
|
} else if(TurnType.TSLR.equals(t.getValue())){
|
||||||
|
return CommandPlayer.A_RIGHT_SL;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void newRouteIsCalculated() {
|
||||||
|
CommandBuilder play = getNewCommandPlayerToPlay();
|
||||||
|
if(play != null){
|
||||||
|
play.newRouteCalculated(router.getLeftDistance()).play();
|
||||||
|
}
|
||||||
|
currentDirection = router.currentDirectionInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void arrivedDestinationPoint() {
|
||||||
|
CommandBuilder play = getNewCommandPlayerToPlay();
|
||||||
|
if(play != null){
|
||||||
|
play.arrivedAtDestination().play();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -384,7 +384,7 @@ public class OsmBugsLayer implements OsmandMapLayer {
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
String text = ((EditText)view.findViewById(R.id.BugMessage)).getText().toString();
|
String text = ((EditText)view.findViewById(R.id.BugMessage)).getText().toString();
|
||||||
String author = ((EditText)view.findViewById(R.id.AuthorName)).getText().toString();
|
String author = ((EditText)view.findViewById(R.id.AuthorName)).getText().toString();
|
||||||
OsmandSettings.setUserName(ctx, author);
|
// OsmandSettings.setUserName(ctx, author);
|
||||||
boolean added = addingComment(bug.getId(), text, author);
|
boolean added = addingComment(bug.getId(), text, author);
|
||||||
if (added) {
|
if (added) {
|
||||||
Toast.makeText(ctx, ctx.getResources().getString(R.string.osb_comment_dialog_success), Toast.LENGTH_LONG).show();
|
Toast.makeText(ctx, ctx.getResources().getString(R.string.osb_comment_dialog_success), Toast.LENGTH_LONG).show();
|
||||||
|
|
|
@ -4,6 +4,7 @@ package com.osmand.voice;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -39,13 +40,17 @@ public class CommandPlayer {
|
||||||
private static CommandPlayer instance = null;
|
private static CommandPlayer instance = null;
|
||||||
|
|
||||||
protected Context ctx;
|
protected Context ctx;
|
||||||
|
// or zip file
|
||||||
private File voiceDir;
|
private File voiceDir;
|
||||||
|
// private ZipFile voiceZipFile;
|
||||||
|
|
||||||
// resolving commands to play
|
// resolving commands to play
|
||||||
private Prolog prologSystem;
|
private Prolog prologSystem;
|
||||||
|
|
||||||
// playing media
|
// playing media
|
||||||
private MediaPlayer mediaPlayer;
|
private MediaPlayer mediaPlayer;
|
||||||
|
// indicates that player is ready to play first file
|
||||||
|
private boolean playNext = true;
|
||||||
private List<String> filesToPlay = new ArrayList<String>();
|
private List<String> filesToPlay = new ArrayList<String>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -107,20 +112,29 @@ public class CommandPlayer {
|
||||||
return ctx.getString(R.string.voice_data_unavailable);
|
return ctx.getString(R.string.voice_data_unavailable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// see comments while it is impossible to read from zip
|
||||||
|
// voiceZipFile = null;
|
||||||
if(voiceDir != null) {
|
if(voiceDir != null) {
|
||||||
long time = System.currentTimeMillis();
|
long time = System.currentTimeMillis();
|
||||||
File config = new File(voiceDir, "_config.p"); //$NON-NLS-1$
|
boolean wrong = false;
|
||||||
boolean wrong = !config.exists();
|
|
||||||
|
|
||||||
if (!wrong) {
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
prologSystem.setTheory(new Theory(new FileInputStream(config)));
|
InputStream config;
|
||||||
|
// if (voiceDir.getName().endsWith(".zip")) { //$NON-NLS-1$
|
||||||
|
// voiceZipFile = new ZipFile(voiceDir);
|
||||||
|
// config = voiceZipFile.getInputStream(voiceZipFile.getEntry("_config.p")); //$NON-NLS-1$
|
||||||
|
// } else {
|
||||||
|
config = new FileInputStream(new File(voiceDir, "_config.p")); //$NON-NLS-1$
|
||||||
|
// }
|
||||||
|
if (!wrong) {
|
||||||
|
prologSystem.setTheory(new Theory(config));
|
||||||
|
}
|
||||||
} catch (InvalidTheoryException e) {
|
} catch (InvalidTheoryException e) {
|
||||||
log.error("Loading voice config exception " + voiceProvider, e); //$NON-NLS-1$
|
log.error("Loading voice config exception " + voiceProvider, e); //$NON-NLS-1$
|
||||||
|
wrong = true;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
log.error("Loading voice config exception " + voiceProvider, e); //$NON-NLS-1$
|
log.error("Loading voice config exception " + voiceProvider, e); //$NON-NLS-1$
|
||||||
}
|
wrong = true;
|
||||||
}
|
}
|
||||||
if(wrong){
|
if(wrong){
|
||||||
return ctx.getString(R.string.voice_data_corrupted);
|
return ctx.getString(R.string.voice_data_corrupted);
|
||||||
|
@ -186,14 +200,25 @@ public class CommandPlayer {
|
||||||
playQueue();
|
playQueue();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void playQueue() {
|
private synchronized void playQueue() {
|
||||||
boolean playNext = true;
|
|
||||||
while (!filesToPlay.isEmpty() && playNext) {
|
while (!filesToPlay.isEmpty() && playNext) {
|
||||||
String f = filesToPlay.remove(0);
|
String f = filesToPlay.remove(0);
|
||||||
if (f != null && voiceDir != null) {
|
if (f != null && voiceDir != null) {
|
||||||
|
boolean exists = false;
|
||||||
|
// if(voiceZipFile != null){
|
||||||
|
// ZipEntry entry = voiceZipFile.getEntry(f);
|
||||||
|
// exists = entry != null;
|
||||||
|
// voiceZipFile.getInputStream(entry);
|
||||||
|
//
|
||||||
|
// } else {
|
||||||
File file = new File(voiceDir, f);
|
File file = new File(voiceDir, f);
|
||||||
if (file.exists()) {
|
exists = file.exists();
|
||||||
|
// }
|
||||||
|
if (exists) {
|
||||||
|
log.debug("Playing file : " + f); //$NON-NLS-1$
|
||||||
|
playNext = false;
|
||||||
try {
|
try {
|
||||||
|
// Can't play sound file from zip it seams to be impossible only unpack and play!!!
|
||||||
mediaPlayer.setDataSource(file.getAbsolutePath());
|
mediaPlayer.setDataSource(file.getAbsolutePath());
|
||||||
mediaPlayer.prepare();
|
mediaPlayer.prepare();
|
||||||
mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
|
mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
|
||||||
|
@ -215,16 +240,19 @@ public class CommandPlayer {
|
||||||
Thread.sleep(sleep);
|
Thread.sleep(sleep);
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
}
|
}
|
||||||
|
playNext = true;
|
||||||
playQueue();
|
playQueue();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
playNext = false;
|
|
||||||
mediaPlayer.start();
|
mediaPlayer.start();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("Error while playing voice command", e); //$NON-NLS-1$
|
log.error("Error while playing voice command", e); //$NON-NLS-1$
|
||||||
playNext = true;
|
playNext = true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
log.info("Play file not found : " + f); //$NON-NLS-1$
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -235,12 +263,12 @@ public class CommandPlayer {
|
||||||
protected static final String P_VERSION = "version"; //$NON-NLS-1$
|
protected static final String P_VERSION = "version"; //$NON-NLS-1$
|
||||||
protected static final String P_RESOLVE = "resolve"; //$NON-NLS-1$
|
protected static final String P_RESOLVE = "resolve"; //$NON-NLS-1$
|
||||||
|
|
||||||
protected static final String A_LEFT = "left"; //$NON-NLS-1$
|
public static final String A_LEFT = "left"; //$NON-NLS-1$
|
||||||
protected static final String A_LEFT_SH = "left_sh"; //$NON-NLS-1$
|
public static final String A_LEFT_SH = "left_sh"; //$NON-NLS-1$
|
||||||
protected static final String A_LEFT_SL = "left_sl"; //$NON-NLS-1$
|
public static final String A_LEFT_SL = "left_sl"; //$NON-NLS-1$
|
||||||
protected static final String A_RIGHT = "right"; //$NON-NLS-1$
|
public static final String A_RIGHT = "right"; //$NON-NLS-1$
|
||||||
protected static final String A_RIGHT_SH = "right_sh"; //$NON-NLS-1$
|
public static final String A_RIGHT_SH = "right_sh"; //$NON-NLS-1$
|
||||||
protected static final String A_RIGHT_SL = "right_sl"; //$NON-NLS-1$
|
public static final String A_RIGHT_SL = "right_sl"; //$NON-NLS-1$
|
||||||
|
|
||||||
protected static final String С_PREPARE_TURN = "prepare_turn"; //$NON-NLS-1$
|
protected static final String С_PREPARE_TURN = "prepare_turn"; //$NON-NLS-1$
|
||||||
protected static final String С_PREPARE_ROUNDABOUT = "prepare_roundabout"; //$NON-NLS-1$
|
protected static final String С_PREPARE_ROUNDABOUT = "prepare_roundabout"; //$NON-NLS-1$
|
||||||
|
@ -250,6 +278,13 @@ public class CommandPlayer {
|
||||||
protected static final String С_TURN = "turn"; //$NON-NLS-1$
|
protected static final String С_TURN = "turn"; //$NON-NLS-1$
|
||||||
protected static final String С_MAKE_UT = "make_ut"; //$NON-NLS-1$
|
protected static final String С_MAKE_UT = "make_ut"; //$NON-NLS-1$
|
||||||
protected static final String С_PREAMBLE = "preamble"; //$NON-NLS-1$
|
protected static final String С_PREAMBLE = "preamble"; //$NON-NLS-1$
|
||||||
|
protected static final String С_AND_ARRIVE_DESTINATION = "and_arrive_destination"; //$NON-NLS-1$
|
||||||
|
protected static final String С_THEN = "then"; //$NON-NLS-1$
|
||||||
|
protected static final String С_REACHED_DESTINATION = "reached_destination"; //$NON-NLS-1$
|
||||||
|
protected static final String С_BEAR_LEFT = "bear_left"; //$NON-NLS-1$
|
||||||
|
protected static final String С_BEAR_RIGHT = "bear_right"; //$NON-NLS-1$
|
||||||
|
protected static final String С_ROUTE_RECALC = "route_recalc"; //$NON-NLS-1$
|
||||||
|
|
||||||
|
|
||||||
protected static final String DELAY_CONST = "delay_"; //$NON-NLS-1$
|
protected static final String DELAY_CONST = "delay_"; //$NON-NLS-1$
|
||||||
|
|
||||||
|
@ -298,6 +333,7 @@ public class CommandPlayer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Struct struct = new Struct(name, list);
|
Struct struct = new Struct(name, list);
|
||||||
|
log.debug("Adding command : " + name); //$NON-NLS-1$
|
||||||
listStruct.add(struct);
|
listStruct.add(struct);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -324,76 +360,22 @@ public class CommandPlayer {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public CommandBuilder turnLeft(){
|
public CommandBuilder turn(String param){
|
||||||
return addCommand(С_TURN, A_LEFT);
|
return addCommand(С_TURN, param);
|
||||||
}
|
}
|
||||||
|
|
||||||
public CommandBuilder turnSLLeft(){
|
public CommandBuilder turn(String param, double dist){
|
||||||
return addCommand(С_TURN, A_LEFT_SL);
|
return addCommand(С_TURN, param, dist);
|
||||||
}
|
}
|
||||||
|
|
||||||
public CommandBuilder turnSHLeft(){
|
/**
|
||||||
return addCommand(С_TURN, A_LEFT_SH);
|
*
|
||||||
}
|
* @param param A_LEFT, A_RIGHT, ...
|
||||||
|
* @param dist
|
||||||
public CommandBuilder turnRight(){
|
* @return
|
||||||
return addCommand(С_TURN, A_RIGHT);
|
*/
|
||||||
}
|
public CommandBuilder prepareTurn(String param, double dist){
|
||||||
|
return addCommand(С_PREPARE_TURN, param, dist);
|
||||||
public CommandBuilder turnSLRight(){
|
|
||||||
return addCommand(С_TURN, A_RIGHT_SL);
|
|
||||||
}
|
|
||||||
|
|
||||||
public CommandBuilder turnSHRight(){
|
|
||||||
return addCommand(С_TURN, A_RIGHT_SL);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public CommandBuilder turnLeft(double dist){
|
|
||||||
return addCommand(С_TURN, A_LEFT, dist);
|
|
||||||
}
|
|
||||||
|
|
||||||
public CommandBuilder turnSLLeft(double dist){
|
|
||||||
return addCommand(С_TURN, A_LEFT_SL, dist);
|
|
||||||
}
|
|
||||||
|
|
||||||
public CommandBuilder turnSHLeft(double dist){
|
|
||||||
return addCommand(С_TURN, A_LEFT_SH, dist);
|
|
||||||
}
|
|
||||||
|
|
||||||
public CommandBuilder turnRight(double dist){
|
|
||||||
return addCommand(С_TURN, A_RIGHT, dist);
|
|
||||||
}
|
|
||||||
|
|
||||||
public CommandBuilder turnSLRight(double dist){
|
|
||||||
return addCommand(С_TURN, A_RIGHT_SL, dist);
|
|
||||||
}
|
|
||||||
|
|
||||||
public CommandBuilder turnSHRight(double dist){
|
|
||||||
return addCommand(С_TURN, A_RIGHT_SL, dist);
|
|
||||||
}
|
|
||||||
|
|
||||||
public CommandBuilder prepareTurnLeft(double dist){
|
|
||||||
return addCommand(С_PREPARE_TURN, A_LEFT, dist);
|
|
||||||
}
|
|
||||||
|
|
||||||
public CommandBuilder prepareTurnSLLeft(double dist){
|
|
||||||
return addCommand(С_PREPARE_TURN, A_LEFT_SL, dist);
|
|
||||||
}
|
|
||||||
public CommandBuilder prepareTurnSHLeft(double dist){
|
|
||||||
return addCommand(С_PREPARE_TURN, A_LEFT_SH, dist);
|
|
||||||
}
|
|
||||||
|
|
||||||
public CommandBuilder prepareTurnRight(double dist){
|
|
||||||
return addCommand(С_PREPARE_TURN, A_RIGHT, dist);
|
|
||||||
}
|
|
||||||
|
|
||||||
public CommandBuilder prepareTurnSLRight(double dist){
|
|
||||||
return addCommand(С_PREPARE_TURN, A_RIGHT_SL, dist);
|
|
||||||
}
|
|
||||||
|
|
||||||
public CommandBuilder prepareTurnSHRight(double dist){
|
|
||||||
return addCommand(С_PREPARE_TURN, A_RIGHT_SH, dist);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public CommandBuilder prepareRoundAbout(double dist){
|
public CommandBuilder prepareRoundAbout(double dist){
|
||||||
|
@ -408,6 +390,30 @@ public class CommandPlayer {
|
||||||
return addCommand(С_ROUNDABOUT, exit);
|
return addCommand(С_ROUNDABOUT, exit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public CommandBuilder andArriveAtDestination(){
|
||||||
|
return addCommand(С_AND_ARRIVE_DESTINATION);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CommandBuilder arrivedAtDestination(){
|
||||||
|
return addCommand(С_REACHED_DESTINATION);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CommandBuilder bearLeft(){
|
||||||
|
return addCommand(С_BEAR_LEFT);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CommandBuilder bearRight(){
|
||||||
|
return addCommand(С_BEAR_RIGHT);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CommandBuilder then(){
|
||||||
|
return addCommand(С_THEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CommandBuilder newRouteCalculated(double dist){
|
||||||
|
return addCommand(С_ROUTE_RECALC, dist);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public void play(){
|
public void play(){
|
||||||
|
|
|
@ -7,11 +7,11 @@ preamble - [].
|
||||||
|
|
||||||
|
|
||||||
%% TURNS
|
%% TURNS
|
||||||
turn('left', ['turn.ogg', 'left.ogg']).
|
turn('left', ['turn.ogg', delay_350, 'left.ogg']).
|
||||||
turn('left_sh', ['turn_sharply.ogg', 'left.ogg']).
|
turn('left_sh', ['turn_sharply.ogg', delay_350, 'left.ogg']).
|
||||||
turn('left_sl', ['turn_slightly_left.ogg']).
|
turn('left_sl', ['turn_slightly_left.ogg']).
|
||||||
turn('right', ['turn.ogg', 'right.ogg']).
|
turn('right', ['turn.ogg', delay_350, 'right.ogg']).
|
||||||
turn('right_sh', ['turn_sharply.ogg', 'right.ogg']).
|
turn('right_sh', ['turn_sharply.ogg', delay_350,'right.ogg']).
|
||||||
turn('right_sl', ['turn_slightly_right.ogg']).
|
turn('right_sl', ['turn_slightly_right.ogg']).
|
||||||
|
|
||||||
prepare_turn(Turn, Dist) == ['Prepare_to.ogg', 'in.ogg', delay_450, D, delay_450, M] :-
|
prepare_turn(Turn, Dist) == ['Prepare_to.ogg', 'in.ogg', delay_450, D, delay_450, M] :-
|
||||||
|
@ -21,22 +21,22 @@ turn(Turn, Dist) == ['in.ogg', delay_450, D, delay_450, M] :-
|
||||||
turn(Turn) == M :- turn(Turn, M).
|
turn(Turn) == M :- turn(Turn, M).
|
||||||
|
|
||||||
|
|
||||||
prepare_make_ut(Dist) == ['Prepare_to.ogg', 'in.ogg', delay_450, D, delay_450, 'Turn_back.ogg'] :-
|
prepare_make_ut(Dist) == ['Prepare_to.ogg', 'in.ogg', delay_300, D, delay_300,'Turn_back.ogg'] :-
|
||||||
distance(Dist) == D.
|
distance(Dist) == D.
|
||||||
|
|
||||||
prepare_roundabout(Dist) == ['Prepare_to.ogg', 'in.ogg', delay_450, D, delay_450, 'roundabout.ogg'] :-
|
prepare_roundabout(Dist) == ['Prepare_to.ogg', 'in.ogg', delay_300, D, delay_300, 'roundabout.ogg'] :-
|
||||||
distance(Dist) == D.
|
distance(Dist) == D.
|
||||||
|
|
||||||
make_ut(Dist) == ['in.ogg', delay_450, D, delay_450, 'Turn_back.ogg'] :-
|
make_ut(Dist) == ['in.ogg', delay_300, D, delay_300, 'Turn_back.ogg'] :-
|
||||||
distance(Dist) == D.
|
distance(Dist) == D.
|
||||||
make_ut == ['Turn_back.ogg'].
|
make_ut == ['Turn_back.ogg'].
|
||||||
|
|
||||||
roundabout(Dist, Exit) == ['in.ogg', delay_450, D, delay_450, 'roundabout.ogg', delay_450, 'DO.ogg', delay_250, E, 'the_exit.ogg'] :-
|
roundabout(Dist, Exit) == ['in.ogg', delay_300, D, delay_300, 'roundabout.ogg', delay_250, 'DO.ogg', delay_250, E, 'the_exit.ogg'] :-
|
||||||
distance(Dist) == D, nth(Exit, E).
|
distance(Dist) == D, nth(Exit, E).
|
||||||
roundabout(Exit) == ['DO.ogg', delay_250, E, 'the_exit.ogg'] :- nth(Exit, E).
|
roundabout(Exit) == ['DO.ogg', delay_250, E, 'the_exit.ogg'] :- nth(Exit, E).
|
||||||
|
|
||||||
and_arrive_destination == ['arrive_at_destination.ogg'].
|
and_arrive_destination == ['arrive_at_destination.ogg'].
|
||||||
then == ['then', delay_350].
|
then == ['then.ogg', delay_350].
|
||||||
reached_destination == ['you_reached.ogg',delay_250, 'TO_DESTINATION.ogg'].
|
reached_destination == ['you_reached.ogg',delay_250, 'TO_DESTINATION.ogg'].
|
||||||
bear_right == ['bear_right.ogg'].
|
bear_right == ['bear_right.ogg'].
|
||||||
bear_left == ['bear_left.ogg'].
|
bear_left == ['bear_left.ogg'].
|
||||||
|
|
Loading…
Reference in a new issue