Merge tts branch into master

This commit is contained in:
Victor Shcherb 2011-06-21 23:25:59 +02:00
commit 1dc78bb32a
13 changed files with 1005 additions and 516 deletions

View file

@ -1,5 +1,10 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<resources>
<string name="tts_language_not_supported_title">Language unsupported</string>
<string name="tts_language_not_supported">The selected language is not supported by the installed TTS engine. Do you want to go to market and search for other TTS engine? Else preset TTS language will be used.</string>
<string name="tts_missing_language_data_title">Missing data</string>
<string name="tts_missing_language_data">Data for selected language are not installed. Do you want to go market to install them?</string>
<string name="gpx_option_reverse_route">Reverse GPX route</string>
<string name="gpx_option_destination_point">Use current destination point</string>
<string name="gpx_option_from_start_point">Pass whole track</string>

View file

@ -6,9 +6,9 @@ import java.util.List;
import net.osmand.Algoritms;
import net.osmand.CallbackWithObject;
import net.osmand.GPXUtilities.GPXFileResult;
import net.osmand.LogUtil;
import net.osmand.Version;
import net.osmand.GPXUtilities.GPXFileResult;
import net.osmand.data.MapTileDownloader;
import net.osmand.data.MapTileDownloader.DownloadRequest;
import net.osmand.data.MapTileDownloader.IMapDownloaderCallback;
@ -27,17 +27,17 @@ import net.osmand.plus.views.OsmandMapTileView;
import net.osmand.plus.views.PointLocationLayer;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.app.Dialog;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.ProgressDialog;
import android.app.AlertDialog.Builder;
import android.content.ActivityNotFoundException;
import android.content.ComponentName;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.DialogInterface.OnMultiChoiceClickListener;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.graphics.Color;
@ -66,8 +66,8 @@ import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.Window;
import android.view.View.OnClickListener;
import android.view.Window;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.Animation;
import android.view.animation.Transformation;
@ -150,7 +150,7 @@ public class MapActivity extends Activity implements IMapLocationListener, Senso
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
settings = ((OsmandApplication) getApplication()).getSettings();
settings = getMyApplication().getSettings();
requestWindowFeature(Window.FEATURE_NO_TITLE);
// Full screen is not used here
// getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
@ -183,7 +183,7 @@ public class MapActivity extends Activity implements IMapLocationListener, Senso
@Override
public void tileDownloaded(DownloadRequest request) {
if(request != null && !request.error && request.fileToSave != null){
ResourceManager mgr = ((OsmandApplication)getApplication()).getResourceManager();
ResourceManager mgr = getMyApplication().getResourceManager();
mgr.tileDownloaded(request);
}
mapView.tileDownloaded(request);
@ -193,7 +193,8 @@ public class MapActivity extends Activity implements IMapLocationListener, Senso
savingTrackHelper = new SavingTrackHelper(this);
routingHelper = ((OsmandApplication) getApplication()).getRoutingHelper();
routingHelper = getMyApplication().getRoutingHelper();
routingHelper.getVoiceRouter().onActivityInit(this);
LatLon pointToNavigate = settings.getPointToNavigate();
// This situtation could be when navigation suddenly crashed and after restarting
@ -213,7 +214,7 @@ public class MapActivity extends Activity implements IMapLocationListener, Senso
@Override
public void onClick(DialogInterface dialog, int which) {
routingHelper.setFollowingMode(true);
((OsmandApplication)getApplication()).showDialogInitializingCommandPlayer(MapActivity.this);
getMyApplication().showDialogInitializingCommandPlayer(MapActivity.this);
}
});
builder.setNegativeButton(R.string.default_buttons_no, new DialogInterface.OnClickListener(){
@ -269,6 +270,10 @@ public class MapActivity extends Activity implements IMapLocationListener, Senso
}
private OsmandApplication getMyApplication() {
return ((OsmandApplication) getApplication());
}
@Override
protected Dialog onCreateDialog(int id) {
if(id == OsmandApplication.PROGRESS_DIALOG){
@ -334,7 +339,7 @@ public class MapActivity extends Activity implements IMapLocationListener, Senso
public void onClick(View v) {
dlg.dismiss();
((OsmandApplication) getApplication()).closeApplication();
getMyApplication().closeApplication();
// 1. Work for almost all cases when user open apps from main menu
Intent newIntent = new Intent(MapActivity.this, MainMenuActivity.class);
newIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
@ -427,6 +432,7 @@ public class MapActivity extends Activity implements IMapLocationListener, Senso
mNotificationManager.cancel(APP_NOTIFICATION_ID);
}
MapTileDownloader.getInstance().removeDownloaderCallback(mapView);
routingHelper.getVoiceRouter().onActivityStop(this);
}
@ -684,9 +690,6 @@ public class MapActivity extends Activity implements IMapLocationListener, Senso
}
};
@Override
protected void onPause() {
super.onPause();
@ -699,8 +702,9 @@ public class MapActivity extends Activity implements IMapLocationListener, Senso
sensorRegistered = false;
currentLocationProvider = null;
routingHelper.setUiActivity(null);
routingHelper.getVoiceRouter().onActivityStop(this);
((OsmandApplication)getApplication()).getDaynightHelper().onMapPause();
getMyApplication().getDaynightHelper().onMapPause();
settings.setLastKnownMapLocation((float) mapView.getLatitude(), (float) mapView.getLongitude());
AnimateDraggingMapThread animatedThread = mapView.getAnimatedDraggingThread();
@ -715,8 +719,8 @@ public class MapActivity extends Activity implements IMapLocationListener, Senso
wakeLock = null;
}
settings.MAP_ACTIVITY_ENABLED.set(false);
((OsmandApplication)getApplication()).getResourceManager().interruptRendering();
((OsmandApplication)getApplication()).getResourceManager().setBusyIndicator(null);
getMyApplication().getResourceManager().interruptRendering();
getMyApplication().getResourceManager().setBusyIndicator(null);
}
private void updateApplicationModeSettings(){
@ -781,7 +785,7 @@ public class MapActivity extends Activity implements IMapLocationListener, Senso
}
routingHelper.setUiActivity(this);
routingHelper.getVoiceRouter().onActivityInit(this);
LocationManager service = (LocationManager) getSystemService(LOCATION_SERVICE);
try {
@ -831,10 +835,10 @@ public class MapActivity extends Activity implements IMapLocationListener, Senso
View progress = findViewById(R.id.ProgressBar);
if(progress != null){
((OsmandApplication) getApplication()).getResourceManager().setBusyIndicator(new BusyIndicator(this, progress));
getMyApplication().getResourceManager().setBusyIndicator(new BusyIndicator(this, progress));
}
((OsmandApplication)getApplication()).getDaynightHelper().onMapResume();
getMyApplication().getDaynightHelper().onMapResume();
}
@ -937,8 +941,8 @@ public class MapActivity extends Activity implements IMapLocationListener, Senso
boolean val = super.onPrepareOptionsMenu(menu);
MenuItem navigateToPointMenu = menu.findItem(R.id.map_navigate_to_point);
if (navigateToPointMenu != null) {
navigateToPointMenu.setTitle(routingHelper.isRouteCalculated() ? R.string.stop_routing : R.string.stop_navigation);
if (settings.getPointToNavigate() != null) {
navigateToPointMenu.setTitle(routingHelper.isRouteCalculated() ? R.string.stop_routing : R.string.stop_navigation);
navigateToPointMenu.setVisible(true);
} else {
navigateToPointMenu.setVisible(false);
@ -946,64 +950,73 @@ public class MapActivity extends Activity implements IMapLocationListener, Senso
}
MenuItem muteMenu = menu.findItem(R.id.map_mute);
if(muteMenu != null){
muteMenu.setTitle(routingHelper.getVoiceRouter().isMute() ? R.string.menu_mute_on : R.string.menu_mute_off);
if (routingHelper.getFinalLocation() != null && routingHelper.isFollowingMode()) {
muteMenu.setTitle(routingHelper.getVoiceRouter().isMute() ? R.string.menu_mute_on : R.string.menu_mute_off);
muteMenu.setVisible(true);
} else {
muteMenu.setVisible(false);
}
}
return val;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.map_show_settings) {
final Intent settings = new Intent(MapActivity.this, SettingsActivity.class);
startActivity(settings);
switch (item.getItemId()) {
case R.id.map_show_settings:
final Intent intentSettings = new Intent(MapActivity.this,
SettingsActivity.class);
startActivity(intentSettings);
return true;
} else if (item.getItemId() == R.id.map_where_am_i) {
case R.id.map_where_am_i:
backToLocationImpl();
return true;
} else if (item.getItemId() == R.id.map_show_gps_status) {
case R.id.map_show_gps_status:
Intent intent = new Intent();
intent.setComponent(new ComponentName(GPS_STATUS_COMPONENT, GPS_STATUS_ACTIVITY));
ResolveInfo resolved = getPackageManager().resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);
if(resolved != null){
intent.setComponent(new ComponentName(GPS_STATUS_COMPONENT,
GPS_STATUS_ACTIVITY));
ResolveInfo resolved = getPackageManager().resolveActivity(intent,
PackageManager.MATCH_DEFAULT_ONLY);
if (resolved != null) {
startActivity(intent);
} else {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage(getString(R.string.gps_status_app_not_found));
builder.setPositiveButton(getString(R.string.default_buttons_yes),
builder.setPositiveButton(
getString(R.string.default_buttons_yes),
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("market://search?q=pname:" + GPS_STATUS_COMPONENT));
public void onClick(DialogInterface dialog,
int which) {
Intent intent = new Intent(Intent.ACTION_VIEW,
Uri.parse("market://search?q=pname:"
+ GPS_STATUS_COMPONENT));
try {
startActivity(intent);
} catch (ActivityNotFoundException e) {
}
}
});
builder.setNegativeButton(getString(R.string.default_buttons_no), null);
builder.setNegativeButton(
getString(R.string.default_buttons_no), null);
builder.show();
}
return true;
} else if (item.getItemId() == R.id.map_get_directions) {
case R.id.map_get_directions:
getDirections(mapView.getLatitude(), mapView.getLongitude(), true);
return true;
} else if (item.getItemId() == R.id.map_layers) {
case R.id.map_layers:
mapLayers.openLayerSelectionDialog(mapView);
return true;
} else if (item.getItemId() == R.id.map_specify_point) {
case R.id.map_specify_point:
NavigatePointActivity dlg = new NavigatePointActivity(this);
dlg.showDialog();
return true;
} else if (item.getItemId() == R.id.map_mute) {
routingHelper.getVoiceRouter().setMute(!routingHelper.getVoiceRouter().isMute());
case R.id.map_mute:
routingHelper.getVoiceRouter().setMute(
!routingHelper.getVoiceRouter().isMute());
return true;
} else if (item.getItemId() == R.id.map_navigate_to_point) {
case R.id.map_navigate_to_point:
if(mapLayers.getNavigationLayer().getPointToNavigate() != null){
if(routingHelper.isRouteCalculated()){
routingHelper.setFinalAndCurrentLocation(null, null);
@ -1016,15 +1029,17 @@ public class MapActivity extends Activity implements IMapLocationListener, Senso
navigateToPoint(new LatLon(mapView.getLatitude(), mapView.getLongitude()));
}
mapView.refreshMap();
} else if (item.getItemId() == R.id.map_gpx_routing) {
return true;
case R.id.map_gpx_routing:
useGPXRouting();
return true;
} else if (item.getItemId() == R.id.map_show_point_options) {
case R.id.map_show_point_options:
contextMenuPoint(mapView.getLatitude(), mapView.getLongitude());
return true;
}
default:
return super.onOptionsItemSelected(item);
}
}
private ApplicationMode getAppMode(ToggleButton[] buttons){
for(int i=0; i<buttons.length; i++){
@ -1090,9 +1105,7 @@ public class MapActivity extends Activity implements IMapLocationListener, Senso
@Override
public void onClick(DialogInterface dialog, int which) {
ApplicationMode mode = getAppMode(buttons);
Location map = new Location("map"); //$NON-NLS-1$
map.setLatitude(lat);
map.setLongitude(lon);
Location map = getLocationToStartFrom(lat, lon);
routingHelper.setAppMode(mode);
settings.FOLLOW_TO_THE_ROUTE.set(false);
routingHelper.setFollowingMode(false);
@ -1111,19 +1124,13 @@ public class MapActivity extends Activity implements IMapLocationListener, Senso
mapView.refreshMap();
}
Location location = getLastKnownLocation();
if(location == null){
location = new Location("map"); //$NON-NLS-1$
location.setLatitude(lat);
location.setLongitude(lon);
}
Location location = getLocationToStartFrom(lat, lon);
routingHelper.setAppMode(mode);
settings.FOLLOW_TO_THE_ROUTE.set(true);
routingHelper.setFollowingMode(true);
routingHelper.setFinalAndCurrentLocation(getPointToNavigate(), location);
((OsmandApplication) getApplication()).showDialogInitializingCommandPlayer(MapActivity.this);
dialog.dismiss();
getMyApplication().showDialogInitializingCommandPlayer(MapActivity.this);
}
};
DialogInterface.OnClickListener showRoute = new DialogInterface.OnClickListener(){
@ -1177,7 +1184,7 @@ public class MapActivity extends Activity implements IMapLocationListener, Senso
}
public FavouritesDbHelper getFavoritesHelper() {
return ((OsmandApplication)getApplication()).getFavorites();
return getMyApplication().getFavorites();
}
private void useGPXRouting() {
@ -1230,7 +1237,7 @@ public class MapActivity extends Activity implements IMapLocationListener, Senso
settings.FOLLOW_TO_THE_ROUTE.set(true);
routingHelper.setFollowingMode(true);
routingHelper.setFinalAndCurrentLocation(endPoint, startForRouting, l);
((OsmandApplication)getApplication()).showDialogInitializingCommandPlayer(MapActivity.this);
getMyApplication().showDialogInitializingCommandPlayer(MapActivity.this);
}
}
});
@ -1321,4 +1328,14 @@ public class MapActivity extends Activity implements IMapLocationListener, Senso
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
private Location getLocationToStartFrom(final double lat, final double lon) {
Location location = getLastKnownLocation();
if(location == null){
location = new Location("map"); //$NON-NLS-1$
location.setLatitude(lat);
location.setLongitude(lon);
}
return location;
}
}

View file

@ -24,11 +24,13 @@ import net.osmand.plus.R;
import net.osmand.plus.ResourceManager;
import net.osmand.plus.render.RendererRegistry;
import net.osmand.plus.voice.CommandPlayer;
import net.osmand.plus.voice.CommandPlayerException;
import net.osmand.plus.voice.CommandPlayerFactory;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.app.Application;
import android.app.ProgressDialog;
import android.app.AlertDialog.Builder;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
@ -194,7 +196,7 @@ public class OsmandApplication extends Application {
}
public void showDialogInitializingCommandPlayer(final Context uiContext){
public void showDialogInitializingCommandPlayer(final Activity uiContext){
String voiceProvider = osmandSettings.VOICE_PROVIDER.get();
if(voiceProvider == null){
Builder builder = new AlertDialog.Builder(uiContext);
@ -219,30 +221,35 @@ public class OsmandApplication extends Application {
}
private void initVoiceDataInDifferentThread(Context uiContext) {
final ProgressDialog dlg = ProgressDialog.show(uiContext, getString(R.string.loading_data), getString(R.string.voice_data_initializing));
private void initVoiceDataInDifferentThread(final Activity uiContext) {
final ProgressDialog dlg = ProgressDialog.show(uiContext,
getString(R.string.loading_data),
getString(R.string.voice_data_initializing));
new Thread(new Runnable() {
@Override
public void run() {
String w = null;
try {
w = initCommandPlayer();
} finally {
initCommandPlayer(uiContext);
dlg.dismiss();
}
if(w != null){
showWarning(dlg.getContext(), w);
} catch (CommandPlayerException e) {
dlg.dismiss();
showWarning(uiContext, e.getError());
}
}
}).start();
}
public String initCommandPlayer() {
if (player == null) {
player = new CommandPlayer(OsmandApplication.this);
public void initCommandPlayer(Activity ctx)
throws CommandPlayerException
{
final String voiceProvider = osmandSettings.VOICE_PROVIDER.get();
if (player == null || !Algoritms.objectEquals(voiceProvider, player.getCurrentVoice())) {
if (player != null) {
player.clear();
}
player = CommandPlayerFactory.createCommandPlayer(voiceProvider,OsmandApplication.this, ctx);
routingHelper.getVoiceRouter().setPlayer(player);
}
return player.init(osmandSettings.VOICE_PROVIDER.get());
}
public NavigationService getNavigationService() {

View file

@ -7,33 +7,34 @@ import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;
import java.util.Set;
import net.osmand.map.TileSourceManager;
import net.osmand.map.TileSourceManager.TileSourceTemplate;
import net.osmand.plus.NavigationService;
import net.osmand.plus.OsmandSettings;
import net.osmand.plus.ProgressDialogImplementation;
import net.osmand.plus.R;
import net.osmand.plus.ResourceManager;
import net.osmand.plus.OsmandSettings.DayNightMode;
import net.osmand.plus.OsmandSettings.MetricsConstants;
import net.osmand.plus.OsmandSettings.OsmandPreference;
import net.osmand.plus.ProgressDialogImplementation;
import net.osmand.plus.R;
import net.osmand.plus.ResourceManager;
import net.osmand.plus.activities.RouteProvider.RouteService;
import net.osmand.plus.render.MapRenderRepositories;
import net.osmand.plus.views.SeekBarPreference;
import net.osmand.plus.voice.CommandPlayer;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.app.AlertDialog.Builder;
import android.app.ProgressDialog;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.DialogInterface.OnClickListener;
import android.content.pm.ActivityInfo;
import android.location.LocationManager;
import android.media.AudioManager;
@ -42,10 +43,10 @@ import android.preference.CheckBoxPreference;
import android.preference.EditTextPreference;
import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.preference.PreferenceScreen;
import android.preference.Preference.OnPreferenceChangeListener;
import android.preference.Preference.OnPreferenceClickListener;
import android.preference.PreferenceActivity;
import android.preference.PreferenceScreen;
import android.widget.Toast;
public class SettingsActivity extends PreferenceActivity implements OnPreferenceChangeListener, OnPreferenceClickListener {
@ -315,8 +316,12 @@ public class SettingsActivity extends PreferenceActivity implements OnPreference
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(broadcastReceiver);
//we are initializing player in this activity, we must also stop it
final CommandPlayer player = getMyApplication().getPlayer();
if (player != null) {
player.onActvitiyStop(this);
}
}
public void updateAllSettings(){
for(OsmandPreference<Boolean> b : booleanPreferences.values()){
@ -397,6 +402,7 @@ public class SettingsActivity extends PreferenceActivity implements OnPreference
fill(tileSourcePreference, entries, values, value);
}
private void fill(ListPreference component, String[] list, String[] values, String selected) {
component.setEntries(list);
component.setEntryValues(values);
@ -435,7 +441,7 @@ public class SettingsActivity extends PreferenceActivity implements OnPreference
// Specific actions after list preference changed
if (changed) {
if (listPref.getId().equals(osmandSettings.VOICE_PROVIDER.getId())) {
getMyApplication().initCommandPlayer();
getMyApplication().showDialogInitializingCommandPlayer(this);
} else if (listPref.getId().equals(osmandSettings.APPLICATION_MODE.getId())) {
updateAllSettings();
} else if (listPref.getId().equals(osmandSettings.PREFERRED_LOCALE.getId())) {

View file

@ -2,8 +2,10 @@ package net.osmand.plus.activities;
import net.osmand.plus.activities.RoutingHelper.RouteDirectionInfo;
import net.osmand.plus.activities.RoutingHelper.TurnType;
import net.osmand.plus.voice.AbstractPrologCommandPlayer;
import net.osmand.plus.voice.CommandBuilder;
import net.osmand.plus.voice.CommandPlayer;
import net.osmand.plus.voice.CommandPlayer.CommandBuilder;
import android.app.Activity;
public class VoiceRouter {
@ -227,17 +229,17 @@ public class VoiceRouter {
private String getTurnType(TurnType t){
if(TurnType.TL.equals(t.getValue())){
return CommandPlayer.A_LEFT;
return AbstractPrologCommandPlayer.A_LEFT;
} else if(TurnType.TSHL.equals(t.getValue())){
return CommandPlayer.A_LEFT_SH;
return AbstractPrologCommandPlayer.A_LEFT_SH;
} else if(TurnType.TSLL.equals(t.getValue())){
return CommandPlayer.A_LEFT_SL;
return AbstractPrologCommandPlayer.A_LEFT_SL;
} else if(TurnType.TR.equals(t.getValue())){
return CommandPlayer.A_RIGHT;
return AbstractPrologCommandPlayer.A_RIGHT;
} else if(TurnType.TSHR.equals(t.getValue())){
return CommandPlayer.A_RIGHT_SH;
return AbstractPrologCommandPlayer.A_RIGHT_SH;
} else if(TurnType.TSLR.equals(t.getValue())){
return CommandPlayer.A_RIGHT_SL;
return AbstractPrologCommandPlayer.A_RIGHT_SL;
}
return null;
}
@ -262,4 +264,16 @@ public class VoiceRouter {
}
}
public void onActivityInit(Activity activity) {
if (player != null) {
player.onActivityInit(activity);
}
}
public void onActivityStop(Activity activity) {
if (player != null) {
player.onActvitiyStop(activity);
}
}
}

View file

@ -0,0 +1,179 @@
package net.osmand.plus.voice;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import net.osmand.LogUtil;
import net.osmand.plus.OsmandSettings;
import net.osmand.plus.R;
import net.osmand.plus.ResourceManager;
import org.apache.commons.logging.Log;
import alice.tuprolog.InvalidLibraryException;
import alice.tuprolog.InvalidTheoryException;
import alice.tuprolog.NoSolutionException;
import alice.tuprolog.Number;
import alice.tuprolog.Prolog;
import alice.tuprolog.SolveInfo;
import alice.tuprolog.Struct;
import alice.tuprolog.Term;
import alice.tuprolog.Theory;
import alice.tuprolog.Var;
import android.content.Context;
public abstract class AbstractPrologCommandPlayer implements CommandPlayer {
private static final Log log = LogUtil
.getLog(AbstractPrologCommandPlayer.class);
protected Context ctx;
protected File voiceDir;
protected Prolog prologSystem;
protected static final String P_VERSION = "version";
protected static final String P_RESOLVE = "resolve";
public static final String A_LEFT = "left";
public static final String A_LEFT_SH = "left_sh";
public static final String A_LEFT_SL = "left_sl";
public static final String A_RIGHT = "right";
public static final String A_RIGHT_SH = "right_sh";
public static final String A_RIGHT_SL = "right_sl";
protected static final String DELAY_CONST = "delay_";
private final int voiceVersion;
protected AbstractPrologCommandPlayer(Context ctx, String voiceProvider, String configFile, int voiceVersion)
throws CommandPlayerException
{
this.voiceVersion = voiceVersion;
long time = System.currentTimeMillis();
try {
this.ctx = ctx;
prologSystem = new Prolog(
new String[] { "alice.tuprolog.lib.BasicLibrary" }); //$NON-NLS-1$
} catch (InvalidLibraryException e) {
log.error("Initializing error", e); //$NON-NLS-1$
throw new RuntimeException(e);
}
if (log.isInfoEnabled()) {
log.info("Initializing prolog system : " + (System.currentTimeMillis() - time)); //$NON-NLS-1$
}
init(voiceProvider, configFile);
}
private void init(String voiceProvider, String configFile) throws CommandPlayerException {
prologSystem.clearTheory();
voiceDir = null;
if (voiceProvider != null) {
File parent = OsmandSettings.getOsmandSettings(ctx).extendOsmandPath(ResourceManager.VOICE_PATH);
voiceDir = new File(parent, voiceProvider);
if (!voiceDir.exists()) {
voiceDir = null;
throw new CommandPlayerException(
ctx.getString(R.string.voice_data_unavailable));
}
}
// see comments below why it is impossible to read from zip (don't know
// how to play file from zip)
// voiceZipFile = null;
if (voiceDir != null) {
long time = System.currentTimeMillis();
boolean wrong = false;
try {
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, configFile)); //$NON-NLS-1$
// }
if (!wrong) {
prologSystem.setTheory(new Theory(config));
}
} catch (InvalidTheoryException e) {
log.error("Loading voice config exception " + voiceProvider, e); //$NON-NLS-1$
wrong = true;
} catch (IOException e) {
log.error("Loading voice config exception " + voiceProvider, e); //$NON-NLS-1$
wrong = true;
}
if (wrong) {
throw new CommandPlayerException(ctx.getString(R.string.voice_data_corrupted));
} else {
Term val = solveSimplePredicate(P_VERSION);
if (!(val instanceof Number) || ((Number)val).intValue() != voiceVersion) {
throw new CommandPlayerException(ctx.getString(R.string.voice_data_not_supported));
}
}
if (log.isInfoEnabled()) {
log.info("Initializing voice subsystem " + voiceProvider + " : " + (System.currentTimeMillis() - time)); //$NON-NLS-1$ //$NON-NLS-2$
}
}
}
protected Term solveSimplePredicate(String predicate) {
Term val = null;
Var v = new Var("MyVariable"); //$NON-NLS-1$
SolveInfo s = prologSystem.solve(new Struct(predicate, v));
if (s.isSuccess()) {
prologSystem.solveEnd();
try {
val = s.getVarValue(v.getName());
} catch (NoSolutionException e) {
}
}
return val;
}
@Override
public List<String> execute(List<Struct> listCmd){
Struct list = new Struct(listCmd.toArray(new Term[listCmd.size()]));
Var result = new Var("RESULT"); //$NON-NLS-1$
List<String> files = new ArrayList<String>();
SolveInfo res = prologSystem.solve(new Struct(P_RESOLVE, list, result));
if (res.isSuccess()) {
try {
prologSystem.solveEnd();
Term solution = res.getVarValue(result.getName());
Iterator<?> listIterator = ((Struct) solution).listIterator();
while(listIterator.hasNext()){
Object term = listIterator.next();
if(term instanceof Struct){
files.add(((Struct) term).getName());
}
}
} catch (NoSolutionException e) {
}
}
return files;
}
@Override
public String getCurrentVoice() {
if (voiceDir == null) {
return null;
}
return voiceDir.getName();
}
@Override
public CommandBuilder newCommandBuilder() {
return new CommandBuilder(this);
}
@Override
public void clear() {
ctx = null;
prologSystem = null;
}
}

View file

@ -0,0 +1,179 @@
package net.osmand.plus.voice;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import net.osmand.LogUtil;
import org.apache.commons.logging.Log;
import alice.tuprolog.Struct;
import alice.tuprolog.Term;
public class CommandBuilder {
private static final Log log = LogUtil.getLog(CommandBuilder.class);
protected static final String C_PREPARE_TURN = "prepare_turn"; //$NON-NLS-1$
protected static final String C_PREPARE_ROUNDABOUT = "prepare_roundabout"; //$NON-NLS-1$
protected static final String C_PREPARE_MAKE_UT = "prepare_make_ut"; //$NON-NLS-1$
protected static final String C_ROUNDABOUT = "roundabout"; //$NON-NLS-1$
protected static final String C_GO_AHEAD = "go_ahead"; //$NON-NLS-1$
protected static final String C_TURN = "turn"; //$NON-NLS-1$
protected static final String C_MAKE_UT = "make_ut"; //$NON-NLS-1$
protected static final String C_PREAMBLE = "preamble"; //$NON-NLS-1$
protected static final String C_AND_ARRIVE_DESTINATION = "and_arrive_destination"; //$NON-NLS-1$
protected static final String C_THEN = "then"; //$NON-NLS-1$
protected static final String C_REACHED_DESTINATION = "reached_destination"; //$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$
/**
*
*/
private final CommandPlayer commandPlayer;
private boolean alreadyExecuted = false;
private List<Struct> listStruct = new ArrayList<Struct>();
public CommandBuilder(CommandPlayer commandPlayer){
this(commandPlayer, true);
}
public CommandBuilder(CommandPlayer commandPlayer, boolean preamble) {
this.commandPlayer = commandPlayer;
if (preamble) {
addCommand(C_PREAMBLE);
}
}
private void checkState(){
if(alreadyExecuted){
throw new IllegalArgumentException();
}
}
private CommandBuilder addCommand(String name, Object... args){
checkState();
Term[] list = new Term[args.length];
for (int i = 0; i < args.length; i++) {
Object o = args[i];
if(o instanceof java.lang.Number){
if(o instanceof java.lang.Double){
list[i] = new alice.tuprolog.Double((Double) o);
} else if(o instanceof java.lang.Float){
list[i] = new alice.tuprolog.Float((Float) o);
} else if(o instanceof java.lang.Long){
list[i] = new alice.tuprolog.Long((Long) o);
} else {
list[i] = new alice.tuprolog.Int(((java.lang.Number)o).intValue());
}
} else if(o instanceof String){
list[i] = new Struct((String) o);
}
if(list[i]== null){
throw new NullPointerException(name +" " + o); //$NON-NLS-1$
}
}
Struct struct = new Struct(name, list);
if(log.isDebugEnabled()){
log.debug("Adding command : " + name + " " + Arrays.toString(args)); //$NON-NLS-1$ //$NON-NLS-2$
}
listStruct.add(struct);
return this;
}
public CommandBuilder goAhead(){
return addCommand(C_GO_AHEAD);
}
public CommandBuilder goAhead(double dist){
return addCommand(C_GO_AHEAD, dist);
}
public CommandBuilder makeUT(){
return addCommand(C_MAKE_UT);
}
public CommandBuilder makeUT(double dist){
return addCommand(C_MAKE_UT, dist);
}
public CommandBuilder prepareMakeUT(double dist){
return addCommand(C_PREPARE_MAKE_UT, dist);
}
public CommandBuilder turn(String param){
return addCommand(C_TURN, param);
}
public CommandBuilder turn(String param, double dist){
return addCommand(C_TURN, param, dist);
}
/**
*
* @param param A_LEFT, A_RIGHT, ...
* @param dist
* @return
*/
public CommandBuilder prepareTurn(String param, double dist){
return addCommand(C_PREPARE_TURN, param, dist);
}
public CommandBuilder prepareRoundAbout(double dist){
return addCommand(C_PREPARE_ROUNDABOUT, dist);
}
public CommandBuilder roundAbout(double dist, double angle, int exit){
return addCommand(C_ROUNDABOUT, dist, angle, exit);
}
public CommandBuilder roundAbout(double angle, int exit){
return addCommand(C_ROUNDABOUT, angle, exit);
}
public CommandBuilder andArriveAtDestination(){
return addCommand(C_AND_ARRIVE_DESTINATION);
}
public CommandBuilder arrivedAtDestination(){
return addCommand(C_REACHED_DESTINATION);
}
public CommandBuilder bearLeft(){
return addCommand(C_BEAR_LEFT);
}
public CommandBuilder bearRight(){
return addCommand(C_BEAR_RIGHT);
}
public CommandBuilder then(){
return addCommand(C_THEN);
}
public CommandBuilder newRouteCalculated(double dist){
return addCommand(C_ROUTE_NEW_CALC, dist);
}
public CommandBuilder routeRecalculated(double dist){
return addCommand(C_ROUTE_RECALC, dist);
}
public void play(){
this.commandPlayer.playCommands(this);
}
protected List<String> execute(){
alreadyExecuted = true;
return this.commandPlayer.execute(listStruct);
}
}

View file

@ -1,420 +1,24 @@
package net.osmand.plus.voice;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import net.osmand.LogUtil;
import net.osmand.data.IndexConstants;
import net.osmand.plus.OsmandSettings;
import net.osmand.plus.R;
import net.osmand.plus.ResourceManager;
import org.apache.commons.logging.Log;
import alice.tuprolog.InvalidLibraryException;
import alice.tuprolog.InvalidTheoryException;
import alice.tuprolog.NoSolutionException;
import alice.tuprolog.Number;
import alice.tuprolog.Prolog;
import alice.tuprolog.SolveInfo;
import alice.tuprolog.Struct;
import alice.tuprolog.Term;
import alice.tuprolog.Theory;
import alice.tuprolog.Var;
import android.app.Activity;
import android.content.Context;
import android.media.MediaPlayer;
/**
* That class represents command player.
* It gets commands from input, analyze what files should be played and play
* them using media player
*/
public class CommandPlayer {
public interface CommandPlayer {
private static final Log log = LogUtil.getLog(CommandPlayer.class);
public abstract String getCurrentVoice();
protected Context ctx;
// or zip file
private File voiceDir;
// private ZipFile voiceZipFile;
public abstract CommandBuilder newCommandBuilder();
// resolving commands to play
private Prolog prologSystem;
public abstract void playCommands(CommandBuilder builder);
// playing media
private MediaPlayer mediaPlayer;
// indicates that player is ready to play first file
private boolean playNext = true;
private List<String> filesToPlay = Collections.synchronizedList(new ArrayList<String>());
public abstract void clear();
public abstract List<String> execute(List<Struct> listStruct);
public CommandPlayer(Context ctx){
long time = System.currentTimeMillis();
try {
this.ctx = ctx;
prologSystem = new Prolog(new String[]{"alice.tuprolog.lib.BasicLibrary"}); //$NON-NLS-1$
} catch (InvalidLibraryException e) {
log.error("Initializing error", e); //$NON-NLS-1$
throw new RuntimeException(e);
}
mediaPlayer = new MediaPlayer();
if (log.isInfoEnabled()) {
log.info("Initializing prolog system : " + (System.currentTimeMillis() - time)); //$NON-NLS-1$
}
}
public String getCurrentVoice(){
if(voiceDir == null){
return null;
}
return voiceDir.getName();
}
public String init(String voiceProvider){
prologSystem.clearTheory();
voiceDir = null;
if(voiceProvider != null){
File parent = OsmandSettings.getOsmandSettings(ctx).extendOsmandPath(ResourceManager.VOICE_PATH);
voiceDir = new File(parent, voiceProvider);
if(!voiceDir.exists()){
voiceDir = null;
return ctx.getString(R.string.voice_data_unavailable);
}
}
// see comments below why it is impossible to read from zip (don't know how to play file from zip)
// voiceZipFile = null;
if(voiceDir != null) {
long time = System.currentTimeMillis();
boolean wrong = false;
try {
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) {
log.error("Loading voice config exception " + voiceProvider, e); //$NON-NLS-1$
wrong = true;
} catch (IOException e) {
log.error("Loading voice config exception " + voiceProvider, e); //$NON-NLS-1$
wrong = true;
}
if(wrong){
return ctx.getString(R.string.voice_data_corrupted);
} else {
boolean versionSupported = false;
Var v = new Var("VERSION"); //$NON-NLS-1$
SolveInfo s = prologSystem.solve(new Struct(P_VERSION, v));
if(s.isSuccess()){
prologSystem.solveEnd();
try {
Term val = s.getVarValue(v.getName());
if(val instanceof Number){
versionSupported = ((Number) val).intValue() == IndexConstants.VOICE_VERSION;
}
} catch (NoSolutionException e) {
}
}
if(!versionSupported){
return ctx.getString(R.string.voice_data_not_supported);
}
}
if (log.isInfoEnabled()) {
log.info("Initializing voice subsystem " + voiceProvider + " : " + (System.currentTimeMillis() - time)); //$NON-NLS-1$ //$NON-NLS-2$
}
}
return null;
}
public CommandBuilder newCommandBuilder(){
return new CommandBuilder();
}
protected List<String> execute(List<Struct> listCmd){
Struct list = new Struct(listCmd.toArray(new Term[listCmd.size()]));
Var result = new Var("RESULT"); //$NON-NLS-1$
List<String> files = new ArrayList<String>();
SolveInfo res = prologSystem.solve(new Struct(P_RESOLVE, list, result));
if (res.isSuccess()) {
try {
prologSystem.solveEnd();
Term solution = res.getVarValue(result.getName());
Iterator<?> listIterator = ((Struct) solution).listIterator();
while(listIterator.hasNext()){
Object term = listIterator.next();
if(term instanceof Struct){
files.add(((Struct) term).getName());
}
}
} catch (NoSolutionException e) {
}
}
return files;
}
public void playCommands(CommandBuilder builder){
filesToPlay.addAll(builder.execute());
playQueue();
}
private synchronized void playQueue() {
while (!filesToPlay.isEmpty() && playNext) {
String f = filesToPlay.remove(0);
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);
exists = file.exists();
// }
if (exists) {
log.debug("Playing file : " + f); //$NON-NLS-1$
playNext = false;
try {
// Can't play sound file from zip it seams to be impossible only unpack and play!!!
mediaPlayer.setDataSource(file.getAbsolutePath());
mediaPlayer.prepare();
mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
public void onCompletion(MediaPlayer mp) {
mp.release();
mediaPlayer = new MediaPlayer();
int sleep = 60;
boolean delay = true;
while (!filesToPlay.isEmpty() && delay) {
delay = filesToPlay.get(0).startsWith(DELAY_CONST);
if (delay) {
String s = filesToPlay.remove(0).substring(DELAY_CONST.length());
try {
sleep += Integer.parseInt(s);
} catch (NumberFormatException e) {
}
}
}
try {
Thread.sleep(sleep);
} catch (InterruptedException e) {
}
playNext = true;
playQueue();
}
});
mediaPlayer.start();
} catch (Exception e) {
log.error("Error while playing voice command", e); //$NON-NLS-1$
playNext = true;
}
} else {
log.info("Play file not found : " + f); //$NON-NLS-1$
}
}
}
}
protected static final String P_VERSION = "version"; //$NON-NLS-1$
protected static final String P_RESOLVE = "resolve"; //$NON-NLS-1$
public static final String A_LEFT = "left"; //$NON-NLS-1$
public static final String A_LEFT_SH = "left_sh"; //$NON-NLS-1$
public static final String A_LEFT_SL = "left_sl"; //$NON-NLS-1$
public static final String A_RIGHT = "right"; //$NON-NLS-1$
public static final String A_RIGHT_SH = "right_sh"; //$NON-NLS-1$
public static final String A_RIGHT_SL = "right_sl"; //$NON-NLS-1$
protected static final String C_PREPARE_TURN = "prepare_turn"; //$NON-NLS-1$
protected static final String C_PREPARE_ROUNDABOUT = "prepare_roundabout"; //$NON-NLS-1$
protected static final String C_PREPARE_MAKE_UT = "prepare_make_ut"; //$NON-NLS-1$
protected static final String C_ROUNDABOUT = "roundabout"; //$NON-NLS-1$
protected static final String C_GO_AHEAD = "go_ahead"; //$NON-NLS-1$
protected static final String C_TURN = "turn"; //$NON-NLS-1$
protected static final String C_MAKE_UT = "make_ut"; //$NON-NLS-1$
protected static final String C_PREAMBLE = "preamble"; //$NON-NLS-1$
protected static final String C_AND_ARRIVE_DESTINATION = "and_arrive_destination"; //$NON-NLS-1$
protected static final String C_THEN = "then"; //$NON-NLS-1$
protected static final String C_REACHED_DESTINATION = "reached_destination"; //$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 DELAY_CONST = "delay_"; //$NON-NLS-1$
public class CommandBuilder {
private boolean alreadyExecuted = false;
private List<Struct> listStruct = new ArrayList<Struct>();
public CommandBuilder(){
this(true);
}
public CommandBuilder(boolean preamble) {
if (preamble) {
addCommand(C_PREAMBLE);
}
}
private void checkState(){
if(alreadyExecuted){
throw new IllegalArgumentException();
}
}
private CommandBuilder addCommand(String name, Object... args){
checkState();
Term[] list = new Term[args.length];
for (int i = 0; i < args.length; i++) {
Object o = args[i];
if(o instanceof java.lang.Number){
if(o instanceof java.lang.Double){
list[i] = new alice.tuprolog.Double((Double) o);
} else if(o instanceof java.lang.Float){
list[i] = new alice.tuprolog.Float((Float) o);
} else if(o instanceof java.lang.Long){
list[i] = new alice.tuprolog.Long((Long) o);
} else {
list[i] = new alice.tuprolog.Int(((java.lang.Number)o).intValue());
}
} else if(o instanceof String){
list[i] = new Struct((String) o);
}
if(list[i]== null){
throw new NullPointerException(name +" " + o); //$NON-NLS-1$
}
}
Struct struct = new Struct(name, list);
if(log.isDebugEnabled()){
log.debug("Adding command : " + name + " " + Arrays.toString(args)); //$NON-NLS-1$ //$NON-NLS-2$
}
listStruct.add(struct);
return this;
}
public CommandBuilder goAhead(){
return addCommand(C_GO_AHEAD);
}
public CommandBuilder goAhead(double dist){
return addCommand(C_GO_AHEAD, dist);
}
public CommandBuilder makeUT(){
return addCommand(C_MAKE_UT);
}
public CommandBuilder makeUT(double dist){
return addCommand(C_MAKE_UT, dist);
}
public CommandBuilder prepareMakeUT(double dist){
return addCommand(C_PREPARE_MAKE_UT, dist);
}
public CommandBuilder turn(String param){
return addCommand(C_TURN, param);
}
public CommandBuilder turn(String param, double dist){
return addCommand(C_TURN, param, dist);
}
/**
*
* @param param A_LEFT, A_RIGHT, ...
* @param dist
* @return
*/
public CommandBuilder prepareTurn(String param, double dist){
return addCommand(C_PREPARE_TURN, param, dist);
}
public CommandBuilder prepareRoundAbout(double dist){
return addCommand(C_PREPARE_ROUNDABOUT, dist);
}
public CommandBuilder roundAbout(double dist, double angle, int exit){
return addCommand(C_ROUNDABOUT, dist, angle, exit);
}
public CommandBuilder roundAbout(double angle, int exit){
return addCommand(C_ROUNDABOUT, angle, exit);
}
public CommandBuilder andArriveAtDestination(){
return addCommand(C_AND_ARRIVE_DESTINATION);
}
public CommandBuilder arrivedAtDestination(){
return addCommand(C_REACHED_DESTINATION);
}
public CommandBuilder bearLeft(){
return addCommand(C_BEAR_LEFT);
}
public CommandBuilder bearRight(){
return addCommand(C_BEAR_RIGHT);
}
public CommandBuilder then(){
return addCommand(C_THEN);
}
public CommandBuilder newRouteCalculated(double dist){
return addCommand(C_ROUTE_NEW_CALC, dist);
}
public CommandBuilder routeRecalculated(double dist){
return addCommand(C_ROUTE_RECALC, dist);
}
public void play(){
CommandPlayer.this.playCommands(this);
}
protected List<String> execute(){
alreadyExecuted = true;
return CommandPlayer.this.execute(listStruct);
}
}
public void onActivityInit(Activity ctx);
public void onActvitiyStop(Context ctx);
}

View file

@ -0,0 +1,22 @@
package net.osmand.plus.voice;
/**
* Exception on CommandPlayer
*
* @author Pavol Zibrita <pavol.zibrita@gmail.com>
*/
public class CommandPlayerException extends Exception {
private static final long serialVersionUID = 8413902962574061832L;
private final String error;
public CommandPlayerException(String error) {
this.error = error;
}
public String getError() {
return error;
}
}

View file

@ -0,0 +1,34 @@
package net.osmand.plus.voice;
import java.io.File;
import net.osmand.plus.OsmandSettings;
import net.osmand.plus.R;
import net.osmand.plus.ResourceManager;
import net.osmand.plus.activities.OsmandApplication;
import android.app.Activity;
import android.os.Build;
public class CommandPlayerFactory
{
public static CommandPlayer createCommandPlayer(String voiceProvider, OsmandApplication osmandApplication, Activity ctx)
throws CommandPlayerException
{
if (voiceProvider != null){
File parent = OsmandSettings.getOsmandSettings(ctx).extendOsmandPath(ResourceManager.VOICE_PATH);
File voiceDir = new File(parent, voiceProvider);
if(!voiceDir.exists()){
throw new CommandPlayerException(ctx.getString(R.string.voice_data_unavailable));
}
if (MediaCommandPlayerImpl.isMyData(voiceDir)) {
return new MediaCommandPlayerImpl(osmandApplication, voiceProvider);
} else if (Integer.parseInt(Build.VERSION.SDK) >= 4) {
if (TTSCommandPlayerImpl.isMyData(voiceDir)) {
return new TTSCommandPlayerImpl(ctx, voiceProvider);
}
}
throw new CommandPlayerException(ctx.getString(R.string.voice_data_not_supported));
}
return null;
}
}

View file

@ -0,0 +1,127 @@
package net.osmand.plus.voice;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import net.osmand.LogUtil;
import org.apache.commons.logging.Log;
import android.app.Activity;
import android.content.Context;
import android.media.MediaPlayer;
/**
* That class represents command player.
* It gets commands from input, analyze what files should be played and play
* them using media player
*/
public class MediaCommandPlayerImpl extends AbstractPrologCommandPlayer {
private static final String CONFIG_FILE = "_config.p";
private static final int MEDIA_VOICE_VERSION = 0;
private static final Log log = LogUtil.getLog(MediaCommandPlayerImpl.class);
// playing media
private MediaPlayer mediaPlayer;
// indicates that player is ready to play first file
private boolean playNext = true;
private List<String> filesToPlay = Collections.synchronizedList(new ArrayList<String>());
public MediaCommandPlayerImpl(Context ctx, String voiceProvider)
throws CommandPlayerException
{
super(ctx, voiceProvider, CONFIG_FILE, MEDIA_VOICE_VERSION);
mediaPlayer = new MediaPlayer();
}
@Override
public void onActivityInit(Activity ctx) {
//do nothing here
}
@Override
public void onActvitiyStop(Context ctx) {
//do nothing here
}
@Override
public void clear() {
super.clear();
mediaPlayer = null;
}
@Override
public void playCommands(CommandBuilder builder){
filesToPlay.addAll(builder.execute());
playQueue();
}
private synchronized void playQueue() {
while (!filesToPlay.isEmpty() && playNext) {
String f = filesToPlay.remove(0);
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);
exists = file.exists();
// }
if (exists) {
log.debug("Playing file : " + f); //$NON-NLS-1$
playNext = false;
try {
// Can't play sound file from zip it seams to be impossible only unpack and play!!!
mediaPlayer.setDataSource(file.getAbsolutePath());
mediaPlayer.prepare();
mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
public void onCompletion(MediaPlayer mp) {
mp.release();
mediaPlayer = new MediaPlayer();
int sleep = 60;
boolean delay = true;
while (!filesToPlay.isEmpty() && delay) {
delay = filesToPlay.get(0).startsWith(DELAY_CONST);
if (delay) {
String s = filesToPlay.remove(0).substring(DELAY_CONST.length());
try {
sleep += Integer.parseInt(s);
} catch (NumberFormatException e) {
}
}
}
try {
Thread.sleep(sleep);
} catch (InterruptedException e) {
}
playNext = true;
playQueue();
}
});
mediaPlayer.start();
} catch (Exception e) {
log.error("Error while playing voice command", e); //$NON-NLS-1$
playNext = true;
}
} else {
log.info("Play file not found : " + f); //$NON-NLS-1$
}
}
}
}
public static boolean isMyData(File voiceDir) {
return new File(voiceDir, CONFIG_FILE).exists();
}
}

View file

@ -0,0 +1,175 @@
package net.osmand.plus.voice;
import java.io.File;
import java.util.List;
import java.util.Locale;
import net.osmand.Algoritms;
import net.osmand.plus.R;
import net.osmand.plus.activities.SettingsActivity;
import alice.tuprolog.Struct;
import alice.tuprolog.Term;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.speech.tts.TextToSpeech;
import android.speech.tts.TextToSpeech.OnInitListener;
public class TTSCommandPlayerImpl extends AbstractPrologCommandPlayer {
private final class IntentStarter implements
DialogInterface.OnClickListener {
private final Activity ctx;
private final String intentAction;
private final Uri intentData;
private IntentStarter(Activity ctx, String intentAction) {
this(ctx,intentAction, null);
}
private IntentStarter(Activity ctx, String intentAction, Uri intentData) {
this.ctx = ctx;
this.intentAction = intentAction;
this.intentData = intentData;
}
@Override
public void onClick(DialogInterface dialog, int which) {
Intent installIntent = new Intent();
installIntent.setAction(intentAction);
if (intentData != null) {
installIntent.setData(intentData);
}
ctx.startActivity(installIntent);
}
}
private static final String CONFIG_FILE = "_ttsconfig.p";
private static final int TTS_VOICE_VERSION = 100;
private TextToSpeech mTts;
private Context mTtsContext;
private String language;
protected TTSCommandPlayerImpl(Activity ctx, String voiceProvider)
throws CommandPlayerException {
super(ctx, voiceProvider, CONFIG_FILE, TTS_VOICE_VERSION);
final Term langVal = solveSimplePredicate("language");
if (langVal instanceof Struct) {
language = ((Struct) langVal).getName();
}
if (Algoritms.isEmpty(language)) {
throw new CommandPlayerException(
ctx.getString(R.string.voice_data_corrupted));
}
onActivityInit(ctx);
}
@Override
public void playCommands(CommandBuilder builder) {
if (mTts != null) {
final List<String> execute = builder.execute(); //list of strings, the speech text, play it
StringBuilder bld = new StringBuilder();
for (String s : execute) {
bld.append(s).append(' ');
}
mTts.speak(bld.toString(), TextToSpeech.QUEUE_ADD, null);
}
}
@Override
public void onActivityInit(final Activity ctx) {
if (mTts != null && mTtsContext != ctx) {
//clear only, if the mTts was initialized in another context.
//Unfortunately, for example from settings to map first the map is initialized than
//the settingsactivity is destroyed...
internalClear();
}
if (mTts == null) {
mTtsContext = ctx;
mTts = new TextToSpeech(ctx, new OnInitListener() {
@Override
public void onInit(int status) {
if (status != TextToSpeech.SUCCESS) {
internalClear();
} else {
switch (mTts.isLanguageAvailable(new Locale(language)))
{
case TextToSpeech.LANG_MISSING_DATA:
internalClear();
Builder builder = createAlertDialog(
R.string.tts_missing_language_data_title,
R.string.tts_missing_language_data,
new IntentStarter(
ctx,
TextToSpeech.Engine.ACTION_INSTALL_TTS_DATA),
ctx);
builder.show();
break;
case TextToSpeech.LANG_AVAILABLE:
mTts.setLanguage(new Locale(language));
break;
case TextToSpeech.LANG_NOT_SUPPORTED:
//maybe weird, but I didn't want to introduce parameter in around 5 methods just to do
//this if condition
if (ctx instanceof SettingsActivity) {
builder = createAlertDialog(
R.string.tts_language_not_supported_title,
R.string.tts_language_not_supported,
new IntentStarter(
ctx,
Intent.ACTION_VIEW, Uri.parse("market://search?q=text to speech engine"
)),
ctx);
builder.show();
}
break;
}
}
}
});
}
}
private Builder createAlertDialog(int titleResID, int messageResID, IntentStarter intentStarter, final Activity ctx) {
Builder builder = new AlertDialog.Builder(ctx);
builder.setCancelable(true);
builder.setNegativeButton(R.string.default_buttons_no, null);
builder.setPositiveButton(R.string.default_buttons_yes, intentStarter);
builder.setTitle(titleResID);
builder.setMessage(messageResID);
return builder;
}
@Override
public void onActvitiyStop(Context ctx) {
//stop only when the context is the same
if (mTtsContext == ctx) {
internalClear();
}
}
private void internalClear() {
if (mTts != null) {
mTts.shutdown();
mTtsContext = null;
mTts = null;
}
}
@Override
public void clear() {
super.clear();
internalClear();
}
public static boolean isMyData(File voiceDir) throws CommandPlayerException {
return new File(voiceDir, CONFIG_FILE).exists();
}
}

View file

@ -0,0 +1,120 @@
:- op('==', xfy, 500).
version(100).
language(en).
% before each announcement (beep)
preamble - [].
%% TURNS
turn('left', ['turn left ']).
turn('left_sh', ['sharp left ']).
turn('left_sl', ['turn slightly left ']).
turn('right', ['turn right ']).
turn('right_sh', ['sharp right ']).
turn('right_sl', ['turn slightly right ']).
prepare_turn(Turn, Dist) == ['Prepare to ', M, ' after ', D] :-
distance(Dist) == D, turn(Turn, M).
turn(Turn, Dist) == ['After ', D, M] :-
distance(Dist) == D, turn(Turn, M).
turn(Turn) == M :- turn(Turn, M).
prepare_make_ut(Dist) == ['Prepare to turn after ', D, ' turn back'] :-
distance(Dist) == D.
prepare_roundabout(Dist) == ['Prepare to enter roundabout after ', D] :-
distance(Dist) == D.
make_ut(Dist) == ['After ', D, ' turn back '] :-
distance(Dist) == D.
make_ut == ['Turn back '].
roundabout(Dist, _Angle, Exit) == ['After ', D, ' enter the roundabout, and take the ', E, 'exit'] :- distance(Dist) == D, nth(Exit, E).
roundabout(_Angle, Exit) == ['taking the ', E, 'exit'] :- nth(Exit, E).
and_arrive_destination == ['and arrive at your destination ']. % Miss and?
then == ['then '].
reached_destination == ['you have reached your destination '].
bear_right == ['keep right '].
bear_left == ['keep left '].
route_recalc(_Dist) == []. % ['recalculating route ']. %nothing to said possibly beep?
route_new_calc(Dist) == ['The trip is ', D] :- distance(Dist) == D. % nothing to said possibly beep?
go_ahead(Dist) == ['Drive for ', D]:- distance(Dist) == D.
go_ahead == ['Continue straight ahead '].
%%
nth(1, '1st ').
nth(2, '2nd ').
nth(3, '3rd ').
nth(4, '4th ').
nth(5, '5th ').
nth(6, '6th ').
nth(7, '7th ').
nth(8, '8th ').
nth(9, '9th ').
nth(10, '10th ').
nth(11, '11th ').
nth(12, '12th ').
nth(13, '13th ').
nth(14, '14th ').
nth(15, '15th ').
nth(16, '16th ').
nth(17, '17th ').
%%% distance measure
distance(Dist) == T :- Dist < 1000, dist(Dist, F), append(F, ' meters',T).
dist(D, ['10 ']) :- D < 20, !.
dist(D, ['20 ']) :- D < 30, !.
dist(D, ['30 ']) :- D < 40, !.
dist(D, ['40 ']) :- D < 50, !.
dist(D, ['50 ']) :- D < 60, !.
dist(D, ['60 ']) :- D < 70, !.
dist(D, ['70 ']) :- D < 80, !.
dist(D, ['80 ']) :- D < 90, !.
dist(D, ['90 ']) :- D < 100, !.
dist(D, ['100 ']) :- D < 150, !.
dist(D, ['150 ']) :- D < 200, !.
dist(D, ['200 ']) :- D < 250, !.
dist(D, ['250 ']) :- D < 300, !.
dist(D, ['300 ']) :- D < 350, !.
dist(D, ['350 ']) :- D < 400, !.
dist(D, ['400 ']) :- D < 450, !.
dist(D, ['450 ']) :- D < 500, !.
dist(D, ['500 ']) :- D < 550, !.
dist(D, ['550 ']) :- D < 600, !.
dist(D, ['600 ']) :- D < 650, !.
dist(D, ['650 ']) :- D < 700, !.
dist(D, ['700 ']) :- D < 750, !.
dist(D, ['750 ']) :- D < 800, !.
dist(D, ['800 ']) :- D < 850, !.
dist(D, ['850 ']) :- D < 900, !.
dist(D, ['900 ']) :- D < 950, !.
dist(D, ['950 ']) :- !.
distance(Dist) == ['more than 1 kilometer '] :- Dist < 1500.
distance(Dist) == ['more than 2 kilometers '] :- Dist < 3000.
distance(Dist) == ['more than 3 kilometers '] :- Dist < 4000.
distance(Dist) == ['more than 4 kilometers '] :- Dist < 5000.
distance(Dist) == ['more than 5 kilometers '] :- Dist < 6000.
distance(Dist) == ['more than 6 kilometers '] :- Dist < 7000.
distance(Dist) == ['more than 7 kilometers '] :- Dist < 8000.
distance(Dist) == ['more than 8 kilometers '] :- Dist < 9000.
distance(Dist) == ['more than 9 kilometers '] :- Dist < 10000.
distance(Dist) == ['more than ', X, ' kilometers '] :- D is Dist/1000, dist(D, X).
%% resolve command main method
%% if you are familar with Prolog you can input specific to the whole mechanism,
%% by adding exception cases.
flatten(X, Y) :- flatten(X, [], Y), !.
flatten([], Acc, Acc).
flatten([X|Y], Acc, Res):-
flatten(Y, Acc, R), flatten(X, R, Res).
flatten(X, Acc, [X|Acc]).
resolve(X, Y) :- resolve_impl(X,Z), flatten(Z, Y).
resolve_impl([],[]).
resolve_impl([X|Rest], List) :- resolve_impl(Rest, Tail), ((X == L) -> append(L, Tail, List); List = Tail).