TrackStatisticsUpdater updates only by adding TrackPoints.

#316.
This commit is contained in:
Dennis Guse
2021-01-14 19:38:27 +01:00
parent d157e94220
commit c3741611dc
5 changed files with 82 additions and 77 deletions
@@ -268,6 +268,30 @@ public class TrackRecordingServiceTest {
assertEquals(TrackPoint.Type.TRACKPOINT, trackPoints.get(3).getType()); assertEquals(TrackPoint.Type.TRACKPOINT, trackPoints.get(3).getType());
} }
@MediumTest
@Test
public void testRecording_stopPausedTrack() throws TimeoutException {
// given
TrackRecordingServiceInterface service = ((TrackRecordingServiceInterface) mServiceRule.bindService(createStartIntent(context)));
Track.Id trackId = service.startNewTrack();
assertTrue(service.isRecording());
service.pauseCurrentTrack();
assertEquals(2, contentProviderUtils.getTrackPoints(trackId).size());
// when
service.endCurrentTrack();
// then
assertFalse(service.isRecording());
assertNull(service.getRecordingTrackId());
List<TrackPoint> trackPoints = contentProviderUtils.getTrackPoints(trackId);
assertEquals(2, trackPoints.size());
assertEquals(TrackPoint.Type.SEGMENT_START_MANUAL, trackPoints.get(0).getType());
assertEquals(TrackPoint.Type.SEGMENT_END_MANUAL, trackPoints.get(1).getType());
}
@Ignore("Sometimes fails on CI.") @Ignore("Sometimes fails on CI.")
@MediumTest @MediumTest
@Test @Test
@@ -54,7 +54,7 @@ public class TrackController implements View.OnTouchListener {
private final TransitionDrawable transition; private final TransitionDrawable transition;
private boolean isRecording; private boolean isRecording;
private boolean isPaused; private boolean isRecordingPaused;
private Duration totalTime; private Duration totalTime;
private boolean isResumed = false; private boolean isResumed = false;
@@ -63,8 +63,9 @@ public class TrackController implements View.OnTouchListener {
// A runnable to update the total time. // A runnable to update the total time.
private final Runnable updateTotalTimeRunnable = new Runnable() { private final Runnable updateTotalTimeRunnable = new Runnable() {
public void run() { public void run() {
if (isResumed && isRecording && !isPaused) { if (isResumed && isRecording && !isRecordingPaused) {
viewBinding.trackControllerTotalTime.setText(StringUtils.formatElapsedTimeWithHour(totalTime)); updateTotalTime();
setTotalTime();
handlerUpdateTotalTime.postDelayed(this, UnitConversions.ONE_SECOND_MS); handlerUpdateTotalTime.postDelayed(this, UnitConversions.ONE_SECOND_MS);
} }
} }
@@ -82,7 +83,7 @@ public class TrackController implements View.OnTouchListener {
viewBinding.trackControllerRecord.setOnTouchListener(this); viewBinding.trackControllerRecord.setOnTouchListener(this);
viewBinding.trackControllerRecord.setOnClickListener((view) -> { viewBinding.trackControllerRecord.setOnClickListener((view) -> {
if (buttonDelay != null || (isRecording && !isPaused)) { if (buttonDelay != null || (isRecording && !isRecordingPaused)) {
return; return;
} }
@@ -118,7 +119,7 @@ public class TrackController implements View.OnTouchListener {
//To pause a recording //To pause a recording
if (viewBinding.trackControllerRecord.equals(view) if (viewBinding.trackControllerRecord.equals(view)
&& event.getAction() == MotionEvent.ACTION_DOWN && event.getAction() == MotionEvent.ACTION_DOWN
&& isRecording && !isPaused) { && isRecording && !isRecordingPaused) {
transition.startTransition(buttonDelayDuration); transition.startTransition(buttonDelayDuration);
@@ -165,10 +166,11 @@ public class TrackController implements View.OnTouchListener {
public void update(boolean recording, boolean paused) { public void update(boolean recording, boolean paused) {
if (!isResumed) { if (!isResumed) {
handlerUpdateTotalTime.removeCallbacks(updateTotalTimeRunnable);
return; return;
} }
isRecording = recording; isRecording = recording;
isPaused = paused; isRecordingPaused = paused;
boolean visible = alwaysShow || isRecording; boolean visible = alwaysShow || isRecording;
viewBinding.trackControllerContainer.setVisibility(visible ? View.VISIBLE : View.GONE); viewBinding.trackControllerContainer.setVisibility(visible ? View.VISIBLE : View.GONE);
@@ -177,27 +179,26 @@ public class TrackController implements View.OnTouchListener {
return; return;
} }
viewBinding.trackControllerRecord.setImageResource(isRecording && !isPaused ? R.drawable.ic_button_pause : R.drawable.button_record); if (isRecording && !isRecordingPaused) {
viewBinding.trackControllerRecord.setContentDescription(activity.getString(isRecording && !isPaused ? R.string.image_pause : R.string.image_record)); handlerUpdateTotalTime.postDelayed(updateTotalTimeRunnable, UnitConversions.ONE_SECOND_MS);
}
viewBinding.trackControllerRecord.setImageResource(isRecording && !isRecordingPaused ? R.drawable.ic_button_pause : R.drawable.button_record);
viewBinding.trackControllerRecord.setContentDescription(activity.getString(isRecording && !isRecordingPaused ? R.string.image_pause : R.string.image_record));
viewBinding.trackControllerStop.setEnabled(isRecording); viewBinding.trackControllerStop.setEnabled(isRecording);
viewBinding.trackControllerStatus.setVisibility(isRecording ? View.VISIBLE : View.INVISIBLE); viewBinding.trackControllerStatus.setVisibility(isRecording ? View.VISIBLE : View.INVISIBLE);
if (isRecording) { if (isRecording) {
viewBinding.trackControllerStatus.setTextColor(activity.getResources().getColor(isPaused ? android.R.color.white : R.color.recording_text)); viewBinding.trackControllerStatus.setTextColor(activity.getResources().getColor(isRecordingPaused ? android.R.color.white : R.color.recording_text));
showStatusSetDefaultText(); showStatusSetDefaultText();
} }
handlerUpdateTotalTime.removeCallbacks(updateTotalTimeRunnable);
viewBinding.trackControllerTotalTime.setVisibility(isRecording ? View.VISIBLE : View.INVISIBLE); viewBinding.trackControllerTotalTime.setVisibility(isRecording ? View.VISIBLE : View.INVISIBLE);
if (isRecording) { if (isRecording) {
totalTime = getTotalTime(); updateTotalTime();
if (totalTime != null) { setTotalTime();
viewBinding.trackControllerTotalTime.setText(StringUtils.formatElapsedTimeWithHour(totalTime));
}
if (!isPaused) {
handlerUpdateTotalTime.postDelayed(updateTotalTimeRunnable, UnitConversions.ONE_SECOND_MS);
}
} }
} }
@@ -219,16 +220,21 @@ public class TrackController implements View.OnTouchListener {
viewBinding.trackControllerContainer.setVisibility(View.VISIBLE); viewBinding.trackControllerContainer.setVisibility(View.VISIBLE);
} }
/** private void updateTotalTime() {
* Gets the total time for the current recording track.
*/
private Duration getTotalTime() {
TrackRecordingServiceInterface trackRecordingService = trackRecordingServiceConnection.getServiceIfBound(); TrackRecordingServiceInterface trackRecordingService = trackRecordingServiceConnection.getServiceIfBound();
return trackRecordingService != null ? trackRecordingService.getTotalTime() : null; if (trackRecordingService != null) {
totalTime = trackRecordingService.getTotalTime();
}
}
private void setTotalTime() {
if (totalTime != null) {
viewBinding.trackControllerTotalTime.setText(StringUtils.formatElapsedTimeWithHour(totalTime));
}
} }
private void showStatusSetDefaultText() { private void showStatusSetDefaultText() {
viewBinding.trackControllerStatus.setText(isPaused ? R.string.generic_paused : R.string.generic_recording); viewBinding.trackControllerStatus.setText(isRecordingPaused ? R.string.generic_paused : R.string.generic_recording);
} }
public interface Callback { public interface Callback {
@@ -15,7 +15,6 @@ import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import java.time.Duration; import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@@ -409,26 +408,15 @@ public class StatisticsRecordingFragment extends Fragment implements TrackDataLi
} }
private void updateTotalTime() { private void updateTotalTime() {
Duration totalTime; Duration totalTime = lastTrackStatistics.getTotalTime();
if (isSelectedTrackRecording()) { if (isSelectedTrackRecording()) {
totalTime = calculateTotalTime(); TrackRecordingServiceInterface trackRecordingService = trackRecordingServiceConnection.getServiceIfBound();
} else { if (trackRecordingService != null) {
totalTime = lastTrackStatistics.getTotalTime(); totalTime = trackRecordingService.getTotalTime();
}
} }
viewBinding.statsTotalTimeValue.setText(StringUtils.formatElapsedTime(totalTime));
}
/** viewBinding.statsTotalTimeValue.setText(StringUtils.formatElapsedTime(totalTime));
* Return time from service.
* If service isn't bound then use lastTrackStatistics for calculate it.
*/
private Duration calculateTotalTime() {
TrackRecordingServiceInterface trackRecordingService = trackRecordingServiceConnection.getServiceIfBound();
if (trackRecordingService != null) {
return trackRecordingService.getTotalTime();
} else {
return Duration.between(lastTrackStatistics.getStopTime().plus(lastTrackStatistics.getTotalTime()), Instant.now());
}
} }
private void setLocationValues() { private void setLocationValues() {
@@ -234,10 +234,13 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
if (trackStatisticsUpdater == null) { if (trackStatisticsUpdater == null) {
return Duration.ofSeconds(0); return Duration.ofSeconds(0);
} }
if (!isPaused()) { if (isPaused()) {
trackStatisticsUpdater.updateTime(Instant.now()); return trackStatisticsUpdater.getTrackStatistics().getTotalTime();
} }
return trackStatisticsUpdater.getTrackStatistics().getTotalTime();
TrackStatistics statistics = trackStatisticsUpdater.getTrackStatistics();
return Duration.between(statistics.getStopTime(), Instant.now())
.plus(statistics.getTotalTime());
} }
public Marker.Id insertMarker(String name, String category, String description, String photoUrl) { public Marker.Id insertMarker(String name, String category, String description, String photoUrl) {
@@ -420,24 +423,24 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
} }
// Need to remember the recordingTrackId before setting it to -1L // Need to remember the recordingTrackId before setting it to -1L
boolean wasPause = isPaused();
Track.Id trackId = recordingTrackId; Track.Id trackId = recordingTrackId;
boolean wasPaused = recordingTrackPaused;
updateRecordingState(null, true); updateRecordingState(null, true);
// Update database if (!wasPause) {
Track track = contentProviderUtils.getTrack(trackId); // Update database
if (track != null) { Track track = contentProviderUtils.getTrack(trackId);
if (lastTrackPoint != null) { if (track != null) {
insertTrackPointIfNewer(track, lastTrackPoint); if (lastTrackPoint != null) {
insertTrackPointIfNewer(track, lastTrackPoint);
}
insertTrackPoint(track, TrackPoint.createSegmentEnd());
} }
insertTrackPoint(track, TrackPoint.createSegmentEnd());
// Update the recording track time
updateTrackTotalTime(track);
} }
Track track = contentProviderUtils.getTrack(trackId);
ExportUtils.postWorkoutExport(this, track, new ExportServiceResultReceiver(new Handler(), this)); ExportUtils.postWorkoutExport(this, track, new ExportServiceResultReceiver(new Handler(), this));
endRecording(true); endRecording(true);
@@ -663,7 +666,9 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
} }
contentProviderUtils.insertTrackPoint(trackPoint, track.getId()); contentProviderUtils.insertTrackPoint(trackPoint, track.getId());
trackStatisticsUpdater.addTrackPoint(trackPoint, recordingDistanceInterval); trackStatisticsUpdater.addTrackPoint(trackPoint, recordingDistanceInterval);
updateTrackTotalTime(track);
track.setTrackStatistics(trackStatisticsUpdater.getTrackStatistics());
contentProviderUtils.updateTrack(track);
} catch (SQLiteException e) { } catch (SQLiteException e) {
/* /*
* Insert failed, most likely because of SqlLite error code 5 (SQLite_BUSY). * Insert failed, most likely because of SqlLite error code 5 (SQLite_BUSY).
@@ -674,17 +679,6 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
voiceExecutor.update(); voiceExecutor.update();
} }
/**
* Updates the recording track time.
*
* @param track the track
*/
private void updateTrackTotalTime(Track track) {
trackStatisticsUpdater.updateTime(Instant.now());
track.setTrackStatistics(trackStatisticsUpdater.getTrackStatistics());
contentProviderUtils.updateTrack(track);
}
SensorDataSet getSensorDataSet() { SensorDataSet getSensorDataSet() {
if (remoteSensorManager == null) { if (remoteSensorManager == null) {
return null; return null;
@@ -22,7 +22,6 @@ import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
import java.time.Duration; import java.time.Duration;
import java.time.Instant;
import de.dennisguse.opentracks.content.data.TrackPoint; import de.dennisguse.opentracks.content.data.TrackPoint;
import de.dennisguse.opentracks.content.provider.TrackPointIterator; import de.dennisguse.opentracks.content.provider.TrackPointIterator;
@@ -91,11 +90,6 @@ public class TrackStatisticsUpdater {
trackInitialized = true; trackInitialized = true;
} }
public void updateTime(Instant time) {
currentSegment.setStopTime(time);
currentSegment.setTotalTime(Duration.between(currentSegment.getStartTime(), time));
}
public TrackStatistics getTrackStatistics() { public TrackStatistics getTrackStatistics() {
// Take a snapshot - we don't want anyone messing with our trackStatistics // Take a snapshot - we don't want anyone messing with our trackStatistics
TrackStatistics stats = new TrackStatistics(trackStatistics); TrackStatistics stats = new TrackStatistics(trackStatistics);
@@ -120,7 +114,9 @@ public class TrackStatisticsUpdater {
} }
// Always update time // Always update time
updateTime(trackPoint.getTime()); currentSegment.setStopTime(trackPoint.getTime());
currentSegment.setTotalTime(Duration.between(currentSegment.getStartTime(), trackPoint.getTime()));
if (trackPoint.isSegmentStart() || trackPoint.isSegmentEnd()) { if (trackPoint.isSegmentStart() || trackPoint.isSegmentEnd()) {
if (trackPoint.isSegmentEnd()) { if (trackPoint.isSegmentEnd()) {
if (lastTrackPoint != null && lastMovingTrackPoint != null && lastTrackPoint != lastMovingTrackPoint) { if (lastTrackPoint != null && lastMovingTrackPoint != null && lastTrackPoint != lastMovingTrackPoint) {
@@ -240,9 +236,6 @@ public class TrackStatisticsUpdater {
return newAverage - oldAverage; return newAverage - oldAverage;
} }
/**
* Returns true if the speed is valid.
*/
private boolean isValidSpeed(@NonNull TrackPoint trackPoint, @NonNull TrackPoint lastTrackPoint) { private boolean isValidSpeed(@NonNull TrackPoint trackPoint, @NonNull TrackPoint lastTrackPoint) {
// There are a lot of noisy speed readings. Do the cheapest checks first, most expensive last. // There are a lot of noisy speed readings. Do the cheapest checks first, most expensive last.
if (trackPoint.getSpeed() == 0) { if (trackPoint.getSpeed() == 0) {