From c02b8fab530430364df246f6510dd2d4e4815e8c Mon Sep 17 00:00:00 2001 From: Dennis Guse Date: Mon, 20 Jul 2020 18:16:35 +0200 Subject: [PATCH] HandlerServer: use executor service to send data to TrackRecordingService. Fixes #329. --- .../services/handlers/HandlerServerTest.java | 63 +++++++++++++++++++ .../handlers/LocationHandlerTest.java | 51 ++++++--------- .../services/handlers/HandlerServer.java | 27 +++++++- .../services/handlers/LocationHandler.java | 34 +++++----- 4 files changed, 122 insertions(+), 53 deletions(-) create mode 100644 src/androidTest/java/de/dennisguse/opentracks/services/handlers/HandlerServerTest.java diff --git a/src/androidTest/java/de/dennisguse/opentracks/services/handlers/HandlerServerTest.java b/src/androidTest/java/de/dennisguse/opentracks/services/handlers/HandlerServerTest.java new file mode 100644 index 000000000..c04b5a005 --- /dev/null +++ b/src/androidTest/java/de/dennisguse/opentracks/services/handlers/HandlerServerTest.java @@ -0,0 +1,63 @@ +package de.dennisguse.opentracks.services.handlers; + +import android.content.Context; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +import de.dennisguse.opentracks.content.data.TrackPoint; + +import static org.mockito.Mockito.verify; + +@RunWith(MockitoJUnitRunner.class) +public class HandlerServerTest { + + @Mock + private Context context; + + @Mock + private HandlerServer.HandlerServerInterface server; + + @Mock + private LocationHandler locationHandler; + + private HandlerServer subject; + + @Before + public void setUp() { + subject = new HandlerServer(locationHandler, server); + subject.start(context); + } + + @After + public void tearDown() { + subject.stop(context); + } + + @Test + public void onSharedPreferenceChanged() { + // when + subject.onSharedPreferenceChanged(null, null, null); + + // then + verify(locationHandler).onSharedPreferenceChanged(null, null, null); + } + + @Test + public void sendTrackPoint() throws InterruptedException { + // given + TrackPoint trackPoint = new TrackPoint(); + int accuracy = 50; + + // when + subject.sendTrackPoint(trackPoint, accuracy); + + // then + Thread.sleep(10); // Wait for executor service + verify(server).newTrackPoint(trackPoint, accuracy); + } +} \ No newline at end of file diff --git a/src/androidTest/java/de/dennisguse/opentracks/services/handlers/LocationHandlerTest.java b/src/androidTest/java/de/dennisguse/opentracks/services/handlers/LocationHandlerTest.java index 6ba081ff3..bffaacc39 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/services/handlers/LocationHandlerTest.java +++ b/src/androidTest/java/de/dennisguse/opentracks/services/handlers/LocationHandlerTest.java @@ -5,29 +5,32 @@ import android.content.SharedPreferences; import android.location.Location; import androidx.test.core.app.ApplicationProvider; -import androidx.test.ext.junit.runners.AndroidJUnit4; -import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.Mockito; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; import de.dennisguse.opentracks.R; import de.dennisguse.opentracks.content.data.TrackPoint; -import de.dennisguse.opentracks.services.TrackRecordingService; import de.dennisguse.opentracks.util.PreferencesUtils; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; -@RunWith(AndroidJUnit4.class) +@RunWith(MockitoJUnitRunner.class) public class LocationHandlerTest { + private final Context context = ApplicationProvider.getApplicationContext(); + + @Mock private HandlerServer handlerServer; + + @InjectMocks private LocationHandler locationHandler; - private TrackRecordingService mockService; @Before public void setUp() { @@ -35,18 +38,9 @@ public class LocationHandlerTest { SharedPreferences sharedPreferences = PreferencesUtils.getSharedPreferences(context); sharedPreferences.edit().clear().commit(); - mockService = Mockito.mock(TrackRecordingService.class); - handlerServer = new HandlerServer(mockService); - locationHandler = new LocationHandler(handlerServer); locationHandler.onSharedPreferenceChanged(context, PreferencesUtils.getSharedPreferences(context), context.getString(R.string.recording_gps_accuracy_key)); locationHandler.onSharedPreferenceChanged(context, PreferencesUtils.getSharedPreferences(context), context.getString(R.string.min_recording_interval_key)); - } - - @After - public void tearDown() { - mockService = null; - handlerServer = null; - locationHandler = null; + locationHandler.onStart(context); } /** @@ -58,7 +52,7 @@ public class LocationHandlerTest { locationHandler.onLocationChanged(createLocation(45f, 35f, 3, 5, System.currentTimeMillis())); // then - verify(mockService, times(1)).newTrackPoint(any(TrackPoint.class), any(Integer.class)); + verify(handlerServer, times(1)).sendTrackPoint(any(TrackPoint.class), any(Integer.class)); } /** @@ -74,7 +68,7 @@ public class LocationHandlerTest { locationHandler.onLocationChanged(createLocation(latitude, 35f, 3, 5, System.currentTimeMillis())); // then - verify(mockService, times(0)).newTrackPoint(any(TrackPoint.class), any(Integer.class)); + verify(handlerServer, times(0)).sendTrackPoint(any(TrackPoint.class), any(Integer.class)); } /** @@ -91,25 +85,20 @@ public class LocationHandlerTest { // then // no newTrackPoint called - verify(mockService, times(0)).newTrackPoint(any(TrackPoint.class), any(Integer.class)); + verify(handlerServer, times(0)).sendTrackPoint(any(TrackPoint.class), any(Integer.class)); } @Test - public void testOnLocationChanged_movingInaccurate() throws Exception { + public void testOnLocationChanged_movingInaccurate() { // when - locationHandler.onLocationChanged( - createLocation(45.0, 35.0, 5, 15, System.currentTimeMillis())); - locationHandler.onLocationChanged( - createLocation(45.1, 35.0, Long.MAX_VALUE, 15, System.currentTimeMillis())); - locationHandler.onLocationChanged( - createLocation(45.2, 35.0, Long.MAX_VALUE, 15, System.currentTimeMillis())); - locationHandler.onLocationChanged( - createLocation(45.3, 35.0, Long.MAX_VALUE, 15, System.currentTimeMillis())); - locationHandler.onLocationChanged( - createLocation(99.0, 35.0, Long.MAX_VALUE, 15, System.currentTimeMillis())); + locationHandler.onLocationChanged(createLocation(45.0, 35.0, 5, 15, System.currentTimeMillis())); + locationHandler.onLocationChanged(createLocation(45.1, 35.0, Long.MAX_VALUE, 15, System.currentTimeMillis())); + locationHandler.onLocationChanged(createLocation(45.2, 35.0, Long.MAX_VALUE, 15, System.currentTimeMillis())); + locationHandler.onLocationChanged(createLocation(45.3, 35.0, Long.MAX_VALUE, 15, System.currentTimeMillis())); + locationHandler.onLocationChanged(createLocation(99.0, 35.0, Long.MAX_VALUE, 15, System.currentTimeMillis())); // then - verify(mockService, times(1)).newTrackPoint(any(TrackPoint.class), any(Integer.class)); + verify(handlerServer, times(1)).sendTrackPoint(any(TrackPoint.class), any(Integer.class)); } /** diff --git a/src/main/java/de/dennisguse/opentracks/services/handlers/HandlerServer.java b/src/main/java/de/dennisguse/opentracks/services/handlers/HandlerServer.java index 65b9212ab..99ecd5187 100644 --- a/src/main/java/de/dennisguse/opentracks/services/handlers/HandlerServer.java +++ b/src/main/java/de/dennisguse/opentracks/services/handlers/HandlerServer.java @@ -3,26 +3,46 @@ package de.dennisguse.opentracks.services.handlers; import android.content.Context; import android.content.SharedPreferences; +import androidx.annotation.VisibleForTesting; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + import de.dennisguse.opentracks.content.data.TrackPoint; public class HandlerServer { - private String TAG = HandlerServer.class.getSimpleName(); + + private static String TAG = HandlerServer.class.getSimpleName(); private final LocationHandler locationHandler; private final HandlerServerInterface service; + private ExecutorService serviceExecutor; public HandlerServer(HandlerServerInterface service) { this.locationHandler = new LocationHandler(this); this.service = service; } + @VisibleForTesting + HandlerServer(LocationHandler locationHandler, HandlerServerInterface service) { + this.locationHandler = locationHandler; + this.service = service; + } + public void start(Context context) { + serviceExecutor = Executors.newSingleThreadExecutor(); + locationHandler.onStart(context); locationHandler.onSharedPreferenceChanged(context, null, null); } public void stop(Context context) { locationHandler.onStop(context); + + if (serviceExecutor != null) { + serviceExecutor.shutdownNow(); + } + serviceExecutor = null; } public void onSharedPreferenceChanged(Context context, SharedPreferences preferences, String key) { @@ -30,7 +50,10 @@ public class HandlerServer { } public void sendTrackPoint(TrackPoint trackPoint, int recordingGpsAccuracy) { - service.newTrackPoint(trackPoint, recordingGpsAccuracy); + if (serviceExecutor == null || serviceExecutor.isTerminated() || serviceExecutor.isShutdown()) { + return; + } + serviceExecutor.execute(() -> service.newTrackPoint(trackPoint, recordingGpsAccuracy)); } public interface HandlerServerInterface { diff --git a/src/main/java/de/dennisguse/opentracks/services/handlers/LocationHandler.java b/src/main/java/de/dennisguse/opentracks/services/handlers/LocationHandler.java index 583ee066f..5c00eb821 100644 --- a/src/main/java/de/dennisguse/opentracks/services/handlers/LocationHandler.java +++ b/src/main/java/de/dennisguse/opentracks/services/handlers/LocationHandler.java @@ -67,31 +67,13 @@ class LocationHandler implements HandlerServer.Handler, LocationListener { } } - @Override - public void onLocationChanged(@NonNull Location location) { - // TODO do we still need to process the location processing in an asynchronous manner? Let's go to check it out. - computeLocation(location); - } - - @Override - public void onStatusChanged(String provider, int status, Bundle extras) { - - } - - @Override - public void onProviderEnabled(@NonNull String provider) { - } - - @Override - public void onProviderDisabled(@NonNull String provider) { - } - /** * Checks if location is valid and builds a track point that will be send through HandlerServer. * * @param location {@link Location} object. */ - private void computeLocation(Location location) { + @Override + public void onLocationChanged(@NonNull Location location) { if (!LocationUtils.isValidLocation(location)) { Log.w(TAG, "Ignore newTrackPoint. location is invalid."); return; @@ -118,6 +100,18 @@ class LocationHandler implements HandlerServer.Handler, LocationListener { handlerServer.sendTrackPoint(trackPoint, recordingGpsAccuracy); } + @Override + public void onStatusChanged(String provider, int status, Bundle extras) { + } + + @Override + public void onProviderEnabled(@NonNull String provider) { + } + + @Override + public void onProviderDisabled(@NonNull String provider) { + } + private void registerLocationListener() { if (locationManager == null) { Log.e(TAG, "locationManager is null.");