Compare commits

...

46 Commits

Author SHA1 Message Date
Dennis Guse f578c6bc19 Release: v3.24.1 2022-01-23 21:17:57 +01:00
Dennis Guse a97bf6b883 Track name: use a short version of ISO8601.
Fixes #1093.
2022-01-23 21:04:08 +01:00
Dennis Guse 838f3dc622 Public API: enable other applications to start recordings.
Fixes #671.
2022-01-23 20:13:00 +01:00
Dennis Guse 8ae4d75708 Merge remote-tracking branch 'weblate/main' 2022-01-23 20:03:55 +01:00
mondstern 0c6813aca1 Translated using Weblate (Norwegian Bokmål)
Currently translated at 100.0% (477 of 477 strings)

Translation: OpenTracks/opentracks.src-main-res-values-strings-xml--main
Translate-URL: https://weblate.bubu1.eu/projects/OpenTracks/opentracks/nb_NO/
2022-01-22 12:41:41 +01:00
Dennis Guse 05bd2e6a71 Voice announcement: fix French seconds.
Fixes #1101.
2022-01-21 19:56:53 +01:00
mondstern 8cad813d56 Translated using Weblate (Ukrainian)
Currently translated at 98.3% (468 of 476 strings)

Translation: OpenTracks/opentracks.src-main-res-values-strings-xml--main
Translate-URL: https://weblate.bubu1.eu/projects/OpenTracks/opentracks/uk/
2022-01-20 12:28:29 +01:00
mondstern 52626d5886 Translated using Weblate (Finnish)
Currently translated at 85.9% (409 of 476 strings)

Translation: OpenTracks/opentracks.src-main-res-values-strings-xml--main
Translate-URL: https://weblate.bubu1.eu/projects/OpenTracks/opentracks/fi/
2022-01-20 12:28:29 +01:00
mondstern c238aa7c6d Translated using Weblate (Basque)
Currently translated at 100.0% (476 of 476 strings)

Translation: OpenTracks/opentracks.src-main-res-values-strings-xml--main
Translate-URL: https://weblate.bubu1.eu/projects/OpenTracks/opentracks/eu/
2022-01-20 12:28:29 +01:00
mondstern 019568144a Translated using Weblate (Danish)
Currently translated at 100.0% (476 of 476 strings)

Translation: OpenTracks/opentracks.src-main-res-values-strings-xml--main
Translate-URL: https://weblate.bubu1.eu/projects/OpenTracks/opentracks/da/
2022-01-20 12:28:29 +01:00
Dennis Guse 9abe3cf05b PTets: close cursors. 2022-01-20 12:28:23 +01:00
Peter Storch 1099102e29 Change handling of Uri and DocumentFile handling for #1080
The Uris from Intent.getData() and DocumentFile.getUri() seems to be different. I think PreferencesUtils should only work with the original Uri as well as the permission handling logic.

IntentUtils.toDocumentFile can be used to convert it to a DocumentFile later on to actually work with.

Adds "No file manager found" message if no activity with OPEN_DOCUMENT_TREE is found. #1095

Removed deprecation of `startActivityForResult`.
2022-01-19 22:26:52 +01:00
Dennis Guse f64c1feb1a Bugfix: prevent rare crash due to Actvity lifecycle events in AbstractTrackDeleteActivity. 2022-01-19 20:53:30 +01:00
Dennis Guse e1d3b04dd0 Bugfix: MediaPlayer creation might fail for ttsFallback.
Seen on a Fairphone 4.

Part of #963.
2022-01-16 21:39:16 +01:00
Dennis Guse 619b82a23e Package structure: moved functionality from FileUtils to MarkerUtils.
Part of #963.
2022-01-16 21:39:16 +01:00
Dennis Guse d18c67a648 Cleanup: MarkerEditActivity now uses ActivityResultLauncher and implemented onDestroy(). 2022-01-16 21:39:16 +01:00
Dennis Guse 0eda1eed1d Introduced value objects for heartrate, cadence, and power.
Fixes #896.
2022-01-16 15:30:08 +01:00
Dennis Guse 1df1fe699a Cleanup: removed unused parameter. 2022-01-16 15:30:08 +01:00
Dennis Guse 9a7183738f Update .gitignore 2022-01-16 15:20:17 +01:00
Dennis Guse 864bc8fad9 Cleanup. 2022-01-15 23:16:53 +01:00
Dennis Guse 5ea651d340 Merge pull request #1096 from OpenTracksApp/refactor#800
Refactoring package structure.
2022-01-15 22:59:19 +01:00
Dennis Guse 7484ab03ce Package structure: moved UI utils
Part of #963.
2022-01-15 22:40:03 +01:00
Dennis Guse 7caf33fb66 Package structure: moved share functionality.
Part of #963.
2022-01-15 22:28:47 +01:00
Dennis Guse 88c4e1a109 Package structure: moved sensors.
Part of #963.
2022-01-15 22:24:59 +01:00
Dennis Guse 0645628d7e Package structure: moved models and database.
Part of #963.
2022-01-15 22:24:59 +01:00
Dennis Guse cf993b73d7 Package structure: moved custom recording layout.
Part of #963.
2022-01-15 22:24:59 +01:00
Dennis Guse d49386259a Package structure: moved support files.
Part of #963.
2022-01-15 22:08:30 +01:00
Dennis Guse 10f00c4c99 Package structure: moved UI utilities.
Part of #963.
2022-01-15 22:08:30 +01:00
Dennis Guse 2ca69df447 Package structure: moved Marker UI code.
Part of #963.
2022-01-15 22:08:21 +01:00
Dennis Guse 1a125ca60d Package structure: moved aggregated statistics.
Part of #963.
2022-01-15 22:08:06 +01:00
Dennis Guse 5053c41bec Package structure: moved intervals.
Part of #963.
2022-01-15 22:07:53 +01:00
Dennis Guse 46cf7f9acf TrackRecordingServiceConnection: use a callback instead of a Runnable. 2022-01-15 20:53:46 +01:00
Dennis Guse 522d8b41d8 Bugfix: use monotonic clock.
Fixes #800.
2022-01-15 19:52:27 +01:00
Dennis Guse 43e1c99642 Refactoring package structure.
Part of #963.
2022-01-14 23:34:05 +01:00
mondstern 81d516d11a Translated using Weblate (Slovak)
Currently translated at 99.5% (474 of 476 strings)

Translation: OpenTracks/opentracks.src-main-res-values-strings-xml--main
Translate-URL: https://weblate.bubu1.eu/projects/OpenTracks/opentracks/sk/
2022-01-14 07:25:36 +01:00
mondstern b8ce386556 Translated using Weblate (Slovak)
Currently translated at 72.0% (343 of 476 strings)

Translation: OpenTracks/opentracks.src-main-res-values-strings-xml--main
Translate-URL: https://weblate.bubu1.eu/projects/OpenTracks/opentracks/sk/
2022-01-14 07:25:36 +01:00
mondstern bda8a9ea83 Translated using Weblate (Slovak)
Currently translated at 65.7% (313 of 476 strings)

Translation: OpenTracks/opentracks.src-main-res-values-strings-xml--main
Translate-URL: https://weblate.bubu1.eu/projects/OpenTracks/opentracks/sk/
2022-01-14 07:25:36 +01:00
dependabot[bot] 79b3e4ea5b Bump material from 1.4.0 to 1.5.0
Bumps [material](https://github.com/material-components/material-components-android) from 1.4.0 to 1.5.0.
- [Release notes](https://github.com/material-components/material-components-android/releases)
- [Commits](https://github.com/material-components/material-components-android/compare/1.4.0...1.5.0)

---
updated-dependencies:
- dependency-name: com.google.android.material:material
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-01-14 07:25:17 +01:00
dependabot[bot] 1e15222e99 Bump appcompat from 1.4.0 to 1.4.1
Bumps appcompat from 1.4.0 to 1.4.1.

---
updated-dependencies:
- dependency-name: androidx.appcompat:appcompat
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-01-13 08:00:42 +01:00
Dennis Guse 58b1396d64 Refactoring package structure.
Part of #963.
2022-01-12 22:57:35 +01:00
Dennis Guse a9f1381dae Refactoring package structure.
Part of #963.
2022-01-12 22:42:23 +01:00
Dennis Guse e508c53ca9 TrackRecordingManager: store GPS-based TrackPoints based upon the distance to the previously stored GPS-based TrackPoint. 2022-01-12 18:07:48 +01:00
Dennis Guse d691c958b9 Cleanup: TrackRecordingManager should use onNewTrackPoint(). 2022-01-12 18:07:48 +01:00
Dennis Guse bc1edec372 Bugfix: ChartView needs data.
Fixes #1086.
2022-01-12 18:06:26 +01:00
Dennis Guse 11de7d5868 Cleanup. 2022-01-09 22:35:15 +01:00
Dennis Guse 44e8cd1491 Bugfix: TrackDataHub should abort processing if stopped. 2022-01-09 19:02:54 +01:00
221 changed files with 2406 additions and 1777 deletions
+1
View File
@@ -69,6 +69,7 @@ captures/
.idea/jarRepositories.xml
.idea/markdown-navigator-enh.xml
.idea/markdown-navigator.xml
.idea/deploymentTargetDropDown.xml
# Keystore files
*.jks
+1
View File
@@ -4,6 +4,7 @@
<option name="filePathToZoomLevelMap">
<map>
<entry key="src/main/res/menu/aggregated_statistics.xml" value="0.10208333333333333" />
<entry key="src/main/res/xml/settings_gps.xml" value="0.22604166666666667" />
<entry key="src/main/res/xml/settings_sensors.xml" value="0.2101851851851852" />
</map>
</option>
+13 -1
View File
@@ -117,7 +117,19 @@ OpenTracks can be used with [Gadgetbridge](https://www.gadgetbridge.org/):
__Only required permission:__
* _ACCESS_FINE_LOCATION_: required to use the GPS.
An overview of Bluetooth LE sensors that are known to work with OpenTracks is in [README_TESTED_SENSORS.md](README_TESTED_SENSORS.md).
### API
The following functionalities by sending from an external application (e.g., [Automate](https://llamalab.com/automate/), [Tasker](https://tasker.joaoapps.com), or [Easer](https://github.com/renyuneyun/Easer)).
The API can be invoked by sending an Intent to start an activity.
Package (depends on the variant installed):
* F-Droid: `de.dennisguse.opentracks`
* GooglePlay: `de.dennisguse.opentracks.playStore`
* Debug: `de.dennisguse.opentracks.debug`
* Nightly: `de.dennisguse.opentracks.nightly`
Activity:
* **Start a recording:** `de.dennisguse.opentracks.publicapi.StartRecording`
* For testing via adb: `adb shell am start -n "package/activity"`
## Custom Dashboards (incl. map)
As of v3.3.1, OpenTracks supports custom dashboards.
+4 -4
View File
@@ -63,8 +63,8 @@ android {
defaultConfig {
applicationId "de.dennisguse.opentracks"
versionCode 4646
versionName "v3.24.0"
versionCode 4692
versionName "v3.24.1"
buildConfigField "String", "VERSION_NAME_FULL", "\"${getVersionName()}\""
@@ -123,10 +123,10 @@ android {
dependencies {
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'
implementation 'androidx.appcompat:appcompat:1.4.0'
implementation 'androidx.appcompat:appcompat:1.4.1'
implementation 'androidx.preference:preference:1.1.1'
implementation 'androidx.documentfile:documentfile:1.0.1'
implementation 'com.google.android.material:material:1.4.0'
implementation 'com.google.android.material:material:1.5.0'
implementation 'com.android.support.constraint:constraint-layout:2.0.4'
androidTestImplementation 'androidx.test:core:1.4.0'
@@ -0,0 +1,16 @@
v3.24.1: OpenTracks
Changes:
- Added API for starting recordings from other applications (disabled by default)
- Shortened ISO8601 track names
- BLE distance sensors: store GPS-locations based upon previous GPS-locations
Bugfix:
- While recording: fixed crash when opening charts
- TrackDataHub should end processing after stop()
- Prevent rare crash while deleting tracks
Developer:
- Refactored package structure
- Monotonic clock
- Value objects for heartrate, cadence, and power
@@ -29,10 +29,10 @@ import androidx.test.espresso.ViewInteraction;
import androidx.test.espresso.action.MotionEvents;
import androidx.test.espresso.util.HumanReadables;
import androidx.test.espresso.util.TreeIterables;
import androidx.test.filters.LargeTest;
import androidx.test.rule.ActivityTestRule;
import androidx.test.rule.GrantPermissionRule;
import androidx.test.ext.junit.rules.ActivityScenarioRule;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.LargeTest;
import androidx.test.rule.GrantPermissionRule;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
@@ -49,13 +49,10 @@ import java.util.concurrent.TimeoutException;
public class EspressoEditTrackRecordingTest {
@Rule
public ActivityTestRule<TrackListActivity> mActivityTestRule = new ActivityTestRule<>(TrackListActivity.class);
public ActivityScenarioRule<TrackListActivity> mActivityTestRule = new ActivityScenarioRule<>(TrackListActivity.class);
@Rule
public GrantPermissionRule mGrantPermissionRule =
GrantPermissionRule.grant(
"android.permission.ACCESS_FINE_LOCATION",
"android.permission.ACCESS_COARSE_LOCATION");
public GrantPermissionRule mGrantPermissionRule = GrantPermissionRule.grant(android.Manifest.permission.ACCESS_FINE_LOCATION);
@LargeTest
@Test
@@ -10,11 +10,10 @@ import org.junit.runner.RunWith;
import java.time.Duration;
import de.dennisguse.opentracks.content.data.Altitude;
import de.dennisguse.opentracks.content.data.Distance;
import de.dennisguse.opentracks.content.data.Speed;
import de.dennisguse.opentracks.content.data.TrackPoint;
import de.dennisguse.opentracks.fragments.TrackStubUtils;
import de.dennisguse.opentracks.data.models.Altitude;
import de.dennisguse.opentracks.data.models.Distance;
import de.dennisguse.opentracks.data.models.Speed;
import de.dennisguse.opentracks.data.models.TrackPoint;
import de.dennisguse.opentracks.stats.TrackStatistics;
@RunWith(AndroidJUnit4.class)
@@ -78,8 +77,8 @@ public class ChartPointTest {
public void create_sensorAvailable() {
// given
TrackPoint trackPoint = TrackStubUtils.createDefaultTrackPoint();
trackPoint.setHeartRate_bpm(100f);
trackPoint.setCadence_rpm(101f);
trackPoint.setHeartRate(100f);
trackPoint.setCadence(101f);
trackPoint.setPower(102f);
TrackStatistics statistics = new TrackStatistics();
@@ -14,20 +14,20 @@
* the License.
*/
package de.dennisguse.opentracks.fragments;
package de.dennisguse.opentracks.chart;
import java.time.Instant;
import de.dennisguse.opentracks.content.data.Distance;
import de.dennisguse.opentracks.content.data.Speed;
import de.dennisguse.opentracks.content.data.TrackPoint;
import de.dennisguse.opentracks.data.models.Distance;
import de.dennisguse.opentracks.data.models.Speed;
import de.dennisguse.opentracks.data.models.TrackPoint;
/**
* Commons utilities for creating stubs of track, location.
*
* @author Youtao Liu
*/
public class TrackStubUtils {
class TrackStubUtils {
public static final double INITIAL_ALTITUDE = 22;
public static final long INITIAL_TIME = 1000L;
@@ -11,10 +11,16 @@ import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
import de.dennisguse.opentracks.content.provider.TrackPointIterator;
import de.dennisguse.opentracks.data.ContentProviderUtils;
import de.dennisguse.opentracks.data.TrackPointIterator;
import de.dennisguse.opentracks.data.models.Distance;
import de.dennisguse.opentracks.data.models.Marker;
import de.dennisguse.opentracks.data.models.Speed;
import de.dennisguse.opentracks.data.models.Track;
import de.dennisguse.opentracks.data.models.TrackPoint;
import de.dennisguse.opentracks.stats.TrackStatistics;
import de.dennisguse.opentracks.stats.TrackStatisticsUpdater;
import de.dennisguse.opentracks.ui.markers.MarkerUtils;
import de.dennisguse.opentracks.util.FileUtils;
public class TestDataUtil {
@@ -119,8 +125,8 @@ public class TestDataUtil {
trackPoint.setAltitude(i * ALTITUDE_INTERVAL);
trackPoint.setSpeed(Speed.of(5f + (i / 10f)));
trackPoint.setHeartRate_bpm(100f + i);
trackPoint.setCadence_rpm(300f + i);
trackPoint.setHeartRate(100f + i);
trackPoint.setCadence(300f + i);
trackPoint.setPower(400f + i);
trackPoint.setAltitudeGain(ALTITUDE_GAIN);
trackPoint.setAltitudeLoss(ALTITUDE_LOSS);
@@ -145,7 +151,7 @@ public class TestDataUtil {
}
public static Marker createMarkerWithPhoto(Context context, Track.Id trackId, TrackPoint trackPoint) throws IOException {
File dstFile = new File(FileUtils.getImageUrl(context, trackId));
File dstFile = new File(MarkerUtils.getImageUrl(context, trackId));
dstFile.createNewFile();
Uri photoUri = FileUtils.getUriForFile(context, dstFile);
String photoUrl = photoUri.toString();
@@ -177,7 +183,7 @@ public class TestDataUtil {
for (int i = 0; i < numberOfPoints; i++) {
TrackPoint tp = TestDataUtil.createTrackPoint(i);
contentProviderUtils.insertTrackPoint(tp, dummyTrack.getId());
trackStatisticsUpdater.addTrackPoint(tp, Distance.of(0));
trackStatisticsUpdater.addTrackPoint(tp);
}
dummyTrack.setTrackStatistics(trackStatisticsUpdater.getTrackStatistics());
contentProviderUtils.updateTrack(dummyTrack);
@@ -5,6 +5,10 @@ import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import de.dennisguse.opentracks.data.models.Distance;
import de.dennisguse.opentracks.data.models.Speed;
import de.dennisguse.opentracks.data.models.TrackPoint;
public class TestSensorDataUtil {
private final List<TrackPoint> trackPointList = new ArrayList<>();
@@ -16,9 +20,15 @@ public class TestSensorDataUtil {
int i = trackPointList.size() + 1;
tp.setLatitude(TestDataUtil.INITIAL_LATITUDE + (double) i / 10000.0);
tp.setLongitude(TestDataUtil.INITIAL_LONGITUDE - (double) i / 10000.0);
tp.setHeartRate_bpm(hr);
tp.setCadence_rpm(cadence);
tp.setPower(power);
if (hr != null) {
tp.setHeartRate(hr);
}
if (cadence != null) {
tp.setCadence(cadence);
}
if (power != null) {
tp.setPower(power);
}
tp.setHorizontalAccuracy(Distance.of(1f));
tp.setAltitude(1f);
tp.setSpeed(Speed.of(5f + (i / 10f)));
@@ -14,7 +14,10 @@
* the License.
*/
package de.dennisguse.opentracks.content.provider;
package de.dennisguse.opentracks.data;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import android.content.ContentUris;
import android.content.Context;
@@ -25,12 +28,9 @@ import androidx.test.core.app.ApplicationProvider;
import org.junit.Before;
import org.junit.Test;
import de.dennisguse.opentracks.content.data.MarkerColumns;
import de.dennisguse.opentracks.content.data.TrackPointsColumns;
import de.dennisguse.opentracks.content.data.TracksColumns;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import de.dennisguse.opentracks.data.tables.MarkerColumns;
import de.dennisguse.opentracks.data.tables.TrackPointsColumns;
import de.dennisguse.opentracks.data.tables.TracksColumns;
/**
* Tests {@link CustomContentProvider}.
@@ -13,7 +13,7 @@
* License for the specific language governing permissions and limitations under
* the License.
*/
package de.dennisguse.opentracks.content.provider;
package de.dennisguse.opentracks.data;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -49,20 +49,20 @@ import java.util.Random;
import java.util.UUID;
import java.util.stream.Collectors;
import de.dennisguse.opentracks.content.data.Distance;
import de.dennisguse.opentracks.content.data.Marker;
import de.dennisguse.opentracks.content.data.MarkerColumns;
import de.dennisguse.opentracks.content.data.Speed;
import de.dennisguse.opentracks.content.data.TestDataUtil;
import de.dennisguse.opentracks.content.data.TestSensorDataUtil;
import de.dennisguse.opentracks.content.data.Track;
import de.dennisguse.opentracks.content.data.TrackPoint;
import de.dennisguse.opentracks.content.data.TrackPointsColumns;
import de.dennisguse.opentracks.content.data.TracksColumns;
import de.dennisguse.opentracks.data.models.Distance;
import de.dennisguse.opentracks.data.models.HeartRate;
import de.dennisguse.opentracks.data.models.Marker;
import de.dennisguse.opentracks.data.models.Speed;
import de.dennisguse.opentracks.data.models.Track;
import de.dennisguse.opentracks.data.models.TrackPoint;
import de.dennisguse.opentracks.data.tables.MarkerColumns;
import de.dennisguse.opentracks.data.tables.TrackPointsColumns;
import de.dennisguse.opentracks.data.tables.TracksColumns;
import de.dennisguse.opentracks.stats.SensorStatistics;
import de.dennisguse.opentracks.stats.TrackStatistics;
import de.dennisguse.opentracks.util.FileUtils;
import de.dennisguse.opentracks.util.UUIDUtils;
/**
* A unit test for {@link ContentProviderUtils}.
@@ -739,11 +739,19 @@ public class CustomContentProviderUtilsTest {
Pair<Track, List<TrackPoint>> track = TestDataUtil.createTrack(trackId, 10);
TestDataUtil.insertTrackWithLocations(contentProviderUtils, track.first, track.second);
// when / then
// when
contentProviderUtils.bulkInsertTrackPoint(track.second, trackId);
assertEquals(20, contentProviderUtils.getTrackPointCursor(trackId, null).getCount());
try (Cursor cursor = contentProviderUtils.getTrackPointCursor(trackId, null)) {
// then
assertEquals(20, cursor.getCount());
}
// when
contentProviderUtils.bulkInsertTrackPoint(track.second.subList(0, 8), trackId);
assertEquals(28, contentProviderUtils.getTrackPointCursor(trackId, null).getCount());
try (Cursor cursor = contentProviderUtils.getTrackPointCursor(trackId, null)) {
// then
assertEquals(28, cursor.getCount());
}
}
/**
@@ -777,6 +785,7 @@ public class CustomContentProviderUtilsTest {
when(cursorMock.getColumnIndexOrThrow(TrackPointsColumns.SENSOR_HEARTRATE)).thenReturn(6);
when(cursorMock.isNull(6)).thenReturn(false);
when(cursorMock.getFloat(6)).thenReturn(75f);
// when
TrackPoint trackPoint = contentProviderUtils.createTrackPoint(cursorMock);
@@ -786,7 +795,7 @@ public class CustomContentProviderUtilsTest {
assertEquals(latitude, trackPoint.getLatitude(), 0.01);
assertEquals(time, trackPoint.getTime().toEpochMilli());
assertEquals(speed, trackPoint.getSpeed().toMPS(), 0.01);
assertFalse(trackPoint.hasHeartRate());
assertEquals(HeartRate.of(75f), trackPoint.getHeartRate());
}
/**
@@ -800,7 +809,11 @@ public class CustomContentProviderUtilsTest {
Track track = TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId, 10);
contentProviderUtils.insertTrackPoint(TestDataUtil.createTrackPoint(22), trackId);
assertEquals(11, contentProviderUtils.getTrackPointCursor(trackId, null).getCount());
// when
try (Cursor cursor = contentProviderUtils.getTrackPointCursor(trackId, null)) {
// then
assertEquals(11, cursor.getCount());
}
}
@Test
@@ -810,8 +823,8 @@ public class CustomContentProviderUtilsTest {
Track track = TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId, 10);
TrackPoint trackPoint = TestDataUtil.createTrackPoint(5);
trackPoint.setHeartRate_bpm(1F);
trackPoint.setCadence_rpm(2F);
trackPoint.setHeartRate(1F);
trackPoint.setCadence(2F);
trackPoint.setPower(3F);
// when
@@ -820,9 +833,9 @@ public class CustomContentProviderUtilsTest {
// then
List<TrackPoint> trackPoints = TestDataUtil.getTrackPoints(contentProviderUtils, trackId);
assertTrue(trackPoints.get(10).hasHeartRate());
assertEquals(trackPoint.getHeartRate_bpm(), trackPoints.get(10).getHeartRate_bpm(), 0.01);
assertEquals(trackPoint.getCadence_rpm(), trackPoints.get(10).getCadence_rpm(), 0.01);
assertEquals(trackPoint.getPower(), trackPoints.get(10).getPower(), 0.01);
assertEquals(trackPoint.getHeartRate(), trackPoints.get(10).getHeartRate());
assertEquals(trackPoint.getCadence(), trackPoints.get(10).getCadence());
assertEquals(trackPoint.getPower(), trackPoints.get(10).getPower());
}
/**
@@ -850,10 +863,10 @@ public class CustomContentProviderUtilsTest {
.map(TrackPoint.Id::new).collect(Collectors.toList());
// when
Cursor cursor = contentProviderUtils.getTrackPointCursor(trackId, trackpointIds.get(8));
// then
assertEquals(2, cursor.getCount());
try (Cursor cursor = contentProviderUtils.getTrackPointCursor(trackId, trackpointIds.get(8))) {
// then
assertEquals(2, cursor.getCount());
}
}
@Test
@@ -910,8 +923,8 @@ public class CustomContentProviderUtilsTest {
TrackPoint trackPoint = TestDataUtil.createTrackPoint(1);
trackPoint.setType(TrackPoint.Type.TRACKPOINT);
trackPoint.setPower(null);
trackPoint.setCadence_rpm(null);
trackPoint.setHeartRate_bpm(null);
trackPoint.setCadence(null);
trackPoint.setHeartRate(null);
trackPointList.add(trackPoint);
Track.Id trackId = new Track.Id(System.currentTimeMillis());
Track track = TestDataUtil.createTrack(trackId);
@@ -973,13 +986,13 @@ public class CustomContentProviderUtilsTest {
// then
assertTrue(sensorStatistics.hasHeartRate());
assertEquals(sensorStatistics.getAvgHeartRate(), stats.avgHr, 0f);
assertEquals(sensorStatistics.getMaxHeartRate(), stats.maxHr, 0f);
assertEquals(sensorStatistics.getAvgHeartRate().getBPM(), stats.avgHr, 0f);
assertEquals(sensorStatistics.getMaxHeartRate().getBPM(), stats.maxHr, 0f);
assertTrue(sensorStatistics.hasCadence());
assertEquals(sensorStatistics.getAvgCadence(), stats.avgCadence, 0f);
assertEquals(sensorStatistics.getMaxCadence(), stats.maxCadence, 0f);
assertEquals(sensorStatistics.getAvgCadence().getRPM(), stats.avgCadence, 0f);
assertEquals(sensorStatistics.getMaxCadence().getRPM(), stats.maxCadence, 0f);
assertTrue(sensorStatistics.hasPower());
assertEquals(sensorStatistics.getAvgPower(), stats.avgPower, 0f);
assertEquals(sensorStatistics.getAvgPower().getW(), stats.avgPower, 0f);
}
@Test
@@ -1005,8 +1018,8 @@ public class CustomContentProviderUtilsTest {
// then
assertTrue(sensorStatistics.hasHeartRate());
assertEquals(sensorStatistics.getAvgHeartRate(), stats.avgHr, 0f);
assertEquals(sensorStatistics.getMaxHeartRate(), stats.maxHr, 0f);
assertEquals(sensorStatistics.getAvgHeartRate().getBPM(), stats.avgHr, 0f);
assertEquals(sensorStatistics.getMaxHeartRate().getBPM(), stats.maxHr, 0f);
assertFalse(sensorStatistics.hasCadence());
assertFalse(sensorStatistics.hasPower());
}
@@ -1035,8 +1048,8 @@ public class CustomContentProviderUtilsTest {
// then
assertFalse(sensorStatistics.hasHeartRate());
assertTrue(sensorStatistics.hasCadence());
assertEquals(sensorStatistics.getAvgCadence(), stats.avgCadence, 0f);
assertEquals(sensorStatistics.getMaxCadence(), stats.maxCadence, 0f);
assertEquals(sensorStatistics.getAvgCadence().getRPM(), stats.avgCadence, 0f);
assertEquals(sensorStatistics.getMaxCadence().getRPM(), stats.maxCadence, 0f);
assertFalse(sensorStatistics.hasPower());
}
@@ -1065,7 +1078,7 @@ public class CustomContentProviderUtilsTest {
assertFalse(sensorStatistics.hasHeartRate());
assertFalse(sensorStatistics.hasCadence());
assertTrue(sensorStatistics.hasPower());
assertEquals(sensorStatistics.getAvgPower(), stats.avgPower, 0f);
assertEquals(sensorStatistics.getAvgPower().getW(), stats.avgPower, 0f);
}
@Test
@@ -1098,11 +1111,11 @@ public class CustomContentProviderUtilsTest {
TestSensorDataUtil.SensorDataStats stats = sensorDataUtil.computeStats();
// then
assertEquals(sensorStatistics.getAvgHeartRate(), stats.avgHr, 0f);
assertEquals(sensorStatistics.getMaxHeartRate(), stats.maxHr, 0f);
assertEquals(sensorStatistics.getAvgCadence(), stats.avgCadence, 0f);
assertEquals(sensorStatistics.getMaxCadence(), stats.maxCadence, 0f);
assertEquals(sensorStatistics.getAvgPower(), stats.avgPower, 0f);
assertEquals(sensorStatistics.getAvgHeartRate().getBPM(), stats.avgHr, 0f);
assertEquals(sensorStatistics.getMaxHeartRate().getBPM(), stats.maxHr, 0f);
assertEquals(sensorStatistics.getAvgCadence().getRPM(), stats.avgCadence, 0f);
assertEquals(sensorStatistics.getMaxCadence().getRPM(), stats.maxCadence, 0f);
assertEquals(sensorStatistics.getAvgPower().getW(), stats.avgPower, 0f);
}
@Test
@@ -1143,11 +1156,11 @@ public class CustomContentProviderUtilsTest {
TestSensorDataUtil.SensorDataStats stats = sensorDataUtil.computeStats();
// then
assertEquals(sensorStatistics.getAvgHeartRate(), stats.avgHr, 0f);
assertEquals(sensorStatistics.getMaxHeartRate(), stats.maxHr, 0f);
assertEquals(sensorStatistics.getAvgCadence(), stats.avgCadence, 0f);
assertEquals(sensorStatistics.getMaxCadence(), stats.maxCadence, 0f);
assertEquals(sensorStatistics.getAvgPower(), stats.avgPower, 0f);
assertEquals(sensorStatistics.getAvgHeartRate().getBPM(), stats.avgHr, 0f);
assertEquals(sensorStatistics.getMaxHeartRate().getBPM(), stats.maxHr, 0f);
assertEquals(sensorStatistics.getAvgCadence().getRPM(), stats.avgCadence, 0f);
assertEquals(sensorStatistics.getMaxCadence().getRPM(), stats.maxCadence, 0f);
assertEquals(sensorStatistics.getAvgPower().getW(), stats.avgPower, 0f);
}
@Test
@@ -1188,11 +1201,11 @@ public class CustomContentProviderUtilsTest {
TestSensorDataUtil.SensorDataStats stats = sensorDataUtil.computeStats();
// then
assertEquals(sensorStatistics.getAvgHeartRate(), stats.avgHr, 0f);
assertEquals(sensorStatistics.getMaxHeartRate(), stats.maxHr, 0f);
assertEquals(sensorStatistics.getAvgCadence(), stats.avgCadence, 0f);
assertEquals(sensorStatistics.getMaxCadence(), stats.maxCadence, 0f);
assertEquals(sensorStatistics.getAvgPower(), stats.avgPower, 0f);
assertEquals(sensorStatistics.getAvgHeartRate().getBPM(), stats.avgHr, 0f);
assertEquals(sensorStatistics.getMaxHeartRate().getBPM(), stats.maxHr, 0f);
assertEquals(sensorStatistics.getAvgCadence().getRPM(), stats.avgCadence, 0f);
assertEquals(sensorStatistics.getMaxCadence().getRPM(), stats.maxCadence, 0f);
assertEquals(sensorStatistics.getAvgPower().getW(), stats.avgPower, 0f);
}
private void testGetSensorStats_randomData(int totalPoints, boolean withStartSegments) {
@@ -1219,11 +1232,11 @@ public class CustomContentProviderUtilsTest {
TestSensorDataUtil.SensorDataStats stats = sensorDataUtil.computeStats();
// then
assertEquals(sensorStatistics.getAvgHeartRate(), stats.avgHr, 0.01f);
assertEquals(sensorStatistics.getMaxHeartRate(), stats.maxHr, 0.01f);
assertEquals(sensorStatistics.getAvgCadence(), stats.avgCadence, 0.01f);
assertEquals(sensorStatistics.getMaxCadence(), stats.maxCadence, 0.01f);
assertEquals(sensorStatistics.getAvgPower(), stats.avgPower, 0.01f);
assertEquals(sensorStatistics.getAvgHeartRate().getBPM(), stats.avgHr, 0.01f);
assertEquals(sensorStatistics.getMaxHeartRate().getBPM(), stats.maxHr, 0.01f);
assertEquals(sensorStatistics.getAvgCadence().getRPM(), stats.avgCadence, 0.01f);
assertEquals(sensorStatistics.getMaxCadence().getRPM(), stats.maxCadence, 0.01f);
assertEquals(sensorStatistics.getAvgPower().getW(), stats.avgPower, 0.01f);
}
@Test
@@ -1,4 +1,8 @@
package de.dennisguse.opentracks.content.provider;
package de.dennisguse.opentracks.data;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import android.content.Context;
import android.database.Cursor;
@@ -20,13 +24,9 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import de.dennisguse.opentracks.content.data.MarkerColumns;
import de.dennisguse.opentracks.content.data.TrackPointsColumns;
import de.dennisguse.opentracks.content.data.TracksColumns;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import de.dennisguse.opentracks.data.tables.MarkerColumns;
import de.dennisguse.opentracks.data.tables.TrackPointsColumns;
import de.dennisguse.opentracks.data.tables.TracksColumns;
@RunWith(AndroidJUnit4.class)
public class CustomSQLiteOpenHelperTest {
@@ -1,4 +1,6 @@
package de.dennisguse.opentracks.content.provider;
package de.dennisguse.opentracks.data;
import static org.junit.Assert.assertEquals;
import android.net.Uri;
import android.util.Pair;
@@ -8,11 +10,9 @@ import org.junit.Test;
import java.util.HashSet;
import java.util.Set;
import de.dennisguse.opentracks.content.data.Track;
import de.dennisguse.opentracks.data.models.Track;
import de.dennisguse.opentracks.io.file.TrackFileFormat;
import static org.junit.Assert.assertEquals;
public class ShareContentProviderTest {
@Test
@@ -1,4 +1,4 @@
package de.dennisguse.opentracks.content.data;
package de.dennisguse.opentracks.data;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -9,7 +9,7 @@ import org.junit.runner.RunWith;
import java.time.Instant;
import de.dennisguse.opentracks.content.provider.SelectionData;
import de.dennisguse.opentracks.data.models.Track;
@RunWith(AndroidJUnit4.class)
public class TrackSelectionTest extends TestCase {
@@ -1,4 +1,6 @@
package de.dennisguse.opentracks.util;
package de.dennisguse.opentracks.data;
import static org.junit.Assert.assertEquals;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -7,8 +9,6 @@ import org.junit.runner.RunWith;
import java.util.UUID;
import static org.junit.Assert.assertEquals;
@RunWith(AndroidJUnit4.class)
public class UUIDUtilsTest {
@@ -1,13 +1,16 @@
package de.dennisguse.opentracks.content.data;
package de.dennisguse.opentracks.data.model;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import de.dennisguse.opentracks.data.models.Distance;
import de.dennisguse.opentracks.data.models.TrackPoint;
public class TrackPointTest {
@@ -14,7 +14,7 @@ import java.io.ByteArrayOutputStream;
import java.time.Instant;
import java.time.ZoneOffset;
import de.dennisguse.opentracks.content.data.TrackPoint;
import de.dennisguse.opentracks.data.models.TrackPoint;
import de.dennisguse.opentracks.io.file.TrackFileFormat;
@RunWith(JUnit4.class)
@@ -38,24 +38,27 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import de.dennisguse.opentracks.R;
import de.dennisguse.opentracks.content.data.Distance;
import de.dennisguse.opentracks.content.data.Marker;
import de.dennisguse.opentracks.content.data.Speed;
import de.dennisguse.opentracks.content.data.TestDataUtil;
import de.dennisguse.opentracks.content.data.Track;
import de.dennisguse.opentracks.content.data.TrackPoint;
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
import de.dennisguse.opentracks.content.sensor.SensorDataCycling;
import de.dennisguse.opentracks.content.sensor.SensorDataCyclingPower;
import de.dennisguse.opentracks.content.sensor.SensorDataHeartRate;
import de.dennisguse.opentracks.content.sensor.SensorDataSet;
import de.dennisguse.opentracks.data.ContentProviderUtils;
import de.dennisguse.opentracks.data.models.Cadence;
import de.dennisguse.opentracks.data.models.Distance;
import de.dennisguse.opentracks.data.models.HeartRate;
import de.dennisguse.opentracks.data.models.Marker;
import de.dennisguse.opentracks.data.models.Power;
import de.dennisguse.opentracks.data.models.Speed;
import de.dennisguse.opentracks.data.models.Track;
import de.dennisguse.opentracks.data.models.TrackPoint;
import de.dennisguse.opentracks.io.file.TrackFileFormat;
import de.dennisguse.opentracks.io.file.exporter.TrackExporter;
import de.dennisguse.opentracks.sensors.AltitudeSumManager;
import de.dennisguse.opentracks.sensors.BluetoothRemoteSensorManager;
import de.dennisguse.opentracks.sensors.sensorData.SensorDataCycling;
import de.dennisguse.opentracks.sensors.sensorData.SensorDataCyclingPower;
import de.dennisguse.opentracks.sensors.sensorData.SensorDataHeartRate;
import de.dennisguse.opentracks.sensors.sensorData.SensorDataSet;
import de.dennisguse.opentracks.services.TrackRecordingService;
import de.dennisguse.opentracks.services.TrackRecordingServiceTestUtils;
import de.dennisguse.opentracks.services.handlers.TrackPointCreator;
import de.dennisguse.opentracks.services.sensors.AltitudeSumManager;
import de.dennisguse.opentracks.services.sensors.BluetoothRemoteSensorManager;
import de.dennisguse.opentracks.stats.TrackStatistics;
/**
@@ -169,7 +172,7 @@ public class ExportImportTest {
track = contentProviderUtils.getTrack(trackId);
trackPoints = TestDataUtil.getTrackPoints(contentProviderUtils, trackId);
markers = contentProviderUtils.getMarkers(trackId);
assertEquals(10, trackPoints.size());
assertEquals(11, trackPoints.size());
assertEquals(2, markers.size());
}
@@ -336,9 +339,9 @@ public class ExportImportTest {
.setAltitudeLoss(1f)
.setAltitudeGain(1f)
.setSensorDistance(Distance.of(12))
.setHeartRate_bpm(66f)
.setHeartRate(66f)
.setPower(50f)
.setCadence_rpm(3f),
.setCadence(3f),
new TrackPoint(TrackPoint.Type.SEGMENT_START_AUTOMATIC, Instant.parse("2020-02-02T02:02:21Z"))
.setLatitude(3)
.setLongitude(14.002)
@@ -439,18 +442,18 @@ public class ExportImportTest {
}
}
private void mockBLESensorData(TrackPointCreator trackPointCreator, Float speed, Distance distance, Float heartRate, Float cyclingCadence, Float power) {
private void mockBLESensorData(TrackPointCreator trackPointCreator, Float speed, Distance distance, float heartRate, float cadence, Float power) {
trackPointCreator.setRemoteSensorManager(new BluetoothRemoteSensorManager(context, trackPointCreator) {
@Override
public SensorDataSet fill(@NonNull TrackPoint trackPoint) {
SensorDataSet sensorDataSet = new SensorDataSet();
sensorDataSet.set(new SensorDataCyclingPower("power", "power", power));
sensorDataSet.set(new SensorDataHeartRate("heartRate", "heartRate", heartRate));
sensorDataSet.set(new SensorDataCyclingPower("power", "power", Power.of(power)));
sensorDataSet.set(new SensorDataHeartRate("heartRate", "heartRate", HeartRate.of(heartRate)));
SensorDataCycling.Cadence cadence = Mockito.mock(SensorDataCycling.Cadence.class);
Mockito.when(cadence.hasValue()).thenReturn(true);
Mockito.when(cadence.getValue()).thenReturn(cyclingCadence);
sensorDataSet.set(cadence);
SensorDataCycling.CyclingCadence cyclingCadence = Mockito.mock(SensorDataCycling.CyclingCadence.class);
Mockito.when(cyclingCadence.hasValue()).thenReturn(true);
Mockito.when(cyclingCadence.getValue()).thenReturn(Cadence.of(cadence));
sensorDataSet.set(cyclingCadence);
if (distance != null && speed != null) {
SensorDataCycling.DistanceSpeed.Data distanceSpeedData = Mockito.mock(SensorDataCycling.DistanceSpeed.Data.class);
@@ -1,5 +1,8 @@
package de.dennisguse.opentracks.io.file.importer;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import android.content.Context;
import androidx.test.core.app.ApplicationProvider;
@@ -18,17 +21,14 @@ import java.time.Duration;
import java.time.Instant;
import java.util.List;
import de.dennisguse.opentracks.content.data.Distance;
import de.dennisguse.opentracks.content.data.Speed;
import de.dennisguse.opentracks.content.data.TestDataUtil;
import de.dennisguse.opentracks.content.data.Track;
import de.dennisguse.opentracks.content.data.TrackPoint;
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
import de.dennisguse.opentracks.data.ContentProviderUtils;
import de.dennisguse.opentracks.data.models.Distance;
import de.dennisguse.opentracks.data.models.Speed;
import de.dennisguse.opentracks.data.models.Track;
import de.dennisguse.opentracks.data.models.TrackPoint;
import de.dennisguse.opentracks.stats.TrackStatistics;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
/**
* Test that legacy KML/GPX formats can still be imported.
*/
@@ -1,5 +1,8 @@
package de.dennisguse.opentracks.io.file.importer;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import android.content.Context;
import androidx.test.core.app.ApplicationProvider;
@@ -17,15 +20,12 @@ import java.io.InputStream;
import java.time.Instant;
import java.util.List;
import de.dennisguse.opentracks.content.data.Distance;
import de.dennisguse.opentracks.content.data.Speed;
import de.dennisguse.opentracks.content.data.TestDataUtil;
import de.dennisguse.opentracks.content.data.Track;
import de.dennisguse.opentracks.content.data.TrackPoint;
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import de.dennisguse.opentracks.data.ContentProviderUtils;
import de.dennisguse.opentracks.data.models.Distance;
import de.dennisguse.opentracks.data.models.Speed;
import de.dennisguse.opentracks.data.models.Track;
import de.dennisguse.opentracks.data.models.TrackPoint;
/**
* Test that legacy KML/GPX formats can still be imported.
@@ -4,7 +4,7 @@ import org.junit.Assert;
import java.util.List;
import de.dennisguse.opentracks.content.data.TrackPoint;
import de.dennisguse.opentracks.data.models.TrackPoint;
public class TrackPointAssert {
@@ -61,17 +61,17 @@ public class TrackPointAssert {
Assert.assertEquals(expected.hasHeartRate(), actual.hasHeartRate());
if (expected.hasHeartRate()) {
Assert.assertEquals(expected.getHeartRate_bpm(), actual.getHeartRate_bpm(), delta);
Assert.assertEquals(expected.getHeartRate(), actual.getHeartRate());
}
Assert.assertEquals(expected.hasPower(), actual.hasPower());
if (expected.hasPower()) {
Assert.assertEquals(expected.getPower(), actual.getPower(), delta);
Assert.assertEquals(expected.getPower(), actual.getPower());
}
Assert.assertEquals(expected.hasCadence(), actual.hasCadence());
if (expected.hasCadence()) {
Assert.assertEquals(expected.getCadence_rpm(), actual.getCadence_rpm(), delta);
Assert.assertEquals(expected.getCadence(), actual.getCadence());
}
}
@@ -1,4 +1,4 @@
package de.dennisguse.opentracks.services.sensors;
package de.dennisguse.opentracks.sensors;
import org.junit.Assert;
import org.junit.Before;
@@ -1,4 +1,4 @@
package de.dennisguse.opentracks.util;
package de.dennisguse.opentracks.sensors;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
@@ -7,10 +7,11 @@ import android.bluetooth.BluetoothGattCharacteristic;
import org.junit.Test;
import de.dennisguse.opentracks.content.data.Distance;
import de.dennisguse.opentracks.content.data.Speed;
import de.dennisguse.opentracks.content.sensor.SensorDataCycling;
import de.dennisguse.opentracks.content.sensor.SensorDataRunning;
import de.dennisguse.opentracks.data.models.Cadence;
import de.dennisguse.opentracks.data.models.Distance;
import de.dennisguse.opentracks.data.models.Speed;
import de.dennisguse.opentracks.sensors.sensorData.SensorDataCycling;
import de.dennisguse.opentracks.sensors.sensorData.SensorDataRunning;
public class BluetoothUtilsTest {
@@ -101,7 +102,7 @@ public class BluetoothUtilsTest {
// then
assertEquals(Speed.of(5), sensor.getSpeed());
assertEquals(80, sensor.getCadence(), 0.01);
assertEquals(Cadence.of(80), sensor.getCadence());
assertEquals(Distance.of(6553.5 + 1677721.6), sensor.getTotalDistance());
}
}
@@ -1,10 +1,10 @@
package de.dennisguse.opentracks.util;
import org.junit.Test;
package de.dennisguse.opentracks.sensors;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import org.junit.Test;
public class PressureSensorUtilsTest {
// real data at 500Hz stationary
@@ -1,9 +1,9 @@
package de.dennisguse.opentracks.util;
import org.junit.Test;
package de.dennisguse.opentracks.sensors;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
public class UintUtilsTest {
@Test
@@ -1,4 +1,9 @@
package de.dennisguse.opentracks.content.sensor;
package de.dennisguse.opentracks.sensors.sensorData;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNull;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -6,13 +11,9 @@ import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import de.dennisguse.opentracks.content.data.Distance;
import de.dennisguse.opentracks.util.UintUtils;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNull;
import de.dennisguse.opentracks.data.models.Cadence;
import de.dennisguse.opentracks.data.models.Distance;
import de.dennisguse.opentracks.sensors.UintUtils;
@RunWith(AndroidJUnit4.class)
public class SensorDataCyclingTest {
@@ -20,48 +21,48 @@ public class SensorDataCyclingTest {
@Test
public void compute_cadence_1() {
// given
SensorDataCycling.Cadence previous = new SensorDataCycling.Cadence("sensorAddress", "sensorName", 1, 1024); // 1s
SensorDataCycling.Cadence current = new SensorDataCycling.Cadence("sensorAddress", "sensorName", 2, 2048); // 2s
SensorDataCycling.CyclingCadence previous = new SensorDataCycling.CyclingCadence("sensorAddress", "sensorName", 1, 1024); // 1s
SensorDataCycling.CyclingCadence current = new SensorDataCycling.CyclingCadence("sensorAddress", "sensorName", 2, 2048); // 2s
// when
current.compute(previous);
// then
assertEquals(60, current.getValue(), 0.01);
assertEquals(60, current.getValue().getRPM(), 0.01);
}
@Test
public void compute_cadence_2() {
// given
SensorDataCycling.Cadence previous = new SensorDataCycling.Cadence("sensorAddress", "sensorName", 1, 6184);
SensorDataCycling.Cadence current = new SensorDataCycling.Cadence("sensorAddress", "sensorName", 2, 8016);
SensorDataCycling.CyclingCadence previous = new SensorDataCycling.CyclingCadence("sensorAddress", "sensorName", 1, 6184);
SensorDataCycling.CyclingCadence current = new SensorDataCycling.CyclingCadence("sensorAddress", "sensorName", 2, 8016);
// when
current.compute(previous);
// then
assertEquals(33.53, current.getValue(), 0.01);
assertEquals(33.53, current.getValue().getRPM(), 0.01);
}
@Test
public void compute_cadence_sameCount() {
// given
SensorDataCycling.Cadence previous = new SensorDataCycling.Cadence("sensorAddress", "sensorName", 1, 1024);
SensorDataCycling.Cadence current = new SensorDataCycling.Cadence("sensorAddress", "sensorName", 1, 2048);
SensorDataCycling.CyclingCadence previous = new SensorDataCycling.CyclingCadence("sensorAddress", "sensorName", 1, 1024);
SensorDataCycling.CyclingCadence current = new SensorDataCycling.CyclingCadence("sensorAddress", "sensorName", 1, 2048);
// when
current.compute(previous);
// then
assertEquals(0, current.getValue(), 0.01);
assertEquals(Cadence.of(0), current.getValue());
}
@Test
public void compute_cadence_sameTime() {
// given
SensorDataCycling.Cadence previous = new SensorDataCycling.Cadence("sensorAddress", "sensorName", 1, 1024);
SensorDataCycling.Cadence current = new SensorDataCycling.Cadence("sensorAddress", "sensorName", 2, 1024);
SensorDataCycling.CyclingCadence previous = new SensorDataCycling.CyclingCadence("sensorAddress", "sensorName", 1, 1024);
SensorDataCycling.CyclingCadence current = new SensorDataCycling.CyclingCadence("sensorAddress", "sensorName", 2, 1024);
// when
current.compute(previous);
@@ -73,14 +74,14 @@ public class SensorDataCyclingTest {
@Test
public void compute_cadence_rollOverTime() {
// given
SensorDataCycling.Cadence previous = new SensorDataCycling.Cadence("sensorAddress", "sensorName", 1, UintUtils.UINT16_MAX - 1024);
SensorDataCycling.Cadence current = new SensorDataCycling.Cadence("sensorAddress", "sensorName", 2, 0);
SensorDataCycling.CyclingCadence previous = new SensorDataCycling.CyclingCadence("sensorAddress", "sensorName", 1, UintUtils.UINT16_MAX - 1024);
SensorDataCycling.CyclingCadence current = new SensorDataCycling.CyclingCadence("sensorAddress", "sensorName", 2, 0);
// when
current.compute(previous);
// then
assertEquals(60, current.getValue(), 0.01);
assertEquals(60, current.getValue().getRPM(), 0.01);
}
@Ignore("Disabled from #953")
@@ -88,21 +89,21 @@ public class SensorDataCyclingTest {
@Deprecated
public void compute_cadence_rollOverCount() {
// given
SensorDataCycling.Cadence previous = new SensorDataCycling.Cadence("sensorAddress", "sensorName", UintUtils.UINT32_MAX - 1, 1024);
SensorDataCycling.Cadence current = new SensorDataCycling.Cadence("sensorAddress", "sensorName", 0, 2048);
SensorDataCycling.CyclingCadence previous = new SensorDataCycling.CyclingCadence("sensorAddress", "sensorName", UintUtils.UINT32_MAX - 1, 1024);
SensorDataCycling.CyclingCadence current = new SensorDataCycling.CyclingCadence("sensorAddress", "sensorName", 0, 2048);
// when
current.compute(previous);
// then
assertEquals(60, current.getValue(), 0.01);
assertEquals(60, current.getValue().getRPM(), 0.01);
}
@Test
public void compute_cadence_overflow() {
// given
SensorDataCycling.Cadence previous = new SensorDataCycling.Cadence("sensorAddress", "sensorName", UintUtils.UINT32_MAX - 1, 1024);
SensorDataCycling.Cadence current = new SensorDataCycling.Cadence("sensorAddress", "sensorName", 0, 2048);
SensorDataCycling.CyclingCadence previous = new SensorDataCycling.CyclingCadence("sensorAddress", "sensorName", UintUtils.UINT32_MAX - 1, 1024);
SensorDataCycling.CyclingCadence current = new SensorDataCycling.CyclingCadence("sensorAddress", "sensorName", 0, 2048);
// when
current.compute(previous);
@@ -171,8 +172,8 @@ public class SensorDataCyclingTest {
@Test
public void equals_cadence_with_no_data() {
// given
SensorDataCycling.Cadence previous = new SensorDataCycling.Cadence("sensorAddress");
SensorDataCycling.Cadence current = new SensorDataCycling.Cadence("sensorAddress", "sensorName", 0, 2048);
SensorDataCycling.CyclingCadence previous = new SensorDataCycling.CyclingCadence("sensorAddress");
SensorDataCycling.CyclingCadence current = new SensorDataCycling.CyclingCadence("sensorAddress", "sensorName", 0, 2048);
// when
previous.toString();
@@ -1,5 +1,10 @@
package de.dennisguse.opentracks.services;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.NotificationManager;
import android.content.Context;
@@ -11,16 +16,11 @@ import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import de.dennisguse.opentracks.content.data.Distance;
import de.dennisguse.opentracks.content.data.Speed;
import de.dennisguse.opentracks.content.data.TrackPoint;
import de.dennisguse.opentracks.data.models.Distance;
import de.dennisguse.opentracks.data.models.Speed;
import de.dennisguse.opentracks.data.models.TrackPoint;
import de.dennisguse.opentracks.stats.TrackStatistics;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.class)
public class TrackRecordingServiceNotificationManagerTest {
@@ -45,10 +45,10 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import de.dennisguse.opentracks.R;
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.provider.ContentProviderUtils;
import de.dennisguse.opentracks.data.ContentProviderUtils;
import de.dennisguse.opentracks.data.models.Marker;
import de.dennisguse.opentracks.data.models.Track;
import de.dennisguse.opentracks.data.models.TrackPoint;
import de.dennisguse.opentracks.services.handlers.TrackPointCreator;
@RunWith(AndroidJUnit4.class)
@@ -28,17 +28,17 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import de.dennisguse.opentracks.R;
import de.dennisguse.opentracks.content.data.Distance;
import de.dennisguse.opentracks.content.data.Speed;
import de.dennisguse.opentracks.content.data.TestDataUtil;
import de.dennisguse.opentracks.content.data.Track;
import de.dennisguse.opentracks.content.data.TrackPoint;
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
import de.dennisguse.opentracks.content.sensor.SensorDataRunning;
import de.dennisguse.opentracks.data.ContentProviderUtils;
import de.dennisguse.opentracks.data.models.Distance;
import de.dennisguse.opentracks.data.models.Speed;
import de.dennisguse.opentracks.data.models.Track;
import de.dennisguse.opentracks.data.models.TrackPoint;
import de.dennisguse.opentracks.io.file.importer.TrackPointAssert;
import de.dennisguse.opentracks.sensors.AltitudeSumManager;
import de.dennisguse.opentracks.sensors.BluetoothRemoteSensorManager;
import de.dennisguse.opentracks.sensors.sensorData.SensorDataRunning;
import de.dennisguse.opentracks.services.handlers.TrackPointCreator;
import de.dennisguse.opentracks.services.sensors.AltitudeSumManager;
import de.dennisguse.opentracks.services.sensors.BluetoothRemoteSensorManager;
import de.dennisguse.opentracks.settings.PreferencesUtils;
import de.dennisguse.opentracks.stats.TrackStatistics;
@@ -742,7 +742,7 @@ public class TrackRecordingServiceTestRecording {
// when
String sensor2 = "2020-02-02T02:02:04Z";
trackPointCreator.setClock(sensor2);
remoteSensorManager.onChanged(new SensorDataRunning("", "", Speed.of(5), null, Distance.of(2))); //TODO Should be ignored; distance should be added to the next TrackPoint
remoteSensorManager.onChanged(new SensorDataRunning("", "", Speed.of(5), null, Distance.of(2)));
// when
String gps1 = "2020-02-02T02:02:05Z";
@@ -765,7 +765,7 @@ public class TrackRecordingServiceTestRecording {
// when
String sensor5 = "2020-02-02T02:02:10Z";
trackPointCreator.setClock(sensor5);
remoteSensorManager.onChanged(new SensorDataRunning("", "", Speed.of(5), null, Distance.of(16)));
remoteSensorManager.onChanged(new SensorDataRunning("", "", Speed.of(5), null, Distance.of(16))); //Should be ignored
// when
String gps3 = "2020-02-02T02:02:12Z";
@@ -784,7 +784,7 @@ public class TrackRecordingServiceTestRecording {
// then
new TrackPointAssert().assertEquals(List.of(
new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.parse(startTime)),
new TrackPoint(TrackPoint.Type.SENSORPOINT, Instant.parse(sensor2)) // TODO Should be ignored; is stored as it assumed to be first in current segment.
new TrackPoint(TrackPoint.Type.SENSORPOINT, Instant.parse(sensor2)) //First moving TrackPoint: store as the time might be interesting.
.setSpeed(Speed.of(5))
.setSensorDistance(Distance.of(2)),
new TrackPoint(TrackPoint.Type.TRACKPOINT, Instant.parse(gps1))
@@ -796,27 +796,21 @@ public class TrackRecordingServiceTestRecording {
new TrackPoint(TrackPoint.Type.SENSORPOINT, Instant.parse(sensor3))
.setSpeed(Speed.of(5))
.setSensorDistance(Distance.of(10)),
/*
//TODO BUG Should be stored, but sensorDistance is used instead of distance to previous TRACKPOINT.
new TrackPoint(TrackPoint.Type.SENSORPOINT, Instant.parse(sensor5)) //TODO No need to store this TrackPoint, data could be merged into the next one
.setSpeed(Speed.of(5))
.setSensorDistance(Distance.of(4)),
new TrackPoint(TrackPoint.Type.TRACKPOINT, Instant.parse(gps3))
.setLatitude(45.001)
.setLongitude(35)
.setHorizontalAccuracy(Distance.of(1))
.setSpeed(Speed.of(5))
.setSensorDistance(Distance.of(2)),
.setSensorDistance(Distance.of(0)),
new TrackPoint(TrackPoint.Type.TRACKPOINT, Instant.parse(gps4))
.setLatitude(45.001)
.setLongitude(35)
.setHorizontalAccuracy(Distance.of(1))
.setSpeed(Speed.of(5))
.setSensorDistance(Distance.of(2)),
*/
new TrackPoint(TrackPoint.Type.TRACKPOINT, Instant.parse(gps4))
.setLatitude(45.001)
.setLongitude(35)
.setHorizontalAccuracy(Distance.of(1))
.setSpeed(Speed.of(5))
.setSensorDistance(Distance.of(4)),
.setSensorDistance(Distance.of(0)),
new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, Instant.parse(stopTime))
.setSensorDistance(Distance.of(11))
.setSpeed(Speed.of(5))
@@ -45,8 +45,8 @@ import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import de.dennisguse.opentracks.content.data.Track;
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
import de.dennisguse.opentracks.data.ContentProviderUtils;
import de.dennisguse.opentracks.data.models.Track;
import de.dennisguse.opentracks.services.handlers.GpsStatusValue;
/**
@@ -9,8 +9,8 @@ import androidx.test.rule.ServiceTestRule;
import java.time.Clock;
import java.util.concurrent.TimeoutException;
import de.dennisguse.opentracks.sensors.BluetoothRemoteSensorManager;
import de.dennisguse.opentracks.services.handlers.TrackPointCreator;
import de.dennisguse.opentracks.services.sensors.BluetoothRemoteSensorManager;
import de.dennisguse.opentracks.settings.PreferencesUtils;
public class TrackRecordingServiceTestUtils {
@@ -1,4 +1,6 @@
package de.dennisguse.opentracks.services.tasks;
package de.dennisguse.opentracks.services.announcement;
import static org.junit.Assert.assertEquals;
import android.content.Context;
import android.content.Intent;
@@ -19,12 +21,10 @@ import java.time.Duration;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import de.dennisguse.opentracks.content.data.Distance;
import de.dennisguse.opentracks.data.models.Distance;
import de.dennisguse.opentracks.services.TrackRecordingService;
import de.dennisguse.opentracks.stats.TrackStatistics;
import static org.junit.Assert.assertEquals;
@RunWith(AndroidJUnit4.class)
public class VoiceAnnouncementManagerTest {
@@ -1,4 +1,6 @@
package de.dennisguse.opentracks.services.tasks;
package de.dennisguse.opentracks.services.announcement;
import static org.junit.Assert.assertEquals;
import android.content.Context;
import android.util.Pair;
@@ -13,21 +15,18 @@ import org.junit.runner.RunWith;
import java.time.Duration;
import de.dennisguse.opentracks.content.data.Distance;
import de.dennisguse.opentracks.content.data.Speed;
import de.dennisguse.opentracks.content.data.TestDataUtil;
import de.dennisguse.opentracks.content.data.Track;
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
import de.dennisguse.opentracks.content.provider.TrackPointIterator;
import de.dennisguse.opentracks.services.tasks.AnnouncementUtils;
import de.dennisguse.opentracks.data.ContentProviderUtils;
import de.dennisguse.opentracks.data.TrackPointIterator;
import de.dennisguse.opentracks.data.models.Distance;
import de.dennisguse.opentracks.data.models.Speed;
import de.dennisguse.opentracks.data.models.Track;
import de.dennisguse.opentracks.stats.TrackStatistics;
import de.dennisguse.opentracks.ui.intervals.IntervalStatistics;
import de.dennisguse.opentracks.util.StringUtils;
import de.dennisguse.opentracks.viewmodels.IntervalStatistics;
import static org.junit.Assert.assertEquals;
@RunWith(AndroidJUnit4.class)
public class AnnouncementUtilsTest {
public class VoiceAnnouncementUtilsTest {
private final Context context = ApplicationProvider.getApplicationContext();
private ContentProviderUtils contentProviderUtils;
@@ -47,7 +46,7 @@ public class AnnouncementUtilsTest {
stats.setTotalAltitudeGain(6000f);
// when
String announcement = AnnouncementUtils.getAnnouncement(context, stats, true, true, null);
String announcement = VoiceAnnouncementUtils.getAnnouncement(context, stats, true, true, null);
// then
assertEquals("total distance 20.00 kilometers in 1 hour 5 minutes 10 seconds at 18.4 kilometers per hour", announcement);
@@ -68,7 +67,7 @@ public class AnnouncementUtilsTest {
}
// when
String announcement = AnnouncementUtils.getAnnouncement(context, stats, true, true, lastInterval);
String announcement = VoiceAnnouncementUtils.getAnnouncement(context, stats, true, true, lastInterval);
// then
Assert.assertEquals(
@@ -92,7 +91,7 @@ public class AnnouncementUtilsTest {
stats.setTotalAltitudeGain(6000f);
// when
String announcement = AnnouncementUtils.getAnnouncement(context, stats, true, false, null);
String announcement = VoiceAnnouncementUtils.getAnnouncement(context, stats, true, false, null);
// then
assertEquals("total distance 20.00 kilometers in 1 hour 5 minutes 10 seconds at 3 minutes 15 seconds per kilometer", announcement);
@@ -113,7 +112,7 @@ public class AnnouncementUtilsTest {
}
// when
String announcement = AnnouncementUtils.getAnnouncement(context, stats, true, false, lastInterval);
String announcement = VoiceAnnouncementUtils.getAnnouncement(context, stats, true, false, lastInterval);
// then
assertEquals(
@@ -137,7 +136,7 @@ public class AnnouncementUtilsTest {
stats.setTotalAltitudeGain(6000f);
// when
String announcement = AnnouncementUtils.getAnnouncement(context, stats, false, true, null);
String announcement = VoiceAnnouncementUtils.getAnnouncement(context, stats, false, true, null);
// then
assertEquals("total distance 12.43 miles in 1 hour 5 minutes 10 seconds at 11.4 miles per hour", announcement);
@@ -158,7 +157,7 @@ public class AnnouncementUtilsTest {
}
// when
String announcement = AnnouncementUtils.getAnnouncement(context, stats, false, true, lastInterval);
String announcement = VoiceAnnouncementUtils.getAnnouncement(context, stats, false, true, lastInterval);
// then
assertEquals(
@@ -182,7 +181,7 @@ public class AnnouncementUtilsTest {
stats.setTotalAltitudeGain(6000f);
// when
String announcement = AnnouncementUtils.getAnnouncement(context, stats, false, false, null);
String announcement = VoiceAnnouncementUtils.getAnnouncement(context, stats, false, false, null);
// then
assertEquals("total distance 12.43 miles in 1 hour 5 minutes 10 seconds at 5 minutes 15 seconds per mile", announcement);
@@ -203,7 +202,7 @@ public class AnnouncementUtilsTest {
}
// when
String announcement = AnnouncementUtils.getAnnouncement(context, stats, false, false, lastInterval);
String announcement = VoiceAnnouncementUtils.getAnnouncement(context, stats, false, false, lastInterval);
// then
//assertEquals("total distance 12.43 miles in 1 hour 5 minutes 10 seconds at 5 minutes 15 seconds per mile Lap time of 1 minute 53 seconds per mile", announcement);
@@ -21,8 +21,8 @@ import org.mockito.junit.MockitoJUnitRunner;
import java.time.Instant;
import de.dennisguse.opentracks.content.data.Distance;
import de.dennisguse.opentracks.content.data.TrackPoint;
import de.dennisguse.opentracks.data.models.Distance;
import de.dennisguse.opentracks.data.models.TrackPoint;
import de.dennisguse.opentracks.settings.PreferencesUtils;
@RunWith(MockitoJUnitRunner.class)
@@ -12,8 +12,8 @@ import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import de.dennisguse.opentracks.content.data.Distance;
import de.dennisguse.opentracks.content.data.TrackPoint;
import de.dennisguse.opentracks.data.models.Distance;
import de.dennisguse.opentracks.data.models.TrackPoint;
@RunWith(MockitoJUnitRunner.class)
public class TrackPointCreatorTest {
@@ -17,7 +17,7 @@ import org.junit.runner.RunWith;
import java.util.List;
import de.dennisguse.opentracks.R;
import de.dennisguse.opentracks.content.data.Layout;
import de.dennisguse.opentracks.ui.customRecordingLayout.Layout;
@RunWith(AndroidJUnit4.class)
public class PreferencesOpenHelperTest {
@@ -1,4 +1,9 @@
package de.dennisguse.opentracks.util;
package de.dennisguse.opentracks.settings;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import android.content.Context;
import android.content.SharedPreferences;
@@ -11,20 +16,14 @@ import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import de.dennisguse.opentracks.R;
import de.dennisguse.opentracks.content.data.DataField;
import de.dennisguse.opentracks.content.data.Layout;
import de.dennisguse.opentracks.io.file.TrackFileFormat;
import de.dennisguse.opentracks.settings.PreferencesUtils;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.util.ArrayList;
import java.util.List;
import de.dennisguse.opentracks.R;
import de.dennisguse.opentracks.io.file.TrackFileFormat;
import de.dennisguse.opentracks.ui.customRecordingLayout.DataField;
import de.dennisguse.opentracks.ui.customRecordingLayout.Layout;
@RunWith(AndroidJUnit4.class)
public class PreferencesUtilsTest {
@@ -14,7 +14,9 @@
* the License.
*/
package de.dennisguse.opentracks.content;
package de.dennisguse.opentracks.share;
import static org.junit.Assert.assertEquals;
import android.content.Context;
@@ -31,14 +33,12 @@ import java.time.OffsetDateTime;
import java.time.ZoneId;
import de.dennisguse.opentracks.R;
import de.dennisguse.opentracks.content.data.Distance;
import de.dennisguse.opentracks.content.data.Speed;
import de.dennisguse.opentracks.content.data.Track;
import de.dennisguse.opentracks.data.models.Distance;
import de.dennisguse.opentracks.data.models.Speed;
import de.dennisguse.opentracks.data.models.Track;
import de.dennisguse.opentracks.stats.TrackStatistics;
import de.dennisguse.opentracks.util.StringUtils;
import static org.junit.Assert.assertEquals;
/**
* Tests for {@link DescriptionGenerator}.
*
@@ -82,18 +82,18 @@ public class DescriptionGeneratorTest {
+ "Description: -<br>"
+ "Total distance: 20.00 km (12.4 mi)<br>"
+ "Total time: 10:00<br>"
+ "Moving time: 05:00<br>"
+ "Average speed: 120.00 km/h (74.6 mi/h)<br>"
+ "Average moving speed: 240.00 km/h (149.1 mi/h)<br>"
+ "Max speed: 360.00 km/h (223.7 mi/h)<br>"
+ "Average pace: 0:30 min/km (0:48 min/mi)<br>"
+ "Average moving pace: 0:15 min/km (0:24 min/mi)<br>"
+ "Fastest pace: 0:10 min/km (0:16 min/mi)<br>"
+ "Max elevation: 550 m (1804 ft)<br>"
+ "Min elevation: -500 m (-1640 ft)<br>"
+ "Elevation gain: 6000 m (19685 ft)<br>"
+ "Elevation loss: 6000 m (19685 ft)<br>"
+ "Recorded: " + StringUtils.formatDateTime(OffsetDateTime.ofInstant(START_TIME, ZoneId.systemDefault())) + "<br>";
+ "Moving time: 05:00<br>"
+ "Average speed: 120.00 km/h (74.6 mi/h)<br>"
+ "Average moving speed: 240.00 km/h (149.1 mi/h)<br>"
+ "Max speed: 360.00 km/h (223.7 mi/h)<br>"
+ "Average pace: 0:30 min/km (0:48 min/mi)<br>"
+ "Average moving pace: 0:15 min/km (0:24 min/mi)<br>"
+ "Fastest pace: 0:10 min/km (0:16 min/mi)<br>"
+ "Max elevation: 550 m (1804 ft)<br>"
+ "Min elevation: -500 m (-1640 ft)<br>"
+ "Elevation gain: 6000 m (19685 ft)<br>"
+ "Elevation loss: 6000 m (19685 ft)<br>"
+ "Recorded: " + StringUtils.formatDateTime(OffsetDateTime.ofInstant(START_TIME, ZoneId.systemDefault())) + "<br>";
assertEquals(expected, descriptionGenerator.generateTrackDescription(track, true));
}
@@ -15,6 +15,9 @@
*/
package de.dennisguse.opentracks.stats;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Before;
@@ -24,11 +27,8 @@ import org.junit.runner.RunWith;
import java.time.Duration;
import java.time.Instant;
import de.dennisguse.opentracks.content.data.Distance;
import de.dennisguse.opentracks.content.data.Speed;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import de.dennisguse.opentracks.data.models.Distance;
import de.dennisguse.opentracks.data.models.Speed;
/**
* Tests for {@link TrackStatistics}.
@@ -12,12 +12,12 @@ import org.junit.runner.RunWith;
import java.time.Duration;
import java.time.Instant;
import de.dennisguse.opentracks.content.data.Altitude;
import de.dennisguse.opentracks.content.data.Distance;
import de.dennisguse.opentracks.content.data.Speed;
import de.dennisguse.opentracks.content.data.TestDataUtil;
import de.dennisguse.opentracks.content.data.Track;
import de.dennisguse.opentracks.content.data.TrackPoint;
import de.dennisguse.opentracks.data.models.Altitude;
import de.dennisguse.opentracks.data.models.Distance;
import de.dennisguse.opentracks.data.models.Speed;
import de.dennisguse.opentracks.data.models.Track;
import de.dennisguse.opentracks.data.models.TrackPoint;
@RunWith(AndroidJUnit4.class)
public class TrackStatisticsUpdaterTest {
@@ -53,7 +53,7 @@ public class TrackStatisticsUpdaterTest {
// when
TrackStatisticsUpdater subject = new TrackStatisticsUpdater();
subject.addTrackPoint(tp, GPS_DISTANCE);
subject.addTrackPoint(tp);
// then
TrackStatistics statistics = subject.getTrackStatistics();
@@ -77,7 +77,7 @@ public class TrackStatisticsUpdaterTest {
// when
TrackStatisticsUpdater subject = new TrackStatisticsUpdater();
data.trackPoints.forEach(it -> subject.addTrackPoint(it, GPS_DISTANCE));
data.trackPoints.forEach(it -> subject.addTrackPoint(it));
// then
TrackStatistics statistics = subject.getTrackStatistics();
@@ -105,9 +105,9 @@ public class TrackStatisticsUpdaterTest {
TrackPoint tp3 = new TrackPoint(0.00001, 0, Altitude.WGS84.of(5.0), Instant.ofEpochMilli(3000));
// when
subject.addTrackPoint(tp1, GPS_DISTANCE);
subject.addTrackPoint(tp2, GPS_DISTANCE);
subject.addTrackPoint(tp3, GPS_DISTANCE);
subject.addTrackPoint(tp1);
subject.addTrackPoint(tp2);
subject.addTrackPoint(tp3);
// then
assertEquals(0, subject.getTrackStatistics().getTotalDistance().toM(), 0.01);
@@ -124,9 +124,9 @@ public class TrackStatisticsUpdaterTest {
tp3.setSpeed(Speed.of(5f));
// when
subject.addTrackPoint(tp1, GPS_DISTANCE);
subject.addTrackPoint(tp2, GPS_DISTANCE);
subject.addTrackPoint(tp3, GPS_DISTANCE);
subject.addTrackPoint(tp1);
subject.addTrackPoint(tp2);
subject.addTrackPoint(tp3);
// then
assertEquals(1.10, subject.getTrackStatistics().getTotalDistance().toM(), 0.01);
@@ -149,16 +149,16 @@ public class TrackStatisticsUpdaterTest {
tp5.setSensorDistance(Distance.of(10f));
// when
subject.addTrackPoint(tp1, GPS_DISTANCE);
subject.addTrackPoint(tp2, GPS_DISTANCE);
subject.addTrackPoint(tp3, GPS_DISTANCE);
subject.addTrackPoint(tp1);
subject.addTrackPoint(tp2);
subject.addTrackPoint(tp3);
// then
assertEquals(110.57, subject.getTrackStatistics().getTotalDistance().toM(), 0.01);
// when
subject.addTrackPoint(tp4, GPS_DISTANCE);
subject.addTrackPoint(tp5, GPS_DISTANCE);
subject.addTrackPoint(tp4);
subject.addTrackPoint(tp5);
// then
assertEquals(125.57, subject.getTrackStatistics().getTotalDistance().toM(), 0.01);
@@ -178,16 +178,16 @@ public class TrackStatisticsUpdaterTest {
tp5.setSensorDistance(Distance.of(10f));
// when
subject.addTrackPoint(tp1, GPS_DISTANCE);
subject.addTrackPoint(tp2, GPS_DISTANCE);
subject.addTrackPoint(tp3, GPS_DISTANCE);
subject.addTrackPoint(tp1);
subject.addTrackPoint(tp2);
subject.addTrackPoint(tp3);
// then
assertEquals(0, subject.getTrackStatistics().getTotalDistance().toM(), 0.01);
// when
subject.addTrackPoint(tp4, GPS_DISTANCE);
subject.addTrackPoint(tp5, GPS_DISTANCE);
subject.addTrackPoint(tp4);
subject.addTrackPoint(tp5);
// then
assertEquals(15, subject.getTrackStatistics().getTotalDistance().toM(), 0.01);
@@ -209,16 +209,16 @@ public class TrackStatisticsUpdaterTest {
TrackPoint tp5 = new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, Instant.ofEpochMilli(5000));
// when
subject.addTrackPoint(tp1, GPS_DISTANCE);
subject.addTrackPoint(tp2, GPS_DISTANCE);
subject.addTrackPoint(tp3, GPS_DISTANCE);
subject.addTrackPoint(tp1);
subject.addTrackPoint(tp2);
subject.addTrackPoint(tp3);
// then
assertEquals(5, subject.getTrackStatistics().getTotalDistance().toM(), 0.01);
// when
subject.addTrackPoint(tp4, GPS_DISTANCE);
subject.addTrackPoint(tp5, GPS_DISTANCE);
subject.addTrackPoint(tp4);
subject.addTrackPoint(tp5);
// then
assertEquals(59.18, subject.getTrackStatistics().getTotalDistance().toM(), 0.01);
@@ -258,15 +258,15 @@ public class TrackStatisticsUpdaterTest {
tp4.setSpeed(Speed.of(5f));
TrackPoint tp5 = new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, Instant.ofEpochMilli(5000));
subject.addTrackPoint(tp1, GPS_DISTANCE);
subject.addTrackPoint(tp2, GPS_DISTANCE);
subject.addTrackPoint(tp3, GPS_DISTANCE);
subject.addTrackPoint(tp4, GPS_DISTANCE);
subject.addTrackPoint(tp1);
subject.addTrackPoint(tp2);
subject.addTrackPoint(tp3);
subject.addTrackPoint(tp4);
// when
TrackStatisticsUpdater copy = new TrackStatisticsUpdater(subject);
subject.addTrackPoint(tp5, GPS_DISTANCE);
copy.addTrackPoint(tp5, GPS_DISTANCE);
subject.addTrackPoint(tp5);
copy.addTrackPoint(tp5);
// then
@@ -1,4 +1,7 @@
package de.dennisguse.opentracks.viewmodels;
package de.dennisguse.opentracks.ui.aggregatedStatistics;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import android.content.Context;
@@ -13,15 +16,12 @@ import java.time.Instant;
import java.util.List;
import de.dennisguse.opentracks.R;
import de.dennisguse.opentracks.content.data.Distance;
import de.dennisguse.opentracks.content.data.Speed;
import de.dennisguse.opentracks.content.data.Track;
import de.dennisguse.opentracks.data.models.Distance;
import de.dennisguse.opentracks.data.models.Speed;
import de.dennisguse.opentracks.data.models.Track;
import de.dennisguse.opentracks.stats.TrackStatistics;
import de.dennisguse.opentracks.util.TrackIconUtils;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
@RunWith(JUnit4.class)
public class AggregatedStatisticsTest {
@@ -1,4 +1,4 @@
package de.dennisguse.opentracks;
package de.dennisguse.opentracks.ui.aggregatedStatistics;
import static androidx.test.espresso.Espresso.onView;
import static androidx.test.espresso.action.ViewActions.click;
@@ -15,10 +15,11 @@ import android.view.View;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.espresso.ViewInteraction;
import androidx.test.espresso.matcher.ViewMatchers;
import androidx.test.ext.junit.rules.ActivityScenarioRule;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.LargeTest;
import androidx.test.rule.GrantPermissionRule;
import androidx.test.runner.AndroidJUnit4;
import org.hamcrest.core.IsInstanceOf;
import org.junit.Before;
@@ -28,10 +29,12 @@ import org.junit.runner.RunWith;
import java.util.List;
import de.dennisguse.opentracks.R;
import de.dennisguse.opentracks.TrackListActivity;
import de.dennisguse.opentracks.content.data.TestDataUtil;
import de.dennisguse.opentracks.content.data.Track;
import de.dennisguse.opentracks.content.data.TrackPoint;
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
import de.dennisguse.opentracks.data.ContentProviderUtils;
import de.dennisguse.opentracks.data.models.Track;
import de.dennisguse.opentracks.data.models.TrackPoint;
@LargeTest
@RunWith(AndroidJUnit4.class)
@@ -55,7 +58,7 @@ public class EspressoAggregatedFilterTest {
@Test
public void espressoAggregatedFilterTest() {
// open AggregatedStatisticsActivity through toolbar's menu item
onView(withId(R.id.toolbar)).check(matches(isDisplayed()));
onView(ViewMatchers.withId(R.id.toolbar)).check(matches(isDisplayed()));
onView(withId(R.id.toolbar)).check(matches(hasDescendant(withId(R.id.track_list_aggregated_stats))));
onView(withId(R.id.track_list_aggregated_stats)).perform(click());
@@ -1,4 +1,4 @@
package de.dennisguse.opentracks.util;
package de.dennisguse.opentracks.ui.customRecordingLayout;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -1,4 +1,4 @@
package de.dennisguse.opentracks;
package de.dennisguse.opentracks.ui.customRecordingLayout;
import static androidx.test.espresso.Espresso.onView;
@@ -8,23 +8,22 @@ import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
import static androidx.test.espresso.matcher.ViewMatchers.withId;
import static org.hamcrest.CoreMatchers.is;
import android.content.Context;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
import androidx.recyclerview.widget.RecyclerView;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.espresso.NoMatchingViewException;
import androidx.test.espresso.UiController;
import androidx.test.espresso.ViewAction;
import androidx.test.espresso.ViewAssertion;
import androidx.test.espresso.ViewInteraction;
import androidx.test.espresso.action.MotionEvents;
import androidx.test.espresso.matcher.ViewMatchers;
import androidx.test.ext.junit.rules.ActivityScenarioRule;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.LargeTest;
import androidx.test.rule.ActivityTestRule;
import androidx.test.rule.GrantPermissionRule;
import org.hamcrest.Description;
@@ -34,28 +33,24 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import de.dennisguse.opentracks.content.data.DataField;
import de.dennisguse.opentracks.content.data.Layout;
import de.dennisguse.opentracks.R;
import de.dennisguse.opentracks.TrackListActivity;
import de.dennisguse.opentracks.settings.PreferencesUtils;
@LargeTest
@RunWith(AndroidJUnit4.class)
public class EspressoCustomLayoutTest {
private final Context context = ApplicationProvider.getApplicationContext();
@Rule
public ActivityScenarioRule<TrackListActivity> mActivityTestRule = new ActivityScenarioRule<>(TrackListActivity.class);
@Rule
public ActivityTestRule<TrackListActivity> mActivityTestRule = new ActivityTestRule<>(TrackListActivity.class);
@Rule
public GrantPermissionRule mGrantPermissionRule =
GrantPermissionRule.grant(
"android.permission.ACCESS_FINE_LOCATION");
public GrantPermissionRule mGrantPermissionRule = GrantPermissionRule.grant(android.Manifest.permission.ACCESS_FINE_LOCATION);
@Test
public void customLayoutTest() {
// TrackListActivity: start recording
ViewInteraction trackControllerRecordButton = onView(withId(R.id.controller_record));
ViewInteraction trackControllerRecordButton = onView(ViewMatchers.withId(R.id.controller_record));
trackControllerRecordButton.perform(click());
// Get custom layout preferences and check all data fields are showed.
@@ -1,4 +1,4 @@
package de.dennisguse.opentracks.content.data;
package de.dennisguse.opentracks.ui.customRecordingLayout;
import android.content.Context;
import android.content.res.Resources;
@@ -1,4 +1,7 @@
package de.dennisguse.opentracks.viewmodels;
package de.dennisguse.opentracks.ui.intervals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import android.content.Context;
import android.util.Pair;
@@ -12,18 +15,15 @@ import org.junit.runners.JUnit4;
import java.util.List;
import de.dennisguse.opentracks.content.data.Distance;
import de.dennisguse.opentracks.content.data.TestDataUtil;
import de.dennisguse.opentracks.content.data.Track;
import de.dennisguse.opentracks.content.data.TrackPoint;
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
import de.dennisguse.opentracks.content.provider.TrackPointIterator;
import de.dennisguse.opentracks.data.ContentProviderUtils;
import de.dennisguse.opentracks.data.TrackPointIterator;
import de.dennisguse.opentracks.data.models.Distance;
import de.dennisguse.opentracks.data.models.Track;
import de.dennisguse.opentracks.data.models.TrackPoint;
import de.dennisguse.opentracks.data.models.UnitConversions;
import de.dennisguse.opentracks.stats.TrackStatistics;
import de.dennisguse.opentracks.stats.TrackStatisticsUpdater;
import de.dennisguse.opentracks.util.UnitConversions;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
@RunWith(JUnit4.class)
public class IntervalStatisticsTest {
@@ -41,7 +41,7 @@ public class IntervalStatisticsTest {
private TrackStatistics buildTrackStatistics(List<TrackPoint> trackPoints) {
TrackStatisticsUpdater trackStatisticsUpdater = new TrackStatisticsUpdater();
for (TrackPoint tp : trackPoints) {
trackStatisticsUpdater.addTrackPoint(tp, Distance.of(0));
trackStatisticsUpdater.addTrackPoint(tp);
}
return trackStatisticsUpdater.getTrackStatistics();
}
@@ -132,7 +132,7 @@ public class IntervalStatisticsTest {
TrackPoint tp = TestDataUtil.createTrackPoint(i);
tp.setAltitudeLoss(null);
contentProviderUtils.insertTrackPoint(tp, dummyTrack.getId());
trackStatisticsUpdater.addTrackPoint(tp, Distance.of(0));
trackStatisticsUpdater.addTrackPoint(tp);
}
dummyTrack.setTrackStatistics(trackStatisticsUpdater.getTrackStatistics());
contentProviderUtils.updateTrack(dummyTrack);
@@ -1,5 +1,8 @@
package de.dennisguse.opentracks.util;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import android.content.Context;
import androidx.test.core.app.ApplicationProvider;
@@ -16,10 +19,7 @@ import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import de.dennisguse.opentracks.content.data.TrackPoint;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import de.dennisguse.opentracks.data.models.TrackPoint;
@RunWith(JUnit4.class)
public class EGM2008UtilsTest {
@@ -11,8 +11,8 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import de.dennisguse.opentracks.R;
import de.dennisguse.opentracks.content.data.DataField;
import de.dennisguse.opentracks.content.data.Layout;
import de.dennisguse.opentracks.ui.customRecordingLayout.DataField;
import de.dennisguse.opentracks.ui.customRecordingLayout.Layout;
@RunWith(AndroidJUnit4.class)
public class StatisticsUtilsTest extends TestCase {
@@ -45,8 +45,8 @@ import java.util.Locale;
import java.util.TimeZone;
import java.util.stream.Collectors;
import de.dennisguse.opentracks.content.data.Distance;
import de.dennisguse.opentracks.content.data.Speed;
import de.dennisguse.opentracks.data.models.Distance;
import de.dennisguse.opentracks.data.models.Speed;
/**
* Tests for {@link StringUtils}.
@@ -26,11 +26,10 @@ import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import de.dennisguse.opentracks.R;
import de.dennisguse.opentracks.content.data.Track;
import de.dennisguse.opentracks.data.models.Track;
import de.dennisguse.opentracks.settings.PreferencesUtils;
/**
@@ -42,7 +41,7 @@ import de.dennisguse.opentracks.settings.PreferencesUtils;
public class TrackNameUtilsTest {
private static final Track.Id TRACK_ID = new Track.Id(1L);
private static final OffsetDateTime START_TIME = OffsetDateTime.parse("2022-01-02T10:15:30+01:00");
private static final OffsetDateTime START_TIME = OffsetDateTime.parse("2022-01-02T10:15:30.1234+01:00");
private static final Context CONTEXT = ApplicationProvider.getApplicationContext();
@@ -61,7 +60,7 @@ public class TrackNameUtilsTest {
@Test
public void testTrackName_date_iso_8601() {
PreferencesUtils.setString(R.string.track_name_key, CONTEXT.getString(R.string.settings_recording_track_name_date_iso_8601_value));
assertEquals(StringUtils.formatDateTimeIso8601(START_TIME.toInstant(), START_TIME.getOffset()), TrackNameUtils.getTrackName(CONTEXT, TRACK_ID, START_TIME));
assertEquals("2022-01-02T10:15+01", TrackNameUtils.getTrackName(CONTEXT, TRACK_ID, START_TIME));
}
/**
@@ -1,5 +1,7 @@
package de.dennisguse.opentracks.viewmodels;
import static org.mockito.Mockito.when;
import android.content.Context;
import androidx.test.core.app.ApplicationProvider;
@@ -15,14 +17,15 @@ import java.time.Duration;
import java.util.List;
import de.dennisguse.opentracks.R;
import de.dennisguse.opentracks.content.data.Distance;
import de.dennisguse.opentracks.content.data.Layout;
import de.dennisguse.opentracks.content.data.Track;
import de.dennisguse.opentracks.data.models.Cadence;
import de.dennisguse.opentracks.data.models.Distance;
import de.dennisguse.opentracks.data.models.HeartRate;
import de.dennisguse.opentracks.data.models.Power;
import de.dennisguse.opentracks.data.models.Track;
import de.dennisguse.opentracks.services.TrackRecordingService;
import de.dennisguse.opentracks.stats.SensorStatistics;
import de.dennisguse.opentracks.stats.TrackStatistics;
import static org.mockito.Mockito.when;
import de.dennisguse.opentracks.ui.customRecordingLayout.Layout;
@RunWith(MockitoJUnitRunner.class)
public class StatisticDataBuilderTest extends TestCase {
@@ -124,8 +127,8 @@ public class StatisticDataBuilderTest extends TestCase {
@Test
public void testFromSensorStatistics_onlyHeartRate() {
when(sensorStatisticsMock.hasHeartRate()).thenReturn(true);
when(sensorStatisticsMock.getMaxHeartRate()).thenReturn(200f);
when(sensorStatisticsMock.getAvgHeartRate()).thenReturn(150f);
when(sensorStatisticsMock.getMaxHeartRate()).thenReturn(HeartRate.of(200f));
when(sensorStatisticsMock.getAvgHeartRate()).thenReturn(HeartRate.of(150f));
when(sensorStatisticsMock.hasCadence()).thenReturn(false);
when(sensorStatisticsMock.hasPower()).thenReturn(false);
@@ -142,8 +145,8 @@ public class StatisticDataBuilderTest extends TestCase {
public void testFromSensorStatistics_onlyCadence() {
when(sensorStatisticsMock.hasHeartRate()).thenReturn(false);
when(sensorStatisticsMock.hasCadence()).thenReturn(true);
when(sensorStatisticsMock.getAvgCadence()).thenReturn(90f);
when(sensorStatisticsMock.getMaxCadence()).thenReturn(110f);
when(sensorStatisticsMock.getAvgCadence()).thenReturn(Cadence.of(90f));
when(sensorStatisticsMock.getMaxCadence()).thenReturn(Cadence.of(110f));
when(sensorStatisticsMock.hasPower()).thenReturn(false);
// when
@@ -160,7 +163,7 @@ public class StatisticDataBuilderTest extends TestCase {
when(sensorStatisticsMock.hasHeartRate()).thenReturn(false);
when(sensorStatisticsMock.hasCadence()).thenReturn(false);
when(sensorStatisticsMock.hasPower()).thenReturn(true);
when(sensorStatisticsMock.getAvgPower()).thenReturn(300f);
when(sensorStatisticsMock.getAvgPower()).thenReturn(Power.of(300f));
// when
List<StatisticData> statisticDataList = StatisticDataBuilder.fromSensorStatistics(context, sensorStatisticsMock);
@@ -173,13 +176,13 @@ public class StatisticDataBuilderTest extends TestCase {
@Test
public void testFromSensorStatistics() {
when(sensorStatisticsMock.hasHeartRate()).thenReturn(true);
when(sensorStatisticsMock.getMaxHeartRate()).thenReturn(200f);
when(sensorStatisticsMock.getAvgHeartRate()).thenReturn(150f);
when(sensorStatisticsMock.getMaxHeartRate()).thenReturn(HeartRate.of(200f));
when(sensorStatisticsMock.getAvgHeartRate()).thenReturn(HeartRate.of(150f));
when(sensorStatisticsMock.hasCadence()).thenReturn(true);
when(sensorStatisticsMock.getAvgCadence()).thenReturn(90f);
when(sensorStatisticsMock.getMaxCadence()).thenReturn(110f);
when(sensorStatisticsMock.getAvgCadence()).thenReturn(Cadence.of(90f));
when(sensorStatisticsMock.getMaxCadence()).thenReturn(Cadence.of(110f));
when(sensorStatisticsMock.hasPower()).thenReturn(true);
when(sensorStatisticsMock.getAvgPower()).thenReturn(300f);
when(sensorStatisticsMock.getAvgPower()).thenReturn(Power.of(300f));
// when
List<StatisticData> statisticDataList = StatisticDataBuilder.fromSensorStatistics(context, sensorStatisticsMock);
+27 -8
View File
@@ -69,6 +69,23 @@ limitations under the License.
android:supportsRtl="true"
android:theme="@style/ThemeCustom">
<activity
android:name=".publicapi.StartRecording"
android:exported="true"
android:theme="@style/SplashTheme">
<intent-filter>
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<!-- <activity-->
<!-- android:name=".publicapi.StopRecording"-->
<!-- android:exported="true"-->
<!-- android:theme="@style/SplashTheme">-->
<!-- <intent-filter>-->
<!-- <category android:name="android.intent.category.DEFAULT" />-->
<!-- </intent-filter>-->
<!-- </activity>-->
<activity android:name=".AboutActivity" />
<activity
@@ -267,7 +284,7 @@ limitations under the License.
</activity>
<activity
android:name=".MarkerDetailActivity"
android:name=".ui.markers.MarkerDetailActivity"
android:exported="true">
<intent-filter>
<action android:name="de.dennisguse.opentracks.MarkerDetails" />
@@ -275,10 +292,10 @@ limitations under the License.
</intent-filter>
</activity>
<activity android:name=".MarkerEditActivity" />
<activity android:name=".ui.markers.MarkerEditActivity" />
<activity
android:name=".MarkerListActivity"
android:name=".ui.markers.MarkerListActivity"
android:exported="true"
android:label="@string/menu_markers"
android:launchMode="singleTop">
@@ -308,7 +325,9 @@ limitations under the License.
<activity android:name=".TrackRecordedActivity" />
<activity android:name=".TrackRecordingActivity" android:parentActivityName=".TrackListActivity">
<activity
android:name=".TrackRecordingActivity"
android:parentActivityName=".TrackListActivity">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".TrackListActivity" />
@@ -316,7 +335,7 @@ limitations under the License.
<activity android:name=".TrackEditActivity" />
<activity android:name=".AggregatedStatisticsActivity" />
<activity android:name=".ui.aggregatedStatistics.AggregatedStatisticsActivity" />
<activity android:name=".io.file.importer.DirectoryChooserActivity$ExportDirectoryChooserActivity" />
<activity android:name=".io.file.importer.DirectoryChooserActivity$DefaultTrackExportDirectoryChooserActivity" />
@@ -328,7 +347,7 @@ limitations under the License.
<activity android:name=".settings.SettingsCustomLayoutEditActivity" />
<activity
android:name=".ShowOnMapProxyActivity$KML"
android:name=".share.ShowOnMapProxyActivity$KML"
android:exported="true">
<intent-filter android:label="@string/open_track_as_KML">
<action android:name="Intent.OpenTracks-Dashboard" />
@@ -336,7 +355,7 @@ limitations under the License.
</intent-filter>
</activity>
<activity
android:name=".ShowOnMapProxyActivity$GPX"
android:name=".share.ShowOnMapProxyActivity$GPX"
android:exported="true">
<intent-filter android:label="@string/open_track_as_GPX">
<action android:name="Intent.OpenTracks-Dashboard" />
@@ -345,7 +364,7 @@ limitations under the License.
</activity>
<provider
android:name=".content.provider.ShareContentProvider"
android:name=".data.ShareContentProvider"
android:authorities="${applicationId}.content"
android:exported="false"
android:grantUriPermissions="true" />
@@ -6,8 +6,8 @@ import android.view.View;
import androidx.annotation.Nullable;
import de.dennisguse.opentracks.databinding.AboutBinding;
import de.dennisguse.opentracks.ui.util.ViewUtils;
import de.dennisguse.opentracks.util.SystemUtils;
import de.dennisguse.opentracks.util.ViewUtils;
public class AboutActivity extends AbstractActivity {
@@ -22,7 +22,8 @@ import android.view.View;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import de.dennisguse.opentracks.services.tasks.VoiceAnnouncement;
import de.dennisguse.opentracks.services.announcement.VoiceAnnouncement;
/**
* @author Jimmy Shih
@@ -22,11 +22,11 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.stream.Collectors;
import de.dennisguse.opentracks.content.data.Track;
import de.dennisguse.opentracks.fragments.ConfirmDeleteDialogFragment;
import de.dennisguse.opentracks.fragments.ConfirmDeleteDialogFragment.ConfirmDeleteCaller;
import de.dennisguse.opentracks.data.models.Track;
import de.dennisguse.opentracks.services.TrackDeleteService;
import de.dennisguse.opentracks.services.TrackDeleteServiceConnection;
import de.dennisguse.opentracks.ui.aggregatedStatistics.ConfirmDeleteDialogFragment;
import de.dennisguse.opentracks.ui.aggregatedStatistics.ConfirmDeleteDialogFragment.ConfirmDeleteCaller;
/**
* An abstract class for the following common tasks across
@@ -96,11 +96,7 @@ public abstract class AbstractTrackDeleteActivity extends AbstractActivity imple
protected abstract Track.Id getRecordingTrackId();
@Override
public void connected() {
TrackDeleteService service = trackDeleteServiceConnection.getServiceIfBound();
if (service == null) {
return;
}
public void connected(TrackDeleteService service) {
service.getDeletingStatusObservable().observe(AbstractTrackDeleteActivity.this, this::onTrackDeleteStatus);
}
}
@@ -1,46 +0,0 @@
/*
* Copyright 2012 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;
import android.view.Menu;
/**
* Callback when items in the contextual action mode are selected.
*
* @author Jimmy Shih
*/
public interface ContextualActionModeCallback {
/**
* Invoked to prepare the menu for the selected items.
*
* @param menu the menu
* @param positions the selected items' positions
* @param ids the selected items' ids, if available
* @param showSelectAll true to show select all
*/
void onPrepare(Menu menu, int[] positions, long[] ids, boolean showSelectAll);
/**
* Invoked when items are selected.
*
* @param itemId the context menu item id
* @param positions the selected items' positions
* @param ids the selected items' ids, if available
*/
boolean onClick(int itemId, int[] positions, long[] ids);
}
@@ -35,7 +35,7 @@ import androidx.fragment.app.Fragment;
import de.dennisguse.opentracks.databinding.ControllerFragmentBinding;
import de.dennisguse.opentracks.services.TrackRecordingService;
import de.dennisguse.opentracks.services.TrackRecordingServiceConnection;
import de.dennisguse.opentracks.util.ActivityUtils;
import de.dennisguse.opentracks.ui.util.ActivityUtils;
import de.dennisguse.opentracks.util.StringUtils;
/**
@@ -60,21 +60,11 @@ public class ControllerFragment extends Fragment implements View.OnTouchListener
private TrackRecordingService.RecordingStatus recordingStatus;
private TrackRecordingService.RecordingData recordingData;
private final Runnable bindChangedCallback = new Runnable() {
@Override
public void run() {
TrackRecordingService service = trackRecordingServiceConnection.getServiceIfBound();
if (service == null) {
Log.w(TAG, "could not get TrackRecordingService");
return;
}
service.getRecordingStatusObservable()
.observe(ControllerFragment.this, status -> onRecordingStatusChanged(status));
service.getRecordingDataObservable()
.observe(ControllerFragment.this, recordingData -> onTotalTimeChanged(recordingData));
}
private final TrackRecordingServiceConnection.Callback bindChangedCallback = service -> {
service.getRecordingStatusObservable()
.observe(ControllerFragment.this, this::onRecordingStatusChanged);
service.getRecordingDataObservable()
.observe(ControllerFragment.this, this::onTotalTimeChanged);
};
@Override
@@ -6,7 +6,7 @@ import android.view.View;
import androidx.annotation.Nullable;
import de.dennisguse.opentracks.databinding.HelpBinding;
import de.dennisguse.opentracks.util.ViewUtils;
import de.dennisguse.opentracks.ui.util.ViewUtils;
public class HelpActivity extends AbstractActivity {
@@ -1,10 +0,0 @@
package de.dennisguse.opentracks;
import de.dennisguse.opentracks.content.TrackDataHub;
/**
* Interface for communication between activities that use {@link de.dennisguse.opentracks.content.TrackDataHub} and their fragments that need thi data hub.
*/
public interface TrackActivityDataHubInterface {
TrackDataHub getTrackDataHub();
}
@@ -23,8 +23,8 @@ import android.widget.ArrayAdapter;
import androidx.annotation.NonNull;
import de.dennisguse.opentracks.content.data.Track;
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
import de.dennisguse.opentracks.data.ContentProviderUtils;
import de.dennisguse.opentracks.data.models.Track;
import de.dennisguse.opentracks.databinding.TrackEditBinding;
import de.dennisguse.opentracks.fragments.ChooseActivityTypeDialogFragment;
import de.dennisguse.opentracks.services.TrackRecordingServiceConnection;
@@ -28,7 +28,6 @@ import android.graphics.drawable.AnimatedVectorDrawable;
import android.location.LocationManager;
import android.os.Bundle;
import android.provider.Settings;
import android.util.Log;
import android.util.Pair;
import android.view.KeyEvent;
import android.view.Menu;
@@ -55,20 +54,23 @@ import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.Arrays;
import de.dennisguse.opentracks.content.data.Distance;
import de.dennisguse.opentracks.content.data.Track;
import de.dennisguse.opentracks.content.data.TracksColumns;
import de.dennisguse.opentracks.data.models.Distance;
import de.dennisguse.opentracks.data.models.Track;
import de.dennisguse.opentracks.data.tables.TracksColumns;
import de.dennisguse.opentracks.databinding.TrackListBinding;
import de.dennisguse.opentracks.fragments.ConfirmDeleteDialogFragment;
import de.dennisguse.opentracks.services.TrackRecordingService;
import de.dennisguse.opentracks.services.TrackRecordingServiceConnection;
import de.dennisguse.opentracks.services.handlers.GpsStatusValue;
import de.dennisguse.opentracks.settings.PreferencesUtils;
import de.dennisguse.opentracks.settings.SettingsActivity;
import de.dennisguse.opentracks.util.ActivityUtils;
import de.dennisguse.opentracks.share.ShareUtils;
import de.dennisguse.opentracks.ui.aggregatedStatistics.AggregatedStatisticsActivity;
import de.dennisguse.opentracks.ui.aggregatedStatistics.ConfirmDeleteDialogFragment;
import de.dennisguse.opentracks.ui.markers.MarkerListActivity;
import de.dennisguse.opentracks.ui.util.ActivityUtils;
import de.dennisguse.opentracks.ui.util.ListItemUtils;
import de.dennisguse.opentracks.util.IntentDashboardUtils;
import de.dennisguse.opentracks.util.IntentUtils;
import de.dennisguse.opentracks.util.ListItemUtils;
import de.dennisguse.opentracks.util.StringUtils;
import de.dennisguse.opentracks.util.TrackIconUtils;
@@ -96,7 +98,7 @@ public class TrackListActivity extends AbstractTrackDeleteActivity implements Co
private TrackRecordingService.RecordingStatus recordingStatus = TrackRecordingService.STATUS_DEFAULT;
// Callback when an item is selected in the contextual action mode
private final ContextualActionModeCallback contextualActionModeCallback = new ContextualActionModeCallback() {
private final ActivityUtils.ContextualActionModeCallback contextualActionModeCallback = new ActivityUtils.ContextualActionModeCallback() {
@Override
public void onPrepare(Menu menu, int[] positions, long[] trackIds, boolean showSelectAll) {
@@ -128,32 +130,21 @@ public class TrackListActivity extends AbstractTrackDeleteActivity implements Co
private MenuItem searchMenuItem;
private MenuItem startGpsMenuItem;
// Callback when the trackRecordingServiceConnection binding changes.
private final Runnable bindChangedCallback = new Runnable() {
@Override
public void run() {
TrackRecordingService service = trackRecordingServiceConnection.getServiceIfBound();
if (service == null) {
Log.e(TAG, "service not available to start gps or a new recording");
return;
}
private final TrackRecordingServiceConnection.Callback bindChangedCallback = service -> {
service.getRecordingStatusObservable()
.observe(TrackListActivity.this, this::onRecordingStatusChanged);
service.getRecordingStatusObservable()
.observe(TrackListActivity.this, status -> onRecordingStatusChanged(status));
service.getGpsStatusObservable()
.observe(TrackListActivity.this, this::onGpsStatusChanged);
// Get GPS status and listen GPS status changes.
service.getGpsStatusObservable()
.observe(TrackListActivity.this, status -> onGpsStatusChanged(status));
updateGpsMenuItem(true, recordingStatus.isRecording());
updateGpsMenuItem(true, recordingStatus.isRecording());
if (service.getGpsStatusObservable().getValue().isGpsStarted()) {
return;
}
//TODO Not cool to do this in a callback that might be called more than once!
service.tryStartGps();
if (service.getGpsStatusObservable().getValue().isGpsStarted()) {
return;
}
//TODO Not cool to do this in a callback that might be called more than once!
service.tryStartGps();
};
@Override
@@ -305,12 +296,11 @@ public class TrackListActivity extends AbstractTrackDeleteActivity implements Co
} else {
// Invoke trackRecordingService
if (!gpsStatusValue.isGpsStarted()) {
trackRecordingServiceConnection.startAndBind(this);
bindChangedCallback.run();
trackRecordingServiceConnection.startAndBindWithCallback(this);
} else {
TrackRecordingService trackRecordingService = trackRecordingServiceConnection.getServiceIfBound();
if (trackRecordingService != null) {
trackRecordingService.stopGpsAndShutdown();
trackRecordingService.stopGpsAndShutdown(); //TODO Handle this in TrackRecordingServiceConnection
}
trackRecordingServiceConnection.unbindAndStop(this);
}
@@ -460,7 +450,7 @@ public class TrackListActivity extends AbstractTrackDeleteActivity implements Co
}
if (itemId == R.id.list_context_menu_share) {
Intent intent = IntentUtils.newShareFileIntent(this, trackIds);
Intent intent = ShareUtils.newShareFileIntent(this, trackIds);
intent = Intent.createChooser(intent, null);
startActivity(intent);
return true;
@@ -33,21 +33,24 @@ import androidx.viewpager2.adapter.FragmentStateAdapter;
import com.google.android.material.tabs.TabLayoutMediator;
import de.dennisguse.opentracks.content.TrackDataHub;
import de.dennisguse.opentracks.content.data.Track;
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
import de.dennisguse.opentracks.chart.ChartFragment;
import de.dennisguse.opentracks.chart.TrackDataHubInterface;
import de.dennisguse.opentracks.data.ContentProviderUtils;
import de.dennisguse.opentracks.data.TrackDataHub;
import de.dennisguse.opentracks.data.models.Track;
import de.dennisguse.opentracks.databinding.TrackRecordedBinding;
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.TrackDeleteService;
import de.dennisguse.opentracks.services.TrackRecordingService;
import de.dennisguse.opentracks.services.TrackRecordingServiceConnection;
import de.dennisguse.opentracks.settings.PreferencesUtils;
import de.dennisguse.opentracks.settings.SettingsActivity;
import de.dennisguse.opentracks.share.ShareUtils;
import de.dennisguse.opentracks.ui.aggregatedStatistics.ConfirmDeleteDialogFragment;
import de.dennisguse.opentracks.ui.intervals.IntervalsFragment;
import de.dennisguse.opentracks.ui.markers.MarkerListActivity;
import de.dennisguse.opentracks.util.IntentDashboardUtils;
import de.dennisguse.opentracks.util.IntentUtils;
import de.dennisguse.opentracks.settings.PreferencesUtils;
/**
* An activity to show the track detail, record a new track or resumes an existing one.
@@ -56,7 +59,7 @@ import de.dennisguse.opentracks.settings.PreferencesUtils;
* @author Rodrigo Damazio
*/
//TODO Should not use TrackRecordingServiceConnection; only used to determine if there is NO current recording, to enable resume functionality.
public class TrackRecordedActivity extends AbstractTrackDeleteActivity implements ConfirmDeleteDialogFragment.ConfirmDeleteCaller, TrackActivityDataHubInterface {
public class TrackRecordedActivity extends AbstractTrackDeleteActivity implements ConfirmDeleteDialogFragment.ConfirmDeleteCaller, TrackDataHubInterface {
private static final String TAG = TrackRecordedActivity.class.getSimpleName();
@@ -77,20 +80,8 @@ public class TrackRecordedActivity extends AbstractTrackDeleteActivity implement
private TrackRecordingServiceConnection trackRecordingServiceConnection;
private final Runnable bindCallback = new Runnable() {
@Override
public void run() {
TrackRecordingService service = trackRecordingServiceConnection.getServiceIfBound();
if (service == null) {
Log.w(TAG, "could not get TrackRecordingService");
return;
}
service.getRecordingStatusObservable()
.observe(TrackRecordedActivity.this, status -> onRecordingStatusChanged(status));
}
};
private final TrackRecordingServiceConnection.Callback bindCallback = service -> service.getRecordingStatusObservable()
.observe(TrackRecordedActivity.this, this::onRecordingStatusChanged);
private final SharedPreferences.OnSharedPreferenceChangeListener sharedPreferenceChangeListener = new SharedPreferences.OnSharedPreferenceChangeListener() {
@Override
@@ -192,7 +183,7 @@ public class TrackRecordedActivity extends AbstractTrackDeleteActivity implement
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.track_detail_share) {
Intent intent = Intent.createChooser(IntentUtils.newShareFileIntent(this, trackId), null);
Intent intent = Intent.createChooser(ShareUtils.newShareFileIntent(this, trackId), null);
startActivity(intent);
return true;
}
@@ -21,18 +21,21 @@ import com.google.android.material.tabs.TabLayoutMediator;
import java.util.List;
import de.dennisguse.opentracks.content.TrackDataHub;
import de.dennisguse.opentracks.content.data.Track;
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
import de.dennisguse.opentracks.chart.ChartFragment;
import de.dennisguse.opentracks.chart.TrackDataHubInterface;
import de.dennisguse.opentracks.data.ContentProviderUtils;
import de.dennisguse.opentracks.data.TrackDataHub;
import de.dennisguse.opentracks.data.models.Track;
import de.dennisguse.opentracks.databinding.TrackRecordingBinding;
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.TrackRecordingService;
import de.dennisguse.opentracks.services.TrackRecordingServiceConnection;
import de.dennisguse.opentracks.settings.PreferencesUtils;
import de.dennisguse.opentracks.settings.SettingsActivity;
import de.dennisguse.opentracks.ui.intervals.IntervalsFragment;
import de.dennisguse.opentracks.ui.markers.MarkerEditActivity;
import de.dennisguse.opentracks.ui.markers.MarkerListActivity;
import de.dennisguse.opentracks.util.IntentDashboardUtils;
import de.dennisguse.opentracks.util.IntentUtils;
import de.dennisguse.opentracks.util.TrackIconUtils;
@@ -46,7 +49,7 @@ import de.dennisguse.opentracks.util.TrackUtils;
*/
//NOTE: This activity does NOT react to preference changes of R.string.recording_track_id_key.
//This mode of communication should be removed anyhow.
public class TrackRecordingActivity extends AbstractActivity implements ChooseActivityTypeDialogFragment.ChooseActivityTypeCaller, TrackActivityDataHubInterface, ControllerFragment.Callback {
public class TrackRecordingActivity extends AbstractActivity implements ChooseActivityTypeDialogFragment.ChooseActivityTypeCaller, TrackDataHubInterface, ControllerFragment.Callback {
public static final String EXTRA_TRACK_ID = "track_id";
@@ -67,14 +70,9 @@ public class TrackRecordingActivity extends AbstractActivity implements ChooseAc
private TrackRecordingService.RecordingStatus recordingStatus = TrackRecordingService.STATUS_DEFAULT;
private final Runnable bindChangedCallback = new Runnable() {
private final TrackRecordingServiceConnection.Callback bindChangedCallback = new TrackRecordingServiceConnection.Callback() {
@Override
public void run() {
TrackRecordingService service = trackRecordingServiceConnection.getServiceIfBound();
if (service == null) {
Log.w(TAG, "could not get TrackRecordingService");
return;
}
public void onConnected(TrackRecordingService service) {
service.getRecordingStatusObservable()
.observe(TrackRecordingActivity.this, status -> onRecordingStatusChanged(status));
@@ -211,13 +209,7 @@ public class TrackRecordingActivity extends AbstractActivity implements ChooseAc
trackDataHub.setRecordingStatus(recordingStatus);
}
/*
* If the binding has happened, then invoke the callback to start a new recording.
* If the binding hasn't happened, then invoking the callback will have no effect.
* But when the binding occurs, the callback will get invoked.
*/
trackRecordingServiceConnection.startAndBind(this);
bindChangedCallback.run();
trackRecordingServiceConnection.startAndBindWithCallback(this);
}
@Override
@@ -14,7 +14,7 @@ import java.util.ArrayList;
import java.util.List;
import de.dennisguse.opentracks.R;
import de.dennisguse.opentracks.content.data.CustomLayoutFieldType;
import de.dennisguse.opentracks.ui.customRecordingLayout.CustomLayoutFieldType;
import de.dennisguse.opentracks.viewmodels.StatisticData;
public class StatisticsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
@@ -14,7 +14,7 @@
* the License.
*/
package de.dennisguse.opentracks.fragments;
package de.dennisguse.opentracks.chart;
import android.app.Activity;
import android.content.SharedPreferences;
@@ -31,15 +31,12 @@ import java.util.Collections;
import java.util.List;
import de.dennisguse.opentracks.R;
import de.dennisguse.opentracks.TrackActivityDataHubInterface;
import de.dennisguse.opentracks.chart.ChartPoint;
import de.dennisguse.opentracks.content.TrackDataHub;
import de.dennisguse.opentracks.content.TrackDataListener;
import de.dennisguse.opentracks.content.data.Altitude;
import de.dennisguse.opentracks.content.data.Marker;
import de.dennisguse.opentracks.content.data.Speed;
import de.dennisguse.opentracks.content.data.Track;
import de.dennisguse.opentracks.content.data.TrackPoint;
import de.dennisguse.opentracks.data.TrackDataHub;
import de.dennisguse.opentracks.data.models.Altitude;
import de.dennisguse.opentracks.data.models.Marker;
import de.dennisguse.opentracks.data.models.Speed;
import de.dennisguse.opentracks.data.models.Track;
import de.dennisguse.opentracks.data.models.TrackPoint;
import de.dennisguse.opentracks.databinding.ChartBinding;
import de.dennisguse.opentracks.settings.PreferencesUtils;
import de.dennisguse.opentracks.stats.TrackStatistics;
@@ -52,7 +49,7 @@ import de.dennisguse.opentracks.stats.TrackStatisticsUpdater;
* @author Sandor Dornbush
* @author Rodrigo Damazio
*/
public class ChartFragment extends Fragment implements TrackDataListener {
public class ChartFragment extends Fragment implements TrackDataHub.Listener {
private static final String KEY_CHART_VIEW_BY_DISTANCE_KEY = "chartViewByDistance";
@@ -243,7 +240,7 @@ public class ChartFragment extends Fragment implements TrackDataListener {
* Needs to be synchronized because trackDataHub can be accessed by multiple threads.
*/
private synchronized void resumeTrackDataHub() {
trackDataHub = ((TrackActivityDataHubInterface) getActivity()).getTrackDataHub();
trackDataHub = ((TrackDataHubInterface) getActivity()).getTrackDataHub();
trackDataHub.registerTrackDataListener(this);
}
@@ -3,12 +3,12 @@ package de.dennisguse.opentracks.chart;
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
import de.dennisguse.opentracks.content.data.Altitude;
import de.dennisguse.opentracks.content.data.Distance;
import de.dennisguse.opentracks.content.data.Speed;
import de.dennisguse.opentracks.content.data.TrackPoint;
import de.dennisguse.opentracks.data.models.Altitude;
import de.dennisguse.opentracks.data.models.Distance;
import de.dennisguse.opentracks.data.models.Speed;
import de.dennisguse.opentracks.data.models.TrackPoint;
import de.dennisguse.opentracks.data.models.UnitConversions;
import de.dennisguse.opentracks.stats.TrackStatistics;
import de.dennisguse.opentracks.util.UnitConversions;
public class ChartPoint {
//X-axis
@@ -44,13 +44,13 @@ public class ChartPoint {
pace = smoothedSpeed.toPace(metricUnits).toMillis() * UnitConversions.MS_TO_S * UnitConversions.S_TO_MIN;
}
if (trackPoint.hasHeartRate()) {
heartRate = (double) trackPoint.getHeartRate_bpm();
heartRate = (double) trackPoint.getHeartRate().getBPM();
}
if (trackPoint.hasCadence()) {
cadence = (double) trackPoint.getCadence_rpm();
cadence = (double) trackPoint.getCadence().getRPM();
}
if (trackPoint.hasPower()) {
power = (double) trackPoint.getPower();
power = (double) trackPoint.getPower().getW();
}
}
@@ -41,16 +41,17 @@ import androidx.core.view.GestureDetectorCompat;
import java.text.NumberFormat;
import java.time.Duration;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import de.dennisguse.opentracks.MarkerDetailActivity;
import de.dennisguse.opentracks.R;
import de.dennisguse.opentracks.content.data.Marker;
import de.dennisguse.opentracks.data.models.Marker;
import de.dennisguse.opentracks.stats.ExtremityMonitor;
import de.dennisguse.opentracks.ui.markers.MarkerDetailActivity;
import de.dennisguse.opentracks.ui.markers.MarkerUtils;
import de.dennisguse.opentracks.ui.util.ThemeUtils;
import de.dennisguse.opentracks.util.IntentUtils;
import de.dennisguse.opentracks.util.MarkerUtils;
import de.dennisguse.opentracks.util.StringUtils;
import de.dennisguse.opentracks.util.ThemeUtils;
/**
* Visualization of the chart.
@@ -82,12 +83,12 @@ public class ChartView extends View {
X_FRACTION_FORMAT.setMinimumFractionDigits(1);
}
private final List<ChartValueSeries> seriesList = new ArrayList<>();
private final List<ChartValueSeries> seriesList = new LinkedList<>();
private final ChartValueSeries speedSeries;
private final ChartValueSeries paceSeries;
private final List<ChartPoint> chartPoints = new ArrayList<>();
private final List<Marker> markers = new ArrayList<>();
private final LinkedList<ChartPoint> chartPoints = new LinkedList<>();
private final List<Marker> markers = new LinkedList<>();
private final ExtremityMonitor xExtremityMonitor = new ExtremityMonitor();
private final int backgroundColor;
private final Paint axisPaint;
@@ -834,22 +835,22 @@ public class ChartView extends View {
return paint.measureText(marker);
}
/**
* Draws the current pointer.
*
* @param canvas the canvas
*/
private void drawPointer(Canvas canvas) {
if (chartPoints.isEmpty()) {
return;
}
ChartPoint last = chartPoints.getLast();
ChartValueSeries firstChartValueSeries = null;
for (ChartValueSeries chartValueSeries : seriesList) {
if (chartValueSeries.isEnabled() && chartValueSeries.hasData()) {
if (chartValueSeries.isEnabled() && chartValueSeries.hasData() && chartValueSeries.isChartPointValid(last)) {
firstChartValueSeries = chartValueSeries;
break;
}
}
if (firstChartValueSeries != null && chartPoints.size() > 0) {
int dx = getX(maxX) - pointer.getIntrinsicWidth() / 2;
double value = firstChartValueSeries.extractDataFromChartPoint(chartPoints.get(chartPoints.size() - 1));
double value = firstChartValueSeries.extractDataFromChartPoint(last);
int dy = getY(firstChartValueSeries, value) - pointer.getIntrinsicHeight();
canvas.translate(dx, dy);
pointer.draw(canvas);
@@ -0,0 +1,10 @@
package de.dennisguse.opentracks.chart;
import de.dennisguse.opentracks.data.TrackDataHub;
/**
* Interface for communication between activities that use {@link TrackDataHub} and their fragments that need thi data hub.
*/
public interface TrackDataHubInterface {
TrackDataHub getTrackDataHub();
}
@@ -1,91 +0,0 @@
/*
* Copyright 2011 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.content;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import de.dennisguse.opentracks.content.data.Altitude;
import de.dennisguse.opentracks.content.data.Marker;
import de.dennisguse.opentracks.content.data.Speed;
import de.dennisguse.opentracks.content.data.Track;
import de.dennisguse.opentracks.content.data.TrackPoint;
import de.dennisguse.opentracks.stats.TrackStatistics;
/**
* Listener for track data changes.
*
* @author Rodrigo Damazio
*/
public interface TrackDataListener {
/**
* Called when the track or its statistics has been updated.
*
* @param track the track
*/
//TODO Could be @NonNull
void onTrackUpdated(Track track);
/**
* Called to clear previously-sent track points.
*/
void clearTrackPoints();
/**
* Called when a sampled in track point is read.
*
* @param trackPoint the trackPoint
*/
default void onSampledInTrackPoint(@NonNull TrackPoint trackPoint, @NonNull TrackStatistics trackStatistics, Speed smoothedSpeed, @Nullable Altitude smoothedAltitude_m) {
}
/**
* Called when a sampled out track point is read.
*
* @param trackPoint the trackPoint
*/
default void onSampledOutTrackPoint(@NonNull TrackPoint trackPoint, @NonNull TrackStatistics trackStatistics) {
}
/**
* Called when finish sending new track points.
*/
default void onNewTrackPointsDone() {
}
/**
* Called to clear previously sent markers.
*/
default void clearMarkers() {
}
/**
* Called when a new marker is read.
*
* @param marker the marker
*/
default void onNewMarker(@NonNull Marker marker) {
}
/**
* Called when finish sending new markers.
* This gets called after every batch of calls to {@link #clearMarkers()} and {@link #onNewMarker(Marker)}.
*/
default void onNewMarkersDone() {
}
}
@@ -1,27 +0,0 @@
package de.dennisguse.opentracks.content.sensor;
import androidx.annotation.NonNull;
public class SensorDataCyclingPower extends SensorData<Float> {
public SensorDataCyclingPower(String address) {
super(address);
}
public SensorDataCyclingPower(String name, String address, float power_w) {
super(name, address);
this.value = power_w;
}
@NonNull
@Override
public String toString() {
return super.toString() + " power=" + value;
}
@NonNull
@Override
protected Float getNoneValue() {
return 0f;
}
}
@@ -1,27 +0,0 @@
package de.dennisguse.opentracks.content.sensor;
import androidx.annotation.NonNull;
public class SensorDataHeartRate extends SensorData<Float> {
public SensorDataHeartRate(String address) {
super(address);
}
public SensorDataHeartRate(String name, String address, float heartRate_bpm) {
super(name, address);
this.value = heartRate_bpm;
}
@NonNull
@Override
public String toString() {
return super.toString() + " heart=" + value;
}
@NonNull
@Override
protected Float getNoneValue() {
return 0f;
}
}
@@ -1,8 +1,8 @@
package de.dennisguse.opentracks.content.provider;
package de.dennisguse.opentracks.data;
import android.database.Cursor;
import de.dennisguse.opentracks.content.data.TrackPointsColumns;
import de.dennisguse.opentracks.data.tables.TrackPointsColumns;
/**
* A cache of track points indexes.
@@ -14,7 +14,7 @@
* the License.
*/
package de.dennisguse.opentracks.content.provider;
package de.dennisguse.opentracks.data;
import android.content.ContentResolver;
import android.content.ContentUris;
@@ -40,19 +40,22 @@ import java.util.List;
import java.util.UUID;
import de.dennisguse.opentracks.BuildConfig;
import de.dennisguse.opentracks.content.data.Altitude;
import de.dennisguse.opentracks.content.data.Distance;
import de.dennisguse.opentracks.content.data.Marker;
import de.dennisguse.opentracks.content.data.MarkerColumns;
import de.dennisguse.opentracks.content.data.Speed;
import de.dennisguse.opentracks.content.data.Track;
import de.dennisguse.opentracks.content.data.TrackPoint;
import de.dennisguse.opentracks.content.data.TrackPointsColumns;
import de.dennisguse.opentracks.content.data.TracksColumns;
import de.dennisguse.opentracks.data.models.Altitude;
import de.dennisguse.opentracks.data.models.Cadence;
import de.dennisguse.opentracks.data.models.Distance;
import de.dennisguse.opentracks.data.models.HeartRate;
import de.dennisguse.opentracks.data.models.Marker;
import de.dennisguse.opentracks.data.models.Power;
import de.dennisguse.opentracks.data.models.Speed;
import de.dennisguse.opentracks.data.models.Track;
import de.dennisguse.opentracks.data.models.TrackPoint;
import de.dennisguse.opentracks.data.tables.MarkerColumns;
import de.dennisguse.opentracks.data.tables.TrackPointsColumns;
import de.dennisguse.opentracks.data.tables.TracksColumns;
import de.dennisguse.opentracks.stats.SensorStatistics;
import de.dennisguse.opentracks.stats.TrackStatistics;
import de.dennisguse.opentracks.ui.markers.MarkerUtils;
import de.dennisguse.opentracks.util.FileUtils;
import de.dennisguse.opentracks.util.UUIDUtils;
/**
* {@link ContentProviderUtils} implementation.
@@ -475,7 +478,7 @@ public class ContentProviderUtils {
private void deleteMarkerPhoto(Context context, Marker marker) {
if (marker != null && marker.hasPhoto()) {
Uri uri = marker.getPhotoURI();
File file = FileUtils.buildInternalPhotoFile(context, marker.getTrackId(), uri);
File file = MarkerUtils.buildInternalPhotoFile(context, marker.getTrackId(), uri);
if (file.exists()) {
File parent = file.getParentFile();
file.delete();
@@ -578,10 +581,10 @@ public class ContentProviderUtils {
}
if (!cursor.isNull(indexes.sensorHeartRateIndex)) {
trackPoint.setHeartRate_bpm(cursor.getFloat(indexes.sensorHeartRateIndex));
trackPoint.setHeartRate(cursor.getFloat(indexes.sensorHeartRateIndex));
}
if (!cursor.isNull(indexes.sensorCadenceIndex)) {
trackPoint.setCadence_rpm(cursor.getFloat(indexes.sensorCadenceIndex));
trackPoint.setCadence(cursor.getFloat(indexes.sensorCadenceIndex));
}
if (!cursor.isNull(indexes.sensorDistanceIndex)) {
trackPoint.setSensorDistance(Distance.of(cursor.getFloat(indexes.sensorDistanceIndex)));
@@ -740,16 +743,16 @@ public class ContentProviderUtils {
}
if (trackPoint.hasHeartRate()) {
values.put(TrackPointsColumns.SENSOR_HEARTRATE, trackPoint.getHeartRate_bpm());
values.put(TrackPointsColumns.SENSOR_HEARTRATE, trackPoint.getHeartRate().getBPM());
}
if (trackPoint.hasCadence()) {
values.put(TrackPointsColumns.SENSOR_CADENCE, trackPoint.getCadence_rpm());
values.put(TrackPointsColumns.SENSOR_CADENCE, trackPoint.getCadence().getRPM());
}
if (trackPoint.hasSensorDistance()) {
values.put(TrackPointsColumns.SENSOR_DISTANCE, trackPoint.getSensorDistance().toM());
}
if (trackPoint.hasPower()) {
values.put(TrackPointsColumns.SENSOR_POWER, trackPoint.getPower());
values.put(TrackPointsColumns.SENSOR_POWER, trackPoint.getPower().getW());
}
if (trackPoint.hasAltitudeGain()) {
@@ -832,12 +835,17 @@ public class ContentProviderUtils {
SensorStatistics sensorStatistics = null;
try (Cursor cursor = contentResolver.query(ContentUris.withAppendedId(TracksColumns.CONTENT_URI_SENSOR_STATS, trackId.getId()), null, null, null, null)) {
if (cursor != null && cursor.moveToFirst()) {
final int MAX_HR_INDEX = cursor.getColumnIndexOrThrow(TrackPointsColumns.ALIAS_MAX_HR);
final int AVG_HR_INDEX = cursor.getColumnIndexOrThrow(TrackPointsColumns.ALIAS_AVG_HR);
final int MAX_CADENCE_INDEX = cursor.getColumnIndexOrThrow(TrackPointsColumns.ALIAS_MAX_CADENCE);
final int AVG_CADENCE_INDEX = cursor.getColumnIndexOrThrow(TrackPointsColumns.ALIAS_AVG_CADENCE);
final int AVG_POWER_INDEX = cursor.getColumnIndexOrThrow(TrackPointsColumns.ALIAS_AVG_POWER);
sensorStatistics = new SensorStatistics(
!cursor.isNull(cursor.getColumnIndexOrThrow("max_hr")) ? cursor.getFloat(cursor.getColumnIndexOrThrow(TrackPointsColumns.ALIAS_MAX_HR)) : null,
!cursor.isNull(cursor.getColumnIndexOrThrow("avg_hr")) ? cursor.getFloat(cursor.getColumnIndexOrThrow(TrackPointsColumns.ALIAS_AVG_HR)) : null,
!cursor.isNull(cursor.getColumnIndexOrThrow("max_cadence")) ? cursor.getFloat(cursor.getColumnIndexOrThrow(TrackPointsColumns.ALIAS_MAX_CADENCE)) : null,
!cursor.isNull(cursor.getColumnIndexOrThrow("avg_cadence")) ? cursor.getFloat(cursor.getColumnIndexOrThrow(TrackPointsColumns.ALIAS_AVG_CADENCE)) : null,
!cursor.isNull(cursor.getColumnIndexOrThrow("avg_power")) ? cursor.getFloat(cursor.getColumnIndexOrThrow(TrackPointsColumns.ALIAS_AVG_POWER)) : null
!cursor.isNull(MAX_HR_INDEX) ? HeartRate.of(cursor.getFloat(MAX_HR_INDEX)) : null,
!cursor.isNull(AVG_HR_INDEX) ? HeartRate.of(cursor.getFloat(AVG_HR_INDEX)) : null,
!cursor.isNull(MAX_CADENCE_INDEX) ? Cadence.of(cursor.getFloat(MAX_CADENCE_INDEX)) : null,
!cursor.isNull(AVG_CADENCE_INDEX) ? Cadence.of(cursor.getFloat(AVG_CADENCE_INDEX)) : null,
!cursor.isNull(AVG_POWER_INDEX) ? Power.of(cursor.getFloat(AVG_POWER_INDEX)) : null
);
}
@@ -14,7 +14,7 @@
* the License.
*/
package de.dennisguse.opentracks.content.provider;
package de.dennisguse.opentracks.data;
import android.content.ContentProvider;
import android.content.ContentUris;
@@ -35,10 +35,10 @@ import androidx.annotation.VisibleForTesting;
import java.util.Arrays;
import de.dennisguse.opentracks.content.data.MarkerColumns;
import de.dennisguse.opentracks.content.data.TrackPoint;
import de.dennisguse.opentracks.content.data.TrackPointsColumns;
import de.dennisguse.opentracks.content.data.TracksColumns;
import de.dennisguse.opentracks.data.models.TrackPoint;
import de.dennisguse.opentracks.data.tables.MarkerColumns;
import de.dennisguse.opentracks.data.tables.TrackPointsColumns;
import de.dennisguse.opentracks.data.tables.TracksColumns;
/**
* A {@link ContentProvider} that handles access to track points, tracks, and markers tables.
@@ -1,4 +1,4 @@
package de.dennisguse.opentracks.content.provider;
package de.dennisguse.opentracks.data;
import android.content.ContentValues;
import android.content.Context;
@@ -15,11 +15,10 @@ import java.time.zone.ZoneRules;
import java.util.UUID;
import de.dennisguse.opentracks.Startup;
import de.dennisguse.opentracks.content.data.MarkerColumns;
import de.dennisguse.opentracks.content.data.Track;
import de.dennisguse.opentracks.content.data.TrackPointsColumns;
import de.dennisguse.opentracks.content.data.TracksColumns;
import de.dennisguse.opentracks.util.UUIDUtils;
import de.dennisguse.opentracks.data.models.Track;
import de.dennisguse.opentracks.data.tables.MarkerColumns;
import de.dennisguse.opentracks.data.tables.TrackPointsColumns;
import de.dennisguse.opentracks.data.tables.TracksColumns;
/**
* Database helper for creating and upgrading the database.
@@ -1,4 +1,4 @@
package de.dennisguse.opentracks.content.provider;
package de.dennisguse.opentracks.data;
public class SelectionData {
private final String selection;
@@ -1,4 +1,4 @@
package de.dennisguse.opentracks.content.provider;
package de.dennisguse.opentracks.data;
import android.content.Context;
import android.content.UriMatcher;
@@ -25,8 +25,8 @@ import java.util.HashSet;
import java.util.List;
import java.util.Set;
import de.dennisguse.opentracks.content.data.Track;
import de.dennisguse.opentracks.content.data.TracksColumns;
import de.dennisguse.opentracks.data.models.Track;
import de.dennisguse.opentracks.data.tables.TracksColumns;
import de.dennisguse.opentracks.io.file.TrackFileFormat;
import de.dennisguse.opentracks.io.file.exporter.TrackExporter;
@@ -14,7 +14,7 @@
* the License.
*/
package de.dennisguse.opentracks.content;
package de.dennisguse.opentracks.data;
import android.content.ContentResolver;
import android.content.Context;
@@ -25,28 +25,30 @@ import android.os.HandlerThread;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import de.dennisguse.opentracks.content.data.Distance;
import de.dennisguse.opentracks.content.data.Marker;
import de.dennisguse.opentracks.content.data.MarkerColumns;
import de.dennisguse.opentracks.content.data.Track;
import de.dennisguse.opentracks.content.data.TrackPoint;
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.data.models.Altitude;
import de.dennisguse.opentracks.data.models.Distance;
import de.dennisguse.opentracks.data.models.Marker;
import de.dennisguse.opentracks.data.models.Speed;
import de.dennisguse.opentracks.data.models.Track;
import de.dennisguse.opentracks.data.models.TrackPoint;
import de.dennisguse.opentracks.data.tables.MarkerColumns;
import de.dennisguse.opentracks.data.tables.TrackPointsColumns;
import de.dennisguse.opentracks.data.tables.TracksColumns;
import de.dennisguse.opentracks.services.TrackRecordingService;
import de.dennisguse.opentracks.services.handlers.EGM2008CorrectionManager;
import de.dennisguse.opentracks.stats.TrackStatistics;
import de.dennisguse.opentracks.stats.TrackStatisticsUpdater;
/**
* Track data hub.
* Receives data from {@link de.dennisguse.opentracks.content.provider.CustomContentProvider} and distributes it to {@link TrackDataListener} after some processing.
* Receives data from {@link CustomContentProvider} and distributes it to {@link Listener} after some processing.
* <p>
* {@link TrackPoint}s are filtered/downsampled with a dynamic sampling frequency.
*
@@ -70,7 +72,7 @@ public class TrackDataHub {
private static final String TAG = TrackDataHub.class.getSimpleName();
private final Context context;
private final Set<TrackDataListener> listeners;
private final Set<Listener> listeners;
private final ContentProviderUtils contentProviderUtils;
private final int targetNumPoints;
@@ -178,11 +180,11 @@ public class TrackDataHub {
}
/**
* Registers a {@link TrackDataListener}.
* Registers a {@link Listener}.
*
* @param trackDataListener the track data listener
*/
public void registerTrackDataListener(final TrackDataListener trackDataListener) {
public void registerTrackDataListener(final Listener trackDataListener) {
handler.post(() -> {
listeners.add(trackDataListener);
if (isStarted()) {
@@ -192,11 +194,11 @@ public class TrackDataHub {
}
/**
* Unregisters a {@link TrackDataListener}.
* Unregisters a {@link Listener}.
*
* @param trackDataListener the track data listener
*/
public void unregisterTrackDataListener(final TrackDataListener trackDataListener) {
public void unregisterTrackDataListener(final Listener trackDataListener) {
handler.post(() -> listeners.remove(trackDataListener));
}
@@ -218,7 +220,7 @@ public class TrackDataHub {
notifyTracksTableUpdate(listeners);
for (TrackDataListener listener : listeners) {
for (Listener listener : listeners) {
listener.clearTrackPoints();
}
notifyTrackPointsTableUpdate(true, listeners);
@@ -230,8 +232,8 @@ public class TrackDataHub {
*
* @param trackDataListener the track data listener.
*/
private void loadDataForListener(TrackDataListener trackDataListener) {
Set<TrackDataListener> trackDataListeners = Collections.singleton(trackDataListener);
private void loadDataForListener(Listener trackDataListener) {
Set<Listener> trackDataListeners = Collections.singleton(trackDataListener);
//Track
notifyTracksTableUpdate(trackDataListeners);
@@ -253,12 +255,12 @@ public class TrackDataHub {
*
* @param trackDataListeners the track data listeners to notify
*/
private void notifyTracksTableUpdate(Set<TrackDataListener> trackDataListeners) {
private void notifyTracksTableUpdate(Set<Listener> trackDataListeners) {
if (trackDataListeners.isEmpty()) {
return;
}
Track track = contentProviderUtils.getTrack(selectedTrackId);
for (TrackDataListener trackDataListener : trackDataListeners) {
for (Listener trackDataListener : trackDataListeners) {
trackDataListener.onTrackUpdated(track);
}
}
@@ -269,12 +271,12 @@ public class TrackDataHub {
*
* @param trackDataListeners the track data listeners to notify
*/
private void notifyMarkersTableUpdate(Set<TrackDataListener> trackDataListeners) {
private void notifyMarkersTableUpdate(Set<Listener> trackDataListeners) {
if (trackDataListeners.isEmpty()) {
return;
}
for (TrackDataListener trackDataListener : trackDataListeners) {
for (Listener trackDataListener : trackDataListeners) {
trackDataListener.clearMarkers();
}
@@ -282,14 +284,14 @@ public class TrackDataHub {
if (cursor != null && cursor.moveToFirst()) {
do {
Marker marker = contentProviderUtils.createMarker(cursor);
for (TrackDataListener trackDataListener : trackDataListeners) {
for (Listener trackDataListener : trackDataListeners) {
trackDataListener.onNewMarker(marker);
}
} while (cursor.moveToNext());
}
}
for (TrackDataListener trackDataListener : trackDataListeners) {
for (Listener trackDataListener : trackDataListeners) {
trackDataListener.onNewMarkersDone();
}
}
@@ -299,7 +301,7 @@ public class TrackDataHub {
*
* @param updateSamplingState true to update the sampling state
*/
private void notifyTrackPointsTableUpdate(boolean updateSamplingState, Set<TrackDataListener> listeners) {
private void notifyTrackPointsTableUpdate(boolean updateSamplingState, Set<Listener> listeners) {
if (listeners.isEmpty()) {
return;
}
@@ -308,7 +310,7 @@ public class TrackDataHub {
// Reload and resample the track at a lower frequency.
Log.i(TAG, "Resampling track after " + numLoadedPoints + " points.");
resetSamplingState();
for (TrackDataListener listener : listeners) {
for (Listener listener : listeners) {
listener.clearTrackPoints();
}
}
@@ -336,13 +338,13 @@ public class TrackDataHub {
try (TrackPointIterator trackPointIterator = contentProviderUtils.getTrackPointLocationIterator(selectedTrackId, next)) {
while (trackPointIterator.hasNext()) {
if (!isStarted()) {
break;
}
//Prevents a NPE if stop() is happening while notifyTrackPointsTableUpdate()
TrackStatisticsUpdater currentUpdater = trackStatisticsUpdater;
if (!isStarted()) {
return;
}
trackPoint = trackPointIterator.next();
TrackPoint.Id trackPointId = trackPoint.getId();
@@ -362,15 +364,15 @@ public class TrackDataHub {
samplingFrequency = 1 + (int) (numTotalPoints / targetNumPoints);
}
currentUpdater.addTrackPoint(trackPoint, recordingDistanceInterval);
currentUpdater.addTrackPoint(trackPoint);
// Also include the last point if the selected track is not recording.
if ((localNumLoadedTrackPoints % samplingFrequency == 0) || (trackPointId == lastTrackPointId && !isSelectedTrackRecording())) {
for (TrackDataListener trackDataListener : listeners) {
for (Listener trackDataListener : listeners) {
trackDataListener.onSampledInTrackPoint(trackPoint, currentUpdater.getTrackStatistics(), currentUpdater.getSmoothedSpeed(), currentUpdater.getSmoothedAltitude());
}
} else {
for (TrackDataListener trackDataListener : listeners) {
for (Listener trackDataListener : listeners) {
trackDataListener.onSampledOutTrackPoint(trackPoint, currentUpdater.getTrackStatistics());
}
}
@@ -389,7 +391,7 @@ public class TrackDataHub {
lastSeenTrackPointId = localLastSeenTrackPointIdId;
}
listeners.stream().forEach(TrackDataListener::onNewTrackPointsDone);
listeners.stream().forEach(Listener::onNewTrackPointsDone);
}
@@ -415,4 +417,63 @@ public class TrackDataHub {
public void setRecordingDistanceInterval(Distance recordingDistanceInterval) {
this.recordingDistanceInterval = recordingDistanceInterval;
}
public interface Listener {
/**
* Called when the track or its statistics has been updated.
*
* @param track the track
*/
//TODO Could be @NonNull
void onTrackUpdated(Track track);
/**
* Called to clear previously-sent track points.
*/
void clearTrackPoints();
/**
* Called when a sampled in track point is read.
*
* @param trackPoint the trackPoint
*/
default void onSampledInTrackPoint(@NonNull TrackPoint trackPoint, @NonNull TrackStatistics trackStatistics, Speed smoothedSpeed, @Nullable Altitude smoothedAltitude_m) {
}
/**
* Called when a sampled out track point is read.
*
* @param trackPoint the trackPoint
*/
default void onSampledOutTrackPoint(@NonNull TrackPoint trackPoint, @NonNull TrackStatistics trackStatistics) {
}
/**
* Called when finish sending new track points.
*/
default void onNewTrackPointsDone() {
}
/**
* Called to clear previously sent markers.
*/
default void clearMarkers() {
}
/**
* Called when a new marker is read.
*
* @param marker the marker
*/
default void onNewMarker(@NonNull Marker marker) {
}
/**
* Called when finish sending new markers.
* This gets called after every batch of calls to {@link #clearMarkers()} and {@link #onNewMarker(Marker)}.
*/
default void onNewMarkersDone() {
}
}
}
@@ -1,4 +1,4 @@
package de.dennisguse.opentracks.content.provider;
package de.dennisguse.opentracks.data;
import android.database.Cursor;
@@ -8,8 +8,8 @@ import androidx.annotation.VisibleForTesting;
import java.util.Iterator;
import java.util.NoSuchElementException;
import de.dennisguse.opentracks.content.data.Track;
import de.dennisguse.opentracks.content.data.TrackPoint;
import de.dennisguse.opentracks.data.models.Track;
import de.dennisguse.opentracks.data.models.TrackPoint;
/**
* A lightweight wrapper around the original {@link Cursor}.
@@ -1,4 +1,4 @@
package de.dennisguse.opentracks.content.data;
package de.dennisguse.opentracks.data;
import android.text.TextUtils;
@@ -8,8 +8,8 @@ import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
import de.dennisguse.opentracks.content.provider.SelectionData;
import de.dennisguse.opentracks.data.models.Track;
import de.dennisguse.opentracks.data.tables.TracksColumns;
public class TrackSelection implements ContentProviderUtils.ContentProviderSelectionInterface {
private final List<Track.Id> trackIds = new ArrayList<>();
@@ -1,4 +1,4 @@
package de.dennisguse.opentracks.util;
package de.dennisguse.opentracks.data;
import androidx.annotation.NonNull;
@@ -1,4 +1,6 @@
package de.dennisguse.opentracks.content.data;
package de.dennisguse.opentracks.data.models;
import androidx.annotation.NonNull;
import de.dennisguse.opentracks.R;
@@ -60,6 +62,7 @@ public abstract class Altitude {
}
}
@NonNull
@Override
public String toString() {
return "Altitude{" +
@@ -0,0 +1,43 @@
package de.dennisguse.opentracks.data.models;
import androidx.annotation.NonNull;
import java.util.Objects;
public class Cadence {
public static Cadence of(float value) {
return new Cadence(value);
}
private final float value;
private Cadence(float value) {
this.value = value;
}
public float getRPM() {
return value;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Cadence cadence = (Cadence) o;
return Float.compare(cadence.value, value) == 0;
}
@Override
public int hashCode() {
return Objects.hash(value);
}
@NonNull
@Override
public String toString() {
return "Cadence{" +
"value=" + value + " rpm" +
'}';
}
}
@@ -1,11 +1,9 @@
package de.dennisguse.opentracks.content.data;
package de.dennisguse.opentracks.data.models;
import androidx.annotation.NonNull;
import java.util.Objects;
import de.dennisguse.opentracks.util.UnitConversions;
public class Distance {
public static Distance of(double distance_m) {
@@ -0,0 +1,43 @@
package de.dennisguse.opentracks.data.models;
import androidx.annotation.NonNull;
import java.util.Objects;
public class HeartRate {
public static HeartRate of(float value) {
return new HeartRate(value);
}
private final float value;
private HeartRate(float value) {
this.value = value;
}
public float getBPM() {
return value;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
HeartRate heartRate = (HeartRate) o;
return Float.compare(heartRate.value, value) == 0;
}
@Override
public int hashCode() {
return Objects.hash(value);
}
@NonNull
@Override
public String toString() {
return "HeartRate{" +
"value=" + value + " bpm" +
'}';
}
}
@@ -14,7 +14,7 @@
* the License.
*/
package de.dennisguse.opentracks.content.data;
package de.dennisguse.opentracks.data.models;
import android.location.Location;
import android.net.Uri;
@@ -0,0 +1,43 @@
package de.dennisguse.opentracks.data.models;
import androidx.annotation.NonNull;
import java.util.Objects;
public class Power {
public static Power of(float value) {
return new Power(value);
}
private final float value;
private Power(float value) {
this.value = value;
}
public float getW() {
return value;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Power power = (Power) o;
return Float.compare(power.value, value) == 0;
}
@Override
public int hashCode() {
return Objects.hash(value);
}
@NonNull
@Override
public String toString() {
return "Power{" +
"value=" + value + " W" +
'}';
}
}
@@ -1,4 +1,4 @@
package de.dennisguse.opentracks.content.data;
package de.dennisguse.opentracks.data.models;
import androidx.annotation.NonNull;
@@ -6,7 +6,6 @@ import java.time.Duration;
import java.util.Objects;
import de.dennisguse.opentracks.settings.PreferencesUtils;
import de.dennisguse.opentracks.util.UnitConversions;
public class Speed {
@@ -14,7 +14,7 @@
* the License.
*/
package de.dennisguse.opentracks.content.data;
package de.dennisguse.opentracks.data.models;
import android.os.Parcel;
import android.os.Parcelable;
@@ -13,7 +13,7 @@
* License for the specific language governing permissions and limitations under
* the License.
*/
package de.dennisguse.opentracks.content.data;
package de.dennisguse.opentracks.data.models;
import android.location.Location;
import android.os.Parcel;
@@ -91,9 +91,9 @@ public class TrackPoint {
@NonNull
private Type type;
private Float heartRate_bpm = null;
private Float cadence_rpm = null;
private Float power = null;
private HeartRate heartRate = null;
private Cadence cadence = null;
private Power power = null;
private Float altitudeGain_m = null;
private Float altitudeLoss_m = null;
@@ -324,6 +324,11 @@ public class TrackPoint {
if (hasSensorDistance()) {
return getSensorDistance();
}
return distanceToPreviousFromLocation(previous);
}
@NonNull
public Distance distanceToPreviousFromLocation(@NonNull TrackPoint previous) {
if (!hasLocation() || hasLocation() != previous.hasLocation()) {
throw new RuntimeException("Cannot compute distance.");
}
@@ -377,44 +382,57 @@ public class TrackPoint {
}
public boolean hasHeartRate() {
return heartRate_bpm != null && heartRate_bpm > 0;
return heartRate != null;
}
public float getHeartRate_bpm() {
return heartRate_bpm;
public HeartRate getHeartRate() {
return heartRate;
}
public TrackPoint setHeartRate_bpm(Float heartRate_bpm) {
this.heartRate_bpm = heartRate_bpm;
public TrackPoint setHeartRate(HeartRate heartRate) {
this.heartRate = heartRate;
return this;
}
public TrackPoint setHeartRate(float heartRate) {
return setHeartRate(HeartRate.of(heartRate));
}
public boolean hasCadence() {
return cadence_rpm != null;
return cadence != null;
}
public float getCadence_rpm() {
return cadence_rpm;
public Cadence getCadence() {
return cadence;
}
public TrackPoint setCadence_rpm(Float cadence_rpm) {
this.cadence_rpm = cadence_rpm;
public TrackPoint setCadence(Cadence cadence) {
this.cadence = cadence;
return this;
}
public TrackPoint setCadence(float cadence) {
return setCadence(Cadence.of(cadence));
}
public boolean hasPower() {
return power != null;
}
public float getPower() {
public Power getPower() {
return power;
}
public TrackPoint setPower(Float power) {
public TrackPoint setPower(Power power) {
this.power = power;
return this;
}
public TrackPoint setPower(float power) {
return setPower(Power.of(power));
}
@NonNull
@Override
public String toString() {
return "TrackPoint{" +
@@ -428,8 +446,8 @@ public class TrackPoint {
", bearing=" + bearing +
", sensorDistance=" + sensorDistance +
", type=" + type +
", heartRate_bpm=" + heartRate_bpm +
", cadence_rpm=" + cadence_rpm +
", heartRate_bpm=" + heartRate +
", cadence_rpm=" + cadence +
", power=" + power +
", altitudeGain_m=" + altitudeGain_m +
", altitudeLoss_m=" + altitudeLoss_m +
@@ -13,7 +13,7 @@
* License for the specific language governing permissions and limitations under
* the License.
*/
package de.dennisguse.opentracks.util;
package de.dennisguse.opentracks.data.models;
/**
* Unit conversion constants.
@@ -14,12 +14,12 @@
* the License.
*/
package de.dennisguse.opentracks.content.data;
package de.dennisguse.opentracks.data.tables;
import android.net.Uri;
import android.provider.BaseColumns;
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
import de.dennisguse.opentracks.data.ContentProviderUtils;
/**
* Constants for markers table.
@@ -14,12 +14,12 @@
* the License.
*/
package de.dennisguse.opentracks.content.data;
package de.dennisguse.opentracks.data.tables;
import android.net.Uri;
import android.provider.BaseColumns;
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
import de.dennisguse.opentracks.data.ContentProviderUtils;
/**
* Constants for the track points table.
@@ -14,12 +14,12 @@
* the License.
*/
package de.dennisguse.opentracks.content.data;
package de.dennisguse.opentracks.data.tables;
import android.net.Uri;
import android.provider.BaseColumns;
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
import de.dennisguse.opentracks.data.ContentProviderUtils;
/**
* Constants for the tracks table.
@@ -27,7 +27,7 @@ import androidx.core.content.ContextCompat;
import java.util.List;
import de.dennisguse.opentracks.R;
import de.dennisguse.opentracks.util.ResourceUtils;
import de.dennisguse.opentracks.ui.util.ResourceUtils;
/**
* Image adapter for choosing an activity type.
@@ -36,12 +36,12 @@ import java.util.List;
import de.dennisguse.opentracks.R;
import de.dennisguse.opentracks.TrackRecordedActivity;
import de.dennisguse.opentracks.adapters.StatisticsAdapter;
import de.dennisguse.opentracks.content.data.Track;
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
import de.dennisguse.opentracks.data.ContentProviderUtils;
import de.dennisguse.opentracks.data.models.Track;
import de.dennisguse.opentracks.databinding.StatisticsRecordedBinding;
import de.dennisguse.opentracks.settings.PreferencesUtils;
import de.dennisguse.opentracks.stats.SensorStatistics;
import de.dennisguse.opentracks.stats.TrackStatistics;
import de.dennisguse.opentracks.settings.PreferencesUtils;
import de.dennisguse.opentracks.util.StringUtils;
import de.dennisguse.opentracks.util.TrackIconUtils;
import de.dennisguse.opentracks.viewmodels.StatisticData;
@@ -2,7 +2,6 @@ package de.dennisguse.opentracks.fragments;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -20,13 +19,13 @@ import java.util.List;
import de.dennisguse.opentracks.R;
import de.dennisguse.opentracks.adapters.StatisticsAdapter;
import de.dennisguse.opentracks.content.data.Layout;
import de.dennisguse.opentracks.content.data.Track;
import de.dennisguse.opentracks.content.data.TrackPoint;
import de.dennisguse.opentracks.data.models.Track;
import de.dennisguse.opentracks.data.models.TrackPoint;
import de.dennisguse.opentracks.databinding.StatisticsRecordingBinding;
import de.dennisguse.opentracks.services.TrackRecordingService;
import de.dennisguse.opentracks.services.TrackRecordingServiceConnection;
import de.dennisguse.opentracks.settings.PreferencesUtils;
import de.dennisguse.opentracks.ui.customRecordingLayout.Layout;
import de.dennisguse.opentracks.viewmodels.StatisticData;
import de.dennisguse.opentracks.viewmodels.StatisticsDataModel;
@@ -76,19 +75,8 @@ public class StatisticsRecordingFragment extends Fragment {
}
};
private final Runnable bindChangedCallback = new Runnable() {
@Override
public void run() {
TrackRecordingService service = trackRecordingServiceConnection.getServiceIfBound();
if (service == null) {
Log.w(TAG, "could not get TrackRecordingService");
return;
}
service.getRecordingDataObservable()
.observe(StatisticsRecordingFragment.this, recordingData -> onRecordingDataChanged(recordingData));
}
};
private final TrackRecordingServiceConnection.Callback bindChangedCallback = service -> service.getRecordingDataObservable()
.observe(StatisticsRecordingFragment.this, this::onRecordingDataChanged);
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
@@ -6,7 +6,7 @@ import android.graphics.Bitmap;
import java.util.Locale;
import de.dennisguse.opentracks.R;
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
import de.dennisguse.opentracks.data.ContentProviderUtils;
import de.dennisguse.opentracks.io.file.exporter.GPXTrackExporter;
import de.dennisguse.opentracks.io.file.exporter.KMLTrackExporter;
import de.dennisguse.opentracks.io.file.exporter.KmzTrackExporter;
@@ -33,9 +33,9 @@ import java.util.List;
import java.util.concurrent.LinkedBlockingQueue;
import de.dennisguse.opentracks.R;
import de.dennisguse.opentracks.content.data.Track;
import de.dennisguse.opentracks.content.data.TracksColumns;
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
import de.dennisguse.opentracks.data.ContentProviderUtils;
import de.dennisguse.opentracks.data.models.Track;
import de.dennisguse.opentracks.data.tables.TracksColumns;
import de.dennisguse.opentracks.databinding.ExportActivityBinding;
import de.dennisguse.opentracks.databinding.ToolbarBinding;
import de.dennisguse.opentracks.io.file.ErrorListDialog;

Some files were not shown because too many files have changed in this diff Show More