forked from upstream-mirrors/OpenTracks
Announcement: while recording report current interval pace or speed.
Fixes #134.
This commit is contained in:
@@ -9,7 +9,15 @@ import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import de.dennisguse.opentracks.R;
|
||||
import de.dennisguse.opentracks.content.data.TestDataUtil;
|
||||
import de.dennisguse.opentracks.content.data.Track;
|
||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
||||
import de.dennisguse.opentracks.stats.TrackStatistics;
|
||||
import de.dennisguse.opentracks.viewmodels.IntervalStatistics;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class AnnouncementUtilsTest {
|
||||
@@ -26,9 +34,50 @@ public class AnnouncementUtilsTest {
|
||||
stats.setTotalElevationGain(6000);
|
||||
|
||||
// when
|
||||
String announcement = AnnouncementUtils.getAnnouncement(context, stats, "airplane");
|
||||
String announcement = AnnouncementUtils.getAnnouncement(context, stats, "airplane", null);
|
||||
|
||||
// then
|
||||
Assert.assertEquals("OpenTracks total distance 20.00 kilometers in 5 minutes 0 seconds at 240.0 kilometers per hour", announcement);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAnnouncement_withInterval() {
|
||||
TrackStatistics stats = new TrackStatistics();
|
||||
stats.setTotalDistance(20000);
|
||||
stats.setTotalTime(600000);
|
||||
stats.setMovingTime(300000);
|
||||
stats.setMaxSpeed(100);
|
||||
stats.setTotalElevationGain(6000);
|
||||
|
||||
IntervalStatistics intervalStatistics = new IntervalStatistics();
|
||||
List<TrackPoint> trackPoints = Arrays.asList(TestDataUtil.createTrack(new Track.Id(System.currentTimeMillis()), 10).second);
|
||||
intervalStatistics.build(trackPoints, 1000);
|
||||
IntervalStatistics.Interval lastInterval = intervalStatistics.getIntervalList().get(intervalStatistics.getIntervalList().size() - 1);
|
||||
|
||||
int speedId = R.plurals.voiceSpeedKilometersPerHour;
|
||||
double kmPerHour = lastInterval.getSpeed_ms() * UnitConversions.MPS_TO_KMH;
|
||||
|
||||
String firstPartMsg = "OpenTracks total distance 20.00 kilometers in 5 minutes 0 seconds at 240.0 kilometers per hour";
|
||||
String rateMsg = " With a current kilometer speed of " + context.getResources().getQuantityString(speedId, getQuantityCount(kmPerHour), kmPerHour);
|
||||
String msg = firstPartMsg + rateMsg;
|
||||
|
||||
// when
|
||||
String announcement = AnnouncementUtils.getAnnouncement(context, stats, "airplane", lastInterval);
|
||||
|
||||
// then
|
||||
Assert.assertEquals(msg, announcement);
|
||||
}
|
||||
|
||||
private int getQuantityCount(double d) {
|
||||
if (d == 0) {
|
||||
return 0;
|
||||
} else if (d == 1) {
|
||||
return 1;
|
||||
} else if (d == 2) {
|
||||
return 2;
|
||||
} else {
|
||||
int count = (int) d;
|
||||
return Math.max(count, 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -836,7 +836,7 @@ public class ContentProviderUtils {
|
||||
/**
|
||||
* Creates the {@link ContentValues} for a {@link TrackPoint}.
|
||||
*
|
||||
* @param trackPoint the trackPoint
|
||||
* @param trackPoint the trackPointstats_pace_km#87
|
||||
* @param trackId the track id
|
||||
*/
|
||||
private ContentValues createContentValues(TrackPoint trackPoint, Track.Id trackId) {
|
||||
|
||||
+13
-1
@@ -22,14 +22,18 @@ import android.speech.tts.TextToSpeech;
|
||||
import android.speech.tts.UtteranceProgressListener;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import de.dennisguse.opentracks.content.data.Track;
|
||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
||||
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
||||
import de.dennisguse.opentracks.services.TrackRecordingService;
|
||||
import de.dennisguse.opentracks.stats.TrackStatistics;
|
||||
import de.dennisguse.opentracks.util.AnnouncementUtils;
|
||||
import de.dennisguse.opentracks.util.PreferencesUtils;
|
||||
import de.dennisguse.opentracks.util.UnitConversions;
|
||||
import de.dennisguse.opentracks.viewmodels.IntervalStatistics;
|
||||
|
||||
/**
|
||||
* This class will periodically announce the user's {@link TrackStatistics}.
|
||||
@@ -159,9 +163,17 @@ public class AnnouncementPeriodicTask implements PeriodicTask {
|
||||
Log.i(TAG, "Speech is not allowed at this time.");
|
||||
return;
|
||||
}
|
||||
|
||||
Track track = contentProviderUtils.getTrack(PreferencesUtils.getRecordingTrackId(context));
|
||||
String category = track != null ? track.getCategory() : "";
|
||||
String announcement = AnnouncementUtils.getAnnouncement(context, trackStatistics, category);
|
||||
|
||||
List<TrackPoint> trackPoints = contentProviderUtils.getTrackPoints(track.getId());
|
||||
IntervalStatistics intervalStatistics = new IntervalStatistics();
|
||||
intervalStatistics.build(trackPoints, (float) (PreferencesUtils.isMetricUnits(context) ? 1 * UnitConversions.KM_TO_M : 1 * UnitConversions.MI_TO_M));
|
||||
int numIntervals = intervalStatistics.getIntervalList().size();
|
||||
IntervalStatistics.Interval lastInterval = numIntervals > 0 ? intervalStatistics.getIntervalList().get(numIntervals - 1) : null;
|
||||
|
||||
String announcement = AnnouncementUtils.getAnnouncement(context, trackStatistics, category, lastInterval);
|
||||
speakAnnouncement(announcement);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,18 +2,22 @@ package de.dennisguse.opentracks.util;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import de.dennisguse.opentracks.R;
|
||||
import de.dennisguse.opentracks.stats.TrackStatistics;
|
||||
import de.dennisguse.opentracks.viewmodels.IntervalStatistics;
|
||||
|
||||
public class AnnouncementUtils {
|
||||
|
||||
private AnnouncementUtils() {}
|
||||
|
||||
public static String getAnnouncement(Context context, TrackStatistics trackStatistics, String category) {
|
||||
public static String getAnnouncement(Context context, TrackStatistics trackStatistics, String category, @Nullable IntervalStatistics.Interval currentInterval) {
|
||||
boolean metricUnits = PreferencesUtils.isMetricUnits(context);
|
||||
boolean reportSpeed = PreferencesUtils.isReportSpeed(context, category);
|
||||
double distance = trackStatistics.getTotalDistance() * UnitConversions.M_TO_KM;
|
||||
double distancePerTime = trackStatistics.getAverageMovingSpeed() * UnitConversions.MPS_TO_KMH;
|
||||
double currentDistancePerTime = currentInterval != null ? currentInterval.getSpeed_ms() * UnitConversions.MPS_TO_KMH : 0;
|
||||
|
||||
if (distance == 0) {
|
||||
return context.getString(R.string.voice_total_distance_zero);
|
||||
@@ -22,23 +26,36 @@ public class AnnouncementUtils {
|
||||
if (!metricUnits) {
|
||||
distance *= UnitConversions.KM_TO_MI;
|
||||
distancePerTime *= UnitConversions.KM_TO_MI;
|
||||
currentDistancePerTime *= UnitConversions.KM_TO_MI;
|
||||
}
|
||||
|
||||
String rate;
|
||||
String currentRate;
|
||||
String currentRateMsg = "";
|
||||
if (reportSpeed) {
|
||||
int speedId = metricUnits ? R.plurals.voiceSpeedKilometersPerHour : R.plurals.voiceSpeedMilesPerHour;
|
||||
rate = context.getResources().getQuantityString(speedId, getQuantityCount(distancePerTime), distancePerTime);
|
||||
|
||||
currentRate = context.getResources().getQuantityString(speedId, getQuantityCount(currentDistancePerTime), currentDistancePerTime);
|
||||
currentRateMsg = metricUnits ? context.getString(R.string.voice_speed_current_kilometer, currentRate) : context.getString(R.string.voice_speed_current_mile, currentRate);
|
||||
} else {
|
||||
double timePerDistance = distancePerTime == 0 ? 0.0 : 1 / distancePerTime;
|
||||
int paceId = metricUnits ? R.string.voice_pace_per_kilometer : R.string.voice_pace_per_mile;
|
||||
long time = Math.round(timePerDistance * UnitConversions.HR_TO_MIN * UnitConversions.MIN_TO_S * UnitConversions.S_TO_MS);
|
||||
rate = context.getString(paceId, getAnnounceTime(context, time));
|
||||
|
||||
double currentTimePerDistance = currentDistancePerTime == 0 ? 0.0 : 1 / currentDistancePerTime;
|
||||
long currentTime = Math.round(currentTimePerDistance * UnitConversions.HR_TO_MIN * UnitConversions.MIN_TO_S * UnitConversions.S_TO_MS);
|
||||
currentRate = context.getString(paceId, getAnnounceTime(context, currentTime));
|
||||
currentRateMsg = metricUnits ? context.getString(R.string.voice_pace_current_kilometer, currentRate) : context.getString(R.string.voice_pace_current_mile, currentRate);
|
||||
}
|
||||
|
||||
int totalDistanceId = metricUnits ? R.plurals.voiceTotalDistanceKilometers : R.plurals.voiceTotalDistanceMiles;
|
||||
String totalDistance = context.getResources().getQuantityString(totalDistanceId, getQuantityCount(distance), distance);
|
||||
|
||||
return context.getString(R.string.voice_template, totalDistance, getAnnounceTime(context, trackStatistics.getMovingTime()), rate);
|
||||
currentRateMsg = currentInterval == null ? "" : " " + currentRateMsg;
|
||||
|
||||
return context.getString(R.string.voice_template, totalDistance, getAnnounceTime(context, trackStatistics.getMovingTime()), rate) + currentRateMsg;
|
||||
}
|
||||
|
||||
private static String getAnnounceTime(Context context, long time) {
|
||||
|
||||
@@ -10,7 +10,11 @@ import de.dennisguse.opentracks.util.UnitConversions;
|
||||
public class IntervalStatistics {
|
||||
List<Interval> intervalList = new ArrayList<>();
|
||||
|
||||
public void build(List<TrackPoint> trackPointList, float distanceInterval) {
|
||||
/**
|
||||
* @param trackPointList the list of TrackPoint.
|
||||
* @param distanceInterval_m the meters of every interval.
|
||||
*/
|
||||
public void build(List<TrackPoint> trackPointList, float distanceInterval_m) {
|
||||
intervalList.clear();
|
||||
|
||||
if (trackPointList == null || trackPointList.size() == 0) {
|
||||
@@ -26,8 +30,8 @@ public class IntervalStatistics {
|
||||
interval.distance_m += prevTrackPoint.distanceTo(trackPoint);
|
||||
interval.time_ms += trackPoint.getTime() - prevTrackPoint.getTime();
|
||||
|
||||
if (interval.distance_m >= distanceInterval) {
|
||||
float adjustFactor = distanceInterval / interval.distance_m;
|
||||
if (interval.distance_m >= distanceInterval_m) {
|
||||
float adjustFactor = distanceInterval_m / interval.distance_m;
|
||||
Interval adjustedInterval = new Interval(interval);
|
||||
adjustedInterval.adjust(adjustFactor);
|
||||
|
||||
|
||||
@@ -497,6 +497,10 @@ g) haz lo que creas que ayude a OpenTracks.</string>
|
||||
<string name="voice_speed_miles_per_hour_two">2 millas por hora</string>
|
||||
<string name="voice_speed_miles_per_hour_zero">0 millas por hora</string>
|
||||
<string name="voice_template">OpenTracks de %1$s en %2$s a %3$s</string>
|
||||
<string name="voice_speed_current_kilometer">Con una velocidad del kilómetro actual de %1$s</string>
|
||||
<string name="voice_speed_current_mile">Con una velocidad de la milla actual de %1$s</string>
|
||||
<string name="voice_pace_current_kilometer">Con un ritmo del kilómetro actual de %1$s</string>
|
||||
<string name="voice_pace_current_mile">Con un ritmo de la milla actual de %1$s</string>
|
||||
<string name="voice_total_distance_kilometers_few">distancia total de %1$.2f kilómetros</string>
|
||||
<string name="voice_total_distance_kilometers_many">distancia total de %1$.2f kilómetros</string>
|
||||
<string name="voice_total_distance_kilometers_one">distancia total de 1 kilómetro</string>
|
||||
|
||||
@@ -521,6 +521,10 @@ limitations under the License.
|
||||
<string name="voice_speed_miles_per_hour_two">2 miles per hour</string>
|
||||
<string name="voice_speed_miles_per_hour_zero">0 miles per hour</string>
|
||||
<string name="voice_template">OpenTracks %1$s in %2$s at %3$s</string>
|
||||
<string name="voice_speed_current_kilometer">With a current kilometer speed of %1$s</string>
|
||||
<string name="voice_speed_current_mile">With a current mile speed of %1$s</string>
|
||||
<string name="voice_pace_current_kilometer">With a current kilometer pace of %1$s</string>
|
||||
<string name="voice_pace_current_mile">With a current mile pace of %1$s</string>
|
||||
<string name="voice_total_distance_kilometers_few">total distance %1$.2f kilometers</string>
|
||||
<string name="voice_total_distance_kilometers_many">total distance %1$.2f kilometers</string>
|
||||
<string name="voice_total_distance_kilometers_one">total distance 1 kilometer</string>
|
||||
|
||||
Reference in New Issue
Block a user