Compare commits

...

9 Commits

Author SHA1 Message Date
Dennis Guse 8cab43d558 Release: v3.17.2 2021-04-19 19:38:31 +02:00
Dennis Guse 13f2a09652 Bugfix: AnnouncementPeriodicTask does not need to register as TrackRecordingService.Listener. 2021-04-19 19:29:51 +02:00
Dennis Guse 7d4072c0d8 Cleanup: ChartPoint uses null instead of NaN. 2021-04-18 17:50:16 +02:00
Dennis Guse 310b35713d ChartFragmentTest: added test for small changes. 2021-04-18 14:39:48 +02:00
Dennis Guse 7e6237de3a Release: v3.17.1 2021-04-17 22:40:05 +02:00
Román Martínez 772dad4837 announce called after getting recordingTrackId. Fixed a potencial race condition. 2021-04-17 22:26:23 +02:00
Román Martínez 99126fa357 Distance interval bugfixed: interval options are km/mi values. 2021-04-17 21:16:32 +02:00
Román Martínez b2c91d7592 registerListener for barometric sensor uses SENSOR_DELAY_FASTEST instead of nanoseconds. Fixes #714. 2021-04-17 19:34:05 +02:00
Rodrigo Oliveira 3c5a1be16b Fix #711: declare TextToSpeech.Engine.INTENT_ACTION_TTS_SERVICE on queries element
This enables the use of TextToSpeech engine on Android 11.
Ref.: https://developer.android.com/reference/android/speech/tts/TextToSpeech
2021-04-17 19:31:26 +02:00
16 changed files with 106 additions and 67 deletions
+2 -2
View File
@@ -51,8 +51,8 @@ android {
defaultConfig { defaultConfig {
applicationId "de.dennisguse.opentracks" applicationId "de.dennisguse.opentracks"
versionCode 3981 versionCode 3990
versionName "v3.17.0" versionName "v3.17.2"
buildConfigField "String", "VERSION_NAME_FULL", "\"${getVersionName()}\"" buildConfigField "String", "VERSION_NAME_FULL", "\"${getVersionName()}\""
@@ -0,0 +1,7 @@
v3.17.1: OpenTracks
Bugfix:
- Interval length in meters instead of kilometers (introduced in v3.17.0)
- Elevation gain/loss not recorded (introduced in v3.17.0)
- Announcements not working on Android 11
@@ -0,0 +1,8 @@
v3.17.2: OpenTracks
WARNING: The v3.17.0+ releases contain a memory leak.
This issues is NOT FIXED by this release.
It is recommended to not upgrade if you still use a release before v3.17.0
Bugfix:
- Crash while using voice announcements
@@ -44,7 +44,7 @@ public class ChartValueSeriesTest {
ApplicationProvider.getApplicationContext(), ApplicationProvider.getApplicationContext(),
Integer.MIN_VALUE, Integer.MIN_VALUE,
Integer.MAX_VALUE, Integer.MAX_VALUE,
new int[]{100, 1000}, new int[]{1, 100, 1000},
R.string.description_altitude_metric, R.string.description_altitude_metric,
R.string.description_altitude_imperial, R.string.description_altitude_imperial,
R.color.chart_altitude_fill, R.color.chart_altitude_fill,
@@ -52,7 +52,7 @@ public class ChartValueSeriesTest {
15, 15,
18) { 18) {
@Override @Override
double extractDataFromChartPoint(@NonNull ChartPoint chartPoint) { Double extractDataFromChartPoint(@NonNull ChartPoint chartPoint) {
return chartPoint.getAltitude(); return chartPoint.getAltitude();
} }
@@ -77,6 +77,17 @@ public class ChartValueSeriesTest {
assertFalse(series.isEnabled()); assertFalse(series.isEnabled());
} }
@Test
public void testVerySmallUpdates() {
series.update(new ChartPoint(1f));
series.update(new ChartPoint(2f));
series.update(new ChartPoint(3f));
series.updateDimension();
assertEquals(1, series.getInterval());
assertEquals(1, series.getMinMarkerValue());
assertEquals(6, series.getMaxMarkerValue());
}
@Test @Test
public void testSmallUpdates() { public void testSmallUpdates() {
series.update(new ChartPoint(0)); series.update(new ChartPoint(0));
@@ -39,6 +39,7 @@ import de.dennisguse.opentracks.content.data.TrackPoint;
import de.dennisguse.opentracks.util.UnitConversions; import de.dennisguse.opentracks.util.UnitConversions;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
/** /**
* Tests {@link ChartFragment}. * Tests {@link ChartFragment}.
@@ -83,9 +84,9 @@ public class ChartFragmentTest {
ChartPoint point = chartFragment.createPendingPoint(trackPoint); ChartPoint point = chartFragment.createPendingPoint(trackPoint);
// then // then
assertEquals(Float.NaN, point.getHeartRate(), 0.01); assertNull(point.getHeartRate());
assertEquals(Float.NaN, point.getCadence(), 0.01); assertNull(point.getCadence());
assertEquals(Float.NaN, point.getPower(), 0.01); assertNull(point.getPower());
} }
/** /**
+6
View File
@@ -351,4 +351,10 @@ limitations under the License.
android:exported="false" android:exported="false"
android:permission="android.permission.BIND_JOB_SERVICE" /> android:permission="android.permission.BIND_JOB_SERVICE" />
</application> </application>
<queries>
<intent>
<action android:name="android.intent.action.TTS_SERVICE" />
</intent>
</queries>
</manifest> </manifest>
@@ -14,11 +14,11 @@ public class ChartPoint {
//Y-axis //Y-axis
private double altitude; private double altitude;
private double speed; private Double speed;
private double pace; private Double pace;
private double heartRate = Double.NaN; private Double heartRate;
private double cadence = Double.NaN; private Double cadence;
private double power = Double.NaN; private Double power;
@VisibleForTesting @VisibleForTesting
ChartPoint(double altitude) { ChartPoint(double altitude) {
@@ -43,13 +43,13 @@ public class ChartPoint {
pace = trackStatisticsUpdater.getSmoothedSpeed().toPace(metricUnits).toMillis() * UnitConversions.MS_TO_S * UnitConversions.S_TO_MIN; pace = trackStatisticsUpdater.getSmoothedSpeed().toPace(metricUnits).toMillis() * UnitConversions.MS_TO_S * UnitConversions.S_TO_MIN;
if (trackPoint != null) { if (trackPoint != null) {
if (trackPoint.hasHeartRate()) { if (trackPoint.hasHeartRate()) {
heartRate = trackPoint.getHeartRate_bpm(); heartRate = (double) trackPoint.getHeartRate_bpm();
} }
if (trackPoint.hasCyclingCadence()) { if (trackPoint.hasCyclingCadence()) {
cadence = trackPoint.getCyclingCadence_rpm(); cadence = (double) trackPoint.getCyclingCadence_rpm();
} }
if (trackPoint.hasPower()) { if (trackPoint.hasPower()) {
power = trackPoint.getPower(); power = (double) trackPoint.getPower();
} }
} }
} }
@@ -58,39 +58,27 @@ public class ChartPoint {
return timeOrDistance; return timeOrDistance;
} }
public double getAltitude() { public Double getAltitude() {
return altitude; return altitude;
} }
public double getSpeed() { public Double getSpeed() {
return speed; return speed;
} }
public double getPace() { public Double getPace() {
return pace; return pace;
} }
public boolean hasHeartRate() { public Double getHeartRate() {
return Double.isNaN(heartRate);
}
public double getHeartRate() {
return heartRate; return heartRate;
} }
public boolean hasCadence() { public Double getCadence() {
return Double.isNaN(cadence);
}
public double getCadence() {
return cadence; return cadence;
} }
public boolean hasPower() { public Double getPower() {
return Double.isNaN(power);
}
public double getPower() {
return power; return power;
} }
} }
@@ -132,10 +132,10 @@ abstract class ChartValueSeries {
} }
} }
abstract double extractDataFromChartPoint(@NonNull ChartPoint chartPoint); abstract Double extractDataFromChartPoint(@NonNull ChartPoint chartPoint);
boolean isChartPointValid(@NonNull ChartPoint chartPoint) { boolean isChartPointValid(@NonNull ChartPoint chartPoint) {
return !Double.isNaN(extractDataFromChartPoint(chartPoint)); return extractDataFromChartPoint(chartPoint) != null;
} }
protected abstract boolean drawIfChartPointHasNoData(); protected abstract boolean drawIfChartPointHasNoData();
@@ -206,7 +206,7 @@ public class ChartView extends View {
fontSizeSmall, fontSizeSmall,
fontSizeMedium) { fontSizeMedium) {
@Override @Override
protected double extractDataFromChartPoint(@NonNull ChartPoint chartPoint) { protected Double extractDataFromChartPoint(@NonNull ChartPoint chartPoint) {
return chartPoint.getAltitude(); return chartPoint.getAltitude();
} }
@@ -227,7 +227,7 @@ public class ChartView extends View {
fontSizeSmall, fontSizeSmall,
fontSizeMedium) { fontSizeMedium) {
@Override @Override
protected double extractDataFromChartPoint(@NonNull ChartPoint chartPoint) { protected Double extractDataFromChartPoint(@NonNull ChartPoint chartPoint) {
return chartPoint.getSpeed(); return chartPoint.getSpeed();
} }
@@ -249,7 +249,7 @@ public class ChartView extends View {
fontSizeSmall, fontSizeSmall,
fontSizeMedium) { fontSizeMedium) {
@Override @Override
protected double extractDataFromChartPoint(@NonNull ChartPoint chartPoint) { protected Double extractDataFromChartPoint(@NonNull ChartPoint chartPoint) {
return chartPoint.getPace(); return chartPoint.getPace();
} }
@@ -271,7 +271,7 @@ public class ChartView extends View {
fontSizeSmall, fontSizeSmall,
fontSizeMedium) { fontSizeMedium) {
@Override @Override
protected double extractDataFromChartPoint(@NonNull ChartPoint chartPoint) { protected Double extractDataFromChartPoint(@NonNull ChartPoint chartPoint) {
return chartPoint.getHeartRate(); return chartPoint.getHeartRate();
} }
@@ -292,7 +292,7 @@ public class ChartView extends View {
fontSizeSmall, fontSizeSmall,
fontSizeMedium) { fontSizeMedium) {
@Override @Override
protected double extractDataFromChartPoint(@NonNull ChartPoint chartPoint) { protected Double extractDataFromChartPoint(@NonNull ChartPoint chartPoint) {
return chartPoint.getCadence(); return chartPoint.getCadence();
} }
@@ -312,7 +312,7 @@ public class ChartView extends View {
fontSizeSmall, fontSizeSmall,
fontSizeMedium) { fontSizeMedium) {
@Override @Override
protected double extractDataFromChartPoint(@NonNull ChartPoint chartPoint) { protected Double extractDataFromChartPoint(@NonNull ChartPoint chartPoint) {
return chartPoint.getPower(); return chartPoint.getPower();
} }
@@ -20,9 +20,13 @@ public class Distance {
return of(distance_mile * UnitConversions.MI_TO_M); return of(distance_mile * UnitConversions.MI_TO_M);
} }
public static Distance ofKilometer(double distance_km) {
return of(distance_km * UnitConversions.KM_TO_M);
}
public static Distance one(boolean metricUnit) { public static Distance one(boolean metricUnit) {
if (metricUnit) { if (metricUnit) {
return Distance.of(1); return Distance.ofKilometer(1);
} else { } else {
return Distance.ofMile(1); return Distance.ofMile(1);
} }
@@ -192,6 +192,10 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
return serviceStatus.getRecordingTrackPaused(); return serviceStatus.getRecordingTrackPaused();
} }
public Track.Id getRecordingTrackId() {
return serviceStatus.getRecordingTrackId();
}
public TrackStatistics getTrackStatistics() { public TrackStatistics getTrackStatistics() {
if (trackStatisticsUpdater == null) { if (trackStatisticsUpdater == null) {
return null; return null;
@@ -569,6 +573,12 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
serviceStatus.addListener(listener); serviceStatus.addListener(listener);
} }
//TODO Check that this is used everywhere, where addListener is called!
//Otherwise, we keep objects in referenced and waste memory until this service instance is terminated.
public void removeListener(@NonNull TrackRecordingServiceStatus.Listener listener) {
serviceStatus.removeListener(listener);
}
/** /**
* Inserts a trackPoint if this trackPoint is different than lastValidTrackPoint. * Inserts a trackPoint if this trackPoint is different than lastValidTrackPoint.
* *
@@ -19,7 +19,7 @@ public class TrackRecordingServiceStatus {
private final List<Listener> listeners = new ArrayList<>(); private final List<Listener> listeners = new ArrayList<>();
public void addListener(@NonNull Listener listener) { void addListener(@NonNull Listener listener) {
if (this.listeners.contains(listener)) { if (this.listeners.contains(listener)) {
return; return;
} }
@@ -28,6 +28,10 @@ public class TrackRecordingServiceStatus {
listener.onTrackRecordingPaused(recordingTrackPaused); listener.onTrackRecordingPaused(recordingTrackPaused);
} }
void removeListener(@NonNull Listener listener) {
this.listeners.remove(listener);
}
public boolean getRecordingTrackPaused() { public boolean getRecordingTrackPaused() {
return this.recordingTrackPaused; return this.recordingTrackPaused;
} }
@@ -40,7 +40,7 @@ public class AltitudeSumManager implements SensorEventListener {
Log.w(TAG, "No pressure sensor available."); Log.w(TAG, "No pressure sensor available.");
isConnected = false; isConnected = false;
} else { } else {
isConnected = sensorManager.registerListener(this, pressureSensor, (int) SAMPLING_RATE.toNanos()); isConnected = sensorManager.registerListener(this, pressureSensor, SensorManager.SENSOR_DELAY_FASTEST);
} }
lastAcceptedPressureValue_hPa = Float.NaN; lastAcceptedPressureValue_hPa = Float.NaN;
@@ -24,6 +24,7 @@ import android.speech.tts.UtteranceProgressListener;
import android.util.Log; import android.util.Log;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Locale; import java.util.Locale;
import de.dennisguse.opentracks.content.data.Distance; import de.dennisguse.opentracks.content.data.Distance;
@@ -32,7 +33,6 @@ import de.dennisguse.opentracks.content.data.TrackPoint;
import de.dennisguse.opentracks.content.provider.ContentProviderUtils; import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
import de.dennisguse.opentracks.content.provider.TrackPointIterator; import de.dennisguse.opentracks.content.provider.TrackPointIterator;
import de.dennisguse.opentracks.services.TrackRecordingService; import de.dennisguse.opentracks.services.TrackRecordingService;
import de.dennisguse.opentracks.services.TrackRecordingServiceStatus;
import de.dennisguse.opentracks.stats.TrackStatistics; import de.dennisguse.opentracks.stats.TrackStatistics;
import de.dennisguse.opentracks.util.AnnouncementUtils; import de.dennisguse.opentracks.util.AnnouncementUtils;
import de.dennisguse.opentracks.util.PreferencesUtils; import de.dennisguse.opentracks.util.PreferencesUtils;
@@ -58,8 +58,6 @@ public class AnnouncementPeriodicTask implements PeriodicTask {
private final ContentProviderUtils contentProviderUtils; private final ContentProviderUtils contentProviderUtils;
private Track.Id recordingTrackId;
private final AudioManager.OnAudioFocusChangeListener audioFocusChangeListener = new AudioManager.OnAudioFocusChangeListener() { private final AudioManager.OnAudioFocusChangeListener audioFocusChangeListener = new AudioManager.OnAudioFocusChangeListener() {
@Override @Override
public void onAudioFocusChange(int focusChange) { public void onAudioFocusChange(int focusChange) {
@@ -142,13 +140,8 @@ public class AnnouncementPeriodicTask implements PeriodicTask {
Log.e(TAG, "TrackRecordingService is null."); Log.e(TAG, "TrackRecordingService is null.");
return; return;
} }
trackRecordingService.addListener(new TrackRecordingServiceStatus.Listener() {
@Override announce(trackRecordingService.getRecordingTrackId(), trackRecordingService.getTrackStatistics());
public void onTrackRecordingId(Track.Id trackId) {
recordingTrackId = trackId;
}
});
announce(trackRecordingService.getTrackStatistics());
} }
/** /**
@@ -156,7 +149,7 @@ public class AnnouncementPeriodicTask implements PeriodicTask {
* *
* @param trackStatistics the track statistics * @param trackStatistics the track statistics
*/ */
private void announce(TrackStatistics trackStatistics) { private void announce(Track.Id trackId, TrackStatistics trackStatistics) {
if (trackStatistics == null) { if (trackStatistics == null) {
Log.e(TAG, "TrackStatistics is null."); Log.e(TAG, "TrackStatistics is null.");
return; return;
@@ -175,13 +168,18 @@ public class AnnouncementPeriodicTask implements PeriodicTask {
} }
} }
if (audioManager.getMode() == AudioManager.MODE_IN_CALL || audioManager.getMode() == AudioManager.MODE_IN_COMMUNICATION) { if (Arrays.asList(AudioManager.MODE_IN_CALL, AudioManager.MODE_IN_COMMUNICATION)
.contains(audioManager.getMode())) {
Log.i(TAG, "Speech is not allowed at this time."); Log.i(TAG, "Speech is not allowed at this time.");
return; return;
} }
Track track = contentProviderUtils.getTrack(recordingTrackId); Track track = contentProviderUtils.getTrack(trackId);
String category = track != null ? track.getCategory() : ""; if (track == null) {
Log.i(TAG, "It doesn't exists a track with trackid = " + track);
return;
}
String category = track.getCategory();
//TODO Querying all TrackPoints all the time is inefficient; use TrackDataHub or something else. //TODO Querying all TrackPoints all the time is inefficient; use TrackDataHub or something else.
TrackPointIterator trackPointIterator = contentProviderUtils.getTrackPointLocationIterator(track.getId(), null); TrackPointIterator trackPointIterator = contentProviderUtils.getTrackPointLocationIterator(track.getId(), null);
@@ -106,7 +106,7 @@ public class TrackStatisticsUpdater {
*/ */
public void addTrackPoint(TrackPoint trackPoint, Distance minGPSDistance) { public void addTrackPoint(TrackPoint trackPoint, Distance minGPSDistance) {
internalAddTrackPoint(trackPoint, minGPSDistance); internalAddTrackPoint(trackPoint, minGPSDistance);
Log.d(TAG, this.toString()); Log.v(TAG, this.toString());
} }
private void internalAddTrackPoint(TrackPoint trackPoint, Distance minGPSDistance) { private void internalAddTrackPoint(TrackPoint trackPoint, Distance minGPSDistance) {
@@ -35,7 +35,7 @@ public class IntervalStatisticsModel extends AndroidViewModel {
} }
intervalsLiveData = new MutableLiveData<>(); intervalsLiveData = new MutableLiveData<>();
distanceInterval = interval.getValue(); distanceInterval = interval.getDistance(metricUnits);
loadIntervalStatistics(); loadIntervalStatistics();
} }
return intervalsLiveData; return intervalsLiveData;
@@ -73,7 +73,7 @@ public class IntervalStatisticsModel extends AndroidViewModel {
interval = IntervalOption.OPTION_1; interval = IntervalOption.OPTION_1;
} }
distanceInterval = interval.getValue(); distanceInterval = interval.getDistance(metricUnits);
loadIntervalStatistics(); loadIntervalStatistics();
} }
} }
@@ -91,19 +91,21 @@ public class IntervalStatisticsModel extends AndroidViewModel {
OPTION_20(20), OPTION_20(20),
OPTION_50(50); OPTION_50(50);
private final Distance value; private final int multiplier;
IntervalOption(int value) { IntervalOption(int multiplier) {
this.value = Distance.of(value); this.multiplier = multiplier;
} }
public Distance getValue() { public Distance getDistance(boolean metricUnits) {
return value; return Distance
.one(metricUnits)
.multipliedBy(multiplier);
} }
@Override @Override
public String toString() { public String toString() {
return "" + (int) value.toM(); //TODO Somehow IntervalsFragment relies on a parsable Integer. return "" + multiplier; //TODO Somehow IntervalsFragment relies on a parsable Integer.
} }
} }
} }