aboutsummaryrefslogtreecommitdiffstats
path: root/main
diff options
context:
space:
mode:
Diffstat (limited to 'main')
-rw-r--r--main/AndroidManifest.xml8
-rw-r--r--main/res/drawable-hdpi/ic_menu_start_conversation.pngbin0 -> 1650 bytes
-rw-r--r--main/res/drawable-ldpi/ic_menu_start_conversation.pngbin0 -> 1293 bytes
-rw-r--r--main/res/drawable-mdpi/ic_menu_start_conversation.pngbin0 -> 1104 bytes
-rw-r--r--main/res/menu/compass_activity_options.xml11
-rw-r--r--main/res/values-de/strings.xml6
-rw-r--r--main/res/values/strings.xml6
-rw-r--r--main/src/cgeo/geocaching/CompassActivity.java10
-rw-r--r--main/src/cgeo/geocaching/speech/SpeechService.java160
-rw-r--r--main/src/cgeo/geocaching/speech/TextFactory.java52
10 files changed, 251 insertions, 2 deletions
diff --git a/main/AndroidManifest.xml b/main/AndroidManifest.xml
index 0f1afcd..085f2b3 100644
--- a/main/AndroidManifest.xml
+++ b/main/AndroidManifest.xml
@@ -230,6 +230,10 @@
<activity
android:name=".ImageSelectActivity"
android:label="@string/log_image">
- </activity>
- </application>
+ </activity>
+ <service
+ android:name=".speech.SpeechService"
+ android:label="@string/tts_service" >
+ </service>
+</application>
</manifest>
diff --git a/main/res/drawable-hdpi/ic_menu_start_conversation.png b/main/res/drawable-hdpi/ic_menu_start_conversation.png
new file mode 100644
index 0000000..395a5ec
--- /dev/null
+++ b/main/res/drawable-hdpi/ic_menu_start_conversation.png
Binary files differ
diff --git a/main/res/drawable-ldpi/ic_menu_start_conversation.png b/main/res/drawable-ldpi/ic_menu_start_conversation.png
new file mode 100644
index 0000000..1e39928
--- /dev/null
+++ b/main/res/drawable-ldpi/ic_menu_start_conversation.png
Binary files differ
diff --git a/main/res/drawable-mdpi/ic_menu_start_conversation.png b/main/res/drawable-mdpi/ic_menu_start_conversation.png
new file mode 100644
index 0000000..24b6540
--- /dev/null
+++ b/main/res/drawable-mdpi/ic_menu_start_conversation.png
Binary files differ
diff --git a/main/res/menu/compass_activity_options.xml b/main/res/menu/compass_activity_options.xml
index 7a6d570..f78aad6 100644
--- a/main/res/menu/compass_activity_options.xml
+++ b/main/res/menu/compass_activity_options.xml
@@ -22,4 +22,15 @@
android:title="@string/destination_select">
<menu/> <!-- filled dynamically -->
</item>
+ <item
+ android:id="@+id/menu_tts_start"
+ android:icon="@drawable/ic_menu_start_conversation"
+ android:title="@string/tts_start">
+ </item>
+ <item
+ android:id="@+id/menu_tts_stop"
+ android:icon="@drawable/ic_menu_start_conversation"
+ android:title="@string/tts_stop"
+ android:visible="false">
+ </item>
</menu> \ No newline at end of file
diff --git a/main/res/values-de/strings.xml b/main/res/values-de/strings.xml
index 5d19848..e7729bf 100644
--- a/main/res/values-de/strings.xml
+++ b/main/res/values-de/strings.xml
@@ -1061,4 +1061,10 @@
<item quantity="one">gestern</item>
<item quantity="other">vor %d Tagen</item>
</plurals>
+ <string name="tts_service">Sprechender Kompass</string>
+ <string name="tts_start">Starte Sprache</string>
+ <string name="tts_stop">Stoppe Sprache</string>
+ <string name="tts_kilometers">%s Kilometer</string>
+ <string name="tts_meters">%s Meter</string>
+ <string name="tts_oclock">%s Uhr</string>
</resources>
diff --git a/main/res/values/strings.xml b/main/res/values/strings.xml
index b537b74..0ed800f 100644
--- a/main/res/values/strings.xml
+++ b/main/res/values/strings.xml
@@ -1075,4 +1075,10 @@
<item quantity="one">yesterday</item>
<item quantity="other">%d days ago</item>
</plurals>
+ <string name="tts_service">Talking compass</string>
+ <string name="tts_start">Start talking</string>
+ <string name="tts_stop">Stop talking</string>
+ <string name="tts_kilometers">%s kilometers</string>
+ <string name="tts_meters">%s meters</string>
+ <string name="tts_oclock">%s o\'clock</string>
</resources>
diff --git a/main/src/cgeo/geocaching/CompassActivity.java b/main/src/cgeo/geocaching/CompassActivity.java
index 5aa159c..7e97e46 100644
--- a/main/src/cgeo/geocaching/CompassActivity.java
+++ b/main/src/cgeo/geocaching/CompassActivity.java
@@ -4,6 +4,7 @@ import cgeo.geocaching.activity.AbstractActivity;
import cgeo.geocaching.geopoint.Geopoint;
import cgeo.geocaching.geopoint.Units;
import cgeo.geocaching.maps.CGeoMap;
+import cgeo.geocaching.speech.SpeechService;
import cgeo.geocaching.ui.CompassView;
import cgeo.geocaching.utils.GeoDirHandler;
import cgeo.geocaching.utils.Log;
@@ -96,6 +97,7 @@ public class CompassActivity extends AbstractActivity {
@Override
public void onDestroy() {
compassView.destroyDrawingCache();
+ SpeechService.stopService(this);
super.onDestroy();
}
@@ -119,6 +121,8 @@ public class CompassActivity extends AbstractActivity {
public boolean onPrepareOptionsMenu(Menu menu) {
super.onPrepareOptionsMenu(menu);
menu.findItem(R.id.menu_switch_compass_gps).setTitle(res.getString(Settings.isUseCompass() ? R.string.use_gps : R.string.use_compass));
+ menu.findItem(R.id.menu_tts_start).setVisible(!SpeechService.isRunning());
+ menu.findItem(R.id.menu_tts_stop).setVisible(SpeechService.isRunning());
return true;
}
@@ -145,6 +149,12 @@ public class CompassActivity extends AbstractActivity {
finish();
return true;
+ case R.id.menu_tts_start:
+ SpeechService.startService(this, dstCoords);
+ return true;
+ case R.id.menu_tts_stop:
+ SpeechService.stopService(this);
+ return true;
default:
int coordinatesIndex = id - COORDINATES_OFFSET;
if (coordinatesIndex >= 0 && coordinatesIndex < coordinates.size()) {
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));
+ }
+}