package net.osmand.plus.development;
import android.app.ActionBar;
import android.content.DialogInterface;
import android.content.pm.ActivityInfo;
import android.os.Build;
import android.os.Bundle;
import android.support.v7.app.AlertDialog;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.Gravity;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;
import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.Toast;
import net.osmand.IndexConstants;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.activities.OsmandActionBarActivity;
import net.osmand.plus.voice.AbstractPrologCommandPlayer;
import net.osmand.plus.voice.TTSCommandPlayerImpl;
import net.osmand.plus.voice.CommandBuilder;
import net.osmand.plus.voice.CommandPlayer;
import net.osmand.util.Algorithms;
import java.io.File;
import java.util.LinkedHashSet;
import java.util.Set;
import alice.tuprolog.Struct;
import alice.tuprolog.Term;
/**
* Test Voice activity
*/
public class TestVoiceActivity extends OsmandActionBarActivity {
@Override
public void onCreate(Bundle icicle) {
((OsmandApplication) getApplication()).applyTheme(this);
super.onCreate(icicle);
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
getWindow().setUiOptions(ActivityInfo.UIOPTION_SPLIT_ACTION_BAR_WHEN_NARROW);
}
getSupportActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
final OsmandApplication app = ((OsmandApplication) getApplication());
LinearLayout gl = new LinearLayout(this);
gl.setOrientation(LinearLayout.VERTICAL);
gl.setPadding(3, 3, 3, 3);
TextView tv = new TextView(this);
tv.setText("Tap a button and listen to the corresponding voice prompt to identify missing or faulty propmts.");
tv.setPadding(0, 5, 0, 7);
ScrollView sv = new ScrollView(this);
gl.addView(sv, new LayoutParams(android.view.ViewGroup.LayoutParams.FILL_PARENT,
android.view.ViewGroup.LayoutParams.FILL_PARENT));
final LinearLayout ll = new LinearLayout(this);
ll.setOrientation(LinearLayout.VERTICAL);
sv.addView(ll, new LayoutParams(android.view.ViewGroup.LayoutParams.FILL_PARENT,
android.view.ViewGroup.LayoutParams.FILL_PARENT));
// add buttons
setContentView(gl);
getSupportActionBar(). setTitle(R.string.test_voice_prompts);
selectVoice(ll);
}
private Set<String> getVoiceFiles() {
// read available voice data
File extStorage = ((OsmandApplication) getApplication()).getAppPath(IndexConstants.VOICE_INDEX_DIR);
Set<String> setFiles = new LinkedHashSet<String>();
if (extStorage.exists()) {
for (File f : extStorage.listFiles()) {
if (f.isDirectory()) {
setFiles.add(f.getName());
}
}
}
return setFiles;
}
private void selectVoice(final LinearLayout ll) {
String[] entries;
final String[] entrieValues;
Set<String> voiceFiles = getVoiceFiles();
entries = new String[voiceFiles.size() ];
entrieValues = new String[voiceFiles.size() ];
int k = 0;
int selected = 0;
for (String s : voiceFiles) {
entries[k] = s;
entrieValues[k] = s;
if(s.equals(((OsmandApplication) getApplication()).getSettings().VOICE_PROVIDER.get())) {
selected = k;
}
k++;
}
AlertDialog.Builder bld = new AlertDialog.Builder(this);
bld.setSingleChoiceItems(entrieValues, selected, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, final int which) {
final OsmandApplication app = (OsmandApplication) getApplication();
getSupportActionBar().setTitle(app.getString(R.string.test_voice_prompts) + " (" + entrieValues[which] + ")");
app.getSettings().VOICE_PROVIDER.set(entrieValues[which]);
app.initVoiceCommandPlayer(TestVoiceActivity.this,
app.getSettings().APPLICATION_MODE.get(), true, new Runnable() {
@Override
public void run() {
CommandPlayer p = app.getRoutingHelper().getVoiceRouter().getPlayer();
if (p == null) {
Toast.makeText(TestVoiceActivity.this, "Voice player not initialized", Toast.LENGTH_SHORT).show();
} else {
final String osmandVoice = entrieValues[which];
final String osmandVoiceLang = p.getLanguage();
addButtons(ll, p, osmandVoice, osmandVoiceLang);
}
}
}, true, true);
dialog.dismiss();
}
});
bld.show();
}
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) {
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, final String osmandVoice, final String osmandVoiceLang) {
addButton(ll, " Route calculated and number tests:", builder(p));
addButton(ll, "(1.1) New route calculated, 150m, 230sec (00:03:50)", builder(p).newRouteCalculated(150, 230));
addButton(ll, "(1.2) New route calculated, 1350m, 3680sec (01:01:20)", builder(p).newRouteCalculated(1350, 3680));
addButton(ll, "(1.3) New route calculated 3700m, 7320sec (02:02)", builder(p).newRouteCalculated(3700, 7320));
addButton(ll, "(1.4) New route calculated 9100m, 10980sec (03:03)", builder(p).newRouteCalculated(9100, 10980));
addButton(ll, "(2.1) Route recalculated 11500m, 18600sec (05:10)", builder(p).routeRecalculated(11500, 18600));
addButton(ll, "(2.2) Route recalculated 19633m, 26700sec (07:25)", builder(p).routeRecalculated(19633, 26700));
addButton(ll, "(2.3) Route recalculated 89750m, 55800sec (15:30)", builder(p).routeRecalculated(89750, 55800));
addButton(ll, "(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, "(3.1) After 1520m turn slightly left", builder(p).prepareTurn(AbstractPrologCommandPlayer.A_LEFT_SL, 1520, street(p, "")));
addButton(ll, "(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, "(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, "(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, "(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, "(3.6) Turn sharply right onto 'Main Street'", builder(p).turn(AbstractPrologCommandPlayer.A_RIGHT_SH, street(p, "Main Street")));
addButton(ll, " Keep left/right: prepareTurn, makeTurnIn, turn:", builder(p));
addButton(ll, "(4.1) After 1810m keep left ' '", builder(p).prepareTurn(AbstractPrologCommandPlayer.A_LEFT_KEEP, 1810, street(p, "")));
addButton(ll, "(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, "(4.3) Keep right on 'Highway 60'", builder(p).turn(AbstractPrologCommandPlayer.A_RIGHT_KEEP, street(p, "Highway 60", "", "", "Highway 60")));
addButton(ll, "(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"));
addButton(ll, " Roundabouts: prepareTurn, makeTurnIn, turn:", builder(p));
addButton(ll, "(5.1) After 1250m enter a roundabout", builder(p).prepareRoundAbout(1250, 3, street(p,"", "I 15", "Los Angeles")));
addButton(ll, "(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, "(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, "(6.1) After 640m make a U-turn", builder(p).prepareMakeUT(640, street(p, "")));
addButton(ll, "(6.2) In 400m make a U-turn", builder(p).makeUT(400, street(p, "")));
addButton(ll, "(6.3) Make a U-turn on 'Riviera'", builder(p).makeUT(street(p, "Riviera", "", "", "Riviera")));
addButton(ll, "(6.4) When possible, make a U-turn", builder(p).makeUTwp());
addButton(ll, " Go straight, follow the road, approaching:", builder(p));
addButton(ll, "(7.1) Straight ahead", builder(p).goAhead());
addButton(ll, "(7.2) Continue for 2350m to ' '", builder(p).goAhead(2350, street(p, "")));
addButton(ll, "(7.3) Continue for 360m to 'Broadway' and arrive at your intermediate destination ' '", builder(p).goAhead(360, street(p,"Broadway")).andArriveAtIntermediatePoint(""));
addButton(ll, "(7.4) Continue for 800m to 'A33' and arrive at your destination ' '", builder(p).goAhead(800, street(p,"", "A33")).andArriveAtDestination(""));
addButton(ll, "(7.5) Continue for 200m and arrive at your GPX waypoint 'Trailhead'", builder(p).goAhead(200, null).andArriveAtWayPoint("Trailhead"));
addButton(ll, "(7.6) Continue for 400m and arrive at your favorite 'Brewery'", builder(p).goAhead(400, null).andArriveAtFavorite("Brewery"));
addButton(ll, "(7.7) Continue for 600m and arrive at your POI 'Museum'", builder(p).goAhead(600, null).andArriveAtPoi("Museum"));
addButton(ll, " Arriving and passing points:", builder(p));
addButton(ll, "(8.1) Arrive at your destination 'Home'", builder(p).arrivedAtDestination("Home"));
addButton(ll, "(8.2) Arrive at your intermediate destination 'Friend'", builder(p).arrivedAtIntermediatePoint("Friend"));
addButton(ll, "(8.3) Passing GPX waypoint 'Trailhead'", builder(p).arrivedAtWayPoint("Trailhead"));
addButton(ll, "(8.4) Passing favorite 'Brewery'", builder(p).arrivedAtFavorite("Brewery"));
addButton(ll, "(8.5) Passing POI 'Museum'", builder(p).arrivedAtPoi("Museum"));
addButton(ll, " Attention prompts:", builder(p));
addButton(ll, "(9.1) You are exceeding the speed limit '50' (18 m/s)", builder(p).speedAlarm(50, 18f));
addButton(ll, "(9.2) Attention, speed camera", builder(p).attention("SPEED_CAMERA"));
addButton(ll, "(9.3) Attention, border control", builder(p).attention("BORDER_CONTROL"));
addButton(ll, "(9.4) Attention, railroad crossing", builder(p).attention("RAILWAY"));
addButton(ll, "(9.5) Attention, traffic calming", builder(p).attention("TRAFFIC_CALMING"));
addButton(ll, "(9.6) Attention, toll booth", builder(p).attention("TOLL_BOOTH"));
addButton(ll, "(9.7) Attention, stop sign", builder(p).attention("STOP"));
addButton(ll, "(9.8) Attention, pedestrian crosswalk", builder(p).attention("PEDESTRIAN"));
addButton(ll, " Other prompts:", builder(p));
addButton(ll, "(10.1) GPS signal lost", builder(p).gpsLocationLost());
addButton(ll, "(10.2) GPS signal recovered", builder(p).gpsLocationRecover());
addButton(ll, "(10.3) You have been off the route for 1050m", builder(p).offRoute(1050));
addButton(ll, "(10.4) You are back on the route", builder(p).backOnRoute());
addButton(ll, " System checks:", builder(p));
addButton(ll, "(11.1)\nDisplay BT SCO availability (Phone call audio only)", builder(p).attention(""));
addButton(ll, "(11.2)\nTap to change Phone call audio delay (if car stereo cuts off prompts). Default is 1500 ms.", builder(p).attention(""));
addButton(ll, "(11.3)\nOsmAnd voice: " + osmandVoice + "\nOsmAnd voice language: " + osmandVoiceLang + "\n\nTap to view system's language availability status and voice actually used", builder(p));
ll.forceLayout();
}
private CommandBuilder builder(CommandPlayer p){
return p.newCommandBuilder();
}
public void addButton(ViewGroup layout, final String description, final CommandBuilder builder){
Button button = new Button(this);
button.setGravity(Gravity.LEFT);
button.setTransformationMethod(null); //or else button text is all upper case
button.setText(description);
button.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
button.setPadding(10, 5, 10, 2);
layout.addView(button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
builder.play();
if (description.startsWith("(11.1)")) {
if (((OsmandApplication) getApplication()).getSettings().AUDIO_STREAM_GUIDANCE.get() == 0) {
Toast.makeText(TestVoiceActivity.this, AbstractPrologCommandPlayer.btScoInit + "\nBT SCO init delay: " + ((OsmandApplication) getApplication()).getSettings().BT_SCO_DELAY.get() + " ms", Toast.LENGTH_LONG).show();
} else {
Toast.makeText(TestVoiceActivity.this, "Action only available for Phone Call Audio", Toast.LENGTH_LONG).show();
}
}
if (description.startsWith("(11.2)")) {
if (((OsmandApplication) getApplication()).getSettings().AUDIO_STREAM_GUIDANCE.get() == 0) {
if (((OsmandApplication) getApplication()).getSettings().BT_SCO_DELAY.get() == 1000) {
((OsmandApplication) getApplication()).getSettings().BT_SCO_DELAY.set(1500);
} else if (((OsmandApplication) getApplication()).getSettings().BT_SCO_DELAY.get() == 1500) {
((OsmandApplication) getApplication()).getSettings().BT_SCO_DELAY.set(2000);
} else if (((OsmandApplication) getApplication()).getSettings().BT_SCO_DELAY.get() == 2000) {
((OsmandApplication) getApplication()).getSettings().BT_SCO_DELAY.set(2500);
} else if (((OsmandApplication) getApplication()).getSettings().BT_SCO_DELAY.get() == 2500) {
((OsmandApplication) getApplication()).getSettings().BT_SCO_DELAY.set(3000);
} else {
((OsmandApplication) getApplication()).getSettings().BT_SCO_DELAY.set(1000);
}
Toast.makeText(TestVoiceActivity.this, "BT SCO init delay changed to " + ((OsmandApplication) getApplication()).getSettings().BT_SCO_DELAY.get() + " ms", Toast.LENGTH_LONG).show();
} else {
Toast.makeText(TestVoiceActivity.this, "Action only available for Phone Call Audio", Toast.LENGTH_LONG).show();
}
}
if (description.startsWith("(11.3)")) {
final String systemVoiceUsed = AbstractPrologCommandPlayer.getCurrentVersion() > 99 ? TTSCommandPlayerImpl.getTtsVoiceName() : "Recorded voice";
Toast.makeText(TestVoiceActivity.this, "System's language availability status and voice actually used:\n\n" + systemVoiceUsed, Toast.LENGTH_LONG).show();
}
}
});
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int itemId = item.getItemId();
switch (itemId) {
case android.R.id.home:
finish();
return true;
}
return false;
}
}