diff --git a/src/androidTest/java/de/dennisguse/opentracks/fragments/ChartFragmentTest.java b/src/androidTest/java/de/dennisguse/opentracks/fragments/ChartFragmentTest.java index b8d20ec73..ee0e0b6db 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/fragments/ChartFragmentTest.java +++ b/src/androidTest/java/de/dennisguse/opentracks/fragments/ChartFragmentTest.java @@ -190,9 +190,15 @@ public class ChartFragmentTest { */ @Test public void testCreatePendingPoint_time() { + // given chartFragment.setChartByDistance(false); TrackPoint trackPoint1 = TrackStubUtils.createDefaultTrackPoint(); + trackPoint1.setTime(TrackStubUtils.INITIAL_TIME); //Keep old TrackPoint behavior of having time=0 for this test + + // when ChartPoint point = chartFragment.createPendingPoint(trackPoint1); + + // then assertEquals(0.0, point.getTimeOrDistance(), 0.01); long timeSpan = 222; TrackPoint trackPoint2 = TrackStubUtils.createDefaultTrackPoint(); 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 bffaacc39..b5e6f98a7 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/services/handlers/LocationHandlerTest.java +++ b/src/androidTest/java/de/dennisguse/opentracks/services/handlers/LocationHandlerTest.java @@ -3,10 +3,12 @@ package de.dennisguse.opentracks.services.handlers; import android.content.Context; import android.content.SharedPreferences; import android.location.Location; +import android.os.Looper; import androidx.test.core.app.ApplicationProvider; import org.junit.Before; +import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.InjectMocks; @@ -32,6 +34,12 @@ public class LocationHandlerTest { @InjectMocks private LocationHandler locationHandler; + @BeforeClass + public static void preSetUp() { + // Prepare looper for Android's message queue + if (Looper.myLooper() == null) Looper.prepare(); + } + @Before public void setUp() { // Let's use default values. @@ -80,7 +88,6 @@ public class LocationHandlerTest { int prefAccuracy = PreferencesUtils.getRecordingGPSAccuracy(context); // when - // poor latitude locationHandler.onLocationChanged(createLocation(45f, 35f, prefAccuracy + 1, 5, System.currentTimeMillis())); // then diff --git a/src/androidTest/java/de/dennisguse/opentracks/util/TrackPointUtilsTest.java b/src/androidTest/java/de/dennisguse/opentracks/util/TrackPointUtilsTest.java deleted file mode 100644 index b01136820..000000000 --- a/src/androidTest/java/de/dennisguse/opentracks/util/TrackPointUtilsTest.java +++ /dev/null @@ -1,53 +0,0 @@ -package de.dennisguse.opentracks.util; - -import org.junit.Test; - -import de.dennisguse.opentracks.content.data.TrackPoint; - -import static org.junit.Assert.assertEquals; - -public class TrackPointUtilsTest { - - @Test - public void fixTime_none() { - // given - long time = System.currentTimeMillis(); - TrackPoint trackPoint = new TrackPoint(); - trackPoint.setTime(time); - - // when - TrackPointUtils.fixTime(trackPoint); - - // then - assertEquals(time, trackPoint.getTime()); - } - - @Test - public void fixTime_0() { - // given - long time = System.currentTimeMillis(); - TrackPoint trackPoint = new TrackPoint(); - trackPoint.setTime(0); - - // when - TrackPointUtils.fixTime(trackPoint); - - // then - assertEquals(time, trackPoint.getTime(), 1000); - } - - @Test - public void fixTime_gpsWeekRollover() { - // given - long time = System.currentTimeMillis(); - TrackPoint trackPoint = new TrackPoint(); - trackPoint.setTime(time - 1024 * UnitConversions.ONE_WEEK_MS); - - // when - TrackPointUtils.fixTime(trackPoint); - - // then - assertEquals(time, trackPoint.getTime()); - } - -} \ No newline at end of file diff --git a/src/main/java/de/dennisguse/opentracks/content/data/TrackPoint.java b/src/main/java/de/dennisguse/opentracks/content/data/TrackPoint.java index a29d98d97..793dc6e33 100644 --- a/src/main/java/de/dennisguse/opentracks/content/data/TrackPoint.java +++ b/src/main/java/de/dennisguse/opentracks/content/data/TrackPoint.java @@ -27,7 +27,8 @@ import java.util.Objects; /** * This class extends the standard Android location with extra information. *

- * NOTE: default location will be latitude=0.0 and longitude=0.0 (this is not meaningful). + * NOTE: default location will be latitude=0.0 and longitude=0.0. + * For {@link TrackPoint}s with `type == null` this is not meaningful. *

* NOTE: For Locations provided by the GPS. * We are replacing the GPS-provided time using the system time. @@ -99,6 +100,7 @@ public class TrackPoint { public TrackPoint(@NonNull Location location) { this.type = Type.TRACKPOINT; this.location = location; + setTime(System.currentTimeMillis()); } public TrackPoint(@NonNull Type type, @NonNull Location location) { diff --git a/src/main/java/de/dennisguse/opentracks/services/TrackRecordingService.java b/src/main/java/de/dennisguse/opentracks/services/TrackRecordingService.java index a62687d9c..54e02dd09 100644 --- a/src/main/java/de/dennisguse/opentracks/services/TrackRecordingService.java +++ b/src/main/java/de/dennisguse/opentracks/services/TrackRecordingService.java @@ -554,8 +554,6 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand notificationManager.updateTrackPoint(this, trackPoint, recordingGpsAccuracy); - TrackPointUtils.fixTime(trackPoint); - //TODO Figure out how to avoid loading the lastValidTrackPoint from the database TrackPoint lastValidTrackPoint = getLastValidTrackPointInCurrentSegment(track.getId()); diff --git a/src/main/java/de/dennisguse/opentracks/services/handlers/GpsStatus.java b/src/main/java/de/dennisguse/opentracks/services/handlers/GpsStatus.java index e376b79d5..d56ee70ea 100644 --- a/src/main/java/de/dennisguse/opentracks/services/handlers/GpsStatus.java +++ b/src/main/java/de/dennisguse/opentracks/services/handlers/GpsStatus.java @@ -1,10 +1,12 @@ package de.dennisguse.opentracks.services.handlers; import android.content.Context; -import android.location.Location; import android.location.LocationManager; import android.os.Handler; +import androidx.annotation.Nullable; + +import de.dennisguse.opentracks.content.data.TrackPoint; import de.dennisguse.opentracks.util.PreferencesUtils; import de.dennisguse.opentracks.util.UnitConversions; @@ -27,10 +29,12 @@ class GpsStatus { private GpsStatusListener client; private final Context context; - // Last location. It can be null. - private Location lastLocation = null; + @Nullable + private TrackPoint lastTrackPoint = null; + + @Nullable // The last valid (not null) location. Null value means that there have not been any location yet. - private Location lastValidLocation = null; + private TrackPoint lastValidTrackPoint = null; // Flag to prevent GpsStatus checks two or more locations at the same time. private boolean checking = false; @@ -97,28 +101,28 @@ class GpsStatus { } /** - * This method must be called from the client every time a new location is received. - * Receive new location and calculate the new status if needed. + * This method must be called from the client every time a new trackPoint is received. + * Receive new trackPoint and calculate the new status if needed. * It look for GPS changes in lastLocation if it's not null. If it's null then look for in lastValidLocation if any. */ - public void onLocationChanged(final Location location) { + public void onLocationChanged(final TrackPoint trackPoint) { if (checking) { return; } checking = true; - if (lastLocation != null) { + if (lastTrackPoint != null) { checkStatusFromLastLocation(); - } else if (lastValidLocation != null) { + } else if (lastValidTrackPoint != null) { checkStatusFromLastValidLocation(); } - if (location != null) { - // Update location's time to the current time millis when location has been received. - location.setTime(System.currentTimeMillis()); - lastValidLocation = location; + if (trackPoint != null) { + // Update trackPoint's time to the current time millis when trackPoint has been received. + trackPoint.setTime(System.currentTimeMillis()); + lastValidTrackPoint = trackPoint; } - lastLocation = location; + lastTrackPoint = trackPoint; checking = false; } @@ -129,19 +133,19 @@ class GpsStatus { * Also, it'll run the runnable if signal is bad or stop it if the signal is lost. */ private void checkStatusFromLastLocation() { - if (System.currentTimeMillis() - lastLocation.getTime() > signalLostThreshold && gpsStatus != GpsStatusValue.GPS_SIGNAL_LOST) { + if (System.currentTimeMillis() - lastTrackPoint.getTime() > signalLostThreshold && gpsStatus != GpsStatusValue.GPS_SIGNAL_LOST) { // Too much time without receiving signal -> signal lost. GpsStatusValue oldStatus = gpsStatus; gpsStatus = GpsStatusValue.GPS_SIGNAL_LOST; sendStatus(oldStatus, gpsStatus); stopStatusRunner(); - } else if (lastLocation.getAccuracy() > signalBadThreshold && gpsStatus != GpsStatusValue.GPS_SIGNAL_BAD) { + } else if (lastTrackPoint.getAccuracy() > signalBadThreshold && gpsStatus != GpsStatusValue.GPS_SIGNAL_BAD) { // Too little accuracy -> bad signal. GpsStatusValue oldStatus = gpsStatus; gpsStatus = GpsStatusValue.GPS_SIGNAL_BAD; sendStatus(oldStatus, gpsStatus); startStatusRunner(); - } else if (lastLocation.getAccuracy() <= signalBadThreshold && gpsStatus != GpsStatusValue.GPS_SIGNAL_FIX) { + } else if (lastTrackPoint.getAccuracy() <= signalBadThreshold && gpsStatus != GpsStatusValue.GPS_SIGNAL_FIX) { // Gps okay. GpsStatusValue oldStatus = gpsStatus; gpsStatus = GpsStatusValue.GPS_SIGNAL_FIX; @@ -156,13 +160,13 @@ class GpsStatus { * If there is any change then it does the change. */ private void checkStatusFromLastValidLocation() { - if (System.currentTimeMillis() - lastValidLocation.getTime() > signalLostThreshold) { + if (System.currentTimeMillis() - lastValidTrackPoint.getTime() > signalLostThreshold) { // Too much time without locations -> lost signal? (wait signalLostThreshold from last valid location). GpsStatusValue oldStatus = gpsStatus; gpsStatus = GpsStatusValue.GPS_SIGNAL_LOST; sendStatus(oldStatus, gpsStatus); stopStatusRunner(); - lastValidLocation = null; + lastValidTrackPoint = null; } } @@ -192,8 +196,8 @@ class GpsStatus { GpsStatusValue oldStatus = gpsStatus; gpsStatus = GpsStatusValue.GPS_DISABLED; sendStatus(oldStatus, gpsStatus); - lastLocation = null; - lastValidLocation = null; + lastTrackPoint = null; + lastValidTrackPoint = null; stopStatusRunner(); } } 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 751e06698..9846fc523 100644 --- a/src/main/java/de/dennisguse/opentracks/services/handlers/LocationHandler.java +++ b/src/main/java/de/dennisguse/opentracks/services/handlers/LocationHandler.java @@ -90,18 +90,20 @@ class LocationHandler implements HandlerServer.Handler, LocationListener, GpsSta */ @Override public void onLocationChanged(@NonNull Location location) { + TrackPoint trackPoint = new TrackPoint(location); + boolean isAccurate = TrackPointUtils.fulfillsAccuracy(trackPoint, recordingGpsAccuracy); + boolean isValid = LocationUtils.isValidLocation(location); + if (gpsStatus != null) { - gpsStatus.onLocationChanged(location); + gpsStatus.onLocationChanged(trackPoint); } - if (!LocationUtils.isValidLocation(location)) { + if (!isValid) { Log.w(TAG, "Ignore newTrackPoint. location is invalid."); return; } - TrackPoint trackPoint = new TrackPoint(location); - - if (!TrackPointUtils.fulfillsAccuracy(trackPoint, recordingGpsAccuracy)) { + if (!isAccurate) { Log.d(TAG, "Ignore newTrackPoint. Poor accuracy."); return; } diff --git a/src/main/java/de/dennisguse/opentracks/util/TrackPointUtils.java b/src/main/java/de/dennisguse/opentracks/util/TrackPointUtils.java index 678fc4039..6343423e9 100644 --- a/src/main/java/de/dennisguse/opentracks/util/TrackPointUtils.java +++ b/src/main/java/de/dennisguse/opentracks/util/TrackPointUtils.java @@ -1,7 +1,5 @@ package de.dennisguse.opentracks.util; -import android.util.Log; - import androidx.annotation.NonNull; import de.dennisguse.opentracks.content.data.TrackPoint; @@ -16,27 +14,6 @@ public class TrackPointUtils { private TrackPointUtils() { } - /** - * 1. Ancient fix for phones that do not set the time in {@link android.location.Location}. - * 2. Fix for GPS time rollover happening every 19.7 years: https://en.wikipedia.org/wiki/GPS_Week_Number_Rollover - */ - public static void fixTime(@NonNull TrackPoint trackPoint) { - if (trackPoint.getTime() == 0L) { - Log.w(TAG, "Time of provided location was 0. Using current time."); - trackPoint.setTime(System.currentTimeMillis()); - return; - } - - { - long timeDiff = Math.abs(trackPoint.getTime() - System.currentTimeMillis()); - - if (timeDiff > 1023 * UnitConversions.ONE_WEEK_MS) { - Log.w(TAG, "GPS week rollover."); - trackPoint.setTime(trackPoint.getTime() + 1024 * UnitConversions.ONE_WEEK_MS); - } - } - } - public static boolean isMoving(@NonNull TrackPoint trackPoint) { return trackPoint.hasSpeed() && trackPoint.getSpeed() >= MAX_NO_MOVEMENT_SPEED; }