Idle: TrackRecordingManager creates IDLE TrackPoints.

Fixes of #1187.
This commit is contained in:
Dennis Guse
2023-07-31 20:07:53 +02:00
parent 60fd1cd105
commit 6be9d2477c
14 changed files with 167 additions and 361 deletions
@@ -287,11 +287,6 @@ public class TrackPoint {
this.speed = speed;
return this;
}
public boolean isMoving() {
return hasSpeed() && getSpeed().isMoving();
}
public boolean hasBearing() {
return bearing != null;
}
@@ -352,9 +347,8 @@ public class TrackPoint {
return hasHorizontalAccuracy() && horizontalAccuracy.lessThan(thresholdHorizontalAccuracy);
}
//TODO Bearing requires a location; what do we do if we don't have any?
public float bearingTo(@NonNull TrackPoint dest) {
return getLocation().bearingTo(dest.getLocation());
return bearingTo(dest.getLocation());
}
//TODO Bearing requires a location; what do we do if we don't have any?
@@ -315,6 +315,10 @@ public class KmlTrackImporter extends DefaultHandler implements XMLImporter.Trac
if (i < sensorSpeedList.size() && sensorSpeedList.get(i) != null) {
trackPoint.setSpeed(Speed.of(sensorSpeedList.get(i)));
if (TrackPoint.IDLE_SPEED.greaterOrEqualThan(trackPoint.getSpeed())) {
trackPoint.setType(TrackPoint.Type.IDLE);
}
}
if (i < sensorDistanceList.size() && sensorDistanceList.get(i) != null) {
trackPoint.setSensorDistance(Distance.of(sensorDistanceList.get(i)));
@@ -5,6 +5,7 @@ import android.content.Context;
import android.content.SharedPreferences;
import android.database.sqlite.SQLiteException;
import android.net.Uri;
import android.os.Handler;
import android.util.Log;
import android.util.Pair;
@@ -32,11 +33,17 @@ class TrackRecordingManager implements SharedPreferences.OnSharedPreferenceChang
private static final String TAG = TrackRecordingManager.class.getSimpleName();
private static final Duration IDLE_TIMEOUT = Duration.ofSeconds(30);
private static final AltitudeCorrectionManager ALTITUDE_CORRECTION_MANAGER = new AltitudeCorrectionManager();
private final Runnable ON_IDLE = this::onIdle;
private final ContentProviderUtils contentProviderUtils;
private final Context context;
private final Handler handler;
private final TrackPointCreator trackPointCreator;
private Distance recordingDistanceInterval;
@@ -52,9 +59,10 @@ class TrackRecordingManager implements SharedPreferences.OnSharedPreferenceChang
private TrackPoint lastStoredTrackPoint;
private TrackPoint lastStoredTrackPointWithLocation;
TrackRecordingManager(Context context, TrackPointCreator trackPointCreator) {
TrackRecordingManager(Context context, TrackPointCreator trackPointCreator, Handler handler) {
this.context = context;
this.trackPointCreator = trackPointCreator;
this.handler = handler;
contentProviderUtils = new ContentProviderUtils(context);
}
@@ -154,16 +162,27 @@ class TrackRecordingManager implements SharedPreferences.OnSharedPreferenceChang
return new Marker.Id(ContentUris.parseId(uri));
}
void onIdle() {
Log.d(TAG, "Becoming idle");
onNewTrackPoint(trackPointCreator.createIdle());
}
/**
* @return TrackPoint was stored?
*/
boolean onNewTrackPoint(@NonNull TrackPoint trackPoint) {
synchronized boolean onNewTrackPoint(@NonNull TrackPoint trackPoint) {
if (trackPoint.hasSpeed()) {
lastTrackPointUIWithSpeed = trackPoint;
}
if (trackPoint.hasAltitude()) {
lastTrackPointUIWithAltitude = trackPoint;
}
if (trackPoint.getType() == TrackPoint.Type.IDLE) {
insertTrackPoint(trackPoint, true);
handler.removeCallbacks(ON_IDLE);
return true;
}
//Storing trackPoint
// Always insert the first segment location
@@ -184,10 +203,10 @@ class TrackRecordingManager implements SharedPreferences.OnSharedPreferenceChang
if (!shouldStore) {
Log.d(TAG, "Ignoring TrackPoint as it has no distance (and sensor data is not new enough).");
return false;
} else {
insertTrackPoint(trackPoint, true);
return true;
}
insertTrackPoint(trackPoint, true);
return true;
}
Distance distanceToLastStoredTrackPoint;
@@ -200,18 +219,17 @@ class TrackRecordingManager implements SharedPreferences.OnSharedPreferenceChang
if (distanceToLastStoredTrackPoint.greaterThan(maxRecordingDistance)) {
trackPoint.setType(TrackPoint.Type.SEGMENT_START_AUTOMATIC);
insertTrackPoint(trackPoint, true);
handler.removeCallbacks(ON_IDLE);
handler.postDelayed(ON_IDLE, IDLE_TIMEOUT.toMillis());
return true;
}
if (distanceToLastStoredTrackPoint.greaterOrEqualThan(recordingDistanceInterval)
&& trackPoint.isMoving()) {
if (distanceToLastStoredTrackPoint.greaterOrEqualThan(recordingDistanceInterval)) {
insertTrackPoint(trackPoint, false);
return true;
}
if (trackPoint.isMoving() != lastStoredTrackPoint.isMoving()) {
// Moving from non-moving to moving or vice versa; required to compute moving time correctly.
insertTrackPoint(trackPoint, true);
handler.removeCallbacks(ON_IDLE);
handler.postDelayed(ON_IDLE, IDLE_TIMEOUT.toMillis());
return true;
}
@@ -107,8 +107,8 @@ public class TrackRecordingService extends Service implements TrackPointCreator.
gpsStatusObservable = new MutableLiveData<>(STATUS_GPS_DEFAULT);
recordingDataObservable = new MutableLiveData<>(NOT_RECORDING);
trackPointCreator = new TrackPointCreator(this, this, handler);
trackRecordingManager = new TrackRecordingManager(this, trackPointCreator);
trackPointCreator = new TrackPointCreator(this);
trackRecordingManager = new TrackRecordingManager(this, trackPointCreator, handler);
voiceAnnouncementManager = new VoiceAnnouncementManager(this);
notificationManager = new TrackRecordingServiceNotificationManager(this);
@@ -36,16 +36,11 @@ public class TrackPointCreator implements SharedPreferences.OnSharedPreferenceCh
private Clock clock = new MonotonicClock();
private SensorManager sensorManager;
public TrackPointCreator(Callback service, Context context, Handler handler) {
public TrackPointCreator(Callback service) {
this.service = service;
this.sensorManager = new SensorManager(this);
}
@VisibleForTesting
TrackPointCreator(Callback service) {
this.service = service;
}
public synchronized void start(@NonNull Context context, @NonNull Handler handler) {
this.context = context;
@@ -106,6 +101,13 @@ public class TrackPointCreator implements SharedPreferences.OnSharedPreferenceCh
return segmentEnd;
}
public synchronized TrackPoint createIdle() {
TrackPoint idle = new TrackPoint(TrackPoint.Type.IDLE, createNow());
addSensorData(idle);
reset();
return idle;
}
public Pair<TrackPoint, SensorDataSet> createCurrentTrackPoint(@Nullable TrackPoint lastTrackPointUISpeed, @Nullable TrackPoint lastTrackPointUIAltitude, @Nullable TrackPoint lastStoredTrackPointWithLocation) {
TrackPoint currentTrackPoint = new TrackPoint(TrackPoint.Type.TRACKPOINT, createNow());
@@ -56,6 +56,8 @@ public class TrackStatisticsUpdater {
// Current segment's last trackPoint
private TrackPoint lastTrackPoint;
private boolean idle;
public TrackStatisticsUpdater() {
this(new TrackStatistics());
}
@@ -77,6 +79,7 @@ public class TrackStatisticsUpdater {
this.trackStatistics = new TrackStatistics(toCopy.trackStatistics);
this.lastTrackPoint = toCopy.lastTrackPoint;
this.idle = idle;
resetAverageHeartRate();
}
@@ -132,26 +135,35 @@ public class TrackStatisticsUpdater {
currentSegment.setAverageHeartRate(HeartRate.of(averageHeartRateBPM));
}
// Update total distance
if (trackPoint.hasSensorDistance()) {
// Sensor-based distance/speed
currentSegment.addTotalDistance(trackPoint.getSensorDistance());
} else if (lastTrackPoint != null
&& lastTrackPoint.hasLocation()
&& trackPoint.hasLocation() && trackPoint.isMoving()) {
// GPS-based distance/speed
// Assumption: we ignore TrackPoints that are not moving as those are likely imprecise GPS measurements
Distance movingDistance = trackPoint.distanceToPrevious(lastTrackPoint);
currentSegment.addTotalDistance(movingDistance);
}
{
// Update total distance
Distance movingDistance = null;
if (trackPoint.hasSensorDistance()) {
movingDistance = trackPoint.getSensorDistance();
} else if (lastTrackPoint != null
&& lastTrackPoint.hasLocation()
&& trackPoint.hasLocation()) {
// GPS-based distance/speed
movingDistance = trackPoint.distanceToPrevious(lastTrackPoint);
}
if (movingDistance != null) {
idle = false;
currentSegment.addTotalDistance(movingDistance);
}
if (!idle && !trackPoint.isSegmentManualStart()) {
if (lastTrackPoint != null) {
currentSegment.addMovingTime(trackPoint, lastTrackPoint);
}
}
// Update moving time
if (trackPoint.isMoving() && lastTrackPoint != null && lastTrackPoint.isMoving()) {
currentSegment.addMovingTime(trackPoint, lastTrackPoint);
if (trackPoint.getType() == TrackPoint.Type.IDLE) {
idle = true;
}
// Update max speed
updateSpeed(trackPoint, lastTrackPoint);
if (trackPoint.hasSpeed()) {
updateSpeed(trackPoint);
}
}
if (trackPoint.isSegmentManualEnd()) {