TrackRecordingService: must be stopped via TrackRecordingServiceConnection and handles Preference changes.

This commit is contained in:
Dennis Guse
2023-08-08 23:22:35 +02:00
parent 0a5b46655a
commit 4d5c59be96
10 changed files with 96 additions and 101 deletions
+1
View File
@@ -53,6 +53,7 @@ captures/
.idea/.name .idea/.name
.idea/caches/ .idea/caches/
.idea/compiler.xml .idea/compiler.xml
.idea/androidTestResultsUserPreferences.xml
.idea/copyright/profiles_settings.xml .idea/copyright/profiles_settings.xml
.idea/dataSources.ids .idea/dataSources.ids
.idea/datasources.xml .idea/datasources.xml
@@ -132,7 +132,7 @@ public class TrackRecordingServiceStateMachineTest {
assertEquals(GpsStatusValue.GPS_ENABLED, service.getGpsStatusObservable().getValue()); assertEquals(GpsStatusValue.GPS_ENABLED, service.getGpsStatusObservable().getValue());
// when // when
service.stopSensorsAndShutdown(); service.stopSensors();
Thread.sleep(1000); Thread.sleep(1000);
// then // then
@@ -177,7 +177,7 @@ public class TrackRecordingServiceStateMachineTest {
// then // then
assertFalse(service.isRecording()); assertFalse(service.isRecording());
assertEquals(TrackRecordingService.STATUS_DEFAULT, service.getRecordingStatusObservable().getValue()); assertEquals(TrackRecordingService.STATUS_DEFAULT, service.getRecordingStatusObservable().getValue());
assertEquals(TrackRecordingService.NOT_RECORDING, service.getRecordingDataObservable().getValue()); assertNotEquals(TrackRecordingService.NOT_RECORDING, service.getRecordingDataObservable().getValue());
assertEquals(GpsStatusValue.GPS_NONE, service.getGpsStatusObservable().getValue()); assertEquals(GpsStatusValue.GPS_NONE, service.getGpsStatusObservable().getValue());
@@ -47,7 +47,7 @@ import de.dennisguse.opentracks.util.PermissionRequester;
* *
* @author Sandor Dornbush * @author Sandor Dornbush
*/ */
public class BluetoothRemoteSensorManager implements SensorConnector, AbstractBluetoothConnectionManager.SensorDataObserver { public class BluetoothRemoteSensorManager implements SensorConnector, AbstractBluetoothConnectionManager.SensorDataObserver, SharedPreferences.OnSharedPreferenceChangeListener {
private static final String TAG = BluetoothRemoteSensorManager.class.getSimpleName(); private static final String TAG = BluetoothRemoteSensorManager.class.getSimpleName();
@@ -65,39 +65,6 @@ public class BluetoothRemoteSensorManager implements SensorConnector, AbstractBl
private final BluetoothConnectionManagerCyclingPower cyclingPower = new BluetoothConnectionManagerCyclingPower(this); private final BluetoothConnectionManagerCyclingPower cyclingPower = new BluetoothConnectionManagerCyclingPower(this);
private final BluetoothConnectionRunningSpeedAndCadence runningSpeedAndCadence = new BluetoothConnectionRunningSpeedAndCadence(this); private final BluetoothConnectionRunningSpeedAndCadence runningSpeedAndCadence = new BluetoothConnectionRunningSpeedAndCadence(this);
private final SharedPreferences.OnSharedPreferenceChangeListener sharedPreferenceChangeListener = (sharedPreferences, key) -> {
if (!started) return;
if (PreferencesUtils.isKey(R.string.settings_sensor_bluetooth_heart_rate_key, key)) {
String address = PreferencesUtils.getBluetoothHeartRateSensorAddress();
connect(heartRate, address);
}
if (PreferencesUtils.isKey(R.string.settings_sensor_bluetooth_cycling_cadence_key, key)) {
String address = PreferencesUtils.getBluetoothCyclingCadenceSensorAddress();
connect(cyclingCadence, address);
}
if (PreferencesUtils.isKey(R.string.settings_sensor_bluetooth_cycling_speed_key, key)) {
String address = PreferencesUtils.getBluetoothCyclingSpeedSensorAddress();
connect(cyclingSpeed, address);
}
if (PreferencesUtils.isKey(R.string.settings_sensor_bluetooth_cycling_power_key, key)) {
String address = PreferencesUtils.getBluetoothCyclingPowerSensorAddress();
connect(cyclingPower, address);
}
if (PreferencesUtils.isKey(R.string.settings_sensor_bluetooth_running_speed_and_cadence_key, key)) {
String address = PreferencesUtils.getBluetoothRunningSpeedAndCadenceAddress();
connect(runningSpeedAndCadence, address);
}
};
public BluetoothRemoteSensorManager(@NonNull Context context, @NonNull Handler handler, @Nullable SensorManager.SensorDataChangedObserver observer) { public BluetoothRemoteSensorManager(@NonNull Context context, @NonNull Handler handler, @Nullable SensorManager.SensorDataChangedObserver observer) {
this.context = context; this.context = context;
this.handler = handler; this.handler = handler;
@@ -109,8 +76,8 @@ public class BluetoothRemoteSensorManager implements SensorConnector, AbstractBl
public void start(Context context, Handler handler) { public void start(Context context, Handler handler) {
started = true; started = true;
//Registering triggers connection startup // Triggers connection startup
PreferencesUtils.registerOnSharedPreferenceChangeListener(sharedPreferenceChangeListener); onSharedPreferenceChanged(null, null);
} }
@Override @Override
@@ -121,7 +88,6 @@ public class BluetoothRemoteSensorManager implements SensorConnector, AbstractBl
cyclingPower.disconnect(); cyclingPower.disconnect();
runningSpeedAndCadence.disconnect(); runningSpeedAndCadence.disconnect();
PreferencesUtils.unregisterOnSharedPreferenceChangeListener(sharedPreferenceChangeListener);
started = false; started = false;
} }
@@ -175,4 +141,37 @@ public class BluetoothRemoteSensorManager implements SensorConnector, AbstractBl
public Handler getHandler() { public Handler getHandler() {
return handler; return handler;
} }
@Override
public void onSharedPreferenceChanged(SharedPreferences unused, @Nullable String key) {
if (!started) return;
if (PreferencesUtils.isKey(R.string.settings_sensor_bluetooth_heart_rate_key, key)) {
String address = PreferencesUtils.getBluetoothHeartRateSensorAddress();
connect(heartRate, address);
}
if (PreferencesUtils.isKey(R.string.settings_sensor_bluetooth_cycling_cadence_key, key)) {
String address = PreferencesUtils.getBluetoothCyclingCadenceSensorAddress();
connect(cyclingCadence, address);
}
if (PreferencesUtils.isKey(R.string.settings_sensor_bluetooth_cycling_speed_key, key)) {
String address = PreferencesUtils.getBluetoothCyclingSpeedSensorAddress();
connect(cyclingSpeed, address);
}
if (PreferencesUtils.isKey(R.string.settings_sensor_bluetooth_cycling_power_key, key)) {
String address = PreferencesUtils.getBluetoothCyclingPowerSensorAddress();
connect(cyclingPower, address);
}
if (PreferencesUtils.isKey(R.string.settings_sensor_bluetooth_running_speed_and_cadence_key, key)) {
String address = PreferencesUtils.getBluetoothRunningSpeedAndCadenceAddress();
connect(runningSpeedAndCadence, address);
}
}
} }
@@ -1,9 +1,11 @@
package de.dennisguse.opentracks.sensors; package de.dennisguse.opentracks.sensors;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences;
import android.os.Handler; import android.os.Handler;
import android.util.Log; import android.util.Log;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
import de.dennisguse.opentracks.data.models.TrackPoint; import de.dennisguse.opentracks.data.models.TrackPoint;
@@ -12,7 +14,7 @@ import de.dennisguse.opentracks.sensors.sensorData.SensorDataSet;
import de.dennisguse.opentracks.services.handlers.GPSManager; import de.dennisguse.opentracks.services.handlers.GPSManager;
import de.dennisguse.opentracks.services.handlers.TrackPointCreator; import de.dennisguse.opentracks.services.handlers.TrackPointCreator;
public class SensorManager { public class SensorManager implements SharedPreferences.OnSharedPreferenceChangeListener {
private static final String TAG = SensorManager.class.getSimpleName(); private static final String TAG = SensorManager.class.getSimpleName();
@@ -49,11 +51,12 @@ public class SensorManager {
public void start(Context context, Handler handler) { public void start(Context context, Handler handler) {
gpsManager = new GPSManager(observer); //TODO Pass listener gpsManager = new GPSManager(observer); //TODO Pass listener
gpsManager.start(context, handler);
altitudeSumManager = new AltitudeSumManager(); altitudeSumManager = new AltitudeSumManager();
bluetoothSensorManager = new BluetoothRemoteSensorManager(context, handler, listener); bluetoothSensorManager = new BluetoothRemoteSensorManager(context, handler, listener);
onSharedPreferenceChanged(null, null);
gpsManager.start(context, handler);
altitudeSumManager.start(context, handler); altitudeSumManager.start(context, handler);
bluetoothSensorManager.start(context, handler); bluetoothSensorManager.start(context, handler);
} }
@@ -114,6 +117,14 @@ public class SensorManager {
this.altitudeSumManager = altitudeSumManager; this.altitudeSumManager = altitudeSumManager;
} }
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, @Nullable String key) {
if (gpsManager != null) {
gpsManager.onSharedPreferenceChanged(sharedPreferences, key);
bluetoothSensorManager.onSharedPreferenceChanged(sharedPreferences, key);
}
}
public interface SensorDataChangedObserver { public interface SensorDataChangedObserver {
void onChange(SensorData<?> sensorData); void onChange(SensorData<?> sensorData);
@@ -58,14 +58,6 @@ class TrackRecordingManager implements SharedPreferences.OnSharedPreferenceChang
contentProviderUtils = new ContentProviderUtils(context); contentProviderUtils = new ContentProviderUtils(context);
} }
public void start() {
PreferencesUtils.registerOnSharedPreferenceChangeListener(this);
}
public void stop() {
PreferencesUtils.unregisterOnSharedPreferenceChangeListener(this);
}
Track.Id startNewTrack() { Track.Id startNewTrack() {
TrackPoint segmentStartTrackPoint = trackPointCreator.createSegmentStartManual(); TrackPoint segmentStartTrackPoint = trackPointCreator.createSegmentStartManual();
// Create new track // Create new track
@@ -18,6 +18,7 @@ package de.dennisguse.opentracks.services;
import android.app.Service; import android.app.Service;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.ServiceInfo; import android.content.pm.ServiceInfo;
import android.os.Build; import android.os.Build;
import android.os.Handler; import android.os.Handler;
@@ -26,6 +27,7 @@ import android.os.PowerManager.WakeLock;
import android.util.Log; import android.util.Log;
import android.util.Pair; import android.util.Pair;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
import androidx.lifecycle.LiveData; import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData; import androidx.lifecycle.MutableLiveData;
@@ -40,9 +42,10 @@ import de.dennisguse.opentracks.sensors.sensorData.SensorDataSet;
import de.dennisguse.opentracks.services.announcement.VoiceAnnouncementManager; import de.dennisguse.opentracks.services.announcement.VoiceAnnouncementManager;
import de.dennisguse.opentracks.services.handlers.GpsStatusValue; import de.dennisguse.opentracks.services.handlers.GpsStatusValue;
import de.dennisguse.opentracks.services.handlers.TrackPointCreator; import de.dennisguse.opentracks.services.handlers.TrackPointCreator;
import de.dennisguse.opentracks.settings.PreferencesUtils;
import de.dennisguse.opentracks.util.SystemUtils; import de.dennisguse.opentracks.util.SystemUtils;
public class TrackRecordingService extends Service implements TrackPointCreator.Callback { public class TrackRecordingService extends Service implements TrackPointCreator.Callback, SharedPreferences.OnSharedPreferenceChangeListener {
private static final String TAG = TrackRecordingService.class.getSimpleName(); private static final String TAG = TrackRecordingService.class.getSimpleName();
@@ -81,7 +84,7 @@ public class TrackRecordingService extends Service implements TrackPointCreator.
private MutableLiveData<RecordingData> recordingDataObservable; private MutableLiveData<RecordingData> recordingDataObservable;
// The following variables are set when recording: // The following variables are set when recording:
private WakeLock wakeLock; private WakeLock wakeLock; //TODO Move to SensorManager
private Handler handler; private Handler handler;
private TrackPointCreator trackPointCreator; private TrackPointCreator trackPointCreator;
@@ -93,6 +96,7 @@ public class TrackRecordingService extends Service implements TrackPointCreator.
@Override @Override
public void onCreate() { public void onCreate() {
super.onCreate(); super.onCreate();
Log.d(TAG, "Create");
handler = new Handler(Looper.getMainLooper()); handler = new Handler(Looper.getMainLooper());
@@ -103,40 +107,39 @@ public class TrackRecordingService extends Service implements TrackPointCreator.
trackPointCreator = new TrackPointCreator(this, this, handler); trackPointCreator = new TrackPointCreator(this, this, handler);
trackRecordingManager = new TrackRecordingManager(this, trackPointCreator); trackRecordingManager = new TrackRecordingManager(this, trackPointCreator);
trackRecordingManager.start();
voiceAnnouncementManager = new VoiceAnnouncementManager(this); voiceAnnouncementManager = new VoiceAnnouncementManager(this);
notificationManager = new TrackRecordingServiceNotificationManager(this); notificationManager = new TrackRecordingServiceNotificationManager(this);
PreferencesUtils.registerOnSharedPreferenceChangeListener(this);
} }
@Override @Override
public void onDestroy() { public void onDestroy() {
trackPointCreator.stop(); Log.d(TAG, "Destroying");
if (isRecording()) {
endCurrentTrack();
}
PreferencesUtils.unregisterOnSharedPreferenceChangeListener(this);
trackPointCreator = null; trackPointCreator = null;
handler.removeCallbacksAndMessages(null); //Some tests do not finish the recording completely handler.removeCallbacksAndMessages(null); //Some tests do not finish the recording completely
handler = null; handler = null;
trackRecordingManager.stop();
trackRecordingManager = null; trackRecordingManager = null;
// Reverse order from onCreate // Reverse order from onCreate
stopForeground(true);
notificationManager.stop();
notificationManager = null; notificationManager = null;
voiceAnnouncementManager.stop();
voiceAnnouncementManager = null; voiceAnnouncementManager = null;
// This should be the next to last operation
wakeLock = SystemUtils.releaseWakeLock(wakeLock);
updateRecordingStatus(STATUS_DEFAULT);
recordingStatusObservable = null; recordingStatusObservable = null;
gpsStatusObservable = null; gpsStatusObservable = null;
recordingDataObservable = null; recordingDataObservable = null;
Log.d(TAG, "Destroyed");
super.onDestroy(); super.onDestroy();
} }
@@ -210,34 +213,15 @@ public class TrackRecordingService extends Service implements TrackPointCreator.
updateRecordingStatus(STATUS_DEFAULT); updateRecordingStatus(STATUS_DEFAULT);
trackRecordingManager.end(); trackRecordingManager.end();
endRecording();
stopSelf();
}
private void endRecording() {
stopUpdateRecordingData(); stopUpdateRecordingData();
recordingDataObservable.postValue(NOT_RECORDING);
voiceAnnouncementManager.stop(); voiceAnnouncementManager.stop();
// Update instance variables
trackPointCreator.stop();
stopSensors(); stopSensors();
} }
public void stopSensorsAndShutdown() {
if (isRecording()) {
return;
}
stopSensors();
stopSelf();
}
void stopSensors() { void stopSensors() {
if (!isRecording()) return;
trackPointCreator.stop(); trackPointCreator.stop();
stopForeground(true); stopForeground(true);
notificationManager.cancelNotification(); notificationManager.cancelNotification();
@@ -258,6 +242,8 @@ public class TrackRecordingService extends Service implements TrackPointCreator.
@Override @Override
public void newGpsStatus(GpsStatusValue gpsStatusValue) { public void newGpsStatus(GpsStatusValue gpsStatusValue) {
Log.e(TAG, "newGpsStatus: " + gpsStatusValue.message);
notificationManager.updateContent(getString(gpsStatusValue.message)); notificationManager.updateContent(getString(gpsStatusValue.message));
gpsStatusObservable.postValue(gpsStatusValue); gpsStatusObservable.postValue(gpsStatusValue);
} }
@@ -291,7 +277,7 @@ public class TrackRecordingService extends Service implements TrackPointCreator.
} }
private void updateRecordingDataWhileRecording() { private void updateRecordingDataWhileRecording() {
if (!recordingStatus.isRecording()) { if (!isRecording()) {
Log.w(TAG, "Currently not recording; cannot update data."); Log.w(TAG, "Currently not recording; cannot update data.");
return; return;
} }
@@ -323,4 +309,12 @@ public class TrackRecordingService extends Service implements TrackPointCreator.
public boolean isRecording() { public boolean isRecording() {
return recordingStatus.isRecording(); return recordingStatus.isRecording();
} }
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, @Nullable String key) {
voiceAnnouncementManager.onSharedPreferenceChanged(sharedPreferences, key);
trackRecordingManager.onSharedPreferenceChanged(sharedPreferences, key);
trackPointCreator.onSharedPreferenceChanged(sharedPreferences, key);
notificationManager.onSharedPreferenceChanged(sharedPreferences, key);
}
} }
@@ -42,7 +42,6 @@ class TrackRecordingServiceNotificationManager implements SharedPreferences.OnSh
private UnitSystem unitSystem = null; private UnitSystem unitSystem = null;
TrackRecordingServiceNotificationManager(Context context) { TrackRecordingServiceNotificationManager(Context context) {
PreferencesUtils.registerOnSharedPreferenceChangeListener(this);
notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel notificationChannel = new NotificationChannel(CHANNEL_ID, context.getString(R.string.app_name), NotificationManager.IMPORTANCE_HIGH); NotificationChannel notificationChannel = new NotificationChannel(CHANNEL_ID, context.getString(R.string.app_name), NotificationManager.IMPORTANCE_HIGH);
@@ -65,7 +64,6 @@ class TrackRecordingServiceNotificationManager implements SharedPreferences.OnSh
void stop() { void stop() {
cancelNotification(); cancelNotification();
PreferencesUtils.unregisterOnSharedPreferenceChangeListener(this);
} }
@VisibleForTesting @VisibleForTesting
@@ -60,7 +60,6 @@ public class VoiceAnnouncementManager implements SharedPreferences.OnSharedPrefe
public VoiceAnnouncementManager(@NonNull TrackRecordingService trackRecordingService) { public VoiceAnnouncementManager(@NonNull TrackRecordingService trackRecordingService) {
this.trackRecordingService = trackRecordingService; this.trackRecordingService = trackRecordingService;
PreferencesUtils.registerOnSharedPreferenceChangeListener(this);
} }
public void start(@Nullable TrackStatistics trackStatistics) { public void start(@Nullable TrackStatistics trackStatistics) {
@@ -106,7 +105,6 @@ public class VoiceAnnouncementManager implements SharedPreferences.OnSharedPrefe
} }
public void stop() { public void stop() {
PreferencesUtils.unregisterOnSharedPreferenceChangeListener(this);
if (voiceAnnouncement != null) { if (voiceAnnouncement != null) {
voiceAnnouncement.stop(); voiceAnnouncement.stop();
voiceAnnouncement = null; voiceAnnouncement = null;
@@ -48,7 +48,8 @@ public class GPSManager implements SensorConnector, LocationListenerCompat, GpsS
this.context = context; this.context = context;
this.handler = handler; this.handler = handler;
PreferencesUtils.registerOnSharedPreferenceChangeListener(this); onSharedPreferenceChanged(null, null);
gpsStatusManager = new GpsStatusManager(context, this, handler); gpsStatusManager = new GpsStatusManager(context, this, handler);
locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
registerLocationListener(); registerLocationListener();
@@ -62,20 +63,15 @@ public class GPSManager implements SensorConnector, LocationListenerCompat, GpsS
@SuppressWarnings({"MissingPermission"}) @SuppressWarnings({"MissingPermission"})
//TODO upgrade to AGP7.0.0/API31 started complaining about removeUpdates. //TODO upgrade to AGP7.0.0/API31 started complaining about removeUpdates.
public void stop(Context context) { public void stop(Context context) {
if (locationManager != null && context != null) { if (locationManager != null) {
if (PermissionRequester.GPS.hasPermission(context)) { LocationManagerCompat.removeUpdates(locationManager, this);
LocationManagerCompat.removeUpdates(locationManager, this);
}
locationManager = null;
context = null;
handler = null;
} }
locationManager = null;
this.context = null;
handler = null;
if (gpsStatusManager != null) { gpsStatusManager.stop();
gpsStatusManager.stop(); gpsStatusManager = null;
gpsStatusManager = null;
}
PreferencesUtils.unregisterOnSharedPreferenceChangeListener(this);
} }
@Override @Override
@@ -1,6 +1,7 @@
package de.dennisguse.opentracks.services.handlers; package de.dennisguse.opentracks.services.handlers;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences;
import android.location.Location; import android.location.Location;
import android.os.Handler; import android.os.Handler;
import android.util.Log; import android.util.Log;
@@ -23,7 +24,7 @@ import de.dennisguse.opentracks.settings.PreferencesUtils;
/** /**
* Creates TrackPoints while recording by fusing data from different sensors (e.g., GNSS, barometer, BLE sensors). * Creates TrackPoints while recording by fusing data from different sensors (e.g., GNSS, barometer, BLE sensors).
*/ */
public class TrackPointCreator { public class TrackPointCreator implements SharedPreferences.OnSharedPreferenceChangeListener {
private static final String TAG = TrackPointCreator.class.getSimpleName(); private static final String TAG = TrackPointCreator.class.getSimpleName();
@@ -150,6 +151,11 @@ public class TrackPointCreator {
service.newGpsStatus(gpsStatusValue); service.newGpsStatus(gpsStatusValue);
} }
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, @Nullable String key) {
sensorManager.onSharedPreferenceChanged(sharedPreferences, key);
}
public interface Callback { public interface Callback {
/** /**
* @return Was TrackPoint stored (not discarded)? * @return Was TrackPoint stored (not discarded)?