TrackRecordingService: provide status updates via LiveData.

Fixes #719
This commit is contained in:
Dennis Guse
2021-04-29 18:22:35 +02:00
parent 8357b234d2
commit 6723bfb979
12 changed files with 246 additions and 274 deletions
@@ -33,6 +33,8 @@ import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
import androidx.core.app.TaskStackBuilder;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import java.time.Duration;
import java.time.Instant;
@@ -74,6 +76,9 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
private static final String TAG = TrackRecordingService.class.getSimpleName();
public static final RecordingStatus STATUS_DEFAULT = new RecordingStatus(null, false);
public static final GpsStatusValue STATUS_GPS_DEFAULT = GpsStatusValue.GPS_NONE;
// The following variables are set in onCreate:
private ContentProviderUtils contentProviderUtils;
private PeriodicTaskExecutor voiceExecutor;
@@ -119,12 +124,18 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
private HandlerServer handlerServer;
private final TrackRecordingServiceStatus serviceStatus = new TrackRecordingServiceStatus();
private RecordingStatus recordingStatus;
private MutableLiveData<RecordingStatus> recordingStatusObservable;
private MutableLiveData<GpsStatusValue> gpsStatusObservable;
@Override
public void onCreate() {
super.onCreate();
recordingStatusObservable = new MutableLiveData<>();
updateRecordingStatus(STATUS_DEFAULT);
gpsStatusObservable = new MutableLiveData<>(STATUS_GPS_DEFAULT);
handlerServer = new HandlerServer(this);
contentProviderUtils = new ContentProviderUtils(this);
@@ -149,8 +160,6 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
@Override
public void onDestroy() {
serviceStatus.onStop();
handlerServer.stop(this);
handlerServer = null;
@@ -181,19 +190,22 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
// This should be the next to last operation
wakeLock = SystemUtils.releaseWakeLock(wakeLock);
recordingStatusObservable = null;
gpsStatusObservable = null;
super.onDestroy();
}
public boolean isRecording() {
return serviceStatus.isRecording();
return recordingStatus.isRecording();
}
public boolean isPaused() {
return serviceStatus.getRecordingTrackPaused();
return recordingStatus.isPaused();
}
public Track.Id getRecordingTrackId() {
return serviceStatus.getRecordingTrackId();
return recordingStatus.getTrackId();
}
public TrackStatistics getTrackStatistics() {
@@ -223,14 +235,14 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
}
if (name == null) {
Integer nextMarkerNumber = contentProviderUtils.getNextMarkerNumber(serviceStatus.getRecordingTrackId());
Integer nextMarkerNumber = contentProviderUtils.getNextMarkerNumber(getRecordingTrackId());
if (nextMarkerNumber == null) {
nextMarkerNumber = 1;
}
name = getString(R.string.marker_name_format, nextMarkerNumber + 1);
}
TrackPoint trackPoint = getLastValidTrackPointInCurrentSegment(serviceStatus.getRecordingTrackId());
TrackPoint trackPoint = getLastValidTrackPointInCurrentSegment(getRecordingTrackId());
if (trackPoint == null) {
Log.i(TAG, "Could not create a marker as trackPoint is unknown.");
return null;
@@ -244,7 +256,7 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
TrackStatistics stats = trackStatisticsUpdater.getTrackStatistics();
// Insert marker
Marker marker = new Marker(name, description, category, icon, serviceStatus.getRecordingTrackId(), stats, trackPoint, photoUrl);
Marker marker = new Marker(name, description, category, icon, getRecordingTrackId(), stats, trackPoint, photoUrl);
Uri uri = contentProviderUtils.insertMarker(marker);
return new Marker.Id(ContentUris.parseId(uri));
}
@@ -266,7 +278,7 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
Track.Id trackId = new Track.Id(ContentUris.parseId(uri));
// Set recording status
serviceStatus.onChange(trackId, false);
updateRecordingStatus(new RecordingStatus(trackId, false));
// Update database
track.setId(trackId);
@@ -308,7 +320,7 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
insertTrackPoint(track, TrackPoint.createSegmentStartManual());
// Set recording status
serviceStatus.onChange(trackId, false);
updateRecordingStatus(new RecordingStatus(trackId, false));
startRecording();
}
@@ -321,10 +333,10 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
}
// Set recording status
serviceStatus.onChange(false);
updateRecordingStatus(new RecordingStatus(getRecordingTrackId(), false));
// Update database
Track track = contentProviderUtils.getTrack(serviceStatus.getRecordingTrackId());
Track track = contentProviderUtils.getTrack(getRecordingTrackId());
if (track != null) {
insertTrackPoint(track, TrackPoint.createSegmentStartManual());
}
@@ -373,10 +385,10 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
// Need to remember the recordingTrackId before setting it to null
boolean wasPause = isPaused();
Track.Id trackId = serviceStatus.getRecordingTrackId();
Track.Id trackId = getRecordingTrackId();
// Set recording status
serviceStatus.onChange(null, true);
updateRecordingStatus(STATUS_DEFAULT);
if (!wasPause) {
// Update database
@@ -404,10 +416,10 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
}
// Set recording status
serviceStatus.onChange(true);
updateRecordingStatus(new RecordingStatus(getRecordingTrackId(), true));
// Update database
Track track = contentProviderUtils.getTrack(serviceStatus.getRecordingTrackId());
Track track = contentProviderUtils.getTrack(getRecordingTrackId());
if (track != null) {
if (lastTrackPoint != null) {
insertTrackPointIfNewer(track, lastTrackPoint);
@@ -490,7 +502,7 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
return;
}
Track track = contentProviderUtils.getTrack(serviceStatus.getRecordingTrackId());
Track track = contentProviderUtils.getTrack(getRecordingTrackId());
if (track == null) {
Log.w(TAG, "Ignore newTrackPoint. No track.");
return;
@@ -564,17 +576,8 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
@Override
public void newGpsStatus(GpsStatusValue gpsStatusValue) {
notificationManager.updateContent(getString(gpsStatusValue.message));
serviceStatus.onChange(gpsStatusValue);
}
public void addListener(@NonNull TrackRecordingServiceStatus.Listener 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);
gpsStatusObservable.postValue(gpsStatusValue);
}
/**
@@ -666,7 +669,7 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
private void showNotification(boolean isGpsStarted) {
if (isRecording()) {
Intent intent = IntentUtils.newIntent(this, TrackRecordingActivity.class)
.putExtra(TrackRecordingActivity.EXTRA_TRACK_ID, serviceStatus.getRecordingTrackId());
.putExtra(TrackRecordingActivity.EXTRA_TRACK_ID, getRecordingTrackId());
PendingIntent pendingIntent = TaskStackBuilder.create(this)
.addParentStack(TrackRecordingActivity.class)
.addNextIntent(intent)
@@ -702,8 +705,18 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
this.altitudeSumManager = altitudeSumManager;
}
public GpsStatusValue getGpsStatus() {
return handlerServer.getGpsStatus();
public LiveData<GpsStatusValue> getGpsStatusObservable() {
return gpsStatusObservable;
}
public LiveData<RecordingStatus> getRecordingStatusObservable() {
return recordingStatusObservable;
}
private void updateRecordingStatus(RecordingStatus status) {
Log.i(TAG, "new status " + recordingStatus + " -> " + status);
recordingStatus = status;
recordingStatusObservable.postValue(recordingStatus);
}
@Override
@@ -717,6 +730,7 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
}
}
public class Binder extends android.os.Binder {
private Binder() {
@@ -727,4 +741,51 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
return TrackRecordingService.this;
}
}
public static class RecordingStatus {
private final Track.Id trackId;
private final boolean paused;
public RecordingStatus(Track.Id trackId, boolean paused) {
this.trackId = trackId;
this.paused = paused;
}
public Track.Id getTrackId() {
return trackId;
}
public boolean isRecording() {
return trackId != null;
}
public boolean isPaused() {
return paused;
}
public boolean isRecordingAndNotPaused() {
return isRecording() && !isPaused();
}
public RecordingStatus pause() {
return new RecordingStatus(getTrackId(), true);
}
public RecordingStatus record(@NonNull Track.Id track) {
return new RecordingStatus(trackId, false);
}
public RecordingStatus stop() {
return STATUS_DEFAULT;
}
@Override
public String toString() {
return "RecordingStatus{" +
"trackId=" + trackId +
", paused=" + paused +
'}';
}
}
}
@@ -1,83 +0,0 @@
package de.dennisguse.opentracks.services;
import androidx.annotation.NonNull;
import java.util.ArrayList;
import java.util.List;
import de.dennisguse.opentracks.content.data.Track;
import de.dennisguse.opentracks.services.handlers.GpsStatusValue;
/**
* This class handles the status of the recording service.
* Also offer an interface through which to know the recording Track.Id, pause status and GPS status.
*/
public class TrackRecordingServiceStatus {
private Track.Id recordingTrackId;
private boolean recordingTrackPaused;
private final List<Listener> listeners = new ArrayList<>();
void addListener(@NonNull Listener listener) {
if (this.listeners.contains(listener)) {
return;
}
this.listeners.add(listener);
listener.onTrackRecordingId(recordingTrackId);
listener.onTrackRecordingPaused(recordingTrackPaused);
}
void removeListener(@NonNull Listener listener) {
this.listeners.remove(listener);
}
public boolean getRecordingTrackPaused() {
return this.recordingTrackPaused;
}
public Track.Id getRecordingTrackId() {
return this.recordingTrackId;
}
public void onStop() {
for (Listener listener : listeners) {
listener.onGpsStatus(GpsStatusValue.GPS_NONE);
listener.onTrackRecordingId(null);
listener.onTrackRecordingPaused(true);
}
listeners.clear();
}
public boolean isRecording() {
return recordingTrackId != null;
}
void onChange(Track.Id trackId, boolean paused) {
recordingTrackId = trackId;
recordingTrackPaused = paused;
for (Listener listener : listeners) {
listener.onTrackRecordingId(recordingTrackId);
listener.onTrackRecordingPaused(recordingTrackPaused);
}
}
void onChange(boolean paused) {
recordingTrackPaused = paused;
for (Listener listener : listeners) {
listener.onTrackRecordingPaused(recordingTrackPaused);
}
}
void onChange(GpsStatusValue statusValue) {
for (Listener listener : listeners) {
listener.onGpsStatus(statusValue);
}
}
public interface Listener {
default void onGpsStatus(GpsStatusValue newValue) {}
default void onTrackRecordingPaused(boolean paused) {}
default void onTrackRecordingId(Track.Id trackId) {}
}
}
@@ -20,4 +20,8 @@ public enum GpsStatusValue {
this.icon = icon;
this.message = message;
}
public boolean isGpsStarted() {
return this != GpsStatusValue.GPS_NONE && this != GpsStatusValue.GPS_DISABLED;
}
}