From 1e518a4c35527421acd2f021a58a7b42e6cbad37 Mon Sep 17 00:00:00 2001 From: Dennis Guse Date: Sun, 4 Apr 2021 21:37:12 +0200 Subject: [PATCH] Use a non-static Binder for TrackRecordingService. Fixes #98. --- .../io/file/importer/ExportImportTest.java | 4 +- .../services/TrackRecordingServiceTest.java | 45 +++--- .../TrackRecordingServiceTestLocation.java | 5 +- .../TrackRecordingServiceTestLooper.java | 6 +- .../opentracks/MarkerListActivity.java | 6 +- .../opentracks/TrackController.java | 4 +- .../opentracks/TrackListActivity.java | 12 +- .../opentracks/TrackRecordedActivity.java | 6 +- .../opentracks/TrackRecordingActivity.java | 6 +- .../opentracks/content/TrackDataHub.java | 6 +- .../StatisticsRecordingFragment.java | 8 +- .../services/TrackRecordingService.java | 45 +++--- .../services/TrackRecordingServiceBinder.java | 129 ------------------ .../TrackRecordingServiceConnection.java | 16 +-- .../TrackRecordingServiceInterface.java | 107 --------------- .../opentracks/settings/SettingsActivity.java | 6 +- 16 files changed, 102 insertions(+), 309 deletions(-) diff --git a/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/ExportImportTest.java b/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/ExportImportTest.java index 2f7f52815..9e846337e 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/ExportImportTest.java +++ b/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/ExportImportTest.java @@ -40,7 +40,6 @@ import de.dennisguse.opentracks.content.provider.ContentProviderUtils; import de.dennisguse.opentracks.io.file.TrackFileFormat; import de.dennisguse.opentracks.io.file.exporter.TrackExporter; import de.dennisguse.opentracks.services.TrackRecordingService; -import de.dennisguse.opentracks.services.TrackRecordingServiceInterface; import de.dennisguse.opentracks.stats.TrackStatistics; import de.dennisguse.opentracks.util.PreferencesUtils; @@ -89,7 +88,8 @@ public class ExportImportTest { @Before public void setUp() throws TimeoutException { - TrackRecordingServiceInterface service = ((TrackRecordingServiceInterface) mServiceRule.bindService(new Intent(context, TrackRecordingService.class))); + TrackRecordingService service = ((TrackRecordingService.Binder) mServiceRule.bindService(new Intent(context, TrackRecordingService.class))) + .getService(); trackId = service.startNewTrack(); diff --git a/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceTest.java b/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceTest.java index 8608c3221..f1bfccf30 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceTest.java +++ b/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceTest.java @@ -113,7 +113,8 @@ public class TrackRecordingServiceTest { @After public void tearDown() throws TimeoutException { // Reset service (if some previous test failed) - TrackRecordingServiceInterface service = ((TrackRecordingServiceInterface) mServiceRule.bindService(createStartIntent(context))); + TrackRecordingService service = ((TrackRecordingService.Binder) mServiceRule.bindService(createStartIntent(context))) + .getService(); if (service.isRecording() || service.isPaused()) { service.endCurrentTrack(); } @@ -146,7 +147,8 @@ public class TrackRecordingServiceTest { // when Intent startIntent = createStartIntent(context); mServiceRule.startService(startIntent); - TrackRecordingServiceInterface service = ((TrackRecordingServiceInterface) mServiceRule.bindService(startIntent)); + TrackRecordingService service = ((TrackRecordingService.Binder) mServiceRule.bindService(startIntent)) + .getService(); // then // Test if we start in no-recording mode by default. @@ -160,7 +162,8 @@ public class TrackRecordingServiceTest { createDummyTrack(trackId); // when - TrackRecordingServiceInterface service = ((TrackRecordingServiceInterface) mServiceRule.bindService(createStartIntent(context))); + TrackRecordingService service = ((TrackRecordingService.Binder) mServiceRule.bindService(createStartIntent(context))) + .getService(); // then assertFalse(service.isRecording()); @@ -173,7 +176,8 @@ public class TrackRecordingServiceTest { createDummyTrack(trackId); //when - TrackRecordingServiceInterface service = ((TrackRecordingServiceInterface) mServiceRule.bindService(createStartIntent(context))); + TrackRecordingService service = ((TrackRecordingService.Binder) mServiceRule.bindService(createStartIntent(context))) + .getService(); service.resumeTrack(trackId); // then @@ -184,7 +188,8 @@ public class TrackRecordingServiceTest { @Test public void testRecording_start() throws TimeoutException { // given - TrackRecordingServiceInterface service = ((TrackRecordingServiceInterface) mServiceRule.bindService(createStartIntent(context))); + TrackRecordingService service = ((TrackRecordingService.Binder) mServiceRule.bindService(createStartIntent(context))) + .getService(); // when Track.Id trackId = service.startNewTrack(); @@ -200,7 +205,8 @@ public class TrackRecordingServiceTest { @Test public void testRecording_stop() throws TimeoutException { // given - TrackRecordingServiceInterface service = ((TrackRecordingServiceInterface) mServiceRule.bindService(createStartIntent(context))); + TrackRecordingService service = ((TrackRecordingService.Binder) mServiceRule.bindService(createStartIntent(context))) + .getService(); Track.Id trackId = service.startNewTrack(); // when @@ -218,7 +224,8 @@ public class TrackRecordingServiceTest { @Test public void testRecording_pauseAndResume() throws TimeoutException { // given - TrackRecordingServiceInterface service = ((TrackRecordingServiceInterface) mServiceRule.bindService(createStartIntent(context))); + TrackRecordingService service = ((TrackRecordingService.Binder) mServiceRule.bindService(createStartIntent(context))) + .getService(); Track.Id trackId = service.startNewTrack(); // when @@ -244,7 +251,8 @@ public class TrackRecordingServiceTest { @Test public void testRecording_resumeStoppedTrack() throws TimeoutException, InterruptedException { // given - TrackRecordingServiceInterface service = ((TrackRecordingServiceInterface) mServiceRule.bindService(createStartIntent(context))); + TrackRecordingService service = ((TrackRecordingService.Binder) mServiceRule.bindService(createStartIntent(context))) + .getService(); Track.Id trackId = service.startNewTrack(); assertTrue(service.isRecording()); service.endCurrentTrack(); @@ -270,7 +278,8 @@ public class TrackRecordingServiceTest { @Test public void testRecording_stopPausedTrack() throws TimeoutException { // given - TrackRecordingServiceInterface service = ((TrackRecordingServiceInterface) mServiceRule.bindService(createStartIntent(context))); + TrackRecordingService service = ((TrackRecordingService.Binder) mServiceRule.bindService(createStartIntent(context))) + .getService(); Track.Id trackId = service.startNewTrack(); assertTrue(service.isRecording()); service.pauseCurrentTrack(); @@ -293,7 +302,8 @@ public class TrackRecordingServiceTest { @Test public void testStartNewTrack_alreadyRecording() throws TimeoutException { // given - TrackRecordingServiceInterface service = ((TrackRecordingServiceInterface) mServiceRule.bindService(createStartIntent(context))); + TrackRecordingService service = ((TrackRecordingService.Binder) mServiceRule.bindService(createStartIntent(context))) + .getService(); Track.Id trackId = service.startNewTrack(); assertTrue(service.isRecording()); @@ -309,7 +319,8 @@ public class TrackRecordingServiceTest { @Test public void testEndCurrentTrack_noRecording() throws TimeoutException { // given - TrackRecordingServiceInterface service = ((TrackRecordingServiceInterface) mServiceRule.bindService(createStartIntent(context))); + TrackRecordingService service = ((TrackRecordingService.Binder) mServiceRule.bindService(createStartIntent(context))) + .getService(); assertFalse(service.isRecording()); // when @@ -324,7 +335,8 @@ public class TrackRecordingServiceTest { @Test public void testInsertWaypointMarker_noRecordingTrack() throws TimeoutException { // given - TrackRecordingServiceInterface service = ((TrackRecordingServiceInterface) mServiceRule.bindService(createStartIntent(context))); + TrackRecordingService service = ((TrackRecordingService.Binder) mServiceRule.bindService(createStartIntent(context))) + .getService(); assertFalse(service.isRecording()); // when @@ -338,7 +350,8 @@ public class TrackRecordingServiceTest { @Test public void testInsertWaypointMarker_validWaypoint() throws TimeoutException, InterruptedException { // given - TrackRecordingServiceInterface service = ((TrackRecordingServiceInterface) mServiceRule.bindService(createStartIntent(context))); + TrackRecordingService service = ((TrackRecordingService.Binder) mServiceRule.bindService(createStartIntent(context))) + .getService(); Track.Id trackId = service.startNewTrack(); assertTrue(service.isRecording()); newTrackPoint(service); @@ -377,18 +390,18 @@ public class TrackRecordingServiceTest { addTrack(dummyTrack); } - private static void newTrackPoint(TrackRecordingServiceInterface trackRecordingService) throws InterruptedException { + private static void newTrackPoint(TrackRecordingService trackRecordingService) throws InterruptedException { newTrackPoint(trackRecordingService, 45.0f, 35f, 5, 10, System.currentTimeMillis()); } - static void newTrackPoint(TrackRecordingServiceInterface trackRecordingService, double latitude, double longitude, float accuracy, long speed) throws InterruptedException { + static void newTrackPoint(TrackRecordingService trackRecordingService, double latitude, double longitude, float accuracy, long speed) throws InterruptedException { newTrackPoint(trackRecordingService, latitude, longitude, accuracy, speed, System.currentTimeMillis()); } /** * Inserts a location and waits for 200ms. */ - private static void newTrackPoint(TrackRecordingServiceInterface trackRecordingService, double latitude, double longitude, float accuracy, long speed, long time) throws InterruptedException { + private static void newTrackPoint(TrackRecordingService trackRecordingService, double latitude, double longitude, float accuracy, long speed, long time) throws InterruptedException { Location location = new Location(""); location.setLongitude(longitude); location.setLatitude(latitude); diff --git a/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceTestLocation.java b/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceTestLocation.java index 3262dfc90..8ef1d8559 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceTestLocation.java +++ b/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceTestLocation.java @@ -55,7 +55,7 @@ public class TrackRecordingServiceTestLocation { private final Context context = ApplicationProvider.getApplicationContext(); private ContentProviderUtils contentProviderUtils; - private TrackRecordingServiceInterface service; + private TrackRecordingService service; @BeforeClass public static void preSetUp() { @@ -77,7 +77,8 @@ public class TrackRecordingServiceTestLocation { SharedPreferences sharedPreferences = PreferencesUtils.getSharedPreferences(context); sharedPreferences.edit().clear().commit(); - service = ((TrackRecordingServiceInterface) mServiceRule.bindService(TrackRecordingServiceTest.createStartIntent(context))); + service = ((TrackRecordingService.Binder) mServiceRule.bindService(TrackRecordingServiceTest.createStartIntent(context))) + .getService(); } @After diff --git a/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceTestLooper.java b/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceTestLooper.java index 49b5613bd..61cbe4df5 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceTestLooper.java +++ b/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceTestLooper.java @@ -87,7 +87,8 @@ public class TrackRecordingServiceTestLooper { @After public void tearDown() throws TimeoutException { // Reset service (if some previous test failed) - TrackRecordingServiceInterface service = ((TrackRecordingServiceInterface) mServiceRule.bindService(TrackRecordingServiceTest.createStartIntent(context))); + TrackRecordingService service = ((TrackRecordingService.Binder) mServiceRule.bindService(TrackRecordingServiceTest.createStartIntent(context))) + .getService(); if (service.isRecording() || service.isPaused()) { service.endCurrentTrack(); } @@ -219,7 +220,8 @@ public class TrackRecordingServiceTestLooper { } private void fullRecordingSession() throws TimeoutException { - TrackRecordingServiceInterface service = ((TrackRecordingServiceInterface) mServiceRule.bindService(TrackRecordingServiceTest.createStartIntent(context))); + TrackRecordingService service = ((TrackRecordingService.Binder) mServiceRule.bindService(TrackRecordingServiceTest.createStartIntent(context))) + .getService(); assertFalse(service.isRecording()); // Start a track. diff --git a/src/main/java/de/dennisguse/opentracks/MarkerListActivity.java b/src/main/java/de/dennisguse/opentracks/MarkerListActivity.java index 2080610c7..8044b3ee1 100644 --- a/src/main/java/de/dennisguse/opentracks/MarkerListActivity.java +++ b/src/main/java/de/dennisguse/opentracks/MarkerListActivity.java @@ -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); } diff --git a/src/main/java/de/dennisguse/opentracks/TrackController.java b/src/main/java/de/dennisguse/opentracks/TrackController.java index 01842abde..626174d39 100644 --- a/src/main/java/de/dennisguse/opentracks/TrackController.java +++ b/src/main/java/de/dennisguse/opentracks/TrackController.java @@ -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(); } diff --git a/src/main/java/de/dennisguse/opentracks/TrackListActivity.java b/src/main/java/de/dennisguse/opentracks/TrackListActivity.java index 3c06a0eed..20b731974 100644 --- a/src/main/java/de/dennisguse/opentracks/TrackListActivity.java +++ b/src/main/java/de/dennisguse/opentracks/TrackListActivity.java @@ -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); } diff --git a/src/main/java/de/dennisguse/opentracks/TrackRecordedActivity.java b/src/main/java/de/dennisguse/opentracks/TrackRecordedActivity.java index 1ce3869d9..d77cebf7e 100644 --- a/src/main/java/de/dennisguse/opentracks/TrackRecordedActivity.java +++ b/src/main/java/de/dennisguse/opentracks/TrackRecordedActivity.java @@ -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); } diff --git a/src/main/java/de/dennisguse/opentracks/TrackRecordingActivity.java b/src/main/java/de/dennisguse/opentracks/TrackRecordingActivity.java index 46b8f5b53..516f04bb4 100644 --- a/src/main/java/de/dennisguse/opentracks/TrackRecordingActivity.java +++ b/src/main/java/de/dennisguse/opentracks/TrackRecordingActivity.java @@ -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; diff --git a/src/main/java/de/dennisguse/opentracks/content/TrackDataHub.java b/src/main/java/de/dennisguse/opentracks/content/TrackDataHub.java index 6dbec0f2c..b34254266 100644 --- a/src/main/java/de/dennisguse/opentracks/content/TrackDataHub.java +++ b/src/main/java/de/dennisguse/opentracks/content/TrackDataHub.java @@ -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); } diff --git a/src/main/java/de/dennisguse/opentracks/fragments/StatisticsRecordingFragment.java b/src/main/java/de/dennisguse/opentracks/fragments/StatisticsRecordingFragment.java index f36ad20f5..7786620fe 100644 --- a/src/main/java/de/dennisguse/opentracks/fragments/StatisticsRecordingFragment.java +++ b/src/main/java/de/dennisguse/opentracks/fragments/StatisticsRecordingFragment.java @@ -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 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(); } diff --git a/src/main/java/de/dennisguse/opentracks/services/TrackRecordingService.java b/src/main/java/de/dennisguse/opentracks/services/TrackRecordingService.java index d930778eb..e2558d054 100644 --- a/src/main/java/de/dennisguse/opentracks/services/TrackRecordingService.java +++ b/src/main/java/de/dennisguse/opentracks/services/TrackRecordingService.java @@ -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; + } + } +} \ No newline at end of file diff --git a/src/main/java/de/dennisguse/opentracks/services/TrackRecordingServiceBinder.java b/src/main/java/de/dennisguse/opentracks/services/TrackRecordingServiceBinder.java index 40463c8b7..e69de29bb 100644 --- a/src/main/java/de/dennisguse/opentracks/services/TrackRecordingServiceBinder.java +++ b/src/main/java/de/dennisguse/opentracks/services/TrackRecordingServiceBinder.java @@ -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); - } -} diff --git a/src/main/java/de/dennisguse/opentracks/services/TrackRecordingServiceConnection.java b/src/main/java/de/dennisguse/opentracks/services/TrackRecordingServiceConnection.java index 21b2e4c06..867c5c3c9 100644 --- a/src/main/java/de/dennisguse/opentracks/services/TrackRecordingServiceConnection.java +++ b/src/main/java/de/dennisguse/opentracks/services/TrackRecordingServiceConnection.java @@ -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 { diff --git a/src/main/java/de/dennisguse/opentracks/services/TrackRecordingServiceInterface.java b/src/main/java/de/dennisguse/opentracks/services/TrackRecordingServiceInterface.java index 301e8c875..e69de29bb 100644 --- a/src/main/java/de/dennisguse/opentracks/services/TrackRecordingServiceInterface.java +++ b/src/main/java/de/dennisguse/opentracks/services/TrackRecordingServiceInterface.java @@ -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(); -} diff --git a/src/main/java/de/dennisguse/opentracks/settings/SettingsActivity.java b/src/main/java/de/dennisguse/opentracks/settings/SettingsActivity.java index 1a7586736..15a445c5a 100644 --- a/src/main/java/de/dennisguse/opentracks/settings/SettingsActivity.java +++ b/src/main/java/de/dennisguse/opentracks/settings/SettingsActivity.java @@ -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); }