forked from upstream-mirrors/OpenTracks
+73
-20
@@ -15,6 +15,7 @@ import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
@@ -29,6 +30,7 @@ import de.dennisguse.opentracks.data.models.Distance;
|
||||
import de.dennisguse.opentracks.data.models.HeartRate;
|
||||
import de.dennisguse.opentracks.data.models.Speed;
|
||||
import de.dennisguse.opentracks.data.models.Track;
|
||||
import de.dennisguse.opentracks.sensors.sensorData.SensorDataSet;
|
||||
import de.dennisguse.opentracks.settings.PreferencesUtils;
|
||||
import de.dennisguse.opentracks.settings.UnitSystem;
|
||||
import de.dennisguse.opentracks.stats.SensorStatistics;
|
||||
@@ -48,6 +50,7 @@ public class VoiceAnnouncementUtilsTest {
|
||||
public void setUp() {
|
||||
contentProviderUtils = new ContentProviderUtils(context);
|
||||
|
||||
PreferencesUtils.setVoiceAnnounceHeartRateCurrent(false);
|
||||
PreferencesUtils.setVoiceAnnounceLapHeartRate(false);
|
||||
PreferencesUtils.setVoiceAnnounceAverageHeartRate(false);
|
||||
PreferencesUtils.setVoiceAnnounceTotalDistance(true);
|
||||
@@ -74,8 +77,11 @@ public class VoiceAnnouncementUtilsTest {
|
||||
Track track = new Track();
|
||||
track.setTrackStatistics(stats);
|
||||
|
||||
SensorDataSet dataSet = Mockito.mock(SensorDataSet.class);
|
||||
Mockito.when(dataSet.getHeartRate()).thenReturn(new Pair<>(HeartRate.of(60), "unused"));
|
||||
|
||||
// when
|
||||
String announcement = VoiceAnnouncementUtils.createStatistics(context, track, UnitSystem.METRIC, true, null, null).toString();
|
||||
String announcement = VoiceAnnouncementUtils.createStatistics(context, track, dataSet, UnitSystem.METRIC, true, null, null).toString();
|
||||
|
||||
// then
|
||||
assertEquals("12:00 AM. Total distance 20.0 kilometers. 1 hour 5 minutes 10 seconds. Average moving speed 18.4 kilometers per hour.", announcement);
|
||||
@@ -94,8 +100,11 @@ public class VoiceAnnouncementUtilsTest {
|
||||
Track track = new Track();
|
||||
track.setTrackStatistics(stats);
|
||||
|
||||
SensorDataSet dataSet = Mockito.mock(SensorDataSet.class);
|
||||
Mockito.when(dataSet.getHeartRate()).thenReturn(new Pair<>(HeartRate.of(60), "unused"));
|
||||
|
||||
// when
|
||||
String announcement = VoiceAnnouncementUtils.createStatistics(context, track, UnitSystem.METRIC, true, null, null).toString();
|
||||
String announcement = VoiceAnnouncementUtils.createStatistics(context, track, dataSet, UnitSystem.METRIC, true, null, null).toString();
|
||||
|
||||
// then
|
||||
assertEquals("12:00 AM. Total distance 20.0 kilometers. 1 hour 1 second. Average moving speed 20.0 kilometers per hour.", announcement);
|
||||
@@ -114,8 +123,11 @@ public class VoiceAnnouncementUtilsTest {
|
||||
Track track = new Track();
|
||||
track.setTrackStatistics(stats);
|
||||
|
||||
SensorDataSet dataSet = Mockito.mock(SensorDataSet.class);
|
||||
Mockito.when(dataSet.getHeartRate()).thenReturn(new Pair<>(HeartRate.of(60), "unused"));
|
||||
|
||||
// when
|
||||
String announcement = VoiceAnnouncementUtils.createStatistics(context, track, UnitSystem.METRIC, true, null, null).toString();
|
||||
String announcement = VoiceAnnouncementUtils.createStatistics(context, track, dataSet, UnitSystem.METRIC, true, null, null).toString();
|
||||
|
||||
// then
|
||||
assertEquals("12:00 AM. Total distance 20.0 kilometers. 1 hour. Average moving speed 20.0 kilometers per hour.", announcement);
|
||||
@@ -134,8 +146,11 @@ public class VoiceAnnouncementUtilsTest {
|
||||
Track track = new Track();
|
||||
track.setTrackStatistics(stats);
|
||||
|
||||
SensorDataSet dataSet = Mockito.mock(SensorDataSet.class);
|
||||
Mockito.when(dataSet.getHeartRate()).thenReturn(new Pair<>(HeartRate.of(60), "unused"));
|
||||
|
||||
// when
|
||||
String announcement = VoiceAnnouncementUtils.createStatistics(context, track, UnitSystem.METRIC, true, null, null).toString();
|
||||
String announcement = VoiceAnnouncementUtils.createStatistics(context, track, dataSet, UnitSystem.METRIC, true, null, null).toString();
|
||||
|
||||
// then
|
||||
assertEquals("12:00 AM. Total distance 19.9 kilometers. 1 hour. Average moving speed 19.9 kilometers per hour.", announcement);
|
||||
@@ -156,11 +171,14 @@ public class VoiceAnnouncementUtilsTest {
|
||||
lastInterval = intervalStatistics.getIntervalList().get(intervalStatistics.getIntervalList().size() - 1);
|
||||
}
|
||||
|
||||
SensorDataSet dataSet = Mockito.mock(SensorDataSet.class);
|
||||
Mockito.when(dataSet.getHeartRate()).thenReturn(new Pair<>(HeartRate.of(60), "unused"));
|
||||
|
||||
Track track = new Track();
|
||||
track.setTrackStatistics(stats);
|
||||
|
||||
// when
|
||||
String announcement = VoiceAnnouncementUtils.createStatistics(context, track, UnitSystem.METRIC, true, lastInterval, null).toString();
|
||||
String announcement = VoiceAnnouncementUtils.createStatistics(context, track, dataSet, UnitSystem.METRIC, true, lastInterval, null).toString();
|
||||
|
||||
// then
|
||||
assertEquals("12:16 AM. Total distance 14.2 kilometers. 16 minutes 39 seconds. Average moving speed 51.2 kilometers per hour. Lap speed 51.2 kilometers per hour.", announcement);
|
||||
@@ -179,8 +197,11 @@ public class VoiceAnnouncementUtilsTest {
|
||||
Track track = new Track();
|
||||
track.setTrackStatistics(stats);
|
||||
|
||||
SensorDataSet dataSet = Mockito.mock(SensorDataSet.class);
|
||||
Mockito.when(dataSet.getHeartRate()).thenReturn(new Pair<>(HeartRate.of(60), "unused"));
|
||||
|
||||
// when
|
||||
String announcement = VoiceAnnouncementUtils.createStatistics(context, track, UnitSystem.METRIC, false, null, null).toString();
|
||||
String announcement = VoiceAnnouncementUtils.createStatistics(context, track, dataSet, UnitSystem.METRIC, false, null, null).toString();
|
||||
|
||||
// then
|
||||
assertEquals("12:00 AM. Total distance 20.0 kilometers. 1 hour 5 minutes 10 seconds. Pace 3 minutes 15 seconds per kilometer.", announcement);
|
||||
@@ -204,8 +225,11 @@ public class VoiceAnnouncementUtilsTest {
|
||||
Track track = new Track();
|
||||
track.setTrackStatistics(stats);
|
||||
|
||||
SensorDataSet dataSet = Mockito.mock(SensorDataSet.class);
|
||||
Mockito.when(dataSet.getHeartRate()).thenReturn(new Pair<>(HeartRate.of(60), "unused"));
|
||||
|
||||
// when
|
||||
String announcement = VoiceAnnouncementUtils.createStatistics(context, track, UnitSystem.METRIC, false, lastInterval, null).toString();
|
||||
String announcement = VoiceAnnouncementUtils.createStatistics(context, track, dataSet, UnitSystem.METRIC, false, lastInterval, null).toString();
|
||||
|
||||
// then
|
||||
assertEquals("12:16 AM. Total distance 14.2 kilometers. 16 minutes 39 seconds. Pace 1 minute 10 seconds per kilometer. Lap time 1 minute 10 seconds per kilometer.", announcement);
|
||||
@@ -224,8 +248,11 @@ public class VoiceAnnouncementUtilsTest {
|
||||
Track track = new Track();
|
||||
track.setTrackStatistics(stats);
|
||||
|
||||
SensorDataSet dataSet = Mockito.mock(SensorDataSet.class);
|
||||
Mockito.when(dataSet.getHeartRate()).thenReturn(new Pair<>(HeartRate.of(60), "unused"));
|
||||
|
||||
// when
|
||||
String announcement = VoiceAnnouncementUtils.createStatistics(context, track, UnitSystem.IMPERIAL_FEET, true, null, null).toString();
|
||||
String announcement = VoiceAnnouncementUtils.createStatistics(context, track, dataSet, UnitSystem.IMPERIAL_FEET, true, null, null).toString();
|
||||
|
||||
// then
|
||||
assertEquals("12:00 AM. Total distance 12.4 miles. 1 hour 5 minutes 10 seconds. Average moving speed 11.4 miles per hour.", announcement);
|
||||
@@ -242,8 +269,11 @@ public class VoiceAnnouncementUtilsTest {
|
||||
Track track = new Track();
|
||||
track.setTrackStatistics(stats);
|
||||
|
||||
SensorDataSet dataSet = Mockito.mock(SensorDataSet.class);
|
||||
Mockito.when(dataSet.getHeartRate()).thenReturn(new Pair<>(HeartRate.of(60), "unused"));
|
||||
|
||||
// when
|
||||
String announcement = VoiceAnnouncementUtils.createStatistics(context, track, UnitSystem.IMPERIAL_FEET, true, null, null).toString();
|
||||
String announcement = VoiceAnnouncementUtils.createStatistics(context, track, dataSet, UnitSystem.IMPERIAL_FEET, true, null, null).toString();
|
||||
|
||||
// then
|
||||
assertEquals("12:00 AM. Total distance 1.1 miles. 1 hour. Average moving speed 1.1 miles per hour.", announcement);
|
||||
@@ -260,8 +290,11 @@ public class VoiceAnnouncementUtilsTest {
|
||||
Track track = new Track();
|
||||
track.setTrackStatistics(stats);
|
||||
|
||||
SensorDataSet dataSet = Mockito.mock(SensorDataSet.class);
|
||||
Mockito.when(dataSet.getHeartRate()).thenReturn(new Pair<>(HeartRate.of(60), "unused"));
|
||||
|
||||
// when
|
||||
String announcement = VoiceAnnouncementUtils.createStatistics(context, track, UnitSystem.IMPERIAL_METER, true, null, null).toString();
|
||||
String announcement = VoiceAnnouncementUtils.createStatistics(context, track, dataSet, UnitSystem.IMPERIAL_METER, true, null, null).toString();
|
||||
|
||||
// then
|
||||
assertEquals("12:00 AM. Total distance 1.1 miles. 1 hour. Average moving speed 1.1 miles per hour.", announcement);
|
||||
@@ -278,8 +311,11 @@ public class VoiceAnnouncementUtilsTest {
|
||||
Track track = new Track();
|
||||
track.setTrackStatistics(stats);
|
||||
|
||||
SensorDataSet dataSet = Mockito.mock(SensorDataSet.class);
|
||||
Mockito.when(dataSet.getHeartRate()).thenReturn(new Pair<>(HeartRate.of(60), "unused"));
|
||||
|
||||
// when
|
||||
String announcement = VoiceAnnouncementUtils.createStatistics(context, track, UnitSystem.METRIC, true, null, null).toString();
|
||||
String announcement = VoiceAnnouncementUtils.createStatistics(context, track, dataSet, UnitSystem.METRIC, true, null, null).toString();
|
||||
|
||||
// then
|
||||
assertEquals("12:00 AM. Total distance 1.1 kilometers. 1 hour. Average moving speed 1.1 kilometers per hour.", announcement);
|
||||
@@ -303,8 +339,11 @@ public class VoiceAnnouncementUtilsTest {
|
||||
Track track = new Track();
|
||||
track.setTrackStatistics(stats);
|
||||
|
||||
SensorDataSet dataSet = Mockito.mock(SensorDataSet.class);
|
||||
Mockito.when(dataSet.getHeartRate()).thenReturn(new Pair<>(HeartRate.of(60), "unused"));
|
||||
|
||||
// when
|
||||
String announcement = VoiceAnnouncementUtils.createStatistics(context, track, UnitSystem.IMPERIAL_FEET, true, lastInterval, null).toString();
|
||||
String announcement = VoiceAnnouncementUtils.createStatistics(context, track, dataSet, UnitSystem.IMPERIAL_FEET, true, lastInterval, null).toString();
|
||||
|
||||
// then
|
||||
assertEquals("12:16 AM. Total distance 8.8 miles. 16 minutes 39 seconds. Average moving speed 31.8 miles per hour. Lap speed 31.8 miles per hour.", announcement);
|
||||
@@ -323,8 +362,11 @@ public class VoiceAnnouncementUtilsTest {
|
||||
Track track = new Track();
|
||||
track.setTrackStatistics(stats);
|
||||
|
||||
SensorDataSet dataSet = Mockito.mock(SensorDataSet.class);
|
||||
Mockito.when(dataSet.getHeartRate()).thenReturn(new Pair<>(HeartRate.of(60), "unused"));
|
||||
|
||||
// when
|
||||
String announcement = VoiceAnnouncementUtils.createStatistics(context, track, UnitSystem.IMPERIAL_FEET, false, null, null).toString();
|
||||
String announcement = VoiceAnnouncementUtils.createStatistics(context, track, dataSet, UnitSystem.IMPERIAL_FEET, false, null, null).toString();
|
||||
|
||||
// then
|
||||
assertEquals("12:00 AM. Total distance 12.4 miles. 1 hour 5 minutes 10 seconds. Pace 5 minutes 15 seconds per mile.", announcement);
|
||||
@@ -348,8 +390,11 @@ public class VoiceAnnouncementUtilsTest {
|
||||
Track track = new Track();
|
||||
track.setTrackStatistics(stats);
|
||||
|
||||
SensorDataSet dataSet = Mockito.mock(SensorDataSet.class);
|
||||
Mockito.when(dataSet.getHeartRate()).thenReturn(new Pair<>(HeartRate.of(60), "unused"));
|
||||
|
||||
// when
|
||||
String announcement = VoiceAnnouncementUtils.createStatistics(context, track, UnitSystem.IMPERIAL_FEET, false, lastInterval, null).toString();
|
||||
String announcement = VoiceAnnouncementUtils.createStatistics(context, track, dataSet, UnitSystem.IMPERIAL_FEET, false, lastInterval, null).toString();
|
||||
|
||||
// then
|
||||
assertEquals("12:16 AM. Total distance 8.8 miles. 16 minutes 39 seconds. Pace 1 minute 53 seconds per mile. Lap time 1 minute 53 seconds per mile.", announcement);
|
||||
@@ -377,17 +422,22 @@ public class VoiceAnnouncementUtilsTest {
|
||||
Track track = new Track();
|
||||
track.setTrackStatistics(stats);
|
||||
|
||||
SensorDataSet dataSet = Mockito.mock(SensorDataSet.class);
|
||||
Mockito.when(dataSet.getHeartRate()).thenReturn(new Pair<>(HeartRate.of(60), "unused"));
|
||||
|
||||
// when
|
||||
String announcement = VoiceAnnouncementUtils.createStatistics(context, track, UnitSystem.METRIC, true, lastInterval, sensorStatistics).toString();
|
||||
String announcement = VoiceAnnouncementUtils.createStatistics(context, track, dataSet, UnitSystem.METRIC, true, lastInterval, sensorStatistics).toString();
|
||||
|
||||
// then
|
||||
assertEquals("12:16 AM. Total distance 14.2 kilometers. 16 minutes 39 seconds. Average moving speed 51.2 kilometers per hour. Lap speed 51.2 kilometers per hour. Average heart rate 180 bpm. Current heart rate 133 bpm.", announcement);
|
||||
assertEquals("12:16 AM. Total distance 14.2 kilometers. 16 minutes 39 seconds. Average moving speed 51.2 kilometers per hour. Lap speed 51.2 kilometers per hour. Average heart rate 180 bpm. Lap heart rate 133 bpm.", announcement);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAnnouncement_only_lap_heart_rate() {
|
||||
public void getAnnouncement_heart_rate() {
|
||||
PreferencesUtils.setVoiceAnnounceHeartRateCurrent(true);
|
||||
PreferencesUtils.setVoiceAnnounceLapHeartRate(true);
|
||||
PreferencesUtils.setVoiceAnnounceAverageHeartRate(false);
|
||||
PreferencesUtils.setVoiceAnnounceAverageHeartRate(true);
|
||||
|
||||
PreferencesUtils.setVoiceAnnounceTotalDistance(false);
|
||||
PreferencesUtils.setVoiceAnnounceMovingTime(false);
|
||||
PreferencesUtils.setVoiceAnnounceAverageSpeedPace(false);
|
||||
@@ -410,11 +460,14 @@ public class VoiceAnnouncementUtilsTest {
|
||||
Track track = new Track();
|
||||
track.setTrackStatistics(stats);
|
||||
|
||||
SensorDataSet dataSet = Mockito.mock(SensorDataSet.class);
|
||||
Mockito.when(dataSet.getHeartRate()).thenReturn(new Pair<>(HeartRate.of(60), "unused"));
|
||||
|
||||
// when
|
||||
String announcement = VoiceAnnouncementUtils.createStatistics(context, track, UnitSystem.METRIC, true, lastInterval, sensorStatistics).toString();
|
||||
String announcement = VoiceAnnouncementUtils.createStatistics(context, track, dataSet, UnitSystem.METRIC, true, lastInterval, sensorStatistics).toString();
|
||||
|
||||
// then
|
||||
assertEquals("12:16 AM. Current heart rate 133 bpm.", announcement);
|
||||
assertEquals("12:16 AM. Current heart rate 60 bpm. Average heart rate 180 bpm. Lap heart rate 133 bpm.", announcement);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -20,7 +20,7 @@ import de.dennisguse.opentracks.sensors.BluetoothHandlerRunningSpeedAndCadence;
|
||||
import de.dennisguse.opentracks.services.handlers.TrackPointCreator;
|
||||
import de.dennisguse.opentracks.settings.PreferencesUtils;
|
||||
|
||||
public final class SensorDataSet {
|
||||
public class SensorDataSet {
|
||||
|
||||
private static final String TAG = SensorDataSet.class.getSimpleName();
|
||||
|
||||
|
||||
@@ -317,7 +317,7 @@ public class TrackRecordingService extends Service implements TrackPointCreator.
|
||||
// Compute temporary track statistics using sensorData and update time.
|
||||
Pair<Track, Pair<TrackPoint, SensorDataSet>> data = trackRecordingManager.getDataForUI();
|
||||
|
||||
voiceAnnouncementManager.announceStatisticsIfNeeded(data.first);
|
||||
voiceAnnouncementManager.announceStatisticsIfNeeded(data.first, data.second.second);
|
||||
|
||||
recordingDataObservable.postValue(new RecordingData(data.first, data.second.first, data.second.second));
|
||||
}
|
||||
|
||||
+5
-4
@@ -33,6 +33,7 @@ import de.dennisguse.opentracks.data.TrackPointIterator;
|
||||
import de.dennisguse.opentracks.data.models.Distance;
|
||||
import de.dennisguse.opentracks.data.models.Track;
|
||||
import de.dennisguse.opentracks.data.models.TrackPoint;
|
||||
import de.dennisguse.opentracks.sensors.sensorData.SensorDataSet;
|
||||
import de.dennisguse.opentracks.settings.PreferencesUtils;
|
||||
import de.dennisguse.opentracks.stats.SensorStatistics;
|
||||
import de.dennisguse.opentracks.stats.TrackStatistics;
|
||||
@@ -118,7 +119,7 @@ public class VoiceAnnouncementManager implements SharedPreferences.OnSharedPrefe
|
||||
voiceAnnouncement.speak(VoiceAnnouncementUtils.createIdle(context));
|
||||
}
|
||||
|
||||
public void announceStatisticsIfNeeded(@NonNull Track track) {
|
||||
public void announceStatisticsIfNeeded(@NonNull Track track, @NonNull SensorDataSet sensorDataSet) {
|
||||
if (shouldNotAnnounce()) {
|
||||
return;
|
||||
}
|
||||
@@ -135,11 +136,11 @@ public class VoiceAnnouncementManager implements SharedPreferences.OnSharedPrefe
|
||||
}
|
||||
|
||||
if (announce) {
|
||||
voiceAnnouncement.speak(createAnnouncement(track));
|
||||
voiceAnnouncement.speak(createAnnouncement(track, sensorDataSet));
|
||||
}
|
||||
}
|
||||
|
||||
private Spannable createAnnouncement(Track track) {
|
||||
private Spannable createAnnouncement(Track track, SensorDataSet sensorDataSet) {
|
||||
Distance currentIntervalDistance = PreferencesUtils.getVoiceAnnouncementDistance();
|
||||
if (currentIntervalDistance != intervalDistance) {
|
||||
intervalStatistics = new IntervalStatistics(currentIntervalDistance);
|
||||
@@ -155,7 +156,7 @@ public class VoiceAnnouncementManager implements SharedPreferences.OnSharedPrefe
|
||||
sensorStatistics = contentProviderUtils.getSensorStats(track.getId());
|
||||
}
|
||||
|
||||
return VoiceAnnouncementUtils.createStatistics(context, track, PreferencesUtils.getUnitSystem(), PreferencesUtils.isReportSpeed(track), lastInterval, sensorStatistics);
|
||||
return VoiceAnnouncementUtils.createStatistics(context, track, sensorDataSet, PreferencesUtils.getUnitSystem(), PreferencesUtils.isReportSpeed(track), lastInterval, sensorStatistics);
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
|
||||
+74
-60
@@ -3,6 +3,7 @@ package de.dennisguse.opentracks.services.announcement;
|
||||
import static android.text.Spanned.SPAN_INCLUSIVE_EXCLUSIVE;
|
||||
import static de.dennisguse.opentracks.settings.PreferencesUtils.shouldVoiceAnnounceAverageHeartRate;
|
||||
import static de.dennisguse.opentracks.settings.PreferencesUtils.shouldVoiceAnnounceAverageSpeedPace;
|
||||
import static de.dennisguse.opentracks.settings.PreferencesUtils.shouldVoiceAnnounceHeartRateCurrent;
|
||||
import static de.dennisguse.opentracks.settings.PreferencesUtils.shouldVoiceAnnounceLapHeartRate;
|
||||
import static de.dennisguse.opentracks.settings.PreferencesUtils.shouldVoiceAnnounceLapPower;
|
||||
import static de.dennisguse.opentracks.settings.PreferencesUtils.shouldVoiceAnnounceLapSpeedPace;
|
||||
@@ -17,6 +18,7 @@ import android.text.Spannable;
|
||||
import android.text.SpannableString;
|
||||
import android.text.SpannableStringBuilder;
|
||||
import android.text.style.TtsSpan;
|
||||
import android.util.Pair;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
@@ -29,8 +31,10 @@ import java.util.Map;
|
||||
|
||||
import de.dennisguse.opentracks.R;
|
||||
import de.dennisguse.opentracks.data.models.Distance;
|
||||
import de.dennisguse.opentracks.data.models.HeartRate;
|
||||
import de.dennisguse.opentracks.data.models.Speed;
|
||||
import de.dennisguse.opentracks.data.models.Track;
|
||||
import de.dennisguse.opentracks.sensors.sensorData.SensorDataSet;
|
||||
import de.dennisguse.opentracks.settings.UnitSystem;
|
||||
import de.dennisguse.opentracks.stats.SensorStatistics;
|
||||
import de.dennisguse.opentracks.stats.TrackStatistics;
|
||||
@@ -47,7 +51,7 @@ class VoiceAnnouncementUtils {
|
||||
.append(context.getString(R.string.voiceIdle));
|
||||
}
|
||||
|
||||
static Spannable createStatistics(Context context, Track track, UnitSystem unitSystem, boolean isReportSpeed, @Nullable IntervalStatistics.Interval currentInterval, @Nullable SensorStatistics sensorStatistics) {
|
||||
static Spannable createStatistics(Context context, Track track, SensorDataSet sensorDataSet, UnitSystem unitSystem, boolean isReportSpeed, @Nullable IntervalStatistics.Interval currentInterval, @Nullable SensorStatistics sensorStatistics) {
|
||||
TrackStatistics trackStatistics = track.getTrackStatistics();
|
||||
|
||||
SpannableStringBuilder builder = new SpannableStringBuilder();
|
||||
@@ -104,92 +108,102 @@ class VoiceAnnouncementUtils {
|
||||
// Punctuation helps introduce natural pauses in TTS
|
||||
builder.append(".");
|
||||
}
|
||||
if (totalDistance.isZero()) {
|
||||
return builder;
|
||||
}
|
||||
|
||||
boolean hasTravelledDistance = !totalDistance.isZero();
|
||||
|
||||
// Announce time
|
||||
Duration movingTime = trackStatistics.getMovingTime();
|
||||
if (shouldVoiceAnnounceMovingTime() && !movingTime.isZero()) {
|
||||
if (shouldVoiceAnnounceMovingTime() && hasTravelledDistance && !movingTime.isZero()) {
|
||||
appendDuration(context, builder, movingTime);
|
||||
builder.append(".");
|
||||
}
|
||||
|
||||
if (isReportSpeed) {
|
||||
if (shouldVoiceAnnounceAverageSpeedPace()) {
|
||||
double speedInUnit = averageMovingSpeed.to(unitSystem);
|
||||
builder.append(" ")
|
||||
.append(context.getString(R.string.speed));
|
||||
String template = context.getResources().getString(speedId);
|
||||
appendDecimalUnit(builder, MessageFormat.format(template, Map.of("n", speedInUnit)), speedInUnit, 1, unitSpeedTTS);
|
||||
builder.append(".");
|
||||
}
|
||||
if (shouldVoiceAnnounceLapSpeedPace() && currentDistancePerTime != null) {
|
||||
double currentDistancePerTimeInUnit = currentDistancePerTime.to(unitSystem);
|
||||
if (currentDistancePerTimeInUnit > 0) {
|
||||
if (hasTravelledDistance) {
|
||||
if (isReportSpeed) {
|
||||
if (shouldVoiceAnnounceAverageSpeedPace()) {
|
||||
double speedInUnit = averageMovingSpeed.to(unitSystem);
|
||||
builder.append(" ")
|
||||
.append(context.getString(R.string.lap_speed));
|
||||
.append(context.getString(R.string.speed));
|
||||
String template = context.getResources().getString(speedId);
|
||||
appendDecimalUnit(builder, MessageFormat.format(template, Map.of("n", currentDistancePerTimeInUnit)), currentDistancePerTimeInUnit, 1, unitSpeedTTS);
|
||||
appendDecimalUnit(builder, MessageFormat.format(template, Map.of("n", speedInUnit)), speedInUnit, 1, unitSpeedTTS);
|
||||
builder.append(".");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (shouldVoiceAnnounceAverageSpeedPace()) {
|
||||
Duration time = averageMovingSpeed.toPace(unitSystem);
|
||||
builder.append(" ")
|
||||
.append(context.getString(R.string.pace));
|
||||
appendDuration(context, builder, time);
|
||||
builder.append(" ")
|
||||
.append(context.getString(perUnitStringId))
|
||||
.append(".");
|
||||
}
|
||||
if (shouldVoiceAnnounceLapSpeedPace() && currentDistancePerTime != null) {
|
||||
double currentDistancePerTimeInUnit = currentDistancePerTime.to(unitSystem);
|
||||
if (currentDistancePerTimeInUnit > 0) {
|
||||
builder.append(" ")
|
||||
.append(context.getString(R.string.lap_speed));
|
||||
String template = context.getResources().getString(speedId);
|
||||
appendDecimalUnit(builder, MessageFormat.format(template, Map.of("n", currentDistancePerTimeInUnit)), currentDistancePerTimeInUnit, 1, unitSpeedTTS);
|
||||
builder.append(".");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (shouldVoiceAnnounceAverageSpeedPace()) {
|
||||
Duration time = averageMovingSpeed.toPace(unitSystem);
|
||||
builder.append(" ")
|
||||
.append(context.getString(R.string.pace));
|
||||
appendDuration(context, builder, time);
|
||||
builder.append(" ")
|
||||
.append(context.getString(perUnitStringId))
|
||||
.append(".");
|
||||
}
|
||||
|
||||
if (shouldVoiceAnnounceLapSpeedPace() && currentDistancePerTime != null) {
|
||||
Duration currentTime = currentDistancePerTime.toPace(unitSystem);
|
||||
builder.append(" ")
|
||||
.append(context.getString(R.string.lap_time));
|
||||
appendDuration(context, builder, currentTime);
|
||||
builder.append(" ")
|
||||
.append(context.getString(perUnitStringId))
|
||||
.append(".");
|
||||
if (shouldVoiceAnnounceLapSpeedPace() && currentDistancePerTime != null) {
|
||||
Duration currentTime = currentDistancePerTime.toPace(unitSystem);
|
||||
builder.append(" ")
|
||||
.append(context.getString(R.string.lap_time));
|
||||
appendDuration(context, builder, currentTime);
|
||||
builder.append(" ")
|
||||
.append(context.getString(perUnitStringId))
|
||||
.append(".");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldVoiceAnnounceAverageHeartRate() && sensorStatistics != null && sensorStatistics.hasHeartRate()) {
|
||||
int averageHeartRate = Math.round(sensorStatistics.avgHeartRate().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(".");
|
||||
}
|
||||
if (shouldVoiceAnnounceLapHeartRate() && currentInterval != null && currentInterval.hasAverageHeartRate()) {
|
||||
int currentHeartRate = Math.round(currentInterval.getAverageHeartRate().getBPM());
|
||||
Pair<HeartRate, String> heartrate = sensorDataSet.getHeartRate();
|
||||
if (shouldVoiceAnnounceHeartRateCurrent() && heartrate != null && heartrate.first != null) { //TODO Check has an announcable value?
|
||||
int averageHeartRate = Math.round(heartrate.first.getBPM());
|
||||
|
||||
builder.append(" ")
|
||||
.append(context.getString(R.string.current_heart_rate));
|
||||
appendCardinal(builder, context.getString(R.string.sensor_state_heart_rate_value, currentHeartRate), currentHeartRate);
|
||||
appendCardinal(builder, context.getString(R.string.sensor_state_heart_rate_value, averageHeartRate), averageHeartRate);
|
||||
builder.append(".");
|
||||
}
|
||||
if (hasTravelledDistance) {
|
||||
if (shouldVoiceAnnounceAverageHeartRate() && sensorStatistics != null && sensorStatistics.hasHeartRate()) {
|
||||
int averageHeartRate = Math.round(sensorStatistics.avgHeartRate().getBPM());
|
||||
|
||||
if (shouldVoiceAnnounceLapPower() && currentInterval != null && currentInterval.hasAveragePower()) {
|
||||
int currentPower = Math.round(currentInterval.getAveragePower().getW());
|
||||
if(shouldVoiceAnnounceUnit()) {
|
||||
String template = context.getResources().getString(R.string.power_x_watt);
|
||||
builder.append(" ")
|
||||
.append(MessageFormat.format(template, Map.of("x", currentPower)));
|
||||
} else {
|
||||
builder.append(" ").append(context.getString(R.string.power)).append(" ");
|
||||
builder.append(String.valueOf(currentPower));
|
||||
.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(".");
|
||||
}
|
||||
if (shouldVoiceAnnounceLapHeartRate() && currentInterval != null && currentInterval.hasAverageHeartRate()) {
|
||||
int currentHeartRate = Math.round(currentInterval.getAverageHeartRate().getBPM());
|
||||
|
||||
builder.append(" ")
|
||||
.append(context.getString(R.string.lap_heart_rate));
|
||||
appendCardinal(builder, context.getString(R.string.sensor_state_heart_rate_value, currentHeartRate), currentHeartRate);
|
||||
builder.append(".");
|
||||
}
|
||||
|
||||
if (shouldVoiceAnnounceLapPower() && currentInterval != null && currentInterval.hasAveragePower()) {
|
||||
int currentPower = Math.round(currentInterval.getAveragePower().getW());
|
||||
if (shouldVoiceAnnounceUnit()) {
|
||||
String template = context.getResources().getString(R.string.power_x_watt);
|
||||
builder.append(" ")
|
||||
.append(MessageFormat.format(template, Map.of("x", currentPower)));
|
||||
} else {
|
||||
builder.append(" ").append(context.getString(R.string.power)).append(" ");
|
||||
builder.append(String.valueOf(currentPower));
|
||||
}
|
||||
builder.append(".");
|
||||
}
|
||||
}
|
||||
return builder;
|
||||
}
|
||||
|
||||
//TODO TtsSpan.TimeBuilder?
|
||||
private static void appendDuration(@NonNull Context context, @NonNull SpannableStringBuilder builder, @NonNull Duration duration) {
|
||||
int hours = (int) (duration.toHours());
|
||||
int minutes = (int) (duration.toMinutes() % 60);
|
||||
|
||||
@@ -433,14 +433,23 @@ public class PreferencesUtils {
|
||||
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);
|
||||
}
|
||||
|
||||
public static boolean shouldVoiceAnnounceLapPower() {
|
||||
return getBoolean(R.string.voice_announce_lap_power_key, false);
|
||||
}
|
||||
|
||||
public static boolean shouldVoiceAnnounceHeartRateCurrent() {
|
||||
return getBoolean(R.string.voice_announce_heart_rate_current_key, false);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public static void setVoiceAnnounceHeartRateCurrent(boolean value) {
|
||||
setBoolean(R.string.voice_announce_heart_rate_current_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);
|
||||
|
||||
@@ -255,6 +255,8 @@
|
||||
<string name="voice_announce_unit_key" translatable="false">voiceAnnounceUnit</string>
|
||||
<bool name="voice_announce_unit_default" translatable="false">true</bool>
|
||||
|
||||
<string name="voice_announce_heart_rate_current_key" translatable="false">voiceAnnounceHeartRateCurrent</string>
|
||||
<bool name="voice_announce_heart_rate_current_default" translatable="false">false</bool>
|
||||
<string name="voice_announce_average_heart_rate_key" translatable="false">voiceAnnounceAverageHeartRate</string>
|
||||
<bool name="voice_announce_average_heart_rate_default" translatable="false">false</bool>
|
||||
<string name="voice_announce_lap_heart_rate_key" translatable="false">voiceAnnounceLapHeartRate</string>
|
||||
|
||||
@@ -609,6 +609,7 @@ limitations under the License.
|
||||
</string>
|
||||
<string name="average_heart_rate">Average heart rate</string>
|
||||
<string name="current_heart_rate">Current heart rate</string>
|
||||
<string name="lap_heart_rate">Lap heart rate</string>
|
||||
<!-- Waypoint Type -->
|
||||
<string name="waypoint_type_atm">ATM</string>
|
||||
<string name="waypoint_type_bank">bank</string>
|
||||
|
||||
@@ -59,6 +59,11 @@
|
||||
android:key="@string/voice_announce_average_speed_pace_key"
|
||||
android:title="@string/settings_announcements_average_speed_pace" />
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:defaultValue="@bool/voice_announce_heart_rate_current_default"
|
||||
android:key="@string/voice_announce_heart_rate_current_key"
|
||||
android:title="@string/current_heart_rate" />
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:defaultValue="@bool/voice_announce_average_heart_rate_default"
|
||||
android:key="@string/voice_announce_average_heart_rate_key"
|
||||
|
||||
Reference in New Issue
Block a user