diff --git a/src/androidTest/java/de/dennisguse/opentracks/services/announcement/VoiceAnnouncementUtilsTest.java b/src/androidTest/java/de/dennisguse/opentracks/services/announcement/VoiceAnnouncementUtilsTest.java index 7e74d523f..a237900cb 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/services/announcement/VoiceAnnouncementUtilsTest.java +++ b/src/androidTest/java/de/dennisguse/opentracks/services/announcement/VoiceAnnouncementUtilsTest.java @@ -42,7 +42,13 @@ public class VoiceAnnouncementUtilsTest { @Before public void setUp() { contentProviderUtils = new ContentProviderUtils(context); - PreferencesUtils.setVoiceAnnounceHeartRate(false); + + PreferencesUtils.setVoiceAnnounceLapHeartRate(false); + PreferencesUtils.setVoiceAnnounceAverageHeartRate(false); + PreferencesUtils.setVoiceAnnounceTotalDistance(true); + PreferencesUtils.setVoiceAnnounceMovingTime(true); + PreferencesUtils.setVoiceAnnounceAverageSpeedPace(true); + PreferencesUtils.setVoiceAnnounceLapSpeedPace(true); } @Test @@ -199,7 +205,8 @@ public class VoiceAnnouncementUtilsTest { @Test public void getAnnouncement_heart_rate_and_sensor_statistics() { - PreferencesUtils.setVoiceAnnounceHeartRate(true); + PreferencesUtils.setVoiceAnnounceAverageHeartRate(true); + PreferencesUtils.setVoiceAnnounceLapHeartRate(true); int numberOfPoints = 1000; Pair trackWithStats = TestDataUtil.buildTrackWithTrackPoints(contentProviderUtils, numberOfPoints); @@ -221,4 +228,34 @@ public class VoiceAnnouncementUtilsTest { // then assertEquals("Total distance 14.21 kilometers. 16 minutes 39 seconds. Speed 51.2 kilometers per hour. Lap speed 51.2 kilometers per hour. Average heart rate 180 bpm. Current heart rate 133 bpm.", announcement); } + + @Test + public void getAnnouncement_only_lap_heart_rate() { + PreferencesUtils.setVoiceAnnounceLapHeartRate(true); + PreferencesUtils.setVoiceAnnounceAverageHeartRate(false); + PreferencesUtils.setVoiceAnnounceTotalDistance(false); + PreferencesUtils.setVoiceAnnounceMovingTime(false); + PreferencesUtils.setVoiceAnnounceAverageSpeedPace(false); + PreferencesUtils.setVoiceAnnounceLapSpeedPace(false); + + int numberOfPoints = 1000; + Pair trackWithStats = TestDataUtil.buildTrackWithTrackPoints(contentProviderUtils, numberOfPoints); + Track.Id trackId = trackWithStats.first; + TrackStatistics stats = trackWithStats.second; + IntervalStatistics.Interval lastInterval; + try (TrackPointIterator trackPointIterator = contentProviderUtils.getTrackPointLocationIterator(trackId, null)) { + assertEquals(trackPointIterator.getCount(), numberOfPoints); + IntervalStatistics intervalStatistics = new IntervalStatistics(Distance.of(1000)); + intervalStatistics.addTrackPoints(trackPointIterator); + lastInterval = intervalStatistics.getIntervalList().get(intervalStatistics.getIntervalList().size() - 1); + } + + SensorStatistics sensorStatistics = new SensorStatistics(HeartRate.of(180f), HeartRate.of(180f), null, null, null); + + // when + String announcement = VoiceAnnouncementUtils.getAnnouncement(context, stats, true, true, lastInterval, sensorStatistics).toString(); + + // then + assertEquals(" Current heart rate 132 bpm,", announcement); + } } diff --git a/src/main/java/de/dennisguse/opentracks/services/announcement/VoiceAnnouncement.java b/src/main/java/de/dennisguse/opentracks/services/announcement/VoiceAnnouncement.java index a17338385..caa1ec80c 100644 --- a/src/main/java/de/dennisguse/opentracks/services/announcement/VoiceAnnouncement.java +++ b/src/main/java/de/dennisguse/opentracks/services/announcement/VoiceAnnouncement.java @@ -181,8 +181,10 @@ public class VoiceAnnouncement { Spannable announcement = VoiceAnnouncementUtils.getAnnouncement(context, track.getTrackStatistics(), unitSystem, isReportSpeed, lastInterval, sensorStatistics); - // We don't care about the utterance id. It is supplied here to force onUtteranceCompleted to be called. - tts.speak(announcement, TextToSpeech.QUEUE_FLUSH, null, "not used"); + if (announcement.length() > 0) { + // We don't care about the utterance id. It is supplied here to force onUtteranceCompleted to be called. + tts.speak(announcement, TextToSpeech.QUEUE_FLUSH, null, "not used"); + } } public void stop() { diff --git a/src/main/java/de/dennisguse/opentracks/services/announcement/VoiceAnnouncementUtils.java b/src/main/java/de/dennisguse/opentracks/services/announcement/VoiceAnnouncementUtils.java index a665920c4..861190804 100644 --- a/src/main/java/de/dennisguse/opentracks/services/announcement/VoiceAnnouncementUtils.java +++ b/src/main/java/de/dennisguse/opentracks/services/announcement/VoiceAnnouncementUtils.java @@ -1,7 +1,12 @@ package de.dennisguse.opentracks.services.announcement; import static android.text.Spanned.SPAN_INCLUSIVE_EXCLUSIVE; -import static de.dennisguse.opentracks.settings.PreferencesUtils.shouldVoiceAnnounceHeartRate; +import static de.dennisguse.opentracks.settings.PreferencesUtils.shouldVoiceAnnounceAverageHeartRate; +import static de.dennisguse.opentracks.settings.PreferencesUtils.shouldVoiceAnnounceAverageSpeedPace; +import static de.dennisguse.opentracks.settings.PreferencesUtils.shouldVoiceAnnounceLapHeartRate; +import static de.dennisguse.opentracks.settings.PreferencesUtils.shouldVoiceAnnounceLapSpeedPace; +import static de.dennisguse.opentracks.settings.PreferencesUtils.shouldVoiceAnnounceTotalDistance; +import static de.dennisguse.opentracks.settings.PreferencesUtils.shouldVoiceAnnounceMovingTime; import android.content.Context; import android.text.Spannable; @@ -58,38 +63,42 @@ class VoiceAnnouncementUtils { double distanceInUnit = distance.toKM_Miles(unitSystem); - builder.append(context.getString(R.string.total_distance)); - long distanceIntegerPart = (long) distanceInUnit; - // Extract the decimal part - String distanceFractionalPart = String.format("%.2f", (distanceInUnit - distanceIntegerPart)).substring(2); - // Units should always be english singular for TTS. - // See https://developer.android.com/reference/android/text/style/TtsSpan?hl=en#TYPE_MEASURE - appendDecimalUnit(builder, context.getResources().getQuantityString(distanceId, getQuantityCount(distanceInUnit), distanceInUnit), distanceIntegerPart, distanceFractionalPart, unitDistanceTTS); - // Punctuation helps introduce natural pauses in TTS - builder.append("."); + if (shouldVoiceAnnounceTotalDistance()) { + builder.append(context.getString(R.string.total_distance)); + long distanceIntegerPart = (long) distanceInUnit; + // Extract the decimal part + String distanceFractionalPart = String.format("%.2f", (distanceInUnit - distanceIntegerPart)).substring(2); + // Units should always be english singular for TTS. + // See https://developer.android.com/reference/android/text/style/TtsSpan?hl=en#TYPE_MEASURE + appendDecimalUnit(builder, context.getResources().getQuantityString(distanceId, getQuantityCount(distanceInUnit), distanceInUnit), distanceIntegerPart, distanceFractionalPart, unitDistanceTTS); + // Punctuation helps introduce natural pauses in TTS + builder.append("."); + } if (distance.isZero()) { return builder; } // Announce time Duration movingTime = trackStatistics.getMovingTime(); - if (!movingTime.isZero()) { + if (shouldVoiceAnnounceMovingTime() && !movingTime.isZero()) { appendDuration(context, builder, movingTime); builder.append("."); } if (isReportSpeed) { - double speedInUnit = distancePerTime.to(unitSystem); + if (shouldVoiceAnnounceAverageSpeedPace()) { + double speedInUnit = distancePerTime.to(unitSystem); - builder.append(" ") - .append(context.getString(R.string.speed)); - long speedIntegerPart = (long) speedInUnit; - // Extract the decimal part - String speedFractionalPart = String.format("%.1f", (speedInUnit - speedIntegerPart)).substring(2); - appendDecimalUnit(builder, context.getResources().getQuantityString(speedId, getQuantityCount(speedInUnit), speedInUnit), speedIntegerPart, speedFractionalPart, unitSpeedTTS); - builder.append("."); + builder.append(" ") + .append(context.getString(R.string.speed)); + long speedIntegerPart = (long) speedInUnit; + // Extract the decimal part + String speedFractionalPart = String.format("%.1f", (speedInUnit - speedIntegerPart)).substring(2); + appendDecimalUnit(builder, context.getResources().getQuantityString(speedId, getQuantityCount(speedInUnit), speedInUnit), speedIntegerPart, speedFractionalPart, unitSpeedTTS); + builder.append("."); + } - if (currentDistancePerTime != null) { + if (shouldVoiceAnnounceLapSpeedPace() && currentDistancePerTime != null) { double currentDistancePerTimeInUnit = currentDistancePerTime.to(unitSystem); if (currentDistancePerTimeInUnit > 0) { @@ -104,16 +113,18 @@ class VoiceAnnouncementUtils { } } } else { - Duration time = distancePerTime.toPace(unitSystem); - builder.append(" ") - .append(context.getString(R.string.pace)); - appendDuration(context, builder, time); - builder.append(" ") - .append(context.getString(perUnitStringId)) - .append("."); + if (shouldVoiceAnnounceAverageSpeedPace()) { + Duration time = distancePerTime.toPace(unitSystem); + builder.append(" ") + .append(context.getString(R.string.pace)); + appendDuration(context, builder, time); + builder.append(" ") + .append(context.getString(perUnitStringId)) + .append("."); + } - Duration currentTime = currentDistancePerTime != null ? currentDistancePerTime.toPace(unitSystem) : Duration.ofMillis(0); - if (!currentTime.isZero()) { + if (shouldVoiceAnnounceLapSpeedPace() && currentDistancePerTime != null) { + Duration currentTime = currentDistancePerTime.toPace(unitSystem); builder.append(" ") .append(context.getString(R.string.lap_time)); appendDuration(context, builder, currentTime); @@ -123,24 +134,21 @@ class VoiceAnnouncementUtils { } } - if (shouldVoiceAnnounceHeartRate()) { - if (sensorStatistics != null && sensorStatistics.hasHeartRate()) { - int averageHeartRate = Math.round(sensorStatistics.getAvgHeartRate().getBPM()); + if (shouldVoiceAnnounceAverageHeartRate() && sensorStatistics != null && sensorStatistics.hasHeartRate()) { + int averageHeartRate = Math.round(sensorStatistics.getAvgHeartRate().getBPM()); - builder.append(" ") - .append(context.getString(R.string.average_heart_rate)); - appendCardinal(builder, context.getString(R.string.sensor_state_heart_rate_value, averageHeartRate), averageHeartRate); - builder.append("."); - } + builder.append(" ") + .append(context.getString(R.string.average_heart_rate)); + appendCardinal(builder, context.getString(R.string.sensor_state_heart_rate_value, averageHeartRate), averageHeartRate); + builder.append("."); + } + if (shouldVoiceAnnounceLapHeartRate() && currentInterval != null && currentInterval.hasAverageHeartRate()) { + int currentHeartRate = Math.round(currentInterval.getAverageHeartRate().getBPM()); - if (currentInterval != null && currentInterval.hasAverageHeartRate()) { - int currentHeartRate = Math.round(currentInterval.getAverageHeartRate().getBPM()); - - builder.append(" ") - .append(context.getString(R.string.current_heart_rate)); - appendCardinal(builder, context.getString(R.string.sensor_state_heart_rate_value, currentHeartRate), currentHeartRate); - builder.append("."); - } + builder.append(" ") + .append(context.getString(R.string.current_heart_rate)); + appendCardinal(builder, context.getString(R.string.sensor_state_heart_rate_value, currentHeartRate), currentHeartRate); + builder.append("."); } return builder; diff --git a/src/main/java/de/dennisguse/opentracks/settings/PreferencesUtils.java b/src/main/java/de/dennisguse/opentracks/settings/PreferencesUtils.java index e866f2da2..0615259d0 100644 --- a/src/main/java/de/dennisguse/opentracks/settings/PreferencesUtils.java +++ b/src/main/java/de/dennisguse/opentracks/settings/PreferencesUtils.java @@ -343,13 +343,58 @@ public class PreferencesUtils { return getFloat(R.string.voice_speed_rate_key, DEFAULT); } - public static boolean shouldVoiceAnnounceHeartRate() { - return getBoolean(R.string.voice_announce_heart_rate_key, false); + public static boolean shouldVoiceAnnounceTotalDistance() { + return getBoolean(R.string.voice_announce_total_distance_key, true); } @VisibleForTesting - public static void setVoiceAnnounceHeartRate(boolean value) { - setBoolean(R.string.voice_announce_heart_rate_key, value); + public static void setVoiceAnnounceTotalDistance(boolean value) { + setBoolean(R.string.voice_announce_total_distance_key, value); + } + + public static boolean shouldVoiceAnnounceMovingTime() { + return getBoolean(R.string.voice_announce_moving_time_key, true); + } + + @VisibleForTesting + public static void setVoiceAnnounceMovingTime(boolean value) { + setBoolean(R.string.voice_announce_moving_time_key, value); + } + + public static boolean shouldVoiceAnnounceAverageSpeedPace() { + return getBoolean(R.string.voice_announce_average_speed_pace_key, true); + } + + @VisibleForTesting + public static void setVoiceAnnounceAverageSpeedPace(boolean value) { + setBoolean(R.string.voice_announce_average_speed_pace_key, value); + } + + public static boolean shouldVoiceAnnounceLapSpeedPace() { + return getBoolean(R.string.voice_announce_lap_speed_pace_key, true); + } + + @VisibleForTesting + public static void setVoiceAnnounceLapSpeedPace(boolean value) { + setBoolean(R.string.voice_announce_lap_speed_pace_key, value); + } + + public static boolean shouldVoiceAnnounceLapHeartRate() { + return getBoolean(R.string.voice_announce_lap_heart_rate_key, false); + } + + @VisibleForTesting + public static void setVoiceAnnounceLapHeartRate(boolean value) { + setBoolean(R.string.voice_announce_lap_heart_rate_key, value); + } + + public static boolean shouldVoiceAnnounceAverageHeartRate() { + return getBoolean(R.string.voice_announce_average_heart_rate_key, false); + } + + @VisibleForTesting + public static void setVoiceAnnounceAverageHeartRate(boolean value) { + setBoolean(R.string.voice_announce_average_heart_rate_key, value); } public static Distance getRecordingDistanceInterval() { diff --git a/src/main/res/values-b+es+419/strings.xml b/src/main/res/values-b+es+419/strings.xml index d18f9eae2..5fb0b0f92 100644 --- a/src/main/res/values-b+es+419/strings.xml +++ b/src/main/res/values-b+es+419/strings.xml @@ -520,6 +520,5 @@ Ritmo cardíaco promedio Ritmo cardíaco actual - Anunciar ritmo cardíaco Formato del nombre del archivo \ No newline at end of file diff --git a/src/main/res/values-cs/strings.xml b/src/main/res/values-cs/strings.xml index f5043953f..2c0963a5a 100644 --- a/src/main/res/values-cs/strings.xml +++ b/src/main/res/values-cs/strings.xml @@ -546,7 +546,6 @@ limitations under the License. " (nelze zapisovat!)" Dnes Není nainstalován kompatibilní správce souborů - Hlásit tepovou frekvenci za kilometr Čas kola Rychlost kola diff --git a/src/main/res/values-es/strings.xml b/src/main/res/values-es/strings.xml index 5ca51e412..13a55fa6e 100644 --- a/src/main/res/values-es/strings.xml +++ b/src/main/res/values-es/strings.xml @@ -554,7 +554,6 @@ limitations under the License. Transferencia automática de datos Una aplicación que ha iniciado una grabación puede también acceder a los datos grabados. Los datos grabados no se compartirán automáticamente con otras aplicaciones. - Anunciar ritmo cardíaco por kilometro por milla Tiempo de vuelta diff --git a/src/main/res/values-fr/strings.xml b/src/main/res/values-fr/strings.xml index 4f8afb776..f3fd0c926 100644 --- a/src/main/res/values-fr/strings.xml +++ b/src/main/res/values-fr/strings.xml @@ -542,7 +542,6 @@ Si le dispositif GPS signale des données inexactes (par exemple, la localisatio Impossible d\'écrire dans le répertoire d\'exportation. " (non inscriptible !)" Aucun gestionnaire de fichiers compatible n\'est installé - Rapport de la fréquence cardiaque API publique Fréquence cardiaque moyenne Fréquence cardiaque actuelle diff --git a/src/main/res/values-gl/strings.xml b/src/main/res/values-gl/strings.xml index f5946ea01..7609f6bb6 100644 --- a/src/main/res/values-gl/strings.xml +++ b/src/main/res/values-gl/strings.xml @@ -549,7 +549,6 @@ Se te detés ou estás en interiores, non se gardarán datos do sensor (mais ser " (non escribible!)" Non compatible xestor de ficheiros instalados API pública - Informar do pulso API pública API pública de OpenTracks desactivada: pode activarse nos axustes. Tempo da volta diff --git a/src/main/res/values-nb/strings.xml b/src/main/res/values-nb/strings.xml index 825c323d3..a63c484cd 100644 --- a/src/main/res/values-nb/strings.xml +++ b/src/main/res/values-nb/strings.xml @@ -550,7 +550,6 @@ limitations under the License. Automatisk dataoverføring Et program som startet et opptak kan også få tilgang til de registrerte dataene. Registrerte data blir ikke delt automatisk med andre programmer. - Rapporter puls per kilometer per engelsk mil Rundetid diff --git a/src/main/res/values-nl/strings.xml b/src/main/res/values-nl/strings.xml index 7df1b34ed..b85225958 100644 --- a/src/main/res/values-nl/strings.xml +++ b/src/main/res/values-nl/strings.xml @@ -499,7 +499,6 @@ Als het GPS-apparaat onnauwkeurige gegevens rapporteert (bijv. locatie, snelheid Een app die een opname start, heeft ook toegang tot de opgenomen gegevens. Cadans Hartslag - Hartslag melden Aangepaste lay-out terugzetten Alle lay-out instellingen worden teruggezet naar de standaardwaarden. Tracks worden niet gewist. Andere geïnstalleerde apps kunnen opnames starten of stoppen. diff --git a/src/main/res/values-pt-rBR/strings.xml b/src/main/res/values-pt-rBR/strings.xml index 3642e0b9d..25af71150 100644 --- a/src/main/res/values-pt-rBR/strings.xml +++ b/src/main/res/values-pt-rBR/strings.xml @@ -508,7 +508,6 @@ %1$.2f quilômetros Dispensar - Informar frequência cardíaca API pública Transferência automática de dados por quilômetro diff --git a/src/main/res/values-ru/strings.xml b/src/main/res/values-ru/strings.xml index 50dda9bda..a9c29db97 100644 --- a/src/main/res/values-ru/strings.xml +++ b/src/main/res/values-ru/strings.xml @@ -532,7 +532,6 @@ limitations under the License. Сбросить настройки Порог скорости холостого хода Обычные - Сообщать пульс Выбрать раскладку Раскладка по умолчанию Сбросить свои раскладки\? diff --git a/src/main/res/values-sl/strings.xml b/src/main/res/values-sl/strings.xml index 779cc198e..28cb76a30 100644 --- a/src/main/res/values-sl/strings.xml +++ b/src/main/res/values-sl/strings.xml @@ -386,7 +386,6 @@ limitations under the License. Kolesarjenje Teče Natančnost lokacije: %1$s - Poročanje o srčnem utripu %1$s, %2$s %1$s° Razdalja: %1$s diff --git a/src/main/res/values-tr/strings.xml b/src/main/res/values-tr/strings.xml index 39daf7a19..8f1eda9c9 100644 --- a/src/main/res/values-tr/strings.xml +++ b/src/main/res/values-tr/strings.xml @@ -512,7 +512,6 @@ limitations under the License. %1$s° Sıfırla Genel - Kalp atış hızını bildir Eklemek için dizilimin adını yazın Tüm dizilim ayarları varsayılan değerlere döndürülecektir. Bu cihazdaki hiçbir parçayı silmez. Koşu diff --git a/src/main/res/values-vi/strings.xml b/src/main/res/values-vi/strings.xml index 2d806228d..fe4d0dcb6 100644 --- a/src/main/res/values-vi/strings.xml +++ b/src/main/res/values-vi/strings.xml @@ -535,7 +535,6 @@ limitations under the License. API công khai Chỉ OpenTracks có thể bắt đầu và dừng ghi. Các ứng dụng khác có thể bắt đầu hoặc dừng ghi. - Báo cáo nhịp tim API công khai Bỏ %1$s: %2$s diff --git a/src/main/res/values/settings.xml b/src/main/res/values/settings.xml index 273c25088..2dd63380d 100644 --- a/src/main/res/values/settings.xml +++ b/src/main/res/values/settings.xml @@ -291,7 +291,12 @@ 1.2 1.3 - voiceAnnounceHeartRate + voiceAnnounceTotalDistance + voiceAnnounceMovingTime + voiceAnnounceAverageSpeedPace + voiceAnnounceLapSpeedPace + voiceAnnounceAverageHeartRate + voiceAnnounceLapHeartRate exportTrackFileFormat diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index ccae52a32..b72119a5f 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -395,7 +395,10 @@ limitations under the License. Time interval Distance interval - Report heart rate + Average heart rate + Lap heart rate + Average speed/pace + Lap speed/pace Layouts diff --git a/src/main/res/xml/settings_announcements.xml b/src/main/res/xml/settings_announcements.xml index b8789dbdb..d4f193459 100644 --- a/src/main/res/xml/settings_announcements.xml +++ b/src/main/res/xml/settings_announcements.xml @@ -26,9 +26,37 @@ android:title="@string/menu_voice_rate" app:useSimpleSummaryProvider="true" /> - + + + + + + + + + + + + + + \ No newline at end of file