Use a non-static Binder for TrackRecordingService.

Fixes #98.
This commit is contained in:
Dennis Guse
2021-04-04 21:37:12 +02:00
parent 1c6012596e
commit 1e518a4c35
16 changed files with 102 additions and 309 deletions
@@ -40,9 +40,9 @@ import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
import de.dennisguse.opentracks.databinding.MarkerListBinding;
import de.dennisguse.opentracks.fragments.DeleteMarkerDialogFragment;
import de.dennisguse.opentracks.fragments.DeleteMarkerDialogFragment.DeleteMarkerCaller;
import de.dennisguse.opentracks.services.TrackRecordingServiceStatus;
import de.dennisguse.opentracks.services.TrackRecordingService;
import de.dennisguse.opentracks.services.TrackRecordingServiceConnection;
import de.dennisguse.opentracks.services.TrackRecordingServiceInterface;
import de.dennisguse.opentracks.services.TrackRecordingServiceStatus;
import de.dennisguse.opentracks.util.ActivityUtils;
import de.dennisguse.opentracks.util.IntentUtils;
@@ -73,7 +73,7 @@ public class MarkerListActivity extends AbstractActivity implements DeleteMarker
private final Runnable bindCallback = new Runnable() {
@Override
public void run() {
TrackRecordingServiceInterface service = trackRecordingServiceConnection.getServiceIfBound();
TrackRecordingService service = trackRecordingServiceConnection.getServiceIfBound();
if (service != null) {
service.addListener(MarkerListActivity.this);
}
@@ -27,8 +27,8 @@ import android.view.accessibility.AccessibilityEvent;
import java.time.Duration;
import de.dennisguse.opentracks.databinding.TrackControllerBinding;
import de.dennisguse.opentracks.services.TrackRecordingService;
import de.dennisguse.opentracks.services.TrackRecordingServiceConnection;
import de.dennisguse.opentracks.services.TrackRecordingServiceInterface;
import de.dennisguse.opentracks.util.ActivityUtils;
import de.dennisguse.opentracks.util.StringUtils;
import de.dennisguse.opentracks.util.UnitConversions;
@@ -221,7 +221,7 @@ public class TrackController implements View.OnTouchListener {
}
private void updateTotalTime() {
TrackRecordingServiceInterface trackRecordingService = trackRecordingServiceConnection.getServiceIfBound();
TrackRecordingService trackRecordingService = trackRecordingServiceConnection.getServiceIfBound();
if (trackRecordingService != null) {
totalTime = trackRecordingService.getTotalTime();
}
@@ -52,9 +52,9 @@ import de.dennisguse.opentracks.content.data.Track;
import de.dennisguse.opentracks.content.data.TracksColumns;
import de.dennisguse.opentracks.databinding.TrackListBinding;
import de.dennisguse.opentracks.fragments.ConfirmDeleteDialogFragment;
import de.dennisguse.opentracks.services.TrackRecordingServiceStatus;
import de.dennisguse.opentracks.services.TrackRecordingService;
import de.dennisguse.opentracks.services.TrackRecordingServiceConnection;
import de.dennisguse.opentracks.services.TrackRecordingServiceInterface;
import de.dennisguse.opentracks.services.TrackRecordingServiceStatus;
import de.dennisguse.opentracks.services.handlers.GpsStatusValue;
import de.dennisguse.opentracks.settings.SettingsActivity;
import de.dennisguse.opentracks.util.ActivityUtils;
@@ -134,7 +134,7 @@ public class TrackListActivity extends AbstractListActivity implements ConfirmDe
// After binding changes (e.g., becomes available), update the total time in trackController.
runOnUiThread(() -> trackController.update(isRecording(), recordingTrackPaused));
TrackRecordingServiceInterface service = trackRecordingServiceConnection.getServiceIfBound();
TrackRecordingService service = trackRecordingServiceConnection.getServiceIfBound();
if (service == null) {
Log.d(TAG, "service not available to start gps or a new recording");
gpsStatusValue = GpsStatusValue.GPS_NONE;
@@ -150,7 +150,7 @@ public class TrackListActivity extends AbstractListActivity implements ConfirmDe
return;
}
service.startGps();
service.tryStartGps();
gpsStatusValue = GpsStatusValue.GPS_ENABLED;
updateGpsMenuItem(true, isRecording());
}
@@ -325,9 +325,9 @@ public class TrackListActivity extends AbstractListActivity implements ConfirmDe
trackRecordingServiceConnection.startAndBind(this);
bindChangedCallback.run();
} else {
TrackRecordingServiceInterface trackRecordingService = trackRecordingServiceConnection.getServiceIfBound();
TrackRecordingService trackRecordingService = trackRecordingServiceConnection.getServiceIfBound();
if (trackRecordingService != null) {
trackRecordingService.stopGps();
trackRecordingService.stopGpsAndShutdown();
}
trackRecordingServiceConnection.unbindAndStop(this);
}
@@ -40,9 +40,9 @@ import de.dennisguse.opentracks.fragments.ChartFragment;
import de.dennisguse.opentracks.fragments.ConfirmDeleteDialogFragment;
import de.dennisguse.opentracks.fragments.IntervalsFragment;
import de.dennisguse.opentracks.fragments.StatisticsRecordedFragment;
import de.dennisguse.opentracks.services.TrackRecordingServiceStatus;
import de.dennisguse.opentracks.services.TrackRecordingService;
import de.dennisguse.opentracks.services.TrackRecordingServiceConnection;
import de.dennisguse.opentracks.services.TrackRecordingServiceInterface;
import de.dennisguse.opentracks.services.TrackRecordingServiceStatus;
import de.dennisguse.opentracks.settings.SettingsActivity;
import de.dennisguse.opentracks.util.IntentDashboardUtils;
import de.dennisguse.opentracks.util.IntentUtils;
@@ -77,7 +77,7 @@ public class TrackRecordedActivity extends AbstractListActivity implements Confi
private final Runnable bindCallback = new Runnable() {
@Override
public void run() {
TrackRecordingServiceInterface service = trackRecordingServiceConnection.getServiceIfBound();
TrackRecordingService service = trackRecordingServiceConnection.getServiceIfBound();
if (service != null) {
service.addListener(TrackRecordedActivity.this);
}
@@ -26,9 +26,9 @@ import de.dennisguse.opentracks.fragments.ChartFragment;
import de.dennisguse.opentracks.fragments.ChooseActivityTypeDialogFragment;
import de.dennisguse.opentracks.fragments.IntervalsFragment;
import de.dennisguse.opentracks.fragments.StatisticsRecordingFragment;
import de.dennisguse.opentracks.services.TrackRecordingServiceStatus;
import de.dennisguse.opentracks.services.TrackRecordingService;
import de.dennisguse.opentracks.services.TrackRecordingServiceConnection;
import de.dennisguse.opentracks.services.TrackRecordingServiceInterface;
import de.dennisguse.opentracks.services.TrackRecordingServiceStatus;
import de.dennisguse.opentracks.settings.SettingsActivity;
import de.dennisguse.opentracks.util.IntentDashboardUtils;
import de.dennisguse.opentracks.util.IntentUtils;
@@ -71,7 +71,7 @@ public class TrackRecordingActivity extends AbstractActivity implements ChooseAc
// After binding changes (is available), update the total time in trackController.
runOnUiThread(() -> trackController.update(true, recordingTrackPaused));
TrackRecordingServiceInterface service = trackRecordingServiceConnection.getServiceIfBound();
TrackRecordingService service = trackRecordingServiceConnection.getServiceIfBound();
if (service == null) {
Log.d(TAG, "could not get TrackRecordingService");
return;
@@ -38,9 +38,9 @@ import de.dennisguse.opentracks.content.data.TrackPointsColumns;
import de.dennisguse.opentracks.content.data.TracksColumns;
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
import de.dennisguse.opentracks.content.provider.TrackPointIterator;
import de.dennisguse.opentracks.services.TrackRecordingServiceStatus;
import de.dennisguse.opentracks.services.TrackRecordingService;
import de.dennisguse.opentracks.services.TrackRecordingServiceConnection;
import de.dennisguse.opentracks.services.TrackRecordingServiceInterface;
import de.dennisguse.opentracks.services.TrackRecordingServiceStatus;
/**
* Track data hub.
@@ -93,7 +93,7 @@ public class TrackDataHub implements TrackRecordingServiceStatus.Listener {
private ContentObserver trackPointsTableObserver;
private final Runnable bindCallback = () -> {
TrackRecordingServiceInterface service = trackRecordingServiceConnection.getServiceIfBound();
TrackRecordingService service = trackRecordingServiceConnection.getServiceIfBound();
if (service != null) {
service.addListener(TrackDataHub.this);
}
@@ -30,8 +30,8 @@ import de.dennisguse.opentracks.content.data.TrackPoint;
import de.dennisguse.opentracks.content.sensor.SensorDataCycling;
import de.dennisguse.opentracks.content.sensor.SensorDataSet;
import de.dennisguse.opentracks.databinding.StatisticsRecordingBinding;
import de.dennisguse.opentracks.services.TrackRecordingService;
import de.dennisguse.opentracks.services.TrackRecordingServiceConnection;
import de.dennisguse.opentracks.services.TrackRecordingServiceInterface;
import de.dennisguse.opentracks.stats.TrackStatistics;
import de.dennisguse.opentracks.util.PreferencesUtils;
import de.dennisguse.opentracks.util.StringUtils;
@@ -306,12 +306,12 @@ public class StatisticsRecordingFragment extends Fragment implements TrackDataLi
* Also sets altitude gain and loss.
*/
private void updateSensorDataUI() {
TrackRecordingServiceInterface trackRecordingService = trackRecordingServiceConnection.getServiceIfBound();
TrackRecordingService trackRecordingService = trackRecordingServiceConnection.getServiceIfBound();
if (trackRecordingService == null) {
Log.d(TAG, "Cannot get the track recording service.");
} else {
SensorDataSet sensorDataSet = trackRecordingService.getSensorData();
SensorDataSet sensorDataSet = trackRecordingService.getSensorDataSet();
if (sensorDataSet != null) {
List<SensorDataModel> sensorDataList = new ArrayList<>();
if (sensorDataSet.getHeartRate() != null) {
@@ -438,7 +438,7 @@ public class StatisticsRecordingFragment extends Fragment implements TrackDataLi
private void updateTotalTime() {
Duration totalTime = lastTrackStatistics.getTotalTime();
if (isSelectedTrackRecording()) {
TrackRecordingServiceInterface trackRecordingService = trackRecordingServiceConnection.getServiceIfBound();
TrackRecordingService trackRecordingService = trackRecordingServiceConnection.getServiceIfBound();
if (trackRecordingService != null) {
totalTime = trackRecordingService.getTotalTime();
}
@@ -27,7 +27,6 @@ import android.database.sqlite.SQLiteException;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.PowerManager.WakeLock;
import android.util.Log;
@@ -115,7 +114,7 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
private TrackPoint lastTrackPoint;
private boolean isIdle;
private TrackRecordingServiceBinder binder = new TrackRecordingServiceBinder(this);
private final Binder binder = new Binder();
private HandlerServer handlerServer;
@@ -143,7 +142,7 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
}
@Override
public IBinder onBind(Intent intent) {
public Binder onBind(Intent intent) {
return binder;
}
@@ -178,9 +177,6 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
contentProviderUtils = null;
binder.detachFromService();
binder = null;
// This should be the next to last operation
wakeLock = SystemUtils.releaseWakeLock(wakeLock);
@@ -255,7 +251,7 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
*
* @return the track id
*/
Track.Id startNewTrack() {
public Track.Id startNewTrack() {
if (isRecording()) {
Log.d(TAG, "Ignore startNewTrack. Already recording.");
return null;
@@ -295,7 +291,7 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
*
* @param trackId the id of the track to be resumed.
*/
void resumeTrack(Track.Id trackId) {
public void resumeTrack(Track.Id trackId) {
Track track = contentProviderUtils.getTrack(trackId);
if (track == null) {
Log.e(TAG, "Ignore resumeTrack. Track " + trackId.getId() + " does not exists.");
@@ -314,7 +310,8 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
startRecording();
}
void resumeCurrentTrack() {
@VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
public void resumeCurrentTrack() {
if (!isRecording() || !isPaused()) {
Log.d(TAG, "Ignore resumeCurrentTrack. Not recording or not paused.");
return;
@@ -352,7 +349,7 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
voiceExecutor.restore();
}
void tryStartGps() {
public void tryStartGps() {
if (isRecording()) return;
startGps();
@@ -364,7 +361,8 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
showNotification(true);
}
Track.Id endCurrentTrack() {
@VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
public Track.Id endCurrentTrack() {
if (!isRecording()) {
Log.d(TAG, "Ignore endCurrentTrack. Not recording.");
return null;
@@ -397,7 +395,8 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
return trackId;
}
void pauseCurrentTrack() {
@VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
public void pauseCurrentTrack() {
if (!isRecording() || isPaused()) {
Log.d(TAG, "Ignore pauseCurrentTrack. Not recording or paused.");
return;
@@ -446,6 +445,10 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
stopGps(trackStopped);
}
public void stopGpsAndShutdown() {
stopGps(true);
}
/**
* Stops gps.
*
@@ -616,7 +619,7 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
voiceExecutor.update();
}
SensorDataSet getSensorDataSet() {
public SensorDataSet getSensorDataSet() {
if (remoteSensorManager == null) {
return null;
}
@@ -634,7 +637,7 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
/**
* Returns the relative altitude gain (since last trackpoint).
*/
Float getAltitudeGain_m() {
public Float getAltitudeGain_m() {
if (altitudeSumManager == null || !altitudeSumManager.isConnected()) {
return null;
}
@@ -645,7 +648,7 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
/**
* Returns the relative altitude loss (since last trackpoint).
*/
Float getAltitudeLoss_m() {
public Float getAltitudeLoss_m() {
if (altitudeSumManager == null || !altitudeSumManager.isConnected()) {
return null;
}
@@ -702,4 +705,14 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
}
}
}
public class Binder extends android.os.Binder {
private Binder() {
super();
}
public TrackRecordingService getService() {
return TrackRecordingService.this;
}
}
}
@@ -1,129 +0,0 @@
package de.dennisguse.opentracks.services;
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
import java.time.Duration;
import de.dennisguse.opentracks.content.data.Marker;
import de.dennisguse.opentracks.content.data.Track;
import de.dennisguse.opentracks.content.data.TrackPoint;
import de.dennisguse.opentracks.content.sensor.SensorDataSet;
import de.dennisguse.opentracks.services.handlers.GpsStatusValue;
import de.dennisguse.opentracks.services.sensors.BluetoothRemoteSensorManager;
/**
* TODO: There is a bug in Android that leaks Binder instances. This bug is
* especially visible if we have a non-static class, as there is no way to
* nullify reference to the outer class (the service). A workaround is to use
* a static class and explicitly clear service and detach it from the
* underlying Binder. With this approach, we minimize the leak to 24 bytes per
* each service instance. For more details, see the following bug:
* http://code.google.com/p/android/issues/detail?id=6426.
*/
class TrackRecordingServiceBinder extends android.os.Binder implements TrackRecordingServiceInterface {
private TrackRecordingService trackRecordingService;
TrackRecordingServiceBinder(TrackRecordingService trackRecordingService) {
this.trackRecordingService = trackRecordingService;
}
@Override
public void addListener(@NonNull TrackRecordingServiceStatus.Listener listener) {
trackRecordingService.addListener(listener);
}
@Override
public GpsStatusValue getGpsStatus() {
return trackRecordingService.getGpsStatus();
}
@Override
public void startGps() {
trackRecordingService.tryStartGps();
}
public void stopGps() {
trackRecordingService.stopGps(true);
}
@Override
public Track.Id startNewTrack() {
return trackRecordingService.startNewTrack();
}
@Override
public void resumeTrack(Track.Id trackId) {
trackRecordingService.resumeTrack(trackId);
}
@Override
public void pauseCurrentTrack() {
trackRecordingService.pauseCurrentTrack();
}
@Override
public void resumeCurrentTrack() {
trackRecordingService.resumeCurrentTrack();
}
@Override
public Track.Id endCurrentTrack() {
return trackRecordingService.endCurrentTrack();
}
@Override
public boolean isRecording() {
return trackRecordingService.isRecording();
}
@Override
public boolean isPaused() {
return trackRecordingService.isPaused();
}
@Override
public Duration getTotalTime() {
return trackRecordingService.getTotalTime();
}
@Override
public Marker.Id insertMarker(String name, String category, String description, String photoUrl) {
return trackRecordingService.insertMarker(name, category, description, photoUrl);
}
@Override
public SensorDataSet getSensorData() {
return trackRecordingService.getSensorDataSet();
}
@Override
public Float getAltitudeGain_m() {
return trackRecordingService.getAltitudeGain_m();
}
@Override
public Float getAltitudeLoss_m() {
return trackRecordingService.getAltitudeLoss_m();
}
@VisibleForTesting
@Override
public void setRemoteSensorManager(BluetoothRemoteSensorManager remoteSensorManager) {
trackRecordingService.setRemoteSensorManager(remoteSensorManager);
}
/**
* Detaches from the track recording service. Clears the reference to the
* outer class to minimize the leak.
*/
void detachFromService() {
trackRecordingService = null;
}
@VisibleForTesting
@Override
public void newTrackPoint(TrackPoint trackPoint, int recordingGpsAccuracy) {
trackRecordingService.newTrackPoint(trackPoint, recordingGpsAccuracy);
}
}
@@ -46,7 +46,7 @@ public class TrackRecordingServiceConnection implements ServiceConnection, Death
private final Runnable callback;
private TrackRecordingServiceInterface trackRecordingService;
private TrackRecordingService trackRecordingService;
public TrackRecordingServiceConnection() {
callback = null;
@@ -120,7 +120,7 @@ public class TrackRecordingServiceConnection implements ServiceConnection, Death
/**
* Gets the track recording service if bound. Returns null otherwise
*/
public TrackRecordingServiceInterface getServiceIfBound() {
public TrackRecordingService getServiceIfBound() {
return trackRecordingService;
}
@@ -129,7 +129,7 @@ public class TrackRecordingServiceConnection implements ServiceConnection, Death
*
* @param value the value
*/
private void setTrackRecordingService(TrackRecordingServiceInterface value) {
private void setTrackRecordingService(TrackRecordingService value) {
trackRecordingService = value;
if (callback != null) {
callback.run();
@@ -144,7 +144,7 @@ public class TrackRecordingServiceConnection implements ServiceConnection, Death
} catch (RemoteException e) {
Log.e(TAG, "Failed to bind a death recipient.", e);
}
setTrackRecordingService((TrackRecordingServiceInterface) service);
setTrackRecordingService(((TrackRecordingService.Binder) service).getService());
}
@Override
@@ -163,7 +163,7 @@ public class TrackRecordingServiceConnection implements ServiceConnection, Death
* Resumes the recording track.
*/
public void resumeTrack() {
TrackRecordingServiceInterface service = getServiceIfBound();
TrackRecordingService service = getServiceIfBound();
if (service != null) {
service.resumeCurrentTrack();
}
@@ -173,7 +173,7 @@ public class TrackRecordingServiceConnection implements ServiceConnection, Death
* Pauses the recording track.
*/
public void pauseTrack() {
TrackRecordingServiceInterface service = getServiceIfBound();
TrackRecordingService service = getServiceIfBound();
if (service != null) {
service.pauseCurrentTrack();
}
@@ -185,7 +185,7 @@ public class TrackRecordingServiceConnection implements ServiceConnection, Death
* @return the id of the marker or null if none could be created.
*/
public Marker.Id addMarker(Context context, String name, String category, String description, String photoUrl) {
TrackRecordingServiceInterface trackRecordingService = getServiceIfBound();
TrackRecordingService trackRecordingService = getServiceIfBound();
if (trackRecordingService == null) {
Log.d(TAG, "Unable to add marker, no track recording service");
} else {
@@ -205,7 +205,7 @@ public class TrackRecordingServiceConnection implements ServiceConnection, Death
}
public void stopRecording(@NonNull Context context) {
TrackRecordingServiceInterface trackRecordingService = getServiceIfBound();
TrackRecordingService trackRecordingService = getServiceIfBound();
if (trackRecordingService == null) {
Log.e(TAG, "TrackRecordingService not connected.");
} else {
@@ -1,107 +0,0 @@
/*
* Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package de.dennisguse.opentracks.services;
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
import java.time.Duration;
import de.dennisguse.opentracks.content.data.Marker;
import de.dennisguse.opentracks.content.data.Track;
import de.dennisguse.opentracks.content.data.TrackPoint;
import de.dennisguse.opentracks.content.sensor.SensorDataSet;
import de.dennisguse.opentracks.services.handlers.GpsStatusValue;
import de.dennisguse.opentracks.services.sensors.BluetoothRemoteSensorManager;
/**
* App's service.
* This service is the process that actually records and manages tracks.
*/
public interface TrackRecordingServiceInterface {
void startGps();
void stopGps();
Track.Id startNewTrack();
void pauseCurrentTrack();
void resumeCurrentTrack();
void resumeTrack(Track.Id trackId);
/**
* End current track.
*
* @return the Track.Id of the track that is ended.
*/
Track.Id endCurrentTrack();
boolean isRecording();
/**
* Returns true if the current recording track is paused. Returns true if not recording.
*/
boolean isPaused();
/**
* Gets the total time for the current recording track. Returns 0 if not recording.
*/
Duration getTotalTime();
Marker.Id insertMarker(String name, String category, String description, String photoUrl);
/**
* Gets the current sensor data.
*
* @return SensorDataSet object or null.
*/
SensorDataSet getSensorData();
/**
* Gets the current altitude gain.
*
* @return altitude gain in m or null.
*/
Float getAltitudeGain_m();
/**
* Gets the current altitude loss.
*
* @return altitude loss in m or null.
*/
Float getAltitudeLoss_m();
@VisibleForTesting
void setRemoteSensorManager(BluetoothRemoteSensorManager remoteSensorManager);
/**
* Inserts a track point in the current recording track.
* This is used for inserting special track points or for testing.
*
* @param trackPoint the track point object to be inserted.
* @param recordingGpsAccuracy recording GPS accuracy.
*/
@Deprecated //REMOVE
@VisibleForTesting
void newTrackPoint(TrackPoint trackPoint, int recordingGpsAccuracy);
void addListener(@NonNull TrackRecordingServiceStatus.Listener listener);
GpsStatusValue getGpsStatus();
}
@@ -23,9 +23,9 @@ import de.dennisguse.opentracks.R;
import de.dennisguse.opentracks.content.data.Track;
import de.dennisguse.opentracks.fragments.ChooseActivityTypeDialogFragment;
import de.dennisguse.opentracks.io.file.TrackFileFormat;
import de.dennisguse.opentracks.services.TrackRecordingServiceStatus;
import de.dennisguse.opentracks.services.TrackRecordingService;
import de.dennisguse.opentracks.services.TrackRecordingServiceConnection;
import de.dennisguse.opentracks.services.TrackRecordingServiceInterface;
import de.dennisguse.opentracks.services.TrackRecordingServiceStatus;
import de.dennisguse.opentracks.settings.bluetooth.BluetoothLeCyclingCadenceAndSpeedPreference;
import de.dennisguse.opentracks.settings.bluetooth.BluetoothLeCyclingPowerPreference;
import de.dennisguse.opentracks.settings.bluetooth.BluetoothLeHeartRatePreference;
@@ -112,7 +112,7 @@ public class SettingsActivity extends AbstractActivity implements ChooseActivity
private final Runnable bindServiceCallback = new Runnable() {
@Override
public void run() {
TrackRecordingServiceInterface service = trackRecordingServiceConnection.getServiceIfBound();
TrackRecordingService service = trackRecordingServiceConnection.getServiceIfBound();
if (service != null) {
service.addListener(PrefsFragment.this);
}