From 9942be18775737b96eac96cbb55ddcf92aac0d50 Mon Sep 17 00:00:00 2001 From: jannis Date: Thu, 22 Aug 2019 21:46:09 +0200 Subject: [PATCH 01/10] Ignore undefined properties in Import --- app/src/main/java/de/tadris/fitness/util/export/Exporter.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/src/main/java/de/tadris/fitness/util/export/Exporter.java b/app/src/main/java/de/tadris/fitness/util/export/Exporter.java index ab887ac..8e519b0 100644 --- a/app/src/main/java/de/tadris/fitness/util/export/Exporter.java +++ b/app/src/main/java/de/tadris/fitness/util/export/Exporter.java @@ -24,7 +24,9 @@ import android.content.Context; import android.net.Uri; import android.preference.PreferenceManager; +import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.dataformat.xml.XmlMapper; +import com.fasterxml.jackson.dataformat.xml.deser.FromXmlParser; import java.io.File; import java.io.IOException; @@ -79,6 +81,7 @@ public class Exporter { listener.onStatusChanged(0, context.getString(R.string.loadingFile)); XmlMapper xmlMapper = new XmlMapper(); FitoTrackDataContainer container = xmlMapper.readValue(context.getContentResolver().openInputStream(input), FitoTrackDataContainer.class); + xmlMapper.configure(JsonParser.Feature.IGNORE_UNDEFINED, true); if(container.version != 1){ throw new UnsupportedEncodingException("Version Code" + container.version + " is unsupported!"); From eae7bfb9d978122295fc955c7dc29edb726572fc Mon Sep 17 00:00:00 2001 From: jannis Date: Sat, 24 Aug 2019 16:25:22 +0200 Subject: [PATCH 02/10] Localisation fix --- app/src/main/res/values-de/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 26c3a5b..7262dcb 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -36,7 +36,7 @@ Der Datenimport ist fehlgeschlagen. Als GPX-Datei exportieren Daten exportieren - "Es wird ein Backup von all deinen Einstallungen und " + Erstellt ein Backup von all deinen Einstellungen und deiner Workoutdaten Exportieren Fertig GPS From 7d2e3a063d2a8350540b208d07f753d06dd54a4b Mon Sep 17 00:00:00 2001 From: jannis Date: Sat, 24 Aug 2019 16:27:09 +0200 Subject: [PATCH 03/10] Don't reset firstStart-Dialog on import --- app/src/main/java/de/tadris/fitness/util/export/Exporter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/de/tadris/fitness/util/export/Exporter.java b/app/src/main/java/de/tadris/fitness/util/export/Exporter.java index 8e519b0..a7a0d22 100644 --- a/app/src/main/java/de/tadris/fitness/util/export/Exporter.java +++ b/app/src/main/java/de/tadris/fitness/util/export/Exporter.java @@ -26,7 +26,6 @@ import android.preference.PreferenceManager; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.dataformat.xml.XmlMapper; -import com.fasterxml.jackson.dataformat.xml.deser.FromXmlParser; import java.io.File; import java.io.IOException; @@ -92,6 +91,7 @@ public class Exporter { .edit().clear() .putInt("weight", container.settings.weight) .putString("unitSystem", container.settings.preferredUnitSystem) + .putBoolean("firstStart", false) .commit(); AppDatabase database= Instance.getInstance(context).db; From aac80d67988f1d51440f1f3cb2ee9801437b54cc Mon Sep 17 00:00:00 2001 From: jannis Date: Sat, 24 Aug 2019 21:13:17 +0200 Subject: [PATCH 04/10] #20 Back-Button in Settings screen crashes on earlier Android versions --- .../java/de/tadris/fitness/activity/SettingsActivity.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/app/src/main/java/de/tadris/fitness/activity/SettingsActivity.java b/app/src/main/java/de/tadris/fitness/activity/SettingsActivity.java index e898a4e..d36f871 100644 --- a/app/src/main/java/de/tadris/fitness/activity/SettingsActivity.java +++ b/app/src/main/java/de/tadris/fitness/activity/SettingsActivity.java @@ -325,9 +325,7 @@ public class SettingsActivity extends PreferenceActivity { public boolean onMenuItemSelected(int featureId, MenuItem item) { int id = item.getItemId(); if (id == android.R.id.home) { - if (!super.onMenuItemSelected(featureId, item)) { - NavUtils.navigateUpFromSameTask(this); - } + finish(); return true; } return super.onMenuItemSelected(featureId, item); From 1e789a6b675e7c72bb7ab7c766bf8041710cf9e7 Mon Sep 17 00:00:00 2001 From: jannis Date: Sun, 25 Aug 2019 11:21:23 +0200 Subject: [PATCH 05/10] - Gather height data from pressure sensor - Calculate absolute height by combining GPS and sensor - Show height diagram --- app/src/main/AndroidManifest.xml | 22 +++- .../main/java/de/tadris/fitness/Instance.java | 41 ++++++- .../activity/RecordWorkoutActivity.java | 13 ++- .../fitness/activity/ShowWorkoutActivity.java | 103 ++++++++++++++++-- .../de/tadris/fitness/data/AppDatabase.java | 2 +- .../java/de/tadris/fitness/data/Workout.java | 8 ++ .../tadris/fitness/data/WorkoutManager.java | 46 ++++++++ .../de/tadris/fitness/data/WorkoutSample.java | 18 ++- .../fitness/location/MyLocationOverlay.java | 98 ----------------- .../LocationListener.java | 2 +- .../fitness/recording/PressureService.java | 89 +++++++++++++++ .../WorkoutRecorder.java | 12 +- .../tadris/fitness/util/export/Exporter.java | 2 +- .../util/export/FitoTrackDataContainer.java | 21 ++++ app/src/main/res/values/strings.xml | 6 + 15 files changed, 363 insertions(+), 120 deletions(-) delete mode 100644 app/src/main/java/de/tadris/fitness/location/MyLocationOverlay.java rename app/src/main/java/de/tadris/fitness/{location => recording}/LocationListener.java (99%) create mode 100644 app/src/main/java/de/tadris/fitness/recording/PressureService.java rename app/src/main/java/de/tadris/fitness/{location => recording}/WorkoutRecorder.java (96%) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 2101dcd..a8d2f92 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,4 +1,23 @@ + + @@ -46,7 +65,8 @@ android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/filepaths" /> - + + \ No newline at end of file diff --git a/app/src/main/java/de/tadris/fitness/Instance.java b/app/src/main/java/de/tadris/fitness/Instance.java index 629e249..889fc8c 100644 --- a/app/src/main/java/de/tadris/fitness/Instance.java +++ b/app/src/main/java/de/tadris/fitness/Instance.java @@ -21,14 +21,17 @@ package de.tadris.fitness; import android.content.Context; +import androidx.annotation.NonNull; import androidx.room.Room; +import androidx.room.migration.Migration; +import androidx.sqlite.db.SupportSQLiteDatabase; import java.util.ArrayList; import java.util.List; import de.tadris.fitness.data.AppDatabase; import de.tadris.fitness.data.UserPreferences; -import de.tadris.fitness.location.LocationListener; +import de.tadris.fitness.recording.LocationListener; import de.tadris.fitness.util.unit.UnitUtils; public class Instance { @@ -48,9 +51,45 @@ public class Instance { public List locationChangeListeners= new ArrayList<>(); public UserPreferences userPreferences; + public boolean pressureAvailable= false; + public float lastPressure= 0; + private Instance(Context context) { userPreferences= new UserPreferences(context); db = Room.databaseBuilder(context.getApplicationContext(), AppDatabase.class, DATABASE_NAME) + .addMigrations(new Migration(1, 2) { + @Override + public void migrate(@NonNull SupportSQLiteDatabase database) { + try{ + database.beginTransaction(); + + database.execSQL("ALTER table workout add descent REAL NOT NULL DEFAULT 0;"); + database.execSQL("ALTER table workout add ascent REAL NOT NULL DEFAULT 0"); + + database.execSQL("ALTER TABLE workout_sample RENAME TO workout_sample2;"); + + database.execSQL("CREATE TABLE workout_sample (" + + "id INTEGER NOT NULL DEFAULT NULL PRIMARY KEY," + + "relativeTime INTEGER NOT NULL DEFAULT NULL," + + "elevation REAL NOT NULL DEFAULT NULL," + + "absoluteTime INTEGER NOT NULL DEFAULT NULL," + + "lat REAL NOT NULL DEFAULT NULL," + + "lon REAL NOT NULL DEFAULT NULL," + + "speed REAL NOT NULL DEFAULT NULL," + + "workout_id INTEGER NOT NULL DEFAULT NULL," + + "FOREIGN KEY (workout_id) REFERENCES workout(id) ON DELETE CASCADE);"); + + database.execSQL("INSERT INTO workout_sample (id, relativeTime, elevation, absoluteTime, lat, lon, speed, workout_id) " + + "SELECT id, relativeTime, elevation, absoluteTime, lat, lon, speed, workout_id FROM workout_sample2"); + + database.execSQL("DROP TABLE workout_sample2"); + + database.setTransactionSuccessful(); + }finally { + database.endTransaction(); + } + } + }) .allowMainThreadQueries() .build(); UnitUtils.setUnit(context); diff --git a/app/src/main/java/de/tadris/fitness/activity/RecordWorkoutActivity.java b/app/src/main/java/de/tadris/fitness/activity/RecordWorkoutActivity.java index 4314f15..dcd510e 100644 --- a/app/src/main/java/de/tadris/fitness/activity/RecordWorkoutActivity.java +++ b/app/src/main/java/de/tadris/fitness/activity/RecordWorkoutActivity.java @@ -50,10 +50,11 @@ import java.util.List; import de.tadris.fitness.Instance; import de.tadris.fitness.R; import de.tadris.fitness.data.Workout; -import de.tadris.fitness.location.LocationListener; -import de.tadris.fitness.location.WorkoutRecorder; import de.tadris.fitness.map.MapManager; import de.tadris.fitness.map.tilesource.TileSources; +import de.tadris.fitness.recording.LocationListener; +import de.tadris.fitness.recording.PressureService; +import de.tadris.fitness.recording.WorkoutRecorder; import de.tadris.fitness.util.ThemeManager; import de.tadris.fitness.util.unit.UnitUtils; @@ -72,6 +73,7 @@ public class RecordWorkoutActivity extends FitoTrackActivity implements Location private Handler mHandler= new Handler(); PowerManager.WakeLock wakeLock; Intent locationListener; + Intent pressureService; private boolean saved= false; @Override @@ -154,7 +156,10 @@ public class RecordWorkoutActivity extends FitoTrackActivity implements Location }).start(); } + int i= 0; + private void updateDescription(){ + i++; timeView.setText(UnitUtils.getHourMinuteSecondTime(recorder.getDuration())); infoViews[0].setText(getString(R.string.workoutDistance), UnitUtils.getDistance(recorder.getDistance())); infoViews[1].setText(getString(R.string.workoutBurnedEnergy), recorder.getCalories() + " kcal"); @@ -228,18 +233,22 @@ public class RecordWorkoutActivity extends FitoTrackActivity implements Location public void stopListener(){ stopService(locationListener); + stopService(pressureService); } public void startListener(){ if(locationListener == null){ locationListener= new Intent(this, LocationListener.class); + pressureService= new Intent(this, PressureService.class); }else{ stopListener(); } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { startForegroundService(locationListener); + startService(pressureService); }else{ startService(locationListener); + startService(pressureService); } } diff --git a/app/src/main/java/de/tadris/fitness/activity/ShowWorkoutActivity.java b/app/src/main/java/de/tadris/fitness/activity/ShowWorkoutActivity.java index 58f35ef..86e8cb3 100644 --- a/app/src/main/java/de/tadris/fitness/activity/ShowWorkoutActivity.java +++ b/app/src/main/java/de/tadris/fitness/activity/ShowWorkoutActivity.java @@ -131,6 +131,13 @@ public class ShowWorkoutActivity extends FitoTrackActivity { addKeyValue(getString(R.string.workoutTotalEnergy), workout.calorie + " kcal", getString(R.string.workoutEnergyConsumption), UnitUtils.getRelativeEnergyConsumption((double)workout.calorie / ((double)workout.length / 1000))); + addTitle(getString(R.string.height)); + + addKeyValue(getString(R.string.workoutAscent), UnitUtils.getDistance((int)workout.ascent), + getString(R.string.workoutDescent), UnitUtils.getDistance((int)workout.descent)); + + addHeightDiagram(); + } @@ -199,20 +206,20 @@ public class ShowWorkoutActivity extends FitoTrackActivity { root.addView(v); } - void addSpeedDiagram(){ + void addDiagram(SampleConverter converter){ LineChart chart= new LineChart(this); - WorkoutManager.roundSpeedValues(samples); + converter.onCreate(); List entries = new ArrayList<>(); for (WorkoutSample sample : samples) { // turn your data into Entry objects - Entry e= new Entry((float)(sample.relativeTime) / 1000f / 60f, (float)sample.tmpRoundedSpeed*3.6f); + Entry e= new Entry((float)(sample.relativeTime) / 1000f / 60f, converter.getValue(sample)); entries.add(e); - sample.tmpEntry= e; + converter.sampleGetsEntry(sample, e); } - LineDataSet dataSet = new LineDataSet(entries, "Speed"); // add entries to dataset // TODO: localisatoin + LineDataSet dataSet = new LineDataSet(entries, converter.getName()); // add entries to dataset dataSet.setColor(getThemePrimaryColor()); dataSet.setValueTextColor(getThemePrimaryColor()); dataSet.setDrawCircles(false); @@ -220,11 +227,12 @@ public class ShowWorkoutActivity extends FitoTrackActivity { dataSet.setMode(LineDataSet.Mode.CUBIC_BEZIER); Description description= new Description(); - description.setText("min - km/h"); + description.setText(converter.getDescription()); LineData lineData = new LineData(dataSet); chart.setData(lineData); - chart.setScaleEnabled(false); + chart.setScaleXEnabled(true); + chart.setScaleYEnabled(false); chart.setDescription(description); chart.setOnChartValueSelectedListener(new OnChartValueSelectedListener() { @Override @@ -232,7 +240,7 @@ public class ShowWorkoutActivity extends FitoTrackActivity { onNothingSelected(); Paint p= AndroidGraphicFactory.INSTANCE.createPaint(); p.setColor(Color.BLUE); - highlightingCircle= new FixedPixelCircle(getSamplebyTime(e).toLatLong(), 10, p, null); + highlightingCircle= new FixedPixelCircle(findSample(converter, e).toLatLong(), 10, p, null); map.addLayer(highlightingCircle); } @@ -248,9 +256,84 @@ public class ShowWorkoutActivity extends FitoTrackActivity { root.addView(chart, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, getWindowManager().getDefaultDisplay().getWidth()*3/4)); } - WorkoutSample getSamplebyTime(Entry entry){ + interface SampleConverter{ + void onCreate(); + float getValue(WorkoutSample sample); + void sampleGetsEntry(WorkoutSample sample, Entry entry); + String getName(); + String getDescription(); + boolean compare(WorkoutSample sample, Entry entry); + } + + void addHeightDiagram(){ + addDiagram(new SampleConverter() { + @Override + public void onCreate() { } + + @Override + public float getValue(WorkoutSample sample) { + return (float)UnitUtils.CHOSEN_SYSTEM.getDistanceFromMeters(sample.elevation); + } + + @Override + public void sampleGetsEntry(WorkoutSample sample, Entry entry) { + sample.tmpHeightEntry= entry; + } + + @Override + public String getName() { + return getString(R.string.height); + } + + @Override + public String getDescription() { + return "min - " + UnitUtils.CHOSEN_SYSTEM.getShortDistanceUnit(); + } + + @Override + public boolean compare(WorkoutSample sample, Entry entry) { + return sample.tmpHeightEntry.equalTo(entry); + } + }); + } + + void addSpeedDiagram(){ + addDiagram(new SampleConverter() { + @Override + public void onCreate() { + WorkoutManager.roundSpeedValues(samples); + } + + @Override + public float getValue(WorkoutSample sample) { + return (float)UnitUtils.CHOSEN_SYSTEM.getSpeedFromMeterPerSecond(sample.tmpRoundedSpeed); + } + + @Override + public void sampleGetsEntry(WorkoutSample sample, Entry entry) { + sample.tmpSpeedEntry= entry; + } + + @Override + public String getName() { + return getString(R.string.workoutSpeed); + } + + @Override + public String getDescription() { + return "min - " + UnitUtils.CHOSEN_SYSTEM.getSpeedUnit(); + } + + @Override + public boolean compare(WorkoutSample sample, Entry entry) { + return sample.tmpSpeedEntry.equalTo(entry); + } + }); + } + + WorkoutSample findSample(SampleConverter converter, Entry entry){ for(WorkoutSample sample : samples){ - if(sample.tmpEntry.equalTo(entry)){ + if(converter.compare(sample, entry)){ return sample; } } diff --git a/app/src/main/java/de/tadris/fitness/data/AppDatabase.java b/app/src/main/java/de/tadris/fitness/data/AppDatabase.java index cd1fc75..73ba188 100644 --- a/app/src/main/java/de/tadris/fitness/data/AppDatabase.java +++ b/app/src/main/java/de/tadris/fitness/data/AppDatabase.java @@ -22,7 +22,7 @@ package de.tadris.fitness.data; import androidx.room.Database; import androidx.room.RoomDatabase; -@Database(version = 1, entities = {Workout.class, WorkoutSample.class}) +@Database(version = 2, entities = {Workout.class, WorkoutSample.class}) public abstract class AppDatabase extends RoomDatabase { public abstract WorkoutDao workoutDao(); } diff --git a/app/src/main/java/de/tadris/fitness/data/Workout.java b/app/src/main/java/de/tadris/fitness/data/Workout.java index 90141b2..159ac91 100644 --- a/app/src/main/java/de/tadris/fitness/data/Workout.java +++ b/app/src/main/java/de/tadris/fitness/data/Workout.java @@ -22,10 +22,13 @@ package de.tadris.fitness.data; import androidx.room.Entity; import androidx.room.PrimaryKey; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + import java.text.SimpleDateFormat; import java.util.Date; @Entity(tableName = "workout") +@JsonIgnoreProperties(ignoreUnknown = true) public class Workout{ public static final String WORKOUT_TYPE_RUNNING= "running"; @@ -66,6 +69,11 @@ public class Workout{ public String workoutType; + + public float ascent; + + public float descent; + public int calorie; public String toString(){ diff --git a/app/src/main/java/de/tadris/fitness/data/WorkoutManager.java b/app/src/main/java/de/tadris/fitness/data/WorkoutManager.java index a98bb78..8aea9c6 100644 --- a/app/src/main/java/de/tadris/fitness/data/WorkoutManager.java +++ b/app/src/main/java/de/tadris/fitness/data/WorkoutManager.java @@ -20,6 +20,7 @@ package de.tadris.fitness.data; import android.content.Context; +import android.hardware.SensorManager; import android.util.Log; import java.util.List; @@ -61,10 +62,14 @@ public class WorkoutManager { // Setting workoutId in the samples int i= 0; double topSpeed= 0; + double elevationSum= 0; // Sum of elevation + double pressureSum= 0; // Sum of elevation for(WorkoutSample sample : samples){ i++; sample.id= workout.id + i; sample.workoutId= workout.id; + elevationSum+= sample.elevation; + pressureSum+= sample.tmpPressure; if(sample.speed > topSpeed){ topSpeed= sample.speed; } @@ -72,6 +77,36 @@ public class WorkoutManager { workout.topSpeed= topSpeed; + // Calculating height data + boolean pressureDataAvailable= samples.get(0).tmpPressure != -1; + double avgElevation= elevationSum / samples.size(); + double avgPressure= pressureSum / samples.size(); + + workout.ascent = 0; + workout.descent = 0; + + for(i= 0; i < samples.size(); i++){ + WorkoutSample sample= samples.get(i); + + if(pressureDataAvailable){ + // Altitude Difference to Average Elevation in meters + float altitude_difference = + SensorManager.getAltitude(SensorManager.PRESSURE_STANDARD_ATMOSPHERE, sample.tmpPressure) - + SensorManager.getAltitude(SensorManager.PRESSURE_STANDARD_ATMOSPHERE, (float) avgPressure); + sample.elevation= avgElevation + altitude_difference; + } // Else: use already set GPS elevation in WorkoutSample.elevation + + if(i >= 1){ + WorkoutSample lastSample= samples.get(i-1); + double diff= sample.elevation - lastSample.elevation; + if(diff > 0){ + workout.ascent += diff; + }else{ + workout.descent += Math.abs(diff); + } + } + } + // Saving workout and samples db.workoutDao().insertWorkoutAndSamples(workout, samples.toArray(new WorkoutSample[0])); @@ -91,4 +126,15 @@ public class WorkoutManager { } } + public static void calculateInclination(List samples){ + samples.get(0).tmpInclination= 0; + for(int i= 1; i < samples.size(); i++){ + WorkoutSample sample= samples.get(i); + WorkoutSample lastSample= samples.get(i); + double elevationDifference= sample.elevation - sample.elevation; + double distance= sample.toLatLong().sphericalDistance(lastSample.toLatLong()); + sample.tmpInclination= (float)(elevationDifference*100/distance); + } + } + } diff --git a/app/src/main/java/de/tadris/fitness/data/WorkoutSample.java b/app/src/main/java/de/tadris/fitness/data/WorkoutSample.java index 79ae50a..00ea796 100644 --- a/app/src/main/java/de/tadris/fitness/data/WorkoutSample.java +++ b/app/src/main/java/de/tadris/fitness/data/WorkoutSample.java @@ -26,6 +26,7 @@ import androidx.room.Ignore; import androidx.room.PrimaryKey; import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.github.mikephil.charting.data.Entry; import org.mapsforge.core.model.LatLong; @@ -38,6 +39,7 @@ import static androidx.room.ForeignKey.CASCADE; parentColumns = "id", childColumns = "workout_id", onDelete = CASCADE)) +@JsonIgnoreProperties(ignoreUnknown = true) public class WorkoutSample{ @PrimaryKey @@ -56,18 +58,28 @@ public class WorkoutSample{ public double elevation; - public double relativeElevation; - public double speed; @JsonIgnore @Ignore - public Entry tmpEntry; + public Entry tmpHeightEntry; + + @JsonIgnore + @Ignore + public Entry tmpSpeedEntry; @JsonIgnore @Ignore public double tmpRoundedSpeed; + @JsonIgnore + @Ignore + public float tmpPressure; + + @JsonIgnore + @Ignore + public float tmpInclination; + public LatLong toLatLong(){ return new LatLong(lat, lon); } diff --git a/app/src/main/java/de/tadris/fitness/location/MyLocationOverlay.java b/app/src/main/java/de/tadris/fitness/location/MyLocationOverlay.java deleted file mode 100644 index 7393240..0000000 --- a/app/src/main/java/de/tadris/fitness/location/MyLocationOverlay.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (c) 2019 Jannis Scheibe - * - * This file is part of FitoTrack - * - * FitoTrack is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * FitoTrack is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package de.tadris.fitness.location; - -import android.graphics.drawable.Drawable; - -import org.mapsforge.core.graphics.Canvas; -import org.mapsforge.core.graphics.Paint; -import org.mapsforge.core.graphics.Style; -import org.mapsforge.core.model.BoundingBox; -import org.mapsforge.core.model.LatLong; -import org.mapsforge.core.model.Point; -import org.mapsforge.map.android.graphics.AndroidGraphicFactory; -import org.mapsforge.map.layer.Layer; -import org.mapsforge.map.layer.overlay.Circle; -import org.mapsforge.map.layer.overlay.Marker; - -public class MyLocationOverlay extends Layer { - - private final Circle circle; - private final Marker marker; - private final LocationListener locationListener; - - private static Paint getDefaultFixedPixelCircleFill() { - return getPaint(AndroidGraphicFactory.INSTANCE.createColor(255, 0, 0, 255), 0, Style.FILL); - } - - private static Paint getDefaultOuterFixedPixelCircleFill(){ - return getPaint(AndroidGraphicFactory.INSTANCE.createColor(30, 30, 30, 255), 0, Style.FILL); - } - - private static Paint getDefaultFixedPixelCircleStroke() { - return getPaint(AndroidGraphicFactory.INSTANCE.createColor(255, 255, 255, 255), 7, Style.STROKE); - } - - private static Paint getPaint(int color, int strokeWidth, Style style) { - Paint paint = AndroidGraphicFactory.INSTANCE.createPaint(); - paint.setColor(color); - paint.setStrokeWidth(strokeWidth); - paint.setStyle(style); - return paint; - } - - public MyLocationOverlay(LocationListener locationListener, Drawable icon) { - this.locationListener= locationListener; - this.circle= new Circle(null, 0f, getDefaultFixedPixelCircleFill(), null); - this.marker= new Marker(null, AndroidGraphicFactory.convertToBitmap(icon), 26, 26); - } - - @Override - public synchronized void draw(BoundingBox boundingBox, byte zoomLevel, Canvas canvas, Point topLeftPoint) { - if (this.circle != null) { - this.circle.draw(boundingBox, zoomLevel, canvas, topLeftPoint); - } - this.marker.draw(boundingBox, zoomLevel, canvas, topLeftPoint); - } - - @Override - protected void onAdd() { - this.circle.setDisplayModel(this.displayModel); - this.marker.setDisplayModel(this.displayModel); - } - - @Override - public void onDestroy() { - this.marker.onDestroy(); - } - - public void setPosition(double latitude, double longitude, float accuracy) { - synchronized (this) { - LatLong latLong = new LatLong(latitude, longitude); - this.marker.setLatLong(latLong); - if (this.circle != null) { - this.circle.setLatLong(latLong); - this.circle.setRadius(accuracy); - } - requestRedraw(); - } - } - -} diff --git a/app/src/main/java/de/tadris/fitness/location/LocationListener.java b/app/src/main/java/de/tadris/fitness/recording/LocationListener.java similarity index 99% rename from app/src/main/java/de/tadris/fitness/location/LocationListener.java rename to app/src/main/java/de/tadris/fitness/recording/LocationListener.java index ede574f..3c0f15d 100644 --- a/app/src/main/java/de/tadris/fitness/location/LocationListener.java +++ b/app/src/main/java/de/tadris/fitness/recording/LocationListener.java @@ -18,7 +18,7 @@ * along with this program. If not, see . */ -package de.tadris.fitness.location; +package de.tadris.fitness.recording; import android.app.Notification; import android.app.Service; diff --git a/app/src/main/java/de/tadris/fitness/recording/PressureService.java b/app/src/main/java/de/tadris/fitness/recording/PressureService.java new file mode 100644 index 0000000..cb84c53 --- /dev/null +++ b/app/src/main/java/de/tadris/fitness/recording/PressureService.java @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2019 Jannis Scheibe + * + * This file is part of FitoTrack + * + * FitoTrack is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * FitoTrack is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.tadris.fitness.recording; + +import android.app.Service; +import android.content.Context; +import android.content.Intent; +import android.hardware.Sensor; +import android.hardware.SensorEvent; +import android.hardware.SensorEventListener; +import android.hardware.SensorManager; +import android.os.IBinder; +import android.util.Log; + +import androidx.annotation.Nullable; + +import de.tadris.fitness.Instance; + +public class PressureService extends Service { + + private static final String TAG = "PressureService"; + + private SensorManager sensorManager; + private Instance instance; + private Sensor pressureSensor; + private PressureListener pressureListener; + + private class PressureListener implements SensorEventListener { + + @Override + public void onSensorChanged(SensorEvent event) { + instance.lastPressure= event.values[0]; + } + + @Override + public void onAccuracyChanged(Sensor sensor, int accuracy) { } + } + + @Override + public void onCreate() { + Log.d(TAG, "onCreate"); + super.onCreate(); + instance= Instance.getInstance(this); + sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); + + pressureSensor= sensorManager.getDefaultSensor(Sensor.TYPE_PRESSURE); + + pressureListener= new PressureListener(); + + if (pressureSensor != null){ + instance.pressureAvailable= true; + sensorManager.registerListener(pressureListener, pressureSensor, SensorManager.SENSOR_DELAY_NORMAL); + } else { + instance.pressureAvailable= false; + } + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + Log.d(TAG, "onStartCommand"); + return super.onStartCommand(intent, flags, startId); + } + + @Override + public void onDestroy() { + Log.d(TAG, "onDestroy"); + super.onDestroy(); + sensorManager.unregisterListener(pressureListener); + } + + @Nullable @Override public IBinder onBind(Intent intent) { return null; } +} diff --git a/app/src/main/java/de/tadris/fitness/location/WorkoutRecorder.java b/app/src/main/java/de/tadris/fitness/recording/WorkoutRecorder.java similarity index 96% rename from app/src/main/java/de/tadris/fitness/location/WorkoutRecorder.java rename to app/src/main/java/de/tadris/fitness/recording/WorkoutRecorder.java index 9051404..a99bac7 100644 --- a/app/src/main/java/de/tadris/fitness/location/WorkoutRecorder.java +++ b/app/src/main/java/de/tadris/fitness/recording/WorkoutRecorder.java @@ -17,7 +17,7 @@ * along with this program. If not, see . */ -package de.tadris.fitness.location; +package de.tadris.fitness.recording; import android.content.Context; import android.graphics.Color; @@ -224,10 +224,14 @@ public class WorkoutRecorder implements LocationListener.LocationChangeListener sample.lat= location.getLatitude(); sample.lon= location.getLongitude(); sample.elevation= location.getAltitude(); - sample.relativeElevation= 0.0; sample.speed= location.getSpeed(); sample.relativeTime= location.getTime() - workout.start - pauseTime; sample.absoluteTime= location.getTime(); + if(Instance.getInstance(context).pressureAvailable){ + sample.tmpPressure= Instance.getInstance(context).lastPressure; + }else{ + sample.tmpPressure= -1; + } synchronized (samples){ samples.add(sample); } @@ -282,6 +286,10 @@ public class WorkoutRecorder implements LocationListener.LocationChangeListener workout.comment= comment; } + public boolean isPaused(){ + return state == RecordingState.PAUSED; + } + enum RecordingState{ IDLE, RUNNING, PAUSED, STOPPED diff --git a/app/src/main/java/de/tadris/fitness/util/export/Exporter.java b/app/src/main/java/de/tadris/fitness/util/export/Exporter.java index a7a0d22..d93fc0c 100644 --- a/app/src/main/java/de/tadris/fitness/util/export/Exporter.java +++ b/app/src/main/java/de/tadris/fitness/util/export/Exporter.java @@ -79,8 +79,8 @@ public class Exporter { public static void importData(Context context, Uri input, ExportStatusListener listener) throws IOException{ listener.onStatusChanged(0, context.getString(R.string.loadingFile)); XmlMapper xmlMapper = new XmlMapper(); - FitoTrackDataContainer container = xmlMapper.readValue(context.getContentResolver().openInputStream(input), FitoTrackDataContainer.class); xmlMapper.configure(JsonParser.Feature.IGNORE_UNDEFINED, true); + FitoTrackDataContainer container = xmlMapper.readValue(context.getContentResolver().openInputStream(input), FitoTrackDataContainer.class); if(container.version != 1){ throw new UnsupportedEncodingException("Version Code" + container.version + " is unsupported!"); diff --git a/app/src/main/java/de/tadris/fitness/util/export/FitoTrackDataContainer.java b/app/src/main/java/de/tadris/fitness/util/export/FitoTrackDataContainer.java index 2ad55bb..c1c9c0a 100644 --- a/app/src/main/java/de/tadris/fitness/util/export/FitoTrackDataContainer.java +++ b/app/src/main/java/de/tadris/fitness/util/export/FitoTrackDataContainer.java @@ -1,5 +1,25 @@ +/* + * Copyright (c) 2019 Jannis Scheibe + * + * This file is part of FitoTrack + * + * FitoTrack is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * FitoTrack is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package de.tadris.fitness.util.export; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; import java.util.List; @@ -8,6 +28,7 @@ import de.tadris.fitness.data.Workout; import de.tadris.fitness.data.WorkoutSample; @JacksonXmlRootElement(localName = "fito-track") +@JsonIgnoreProperties(ignoreUnknown = true) public class FitoTrackDataContainer { int version; diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index c43104d..f33977f 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -63,6 +63,12 @@ Total Energy Energy Consumption + Ascent + Descent + + Height + + Running Walking Jogging From 179e271cbfd299ab6b733fb18640ecf9bf0b0c29 Mon Sep 17 00:00:00 2001 From: jannis Date: Sun, 25 Aug 2019 12:47:41 +0200 Subject: [PATCH 06/10] Fix Unit "Imperial with meters" --- .../de/tadris/fitness/util/unit/ImperialWithMeters.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/app/src/main/java/de/tadris/fitness/util/unit/ImperialWithMeters.java b/app/src/main/java/de/tadris/fitness/util/unit/ImperialWithMeters.java index caf47fa..406e767 100644 --- a/app/src/main/java/de/tadris/fitness/util/unit/ImperialWithMeters.java +++ b/app/src/main/java/de/tadris/fitness/util/unit/ImperialWithMeters.java @@ -11,13 +11,9 @@ public class ImperialWithMeters extends Imperial { public double getDistanceFromMeters(double meters) { return meters; } - @Override - public String getLongDistanceUnit() { - return "m"; - } @Override public String getShortDistanceUnit() { - return "yd"; + return "m"; } } From 744f4389d63c8b4b576272e8088b279343f310f6 Mon Sep 17 00:00:00 2001 From: jannis Date: Sun, 25 Aug 2019 12:58:43 +0200 Subject: [PATCH 07/10] Check if GPS was disabled --- .../activity/RecordWorkoutActivity.java | 21 +++++++++++++++++++ app/src/main/res/values/strings.xml | 4 ++++ 2 files changed, 25 insertions(+) diff --git a/app/src/main/java/de/tadris/fitness/activity/RecordWorkoutActivity.java b/app/src/main/java/de/tadris/fitness/activity/RecordWorkoutActivity.java index 4314f15..fd18daa 100644 --- a/app/src/main/java/de/tadris/fitness/activity/RecordWorkoutActivity.java +++ b/app/src/main/java/de/tadris/fitness/activity/RecordWorkoutActivity.java @@ -21,9 +21,12 @@ package de.tadris.fitness.activity; import android.Manifest; import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; import android.content.Intent; import android.content.pm.PackageManager; import android.location.Location; +import android.location.LocationManager; import android.os.Build; import android.os.Bundle; import android.os.Handler; @@ -241,6 +244,24 @@ public class RecordWorkoutActivity extends FitoTrackActivity implements Location }else{ startService(locationListener); } + checkGpsStatus(); + } + + private void checkGpsStatus(){ + final LocationManager manager = (LocationManager) getSystemService(Context.LOCATION_SERVICE); + + if (!manager.isProviderEnabled(LocationManager.GPS_PROVIDER)){ + openDialogNoGps(); + } + } + + private void openDialogNoGps(){ + new AlertDialog.Builder(this) + .setTitle(R.string.noGpsTitle) + .setMessage(R.string.noGpsMessage) + .setNegativeButton(R.string.cancel, (dialog, which) -> finish()) + .setPositiveButton(R.string.enable, (dialog, which) -> startActivity(new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS))) + .create().show(); } @Override diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index c43104d..5dc6d8c 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -72,6 +72,10 @@ Record Workout + GPS disabled + Please enable GPS for tracking your workout. + Enable + Comment Enter Comment Okay From 2ad3ca48806668fcf77419ef3ac0a24ccb9cde64 Mon Sep 17 00:00:00 2001 From: jannis Date: Sun, 25 Aug 2019 13:16:26 +0200 Subject: [PATCH 08/10] test --- .../tadris/fitness/CalorieCalculatorTest.java | 22 ++++++++++++ .../de/tadris/fitness/ExampleUnitTest.java | 36 ------------------- 2 files changed, 22 insertions(+), 36 deletions(-) create mode 100644 app/src/test/java/de/tadris/fitness/CalorieCalculatorTest.java delete mode 100644 app/src/test/java/de/tadris/fitness/ExampleUnitTest.java diff --git a/app/src/test/java/de/tadris/fitness/CalorieCalculatorTest.java b/app/src/test/java/de/tadris/fitness/CalorieCalculatorTest.java new file mode 100644 index 0000000..4c40451 --- /dev/null +++ b/app/src/test/java/de/tadris/fitness/CalorieCalculatorTest.java @@ -0,0 +1,22 @@ +package de.tadris.fitness; + +import org.junit.Assert; +import org.junit.Test; + +import de.tadris.fitness.data.Workout; +import de.tadris.fitness.util.CalorieCalculator; + +public class CalorieCalculatorTest { + + @Test + public void testCalculation(){ + Workout workout= new Workout(); + workout.avgSpeed= 2.7d; + workout.workoutType= Workout.WORKOUT_TYPE_RUNNING; + workout.duration= 1000L * 60 * 10; + int calorie= CalorieCalculator.calculateCalories(workout, 80); + System.out.println("Calories: " + calorie); + Assert.assertEquals(120, calorie, 50); + } + +} diff --git a/app/src/test/java/de/tadris/fitness/ExampleUnitTest.java b/app/src/test/java/de/tadris/fitness/ExampleUnitTest.java deleted file mode 100644 index b12eb70..0000000 --- a/app/src/test/java/de/tadris/fitness/ExampleUnitTest.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2019 Jannis Scheibe - * - * This file is part of FitoTrack - * - * FitoTrack is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * FitoTrack is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package de.tadris.fitness; - -import org.junit.Test; - -import static org.junit.Assert.assertEquals; - -/** - * Example local unit test, which will execute on the development machine (host). - * - * @see Testing documentation - */ -public class ExampleUnitTest { - @Test - public void addition_isCorrect() { - assertEquals(4, 2 + 2); - } -} \ No newline at end of file From 393fd4aba90b79b1e5385e6590126d379f6163d9 Mon Sep 17 00:00:00 2001 From: jannis Date: Sun, 25 Aug 2019 13:23:29 +0200 Subject: [PATCH 09/10] Use running calorie calculation for hiking --- .../main/java/de/tadris/fitness/util/CalorieCalculator.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/app/src/main/java/de/tadris/fitness/util/CalorieCalculator.java b/app/src/main/java/de/tadris/fitness/util/CalorieCalculator.java index d6064aa..3a50270 100644 --- a/app/src/main/java/de/tadris/fitness/util/CalorieCalculator.java +++ b/app/src/main/java/de/tadris/fitness/util/CalorieCalculator.java @@ -48,14 +48,10 @@ public class CalorieCalculator { */ public static double getMET(Workout workout){ double speedInKmh= workout.avgSpeed * 3.6; - if(workout.workoutType.equals(Workout.WORKOUT_TYPE_RUNNING)){ + if(workout.workoutType.equals(Workout.WORKOUT_TYPE_RUNNING) || workout.workoutType.equals(Workout.WORKOUT_TYPE_HIKING)){ // This is a linear graph based on the website linked above return Math.max(1.5, speedInKmh*1.117 - 2.1906); } - if(workout.workoutType.equals(Workout.WORKOUT_TYPE_HIKING)){ - // Use fixed MET because no more precise calculation was found - return 6.0; - } if(workout.workoutType.equals(Workout.WORKOUT_TYPE_CYCLING)){ // This is a linear graph based on the website linked above return Math.max(3, (speedInKmh-10) / 1.5); From b9278e029956ccd4c8d6a3c92e4b06b9e03864f0 Mon Sep 17 00:00:00 2001 From: jannis Date: Sun, 25 Aug 2019 13:49:53 +0200 Subject: [PATCH 10/10] - update 1.1.0 - update translations --- app/build.gradle | 4 ++-- .../de/tadris/fitness/activity/RecordWorkoutActivity.java | 2 +- app/src/main/res/values-de/strings.xml | 6 ++++++ metadata/en-US/changelogs/110.txt | 8 ++++++++ 4 files changed, 17 insertions(+), 3 deletions(-) create mode 100644 metadata/en-US/changelogs/110.txt diff --git a/app/build.gradle b/app/build.gradle index e9d848e..61dda2c 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -35,8 +35,8 @@ android { applicationId "de.tadris.fitness" minSdkVersion 21 targetSdkVersion 28 - versionCode 103 - versionName "1.0.3" + versionCode 110 + versionName "1.1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } buildTypes { diff --git a/app/src/main/java/de/tadris/fitness/activity/RecordWorkoutActivity.java b/app/src/main/java/de/tadris/fitness/activity/RecordWorkoutActivity.java index 7740011..12bd640 100644 --- a/app/src/main/java/de/tadris/fitness/activity/RecordWorkoutActivity.java +++ b/app/src/main/java/de/tadris/fitness/activity/RecordWorkoutActivity.java @@ -22,7 +22,6 @@ package de.tadris.fitness.activity; import android.Manifest; import android.app.AlertDialog; import android.content.Context; -import android.content.DialogInterface; import android.content.Intent; import android.content.pm.PackageManager; import android.location.Location; @@ -270,6 +269,7 @@ public class RecordWorkoutActivity extends FitoTrackActivity implements Location .setMessage(R.string.noGpsMessage) .setNegativeButton(R.string.cancel, (dialog, which) -> finish()) .setPositiveButton(R.string.enable, (dialog, which) -> startActivity(new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS))) + .setCancelable(false) .create().show(); } diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 7262dcb..f4b1a5a 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -88,4 +88,10 @@ Gehen Hinzufügen Workouts + Aktivieren + Höhe + GPS deaktiviert + Bitte aktiviere GPS, damit dein Workout aufgezeichnet werden kann. + Aufstieg + Abstieg \ No newline at end of file diff --git a/metadata/en-US/changelogs/110.txt b/metadata/en-US/changelogs/110.txt new file mode 100644 index 0000000..86a16a4 --- /dev/null +++ b/metadata/en-US/changelogs/110.txt @@ -0,0 +1,8 @@ +New: +- Height measurement via GPS and pressure sensor +- Show height diagram +- Show dialog if GPS is disabled + +Fix: +- Back-Button in Settings crashes on earlier Android versions (#20) +- Fix Unit system "Imperial with meters" \ No newline at end of file