Make timestamp to mpandroidchart float x-value explicit

master
cpfeiffer 2016-10-08 11:16:40 +02:00
parent 125c0092cb
commit c2ff05e849
2 changed files with 58 additions and 37 deletions

View File

@ -411,7 +411,7 @@ public abstract class AbstractChartFragment extends AbstractGBFragment {
protected DefaultChartsData<CombinedData> refresh(GBDevice gbDevice, List<? extends ActivitySample> samples) { protected DefaultChartsData<CombinedData> refresh(GBDevice gbDevice, List<? extends ActivitySample> samples) {
// Calendar cal = GregorianCalendar.getInstance(); // Calendar cal = GregorianCalendar.getInstance();
// cal.clear(); // cal.clear();
int tsOffset = 0; TimestampTranslation tsTranslation = new TimestampTranslation();
// Date date; // Date date;
// String dateStringFrom = ""; // String dateStringFrom = "";
// String dateStringTo = ""; // String dateStringTo = "";
@ -435,13 +435,7 @@ public abstract class AbstractChartFragment extends AbstractGBFragment {
for (int i = 0; i < numEntries; i++) { for (int i = 0; i < numEntries; i++) {
ActivitySample sample = samples.get(i); ActivitySample sample = samples.get(i);
int type = sample.getKind(); int type = sample.getKind();
int ts; int ts = tsTranslation.shorten(sample.getTimestamp());
if (i == 0) {
tsOffset = sample.getTimestamp();
ts = 0;
} else {
ts = sample.getTimestamp() - tsOffset;
}
// System.out.println(ts); // System.out.println(ts);
// ts = i; // ts = i;
@ -541,7 +535,7 @@ public abstract class AbstractChartFragment extends AbstractGBFragment {
combinedData = new CombinedData(); combinedData = new CombinedData();
} }
IAxisValueFormatter xValueFormatter = new SampleXLabelFormatter(tsOffset); IAxisValueFormatter xValueFormatter = new SampleXLabelFormatter(tsTranslation);
return new DefaultChartsData(combinedData, xValueFormatter); return new DefaultChartsData(combinedData, xValueFormatter);
} }
@ -750,13 +744,13 @@ public abstract class AbstractChartFragment extends AbstractGBFragment {
} }
protected static class SampleXLabelFormatter implements IAxisValueFormatter { protected static class SampleXLabelFormatter implements IAxisValueFormatter {
private final int tsOffset; private final TimestampTranslation tsTranslation;
SimpleDateFormat annotationDateFormat = new SimpleDateFormat("HH:mm"); SimpleDateFormat annotationDateFormat = new SimpleDateFormat("HH:mm");
// SimpleDateFormat dateFormat = new SimpleDateFormat("dd.MM.yyyy HH:mm"); // SimpleDateFormat dateFormat = new SimpleDateFormat("dd.MM.yyyy HH:mm");
Calendar cal = GregorianCalendar.getInstance(); Calendar cal = GregorianCalendar.getInstance();
public SampleXLabelFormatter(int tsOffset) { public SampleXLabelFormatter(TimestampTranslation tsTranslation) {
this.tsOffset = tsOffset; this.tsTranslation = tsTranslation;
} }
// TODO: this does not work. Cannot use precomputed labels // TODO: this does not work. Cannot use precomputed labels
@ -764,7 +758,7 @@ public abstract class AbstractChartFragment extends AbstractGBFragment {
public String getFormattedValue(float value, AxisBase axis) { public String getFormattedValue(float value, AxisBase axis) {
cal.clear(); cal.clear();
int ts = (int) value; int ts = (int) value;
cal.setTimeInMillis((ts + tsOffset) * 1000L); cal.setTimeInMillis(tsTranslation.toOriginalValue(ts) * 1000L);
Date date = cal.getTime(); Date date = cal.getTime();
String dateString = annotationDateFormat.format(date); String dateString = annotationDateFormat.format(date);
return dateString; return dateString;
@ -797,4 +791,31 @@ public abstract class AbstractChartFragment extends AbstractGBFragment {
return 0; return 0;
} }
} }
/**
* Awkward class that helps in translating long timestamp
* values to float (sic!) values. It basically rebases all
* timestamps to a base (the very first) timestamp value.
*
* It does this so that the large timestamp values can be used
* floating point values, where the mantissa is just 24 bits.
*/
protected static class TimestampTranslation {
private int tsOffset = -1;
public int shorten(int timestamp) {
if (tsOffset == -1) {
tsOffset = timestamp;
return 0;
}
return timestamp - tsOffset;
}
public int toOriginalValue(int timestamp) {
if (tsOffset == -1) {
return timestamp;
}
return timestamp + tsOffset;
}
}
} }

View File

@ -69,13 +69,13 @@ public class LiveActivityFragment extends AbstractChartFragment {
private List<Measurement> heartRateValues; private List<Measurement> heartRateValues;
private LineDataSet mHeartRateSet; private LineDataSet mHeartRateSet;
private int mHeartRate; private int mHeartRate;
private long tsOffset = -1; private TimestampTranslation tsTranslation;
private class Steps { private class Steps {
private int initialSteps; private int initialSteps;
private int steps; private int steps;
private long lastTimestamp; private int lastTimestamp;
private int currentStepsPerMinute; private int currentStepsPerMinute;
private int maxStepsPerMinute; private int maxStepsPerMinute;
private int lastStepsPerMinute; private int lastStepsPerMinute;
@ -97,7 +97,7 @@ public class LiveActivityFragment extends AbstractChartFragment {
return maxStepsPerMinute; return maxStepsPerMinute;
} }
public void updateCurrentSteps(int newSteps, long timestamp) { public void updateCurrentSteps(int newSteps, int timestamp) {
try { try {
if (steps == 0) { if (steps == 0) {
steps = newSteps; steps = newSteps;
@ -111,7 +111,7 @@ public class LiveActivityFragment extends AbstractChartFragment {
if (newSteps >= steps) { if (newSteps >= steps) {
int stepsDelta = newSteps - steps; int stepsDelta = newSteps - steps;
long timeDelta = timestamp - lastTimestamp; int timeDelta = timestamp - lastTimestamp;
currentStepsPerMinute = calculateStepsPerMinute(stepsDelta, timeDelta); currentStepsPerMinute = calculateStepsPerMinute(stepsDelta, timeDelta);
if (currentStepsPerMinute > maxStepsPerMinute) { if (currentStepsPerMinute > maxStepsPerMinute) {
maxStepsPerMinute = currentStepsPerMinute; maxStepsPerMinute = currentStepsPerMinute;
@ -128,16 +128,16 @@ public class LiveActivityFragment extends AbstractChartFragment {
} }
} }
private int calculateStepsPerMinute(int stepsDelta, long millis) { private int calculateStepsPerMinute(int stepsDelta, int seconds) {
if (stepsDelta == 0) { if (stepsDelta == 0) {
return 0; // not walking or not enough data per mills? return 0; // not walking or not enough data per mills?
} }
if (millis <= 0) { if (seconds <= 0) {
throw new IllegalArgumentException("delta in millis is <= 0 -- time change?"); throw new IllegalArgumentException("delta in seconds is <= 0 -- time change?");
} }
long oneMinute = 60 * 1000; int oneMinute = 60 * 1000;
float factor = oneMinute / millis; float factor = oneMinute / seconds;
int result = (int) (stepsDelta * factor); int result = (int) (stepsDelta * factor);
if (result > MAX_STEPS_PER_MINUTE) { if (result > MAX_STEPS_PER_MINUTE) {
// ignore, return previous value instead // ignore, return previous value instead
@ -154,15 +154,13 @@ public class LiveActivityFragment extends AbstractChartFragment {
switch (action) { switch (action) {
case DeviceService.ACTION_REALTIME_STEPS: { case DeviceService.ACTION_REALTIME_STEPS: {
int steps = intent.getIntExtra(DeviceService.EXTRA_REALTIME_STEPS, 0); int steps = intent.getIntExtra(DeviceService.EXTRA_REALTIME_STEPS, 0);
long timestamp = intent.getLongExtra(DeviceService.EXTRA_TIMESTAMP, System.currentTimeMillis()); int timestamp = translateTimestampFrom(intent);
timestamp = adjust(timestamp);
addEntries(steps, timestamp); addEntries(steps, timestamp);
break; break;
} }
case DeviceService.ACTION_HEARTRATE_MEASUREMENT: { case DeviceService.ACTION_HEARTRATE_MEASUREMENT: {
int heartRate = intent.getIntExtra(DeviceService.EXTRA_HEART_RATE_VALUE, 0); int heartRate = intent.getIntExtra(DeviceService.EXTRA_HEART_RATE_VALUE, 0);
long timestamp = intent.getLongExtra(DeviceService.EXTRA_TIMESTAMP, System.currentTimeMillis()); int timestamp = translateTimestampFrom(intent);
timestamp = adjust(timestamp);
if (isValidHeartRateValue(heartRate)) { if (isValidHeartRateValue(heartRate)) {
setCurrentHeartRate(heartRate, timestamp); setCurrentHeartRate(heartRate, timestamp);
} }
@ -172,15 +170,16 @@ public class LiveActivityFragment extends AbstractChartFragment {
} }
}; };
private long adjust(long timestamp) { private int translateTimestampFrom(Intent intent) {
if (tsOffset == -1) { return translateTimestamp(intent.getLongExtra(DeviceService.EXTRA_TIMESTAMP, System.currentTimeMillis()));
tsOffset = timestamp;
return 0;
}
return timestamp - tsOffset;
} }
private void setCurrentHeartRate(int heartRate, long timestamp) { private int translateTimestamp(long tsMillis) {
int timestamp = (int) (tsMillis / 1000); // translate to seconds
return tsTranslation.shorten(timestamp); // and shorten
}
private void setCurrentHeartRate(int heartRate, int timestamp) {
addHistoryDataSet(true); addHistoryDataSet(true);
mHeartRate = heartRate; mHeartRate = heartRate;
} }
@ -191,7 +190,7 @@ public class LiveActivityFragment extends AbstractChartFragment {
return result; return result;
} }
private void addEntries(int steps, long timestamp) { private void addEntries(int steps, int timestamp) {
mSteps.updateCurrentSteps(steps, timestamp); mSteps.updateCurrentSteps(steps, timestamp);
if (++maxStepsResetCounter > RESET_COUNT) { if (++maxStepsResetCounter > RESET_COUNT) {
maxStepsResetCounter = 0; maxStepsResetCounter = 0;
@ -203,7 +202,7 @@ public class LiveActivityFragment extends AbstractChartFragment {
// addEntries(); // addEntries();
} }
private void addEntries(long timestamp) { private void addEntries(int timestamp) {
mTotalStepsChart.setSingleEntryYValue(mSteps.getTotalSteps()); mTotalStepsChart.setSingleEntryYValue(mSteps.getTotalSteps());
YAxis stepsPerMinuteCurrentYAxis = mStepsPerMinuteCurrentChart.getAxisLeft(); YAxis stepsPerMinuteCurrentYAxis = mStepsPerMinuteCurrentChart.getAxisLeft();
int maxStepsPerMinute = mSteps.getMaxStepsPerMinute(); int maxStepsPerMinute = mSteps.getMaxStepsPerMinute();
@ -255,6 +254,7 @@ public class LiveActivityFragment extends AbstractChartFragment {
filterLocal.addAction(DeviceService.ACTION_REALTIME_STEPS); filterLocal.addAction(DeviceService.ACTION_REALTIME_STEPS);
filterLocal.addAction(DeviceService.ACTION_HEARTRATE_MEASUREMENT); filterLocal.addAction(DeviceService.ACTION_HEARTRATE_MEASUREMENT);
heartRateValues = new ArrayList<>(); heartRateValues = new ArrayList<>();
tsTranslation = new TimestampTranslation();
View rootView = inflater.inflate(R.layout.fragment_live_activity, container, false); View rootView = inflater.inflate(R.layout.fragment_live_activity, container, false);
@ -315,7 +315,7 @@ public class LiveActivityFragment extends AbstractChartFragment {
* Called in the UI thread. * Called in the UI thread.
*/ */
private void pulse() { private void pulse() {
addEntries(adjust(System.currentTimeMillis())); addEntries(translateTimestamp(System.currentTimeMillis()));
LineData historyData = (LineData) mStepsPerMinuteHistoryChart.getData(); LineData historyData = (LineData) mStepsPerMinuteHistoryChart.getData();
if (historyData == null) { if (historyData == null) {
@ -333,7 +333,7 @@ public class LiveActivityFragment extends AbstractChartFragment {
GBApplication.deviceService().onEnableRealtimeHeartRateMeasurement(true); GBApplication.deviceService().onEnableRealtimeHeartRateMeasurement(true);
} }
private long getPulseIntervalMillis() { private int getPulseIntervalMillis() {
return 1000; return 1000;
} }