From c3741611dc2f5b23f15e98973f20b4f00714571c Mon Sep 17 00:00:00 2001 From: Dennis Guse Date: Thu, 14 Jan 2021 19:38:27 +0100 Subject: [PATCH] TrackStatisticsUpdater updates only by adding TrackPoints. #316. --- .../services/TrackRecordingServiceTest.java | 24 +++++++++ .../opentracks/TrackController.java | 52 +++++++++++-------- .../StatisticsRecordingFragment.java | 24 +++------ .../services/TrackRecordingService.java | 46 +++++++--------- .../stats/TrackStatisticsUpdater.java | 13 ++--- 5 files changed, 82 insertions(+), 77 deletions(-) diff --git a/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceTest.java b/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceTest.java index 024588219..2bb021b73 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceTest.java +++ b/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceTest.java @@ -268,6 +268,30 @@ public class TrackRecordingServiceTest { 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 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.") @MediumTest @Test diff --git a/src/main/java/de/dennisguse/opentracks/TrackController.java b/src/main/java/de/dennisguse/opentracks/TrackController.java index 9d8834224..8c50b71a1 100644 --- a/src/main/java/de/dennisguse/opentracks/TrackController.java +++ b/src/main/java/de/dennisguse/opentracks/TrackController.java @@ -54,7 +54,7 @@ public class TrackController implements View.OnTouchListener { private final TransitionDrawable transition; private boolean isRecording; - private boolean isPaused; + private boolean isRecordingPaused; private Duration totalTime; private boolean isResumed = false; @@ -63,8 +63,9 @@ public class TrackController implements View.OnTouchListener { // A runnable to update the total time. private final Runnable updateTotalTimeRunnable = new Runnable() { public void run() { - if (isResumed && isRecording && !isPaused) { - viewBinding.trackControllerTotalTime.setText(StringUtils.formatElapsedTimeWithHour(totalTime)); + if (isResumed && isRecording && !isRecordingPaused) { + updateTotalTime(); + setTotalTime(); handlerUpdateTotalTime.postDelayed(this, UnitConversions.ONE_SECOND_MS); } } @@ -82,7 +83,7 @@ public class TrackController implements View.OnTouchListener { viewBinding.trackControllerRecord.setOnTouchListener(this); viewBinding.trackControllerRecord.setOnClickListener((view) -> { - if (buttonDelay != null || (isRecording && !isPaused)) { + if (buttonDelay != null || (isRecording && !isRecordingPaused)) { return; } @@ -118,7 +119,7 @@ public class TrackController implements View.OnTouchListener { //To pause a recording if (viewBinding.trackControllerRecord.equals(view) && event.getAction() == MotionEvent.ACTION_DOWN - && isRecording && !isPaused) { + && isRecording && !isRecordingPaused) { transition.startTransition(buttonDelayDuration); @@ -165,10 +166,11 @@ public class TrackController implements View.OnTouchListener { public void update(boolean recording, boolean paused) { if (!isResumed) { + handlerUpdateTotalTime.removeCallbacks(updateTotalTimeRunnable); return; } isRecording = recording; - isPaused = paused; + isRecordingPaused = paused; boolean visible = alwaysShow || isRecording; viewBinding.trackControllerContainer.setVisibility(visible ? View.VISIBLE : View.GONE); @@ -177,27 +179,26 @@ public class TrackController implements View.OnTouchListener { return; } - viewBinding.trackControllerRecord.setImageResource(isRecording && !isPaused ? R.drawable.ic_button_pause : R.drawable.button_record); - viewBinding.trackControllerRecord.setContentDescription(activity.getString(isRecording && !isPaused ? R.string.image_pause : R.string.image_record)); + if (isRecording && !isRecordingPaused) { + 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.trackControllerStatus.setVisibility(isRecording ? View.VISIBLE : View.INVISIBLE); 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(); } - handlerUpdateTotalTime.removeCallbacks(updateTotalTimeRunnable); viewBinding.trackControllerTotalTime.setVisibility(isRecording ? View.VISIBLE : View.INVISIBLE); + if (isRecording) { - totalTime = getTotalTime(); - if (totalTime != null) { - viewBinding.trackControllerTotalTime.setText(StringUtils.formatElapsedTimeWithHour(totalTime)); - } - if (!isPaused) { - handlerUpdateTotalTime.postDelayed(updateTotalTimeRunnable, UnitConversions.ONE_SECOND_MS); - } + updateTotalTime(); + setTotalTime(); } } @@ -219,16 +220,21 @@ public class TrackController implements View.OnTouchListener { viewBinding.trackControllerContainer.setVisibility(View.VISIBLE); } - /** - * Gets the total time for the current recording track. - */ - private Duration getTotalTime() { + private void updateTotalTime() { 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() { - 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 { diff --git a/src/main/java/de/dennisguse/opentracks/fragments/StatisticsRecordingFragment.java b/src/main/java/de/dennisguse/opentracks/fragments/StatisticsRecordingFragment.java index b9e8720c3..1e0e295dd 100644 --- a/src/main/java/de/dennisguse/opentracks/fragments/StatisticsRecordingFragment.java +++ b/src/main/java/de/dennisguse/opentracks/fragments/StatisticsRecordingFragment.java @@ -15,7 +15,6 @@ import androidx.recyclerview.widget.GridLayoutManager; import androidx.recyclerview.widget.RecyclerView; import java.time.Duration; -import java.time.Instant; import java.util.ArrayList; import java.util.List; @@ -409,26 +408,15 @@ public class StatisticsRecordingFragment extends Fragment implements TrackDataLi } private void updateTotalTime() { - Duration totalTime; + Duration totalTime = lastTrackStatistics.getTotalTime(); if (isSelectedTrackRecording()) { - totalTime = calculateTotalTime(); - } else { - totalTime = lastTrackStatistics.getTotalTime(); + TrackRecordingServiceInterface trackRecordingService = trackRecordingServiceConnection.getServiceIfBound(); + if (trackRecordingService != null) { + totalTime = trackRecordingService.getTotalTime(); + } } - 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()); - } + viewBinding.statsTotalTimeValue.setText(StringUtils.formatElapsedTime(totalTime)); } private void setLocationValues() { diff --git a/src/main/java/de/dennisguse/opentracks/services/TrackRecordingService.java b/src/main/java/de/dennisguse/opentracks/services/TrackRecordingService.java index 06f4ae447..2cbf92534 100644 --- a/src/main/java/de/dennisguse/opentracks/services/TrackRecordingService.java +++ b/src/main/java/de/dennisguse/opentracks/services/TrackRecordingService.java @@ -234,10 +234,13 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand if (trackStatisticsUpdater == null) { return Duration.ofSeconds(0); } - if (!isPaused()) { - trackStatisticsUpdater.updateTime(Instant.now()); + if (isPaused()) { + 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) { @@ -420,24 +423,24 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand } // Need to remember the recordingTrackId before setting it to -1L + boolean wasPause = isPaused(); Track.Id trackId = recordingTrackId; - boolean wasPaused = recordingTrackPaused; updateRecordingState(null, true); - // Update database - Track track = contentProviderUtils.getTrack(trackId); - if (track != null) { - if (lastTrackPoint != null) { - insertTrackPointIfNewer(track, lastTrackPoint); + if (!wasPause) { + // Update database + Track track = contentProviderUtils.getTrack(trackId); + if (track != null) { + 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)); endRecording(true); @@ -663,7 +666,9 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand } contentProviderUtils.insertTrackPoint(trackPoint, track.getId()); trackStatisticsUpdater.addTrackPoint(trackPoint, recordingDistanceInterval); - updateTrackTotalTime(track); + + track.setTrackStatistics(trackStatisticsUpdater.getTrackStatistics()); + contentProviderUtils.updateTrack(track); } catch (SQLiteException e) { /* * 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(); } - /** - * 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() { if (remoteSensorManager == null) { return null; diff --git a/src/main/java/de/dennisguse/opentracks/stats/TrackStatisticsUpdater.java b/src/main/java/de/dennisguse/opentracks/stats/TrackStatisticsUpdater.java index af87c041c..0a6b09de1 100644 --- a/src/main/java/de/dennisguse/opentracks/stats/TrackStatisticsUpdater.java +++ b/src/main/java/de/dennisguse/opentracks/stats/TrackStatisticsUpdater.java @@ -22,7 +22,6 @@ import androidx.annotation.NonNull; import androidx.annotation.VisibleForTesting; import java.time.Duration; -import java.time.Instant; import de.dennisguse.opentracks.content.data.TrackPoint; import de.dennisguse.opentracks.content.provider.TrackPointIterator; @@ -91,11 +90,6 @@ public class TrackStatisticsUpdater { trackInitialized = true; } - public void updateTime(Instant time) { - currentSegment.setStopTime(time); - currentSegment.setTotalTime(Duration.between(currentSegment.getStartTime(), time)); - } - public TrackStatistics getTrackStatistics() { // Take a snapshot - we don't want anyone messing with our trackStatistics TrackStatistics stats = new TrackStatistics(trackStatistics); @@ -120,7 +114,9 @@ public class TrackStatisticsUpdater { } // 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.isSegmentEnd()) { if (lastTrackPoint != null && lastMovingTrackPoint != null && lastTrackPoint != lastMovingTrackPoint) { @@ -240,9 +236,6 @@ public class TrackStatisticsUpdater { return newAverage - oldAverage; } - /** - * Returns true if the speed is valid. - */ 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. if (trackPoint.getSpeed() == 0) {