mirror of
https://github.com/russok/FitoTrack.git
synced 2025-10-28 00:02:11 -07:00
Migrate the workout saving process to the extra class WorkoutSaver
This commit is contained in:
parent
7617809897
commit
83c0168108
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Jannis Scheibe <jannis@tadris.de>
|
||||
* Copyright (c) 2020 Jannis Scheibe <jannis@tadris.de>
|
||||
*
|
||||
* This file is part of FitoTrack
|
||||
*
|
||||
@ -19,118 +19,10 @@
|
||||
|
||||
package de.tadris.fitness.data;
|
||||
|
||||
import android.content.Context;
|
||||
import android.hardware.SensorManager;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import de.tadris.fitness.Instance;
|
||||
import de.tadris.fitness.util.CalorieCalculator;
|
||||
|
||||
public class WorkoutManager {
|
||||
|
||||
public static void insertWorkout(Context context, Workout workout, List<WorkoutSample> samples){
|
||||
AppDatabase db= Instance.getInstance(context).db;
|
||||
|
||||
|
||||
workout.id= System.currentTimeMillis();
|
||||
|
||||
// Delete Samples with same time
|
||||
for(int i= samples.size()-2; i >= 0; i--){
|
||||
WorkoutSample sample= samples.get(i);
|
||||
WorkoutSample lastSample= samples.get(i+1);
|
||||
if(sample.absoluteTime == lastSample.absoluteTime){
|
||||
samples.remove(lastSample);
|
||||
Log.i("WorkoutManager", "Removed samples at " + sample.absoluteTime + " rel: " + sample.relativeTime + "; " + lastSample.relativeTime);
|
||||
}
|
||||
}
|
||||
|
||||
// Calculating values
|
||||
double length= 0;
|
||||
for(int i= 1; i < samples.size(); i++){
|
||||
double sampleLength= samples.get(i - 1).toLatLong().sphericalDistance(samples.get(i).toLatLong());
|
||||
long timeDiff= (samples.get(i).relativeTime - samples.get(i - 1).relativeTime) / 1000;
|
||||
length+= sampleLength;
|
||||
samples.get(i).speed= Math.abs(sampleLength / timeDiff);
|
||||
}
|
||||
workout.length= (int)length;
|
||||
workout.avgSpeed= ((double) workout.length) / ((double) workout.duration / 1000);
|
||||
workout.avgPace= ((double)workout.duration / 1000 / 60) / ((double) workout.length / 1000);
|
||||
workout.calorie= CalorieCalculator.calculateCalories(workout, Instance.getInstance(context).userPreferences.getUserWeight());
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
int range= 3;
|
||||
for(i= 0; i < samples.size(); i++){
|
||||
int min= Math.max(i-range, 0);
|
||||
int max= Math.min(i+range, samples.size()-1);
|
||||
samples.get(i).tmpElevation= getAverageElevation(samples.subList(min, max));
|
||||
}
|
||||
|
||||
for(i= 0; i < samples.size(); i++) {
|
||||
WorkoutSample sample = samples.get(i);
|
||||
sample.elevation= sample.tmpElevation;
|
||||
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]));
|
||||
|
||||
}
|
||||
|
||||
public static double getAverageElevation(List<WorkoutSample> samples){
|
||||
double sum= 0;
|
||||
for(WorkoutSample sample : samples){
|
||||
sum+= sample.elevation;
|
||||
}
|
||||
return sum / samples.size();
|
||||
}
|
||||
|
||||
public static void roundSpeedValues(List<WorkoutSample> samples){
|
||||
for(int i= 0; i < samples.size(); i++){
|
||||
WorkoutSample sample= samples.get(i);
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Jannis Scheibe <jannis@tadris.de>
|
||||
* Copyright (c) 2020 Jannis Scheibe <jannis@tadris.de>
|
||||
*
|
||||
* This file is part of FitoTrack
|
||||
*
|
||||
@ -31,7 +31,6 @@ import java.util.List;
|
||||
|
||||
import de.tadris.fitness.Instance;
|
||||
import de.tadris.fitness.data.Workout;
|
||||
import de.tadris.fitness.data.WorkoutManager;
|
||||
import de.tadris.fitness.data.WorkoutSample;
|
||||
import de.tadris.fitness.util.CalorieCalculator;
|
||||
|
||||
@ -53,7 +52,7 @@ public class WorkoutRecorder implements LocationListener.LocationChangeListener
|
||||
/**
|
||||
* Time after which the workout is stopped and saved automatically because there is no activity anymore
|
||||
*/
|
||||
private static final int AUTO_STOP_TIMEOUT= 1000*60*60*20;
|
||||
private static final int AUTO_STOP_TIMEOUT= 1000*60*60*20; // 20 minutes
|
||||
|
||||
private Context context;
|
||||
private Workout workout;
|
||||
@ -65,7 +64,7 @@ public class WorkoutRecorder implements LocationListener.LocationChangeListener
|
||||
private long lastPause= 0;
|
||||
private long lastSampleTime= 0;
|
||||
private double distance= 0;
|
||||
private boolean hasBegan = false;
|
||||
private boolean hasBegun = false;
|
||||
|
||||
private static final double SIGNAL_BAD_THRESHOLD= 20; // In meters
|
||||
private static final int SIGNAL_LOST_THRESHOLD= 10000; // In milliseconds
|
||||
@ -135,7 +134,7 @@ public class WorkoutRecorder implements LocationListener.LocationChangeListener
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}).start();
|
||||
}, "WorkoutWatchdog").start();
|
||||
}
|
||||
|
||||
private void checkSignalState(){
|
||||
@ -193,7 +192,7 @@ public class WorkoutRecorder implements LocationListener.LocationChangeListener
|
||||
}
|
||||
Log.i("Recorder", "Save");
|
||||
synchronized (samples){
|
||||
WorkoutManager.insertWorkout(context, workout, samples);
|
||||
new WorkoutSaver(context, workout, samples).saveWorkout();
|
||||
}
|
||||
}
|
||||
|
||||
@ -209,6 +208,8 @@ public class WorkoutRecorder implements LocationListener.LocationChangeListener
|
||||
if(isActive()){
|
||||
double distance= 0;
|
||||
if(getSampleCount() > 0){
|
||||
// Checks whether the minimum distance to last sample was reached
|
||||
// and if the time difference to the last sample is too small
|
||||
synchronized (samples){
|
||||
WorkoutSample lastSample= samples.get(samples.size() - 1);
|
||||
distance= LocationListener.locationToLatLong(location).sphericalDistance(new LatLong(lastSample.lat, lastSample.lon));
|
||||
@ -220,38 +221,44 @@ public class WorkoutRecorder implements LocationListener.LocationChangeListener
|
||||
}
|
||||
lastSampleTime= System.currentTimeMillis();
|
||||
if(state == RecordingState.RUNNING && location.getTime() > workout.start){
|
||||
if(samples.size() == 2 && !hasBegan){
|
||||
lastResume= System.currentTimeMillis();
|
||||
workout.start= System.currentTimeMillis();
|
||||
lastPause= 0;
|
||||
time= 0;
|
||||
pauseTime= 0;
|
||||
this.distance= 0;
|
||||
samples.clear();
|
||||
|
||||
hasBegan = true; // Do not clear a second time
|
||||
if(samples.size() == 2 && !hasBegun){
|
||||
initialClearValues();
|
||||
hasBegun = true; // Do not clear a second time
|
||||
}
|
||||
this.distance+= distance;
|
||||
WorkoutSample sample= new WorkoutSample();
|
||||
sample.lat= location.getLatitude();
|
||||
sample.lon= location.getLongitude();
|
||||
sample.elevation= location.getAltitude();
|
||||
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);
|
||||
}
|
||||
|
||||
addToSamples(location);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addToSamples(Location location){
|
||||
WorkoutSample sample= new WorkoutSample();
|
||||
sample.lat= location.getLatitude();
|
||||
sample.lon= location.getLongitude();
|
||||
sample.elevation= location.getAltitude();
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
private void initialClearValues(){
|
||||
lastResume= System.currentTimeMillis();
|
||||
workout.start= System.currentTimeMillis();
|
||||
lastPause= 0;
|
||||
time= 0;
|
||||
pauseTime= 0;
|
||||
this.distance= 0;
|
||||
samples.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the distance in meters
|
||||
*/
|
||||
|
||||
183
app/src/main/java/de/tadris/fitness/recording/WorkoutSaver.java
Normal file
183
app/src/main/java/de/tadris/fitness/recording/WorkoutSaver.java
Normal file
@ -0,0 +1,183 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Jannis Scheibe <jannis@tadris.de>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.tadris.fitness.recording;
|
||||
|
||||
import android.content.Context;
|
||||
import android.hardware.SensorManager;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import de.tadris.fitness.Instance;
|
||||
import de.tadris.fitness.data.AppDatabase;
|
||||
import de.tadris.fitness.data.Workout;
|
||||
import de.tadris.fitness.data.WorkoutSample;
|
||||
import de.tadris.fitness.util.CalorieCalculator;
|
||||
|
||||
public class WorkoutSaver {
|
||||
|
||||
private Context context;
|
||||
private Workout workout;
|
||||
private List<WorkoutSample> samples;
|
||||
private AppDatabase db;
|
||||
|
||||
public WorkoutSaver(Context context, Workout workout, List<WorkoutSample> samples) {
|
||||
this.context = context;
|
||||
this.workout = workout;
|
||||
this.samples = samples;
|
||||
db= Instance.getInstance(context).db;
|
||||
}
|
||||
|
||||
public void saveWorkout(){
|
||||
setIds();
|
||||
clearSamplesWithSameTime();
|
||||
setSimpleValues();
|
||||
setTopSpeed();
|
||||
|
||||
setRealElevation();
|
||||
setAscentAndDescent();
|
||||
|
||||
storeInDatabase();
|
||||
}
|
||||
|
||||
private void setIds(){
|
||||
workout.id= System.currentTimeMillis();
|
||||
int i= 0;
|
||||
for(WorkoutSample sample : samples) {
|
||||
i++;
|
||||
sample.id = workout.id + i;
|
||||
sample.workoutId = workout.id;
|
||||
}
|
||||
}
|
||||
|
||||
private void clearSamplesWithSameTime(){
|
||||
for(int i= samples.size()-2; i >= 0; i--){
|
||||
WorkoutSample sample= samples.get(i);
|
||||
WorkoutSample lastSample= samples.get(i+1);
|
||||
if(sample.absoluteTime == lastSample.absoluteTime){
|
||||
samples.remove(lastSample);
|
||||
Log.i("WorkoutManager", "Removed samples at " + sample.absoluteTime + " rel: " + sample.relativeTime + "; " + lastSample.relativeTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setSimpleValues(){
|
||||
double length= 0;
|
||||
for(int i= 1; i < samples.size(); i++){
|
||||
double sampleLength= samples.get(i - 1).toLatLong().sphericalDistance(samples.get(i).toLatLong());
|
||||
long timeDiff= (samples.get(i).relativeTime - samples.get(i - 1).relativeTime) / 1000;
|
||||
length+= sampleLength;
|
||||
samples.get(i).speed= Math.abs(sampleLength / timeDiff);
|
||||
}
|
||||
workout.length= (int)length;
|
||||
workout.avgSpeed= ((double) workout.length) / ((double) workout.duration / 1000);
|
||||
workout.avgPace= ((double)workout.duration / 1000 / 60) / ((double) workout.length / 1000);
|
||||
workout.calorie= CalorieCalculator.calculateCalories(workout, Instance.getInstance(context).userPreferences.getUserWeight());
|
||||
}
|
||||
|
||||
private void setTopSpeed(){
|
||||
double topSpeed= 0;
|
||||
for(WorkoutSample sample : samples){
|
||||
if(sample.speed > topSpeed){
|
||||
topSpeed= sample.speed;
|
||||
}
|
||||
}
|
||||
workout.topSpeed= topSpeed;
|
||||
}
|
||||
|
||||
private void setRealElevation(){
|
||||
boolean pressureDataAvailable= samples.get(0).tmpPressure != -1;
|
||||
|
||||
if(!pressureDataAvailable){
|
||||
// Because pressure data isn't available we just use the use GPS elevation
|
||||
// in WorkoutSample.elevation which was already set
|
||||
return;
|
||||
}
|
||||
|
||||
double avgElevation= getAverageElevation();
|
||||
double avgPressure= getAveragePressure();
|
||||
|
||||
for(int i= 0; i < samples.size(); i++){
|
||||
WorkoutSample sample= samples.get(i);
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
private double getAverageElevation(){
|
||||
return getAverageElevation(samples);
|
||||
}
|
||||
|
||||
private double getAverageElevation(List<WorkoutSample> samples){
|
||||
double elevationSum= 0; // Sum of elevation
|
||||
for(WorkoutSample sample : samples){
|
||||
elevationSum+= sample.elevation;
|
||||
}
|
||||
|
||||
return elevationSum / samples.size();
|
||||
}
|
||||
|
||||
private double getAveragePressure(){
|
||||
double pressureSum= 0;
|
||||
for(WorkoutSample sample : samples){
|
||||
pressureSum+= sample.tmpPressure;
|
||||
}
|
||||
return pressureSum / samples.size();
|
||||
}
|
||||
|
||||
private void setAscentAndDescent(){
|
||||
workout.ascent = 0;
|
||||
workout.descent = 0;
|
||||
|
||||
// First calculate a floating average to eliminate pressure noise to influence our ascent/descent
|
||||
int range= 3;
|
||||
for(int i= 0; i < samples.size(); i++){
|
||||
int min= Math.max(i-range, 0);
|
||||
int max= Math.min(i+range, samples.size()-1);
|
||||
samples.get(i).tmpElevation= getAverageElevation(samples.subList(min, max));
|
||||
}
|
||||
|
||||
// Now sum up the ascent/descent
|
||||
for(int i= 0; i < samples.size(); i++) {
|
||||
WorkoutSample sample = samples.get(i);
|
||||
sample.elevation= sample.tmpElevation;
|
||||
if(i >= 1){
|
||||
WorkoutSample lastSample= samples.get(i-1);
|
||||
double diff= sample.elevation - lastSample.elevation;
|
||||
if(diff > 0){
|
||||
// If this sample is higher than the last one, add difference to ascent
|
||||
workout.ascent += diff;
|
||||
}else{
|
||||
// If this sample is lower than the last one, add difference to descent
|
||||
workout.descent += Math.abs(diff);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void storeInDatabase(){
|
||||
db.workoutDao().insertWorkoutAndSamples(workout, samples.toArray(new WorkoutSample[0]));
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user