aboutsummaryrefslogtreecommitdiffstats
path: root/main/src/cgeo/geocaching/speech
diff options
context:
space:
mode:
authorBananeweizen <bananeweizen@gmx.de>2013-05-10 17:16:07 +0200
committerBananeweizen <bananeweizen@gmx.de>2013-05-10 19:38:50 +0200
commit4a24570ba09de30525d4d1ee6e1814ec90927237 (patch)
tree8905dfcc30ce147a97f61396ce52bf2b6ba9557e /main/src/cgeo/geocaching/speech
parent780b883f8b98c7f2074bccb5f6fd931c74758a46 (diff)
downloadcgeo-4a24570ba09de30525d4d1ee6e1814ec90927237.zip
cgeo-4a24570ba09de30525d4d1ee6e1814ec90927237.tar.gz
cgeo-4a24570ba09de30525d4d1ee6e1814ec90927237.tar.bz2
#2710: speech output in compass
Diffstat (limited to 'main/src/cgeo/geocaching/speech')
-rw-r--r--main/src/cgeo/geocaching/speech/SpeechService.java160
-rw-r--r--main/src/cgeo/geocaching/speech/TextFactory.java52
2 files changed, 212 insertions, 0 deletions
diff --git a/main/src/cgeo/geocaching/speech/SpeechService.java b/main/src/cgeo/geocaching/speech/SpeechService.java
new file mode 100644
index 0000000..0a367f8
--- /dev/null
+++ b/main/src/cgeo/geocaching/speech/SpeechService.java
@@ -0,0 +1,160 @@
+package cgeo.geocaching.speech;
+
+import cgeo.geocaching.DirectionProvider;
+import cgeo.geocaching.geopoint.Geopoint;
+import cgeo.geocaching.utils.GeoDirHandler;
+import cgeo.geocaching.utils.Log;
+
+import org.apache.commons.lang3.StringUtils;
+
+import android.app.Activity;
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+import android.speech.tts.TextToSpeech;
+import android.speech.tts.TextToSpeech.OnInitListener;
+
+import java.util.Locale;
+
+/**
+ * Service to speak the compass directions.
+ *
+ */
+public class SpeechService extends Service implements OnInitListener {
+
+ private static final int SPEECH_PAUSE_SECONDS = 30;
+ private static final String EXTRA_TARGET_COORDS = "target";
+ private static Activity startingActivity;
+ private static boolean isRunning = false;
+ /**
+ * Text to speech API of Android
+ */
+ private TextToSpeech tts;
+ /**
+ * TTS has been initialized and we can speak.
+ */
+ private boolean initialized = false;
+ protected float direction;
+ protected Geopoint position;
+ protected boolean directionInitialized;
+ protected boolean positionInitialized;
+
+ GeoDirHandler geoHandler = new GeoDirHandler() {
+ @Override
+ protected void updateDirection(float newDirection) {
+ direction = DirectionProvider.getDirectionNow(startingActivity, newDirection);
+ directionInitialized = true;
+ updateCompass();
+ }
+
+ @Override
+ protected void updateGeoData(cgeo.geocaching.IGeoData newGeo) {
+ position = newGeo.getCoords();
+ positionInitialized = true;
+ if (newGeo.getSpeed() > 5) {
+ direction = newGeo.getBearing();
+ directionInitialized = true;
+ }
+ updateCompass();
+ }
+ };
+ /**
+ * remember when we talked the last time
+ */
+ private long lastSpeechTime = 0;
+ private Geopoint target;
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return null;
+ }
+
+ protected void updateCompass() {
+ // make sure we have both sensor values before talking
+ if (!positionInitialized || !directionInitialized) {
+ return;
+ }
+
+ // avoid any calculation, if the delay since the last output is not long enough
+ long now = System.currentTimeMillis();
+ if (now - lastSpeechTime <= SPEECH_PAUSE_SECONDS * 1000) {
+ return;
+ }
+
+ final String text = TextFactory.getText(position, target, direction);
+ if (StringUtils.isNotEmpty(text)) {
+ speak(text);
+ }
+ }
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ tts = new TextToSpeech(this, this);
+ }
+
+ @Override
+ public void onDestroy() {
+ geoHandler.stopGeoAndDir();
+ if (tts != null) {
+ tts.stop();
+ tts.shutdown();
+ }
+ super.onDestroy();
+ }
+
+ @Override
+ public void onInit(int status) {
+ // The text to speech system takes some time to initialize.
+ if (status != TextToSpeech.SUCCESS) {
+ Log.e("Text to speech cannot be initialized.");
+ return;
+ }
+
+ int switchLocale = tts.setLanguage(Locale.getDefault());
+
+ if (switchLocale == TextToSpeech.LANG_MISSING_DATA
+ || switchLocale == TextToSpeech.LANG_NOT_SUPPORTED) {
+ Log.e("Current languge not supported by text to speech.");
+ return;
+ }
+
+ initialized = true;
+
+ geoHandler.startGeoAndDir();
+ }
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ if (intent != null) {
+ target = intent.getParcelableExtra(EXTRA_TARGET_COORDS);
+ }
+ return START_NOT_STICKY;
+ }
+
+ private void speak(final String text) {
+ if (!initialized) {
+ return;
+ }
+ lastSpeechTime = System.currentTimeMillis();
+ tts.speak(text, TextToSpeech.QUEUE_FLUSH, null);
+ }
+
+ public static void startService(final Activity activity, Geopoint dstCoords) {
+ isRunning = true;
+ startingActivity = activity;
+ Intent talkingService = new Intent(activity, SpeechService.class);
+ talkingService.putExtra(EXTRA_TARGET_COORDS, dstCoords);
+ activity.startService(talkingService);
+ }
+
+ public static void stopService(final Activity activity) {
+ isRunning = false;
+ activity.stopService(new Intent(activity, SpeechService.class));
+ }
+
+ public static boolean isRunning() {
+ return isRunning;
+ }
+
+}
diff --git a/main/src/cgeo/geocaching/speech/TextFactory.java b/main/src/cgeo/geocaching/speech/TextFactory.java
new file mode 100644
index 0000000..6b25147
--- /dev/null
+++ b/main/src/cgeo/geocaching/speech/TextFactory.java
@@ -0,0 +1,52 @@
+package cgeo.geocaching.speech;
+
+import cgeo.geocaching.R;
+import cgeo.geocaching.cgeoapplication;
+import cgeo.geocaching.geopoint.Geopoint;
+import cgeo.geocaching.utils.AngleUtils;
+
+import java.util.Locale;
+
+/**
+ * Creates the output to be read by TTS.
+ *
+ */
+public class TextFactory {
+ public static String getText(Geopoint position, Geopoint target, float direction) {
+ if (position == null || target == null) {
+ return null;
+ }
+ return getDirection(position, target, direction) + ". " + getDistance(position, target);
+ }
+
+ private static String getDistance(Geopoint position, Geopoint target) {
+ float kilometers = position.distanceTo(target);
+ if (kilometers >= 5.0) {
+ return getString(R.string.tts_kilometers, String.valueOf(Math.round(kilometers)));
+ }
+ if (kilometers >= 1.0) {
+ String digits = String.format(Locale.getDefault(), "%.1f", kilometers);
+ return getString(R.string.tts_kilometers, digits);
+ }
+ int meters = (int) (kilometers * 1000.0);
+ if (meters > 50) {
+ return getString(R.string.tts_meters, String.valueOf(Math.round(meters / 10.0) * 10));
+ }
+ return getString(R.string.tts_meters, String.valueOf(meters));
+ }
+
+ private static String getString(int resourceId, Object... formatArgs) {
+ return cgeoapplication.getInstance().getString(resourceId, formatArgs);
+ }
+
+ private static String getDirection(Geopoint position, Geopoint target, float direction) {
+ final int bearing = (int) position.bearingTo(target);
+ int degrees = (int) AngleUtils.normalize(bearing - direction);
+
+ int hours = (degrees + 15) / 30;
+ if (hours == 0) {
+ hours = 12;
+ }
+ return getString(R.string.tts_oclock, String.valueOf(hours));
+ }
+}