1
0
mirror of https://codeberg.org/Freeyourgadget/Gadgetbridge synced 2024-11-28 12:56:49 +01:00

Some work in progress for heart rate graphs #178

Currently we get the heart rate when synchronizing activity data
(i.e. not live) and we write it to the activity database so that we
can show a nice graph. The value is currently always 0 though,
because we can't enable recording hr, yet.
This commit is contained in:
cpfeiffer 2016-02-26 23:45:17 +01:00
parent df741e9571
commit 0ef738067d
17 changed files with 130 additions and 42 deletions

View File

@ -12,9 +12,14 @@ import android.view.View;
import com.github.mikephil.charting.charts.BarLineChartBase; import com.github.mikephil.charting.charts.BarLineChartBase;
import com.github.mikephil.charting.charts.Chart; import com.github.mikephil.charting.charts.Chart;
import com.github.mikephil.charting.charts.CombinedChart;
import com.github.mikephil.charting.data.BarData; import com.github.mikephil.charting.data.BarData;
import com.github.mikephil.charting.data.BarDataSet; import com.github.mikephil.charting.data.BarDataSet;
import com.github.mikephil.charting.data.BarEntry; import com.github.mikephil.charting.data.BarEntry;
import com.github.mikephil.charting.data.CombinedData;
import com.github.mikephil.charting.data.Entry;
import com.github.mikephil.charting.data.LineData;
import com.github.mikephil.charting.data.LineDataSet;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -23,6 +28,7 @@ import java.text.SimpleDateFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Calendar; import java.util.Calendar;
import java.util.Collections;
import java.util.Date; import java.util.Date;
import java.util.GregorianCalendar; import java.util.GregorianCalendar;
import java.util.HashSet; import java.util.HashSet;
@ -72,12 +78,16 @@ public abstract class AbstractChartFragment extends AbstractGBFragment {
} }
}; };
private boolean mChartDirty = true; private boolean mChartDirty = true;
private boolean supportsHeartrateChart = false;
public boolean isChartDirty() { public boolean isChartDirty() {
return mChartDirty; return mChartDirty;
} }
public abstract String getTitle(); public abstract String getTitle();
public boolean supportsHeartrate() {
return supportsHeartrateChart;
}
protected static final class ActivityConfig { protected static final class ActivityConfig {
public final int type; public final int type;
@ -101,6 +111,7 @@ public abstract class AbstractChartFragment extends AbstractGBFragment {
protected int DESCRIPTION_COLOR; protected int DESCRIPTION_COLOR;
protected int CHART_TEXT_COLOR; protected int CHART_TEXT_COLOR;
protected int LEGEND_TEXT_COLOR; protected int LEGEND_TEXT_COLOR;
protected int HEARTRATE_COLOR;
protected int AK_ACTIVITY_COLOR; protected int AK_ACTIVITY_COLOR;
protected int AK_DEEP_SLEEP_COLOR; protected int AK_DEEP_SLEEP_COLOR;
protected int AK_LIGHT_SLEEP_COLOR; protected int AK_LIGHT_SLEEP_COLOR;
@ -134,6 +145,7 @@ public abstract class AbstractChartFragment extends AbstractGBFragment {
DESCRIPTION_COLOR = getResources().getColor(R.color.primarytext); DESCRIPTION_COLOR = getResources().getColor(R.color.primarytext);
CHART_TEXT_COLOR = getResources().getColor(R.color.secondarytext); CHART_TEXT_COLOR = getResources().getColor(R.color.secondarytext);
LEGEND_TEXT_COLOR = getResources().getColor(R.color.primarytext); LEGEND_TEXT_COLOR = getResources().getColor(R.color.primarytext);
HEARTRATE_COLOR = getResources().getColor(R.color.chart_heartrate);
AK_ACTIVITY_COLOR = getResources().getColor(R.color.chart_activity_light); AK_ACTIVITY_COLOR = getResources().getColor(R.color.chart_activity_light);
AK_DEEP_SLEEP_COLOR = getResources().getColor(R.color.chart_light_sleep_light); AK_DEEP_SLEEP_COLOR = getResources().getColor(R.color.chart_light_sleep_light);
AK_LIGHT_SLEEP_COLOR = getResources().getColor(R.color.chart_deep_sleep_light); AK_LIGHT_SLEEP_COLOR = getResources().getColor(R.color.chart_deep_sleep_light);
@ -389,6 +401,8 @@ public abstract class AbstractChartFragment extends AbstractGBFragment {
int numEntries = samples.size(); int numEntries = samples.size();
List<String> xLabels = new ArrayList<>(numEntries); List<String> xLabels = new ArrayList<>(numEntries);
List<BarEntry> activityEntries = new ArrayList<>(numEntries); List<BarEntry> activityEntries = new ArrayList<>(numEntries);
boolean hr = supportsHeartrate();
List<Entry> heartrateEntries = hr ? new ArrayList<Entry>(numEntries) : null;
List<Integer> colors = new ArrayList<>(numEntries); // this is kinda inefficient... List<Integer> colors = new ArrayList<>(numEntries); // this is kinda inefficient...
for (int i = 0; i < numEntries; i++) { for (int i = 0; i < numEntries; i++) {
@ -431,6 +445,9 @@ public abstract class AbstractChartFragment extends AbstractGBFragment {
colors.add(akActivity.color); colors.add(akActivity.color);
} }
activityEntries.add(createBarEntry(value, i)); activityEntries.add(createBarEntry(value, i));
if (hr) {
heartrateEntries.add(createLineEntry(sample.getCustomShortValue(), i));
}
String xLabel = ""; String xLabel = "";
if (annotate) { if (annotate) {
@ -463,13 +480,19 @@ public abstract class AbstractChartFragment extends AbstractGBFragment {
chart.getXAxis().setValues(xLabels); chart.getXAxis().setValues(xLabels);
BarDataSet activitySet = createActivitySet(activityEntries, colors, "Activity"); BarDataSet activitySet = createActivitySet(activityEntries, colors, "Activity");
ArrayList<BarDataSet> dataSets = new ArrayList<>();
dataSets.add(activitySet);
// create a data object with the datasets // create a data object with the datasets
BarData data = new BarData(xLabels, dataSets); CombinedData combinedData = new CombinedData(xLabels);
data.setGroupSpace(0); List<BarDataSet> list = new ArrayList<>();
list.add(activitySet);
BarData barData = new BarData(xLabels, list);
barData.setGroupSpace(0);
combinedData.setData(barData);
if (hr) {
LineDataSet heartrateSet = createHeartrateSet(heartrateEntries, "Heart Rate");
LineData lineData = new LineData(xLabels, heartrateSet);
combinedData.setData(lineData);
}
chart.setDescription(""); chart.setDescription("");
// chart.setDescription(getString(R.string.sleep_activity_date_range, dateStringFrom, dateStringTo)); // chart.setDescription(getString(R.string.sleep_activity_date_range, dateStringFrom, dateStringTo));
@ -477,7 +500,7 @@ public abstract class AbstractChartFragment extends AbstractGBFragment {
setupLegend(chart); setupLegend(chart);
chart.setData(data); chart.setData(combinedData);
} }
} }
@ -498,6 +521,10 @@ public abstract class AbstractChartFragment extends AbstractGBFragment {
return new BarEntry(value, index); return new BarEntry(value, index);
} }
protected Entry createLineEntry(float value, int index) {
return new Entry(value, index);
}
protected BarDataSet createActivitySet(List<BarEntry> values, List<Integer> colors, String label) { protected BarDataSet createActivitySet(List<BarEntry> values, List<Integer> colors, String label) {
BarDataSet set1 = new BarDataSet(values, label); BarDataSet set1 = new BarDataSet(values, label);
set1.setColors(colors); set1.setColors(colors);
@ -515,6 +542,24 @@ public abstract class AbstractChartFragment extends AbstractGBFragment {
return set1; return set1;
} }
protected LineDataSet createHeartrateSet(List<Entry> values, String label) {
LineDataSet set1 = new LineDataSet(values, label);
set1.setColor(HEARTRATE_COLOR);
// set1.setColors(colors);
// set1.setDrawCubic(true);
// set1.setCubicIntensity(0.2f);
// //set1.setDrawFilled(true);
// set1.setDrawCircles(false);
// set1.setLineWidth(2f);
// set1.setCircleSize(5f);
// set1.setFillColor(ColorTemplate.getHoloBlue());
set1.setDrawValues(false);
// set1.setHighLightColor(Color.rgb(128, 0, 255));
// set1.setColor(Color.rgb(89, 178, 44));
set1.setValueTextColor(CHART_TEXT_COLOR);
return set1;
}
protected BarDataSet createDeepSleepSet(List<BarEntry> values, String label) { protected BarDataSet createDeepSleepSet(List<BarEntry> values, String label) {
BarDataSet set1 = new BarDataSet(values, label); BarDataSet set1 = new BarDataSet(values, label);
// set1.setDrawCubic(true); // set1.setDrawCubic(true);

View File

@ -78,7 +78,7 @@ public class ActivitySleepChartFragment extends AbstractChartFragment {
YAxis yAxisRight = mChart.getAxisRight(); YAxis yAxisRight = mChart.getAxisRight();
yAxisRight.setDrawGridLines(false); yAxisRight.setDrawGridLines(false);
yAxisRight.setEnabled(false); yAxisRight.setEnabled(supportsHeartrate());
yAxisRight.setDrawLabels(false); yAxisRight.setDrawLabels(false);
yAxisRight.setDrawTopYLabelEntry(false); yAxisRight.setDrawTopYLabelEntry(false);
yAxisRight.setTextColor(CHART_TEXT_COLOR); yAxisRight.setTextColor(CHART_TEXT_COLOR);

View File

@ -10,6 +10,7 @@ import android.view.ViewGroup;
import com.github.mikephil.charting.animation.Easing; import com.github.mikephil.charting.animation.Easing;
import com.github.mikephil.charting.charts.BarLineChartBase; import com.github.mikephil.charting.charts.BarLineChartBase;
import com.github.mikephil.charting.charts.Chart; import com.github.mikephil.charting.charts.Chart;
import com.github.mikephil.charting.charts.CombinedChart;
import com.github.mikephil.charting.charts.PieChart; import com.github.mikephil.charting.charts.PieChart;
import com.github.mikephil.charting.components.XAxis; import com.github.mikephil.charting.components.XAxis;
import com.github.mikephil.charting.components.YAxis; import com.github.mikephil.charting.components.YAxis;
@ -39,7 +40,7 @@ import nodomain.freeyourgadget.gadgetbridge.util.DateTimeUtils;
public class SleepChartFragment extends AbstractChartFragment { public class SleepChartFragment extends AbstractChartFragment {
protected static final Logger LOG = LoggerFactory.getLogger(ActivitySleepChartFragment.class); protected static final Logger LOG = LoggerFactory.getLogger(ActivitySleepChartFragment.class);
private BarLineChartBase mActivityChart; private CombinedChart mActivityChart;
private PieChart mSleepAmountChart; private PieChart mSleepAmountChart;
private int mSmartAlarmFrom = -1; private int mSmartAlarmFrom = -1;
@ -99,7 +100,7 @@ public class SleepChartFragment extends AbstractChartFragment {
Bundle savedInstanceState) { Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_sleepchart, container, false); View rootView = inflater.inflate(R.layout.fragment_sleepchart, container, false);
mActivityChart = (BarLineChartBase) rootView.findViewById(R.id.sleepchart); mActivityChart = (CombinedChart) rootView.findViewById(R.id.sleepchart);
mSleepAmountChart = (PieChart) rootView.findViewById(R.id.sleepchart_pie_light_deep); mSleepAmountChart = (PieChart) rootView.findViewById(R.id.sleepchart_pie_light_deep);
setupActivityChart(); setupActivityChart();

View File

@ -27,13 +27,14 @@ import static nodomain.freeyourgadget.gadgetbridge.database.DBConstants.KEY_PROV
import static nodomain.freeyourgadget.gadgetbridge.database.DBConstants.KEY_STEPS; import static nodomain.freeyourgadget.gadgetbridge.database.DBConstants.KEY_STEPS;
import static nodomain.freeyourgadget.gadgetbridge.database.DBConstants.KEY_TIMESTAMP; import static nodomain.freeyourgadget.gadgetbridge.database.DBConstants.KEY_TIMESTAMP;
import static nodomain.freeyourgadget.gadgetbridge.database.DBConstants.KEY_TYPE; import static nodomain.freeyourgadget.gadgetbridge.database.DBConstants.KEY_TYPE;
import static nodomain.freeyourgadget.gadgetbridge.database.DBConstants.KEY_CUSTOM_SHORT;
import static nodomain.freeyourgadget.gadgetbridge.database.DBConstants.TABLE_GBACTIVITYSAMPLES; import static nodomain.freeyourgadget.gadgetbridge.database.DBConstants.TABLE_GBACTIVITYSAMPLES;
public class ActivityDatabaseHandler extends SQLiteOpenHelper implements DBHandler { public class ActivityDatabaseHandler extends SQLiteOpenHelper implements DBHandler {
private static final Logger LOG = LoggerFactory.getLogger(ActivityDatabaseHandler.class); private static final Logger LOG = LoggerFactory.getLogger(ActivityDatabaseHandler.class);
private static final int DATABASE_VERSION = 5; private static final int DATABASE_VERSION = 6;
public ActivityDatabaseHandler(Context context) { public ActivityDatabaseHandler(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION); super(context, DATABASE_NAME, null, DATABASE_VERSION);
@ -101,6 +102,7 @@ public class ActivityDatabaseHandler extends SQLiteOpenHelper implements DBHandl
values.put(KEY_PROVIDER, sample.getProvider().getID()); values.put(KEY_PROVIDER, sample.getProvider().getID());
values.put(KEY_INTENSITY, sample.getRawIntensity()); values.put(KEY_INTENSITY, sample.getRawIntensity());
values.put(KEY_STEPS, sample.getSteps()); values.put(KEY_STEPS, sample.getSteps());
values.put(KEY_CUSTOM_SHORT, sample.getCustomShortValue());
values.put(KEY_TYPE, sample.getRawKind()); values.put(KEY_TYPE, sample.getRawKind());
db.insert(TABLE_GBACTIVITYSAMPLES, null, values); db.insert(TABLE_GBACTIVITYSAMPLES, null, values);
@ -117,7 +119,7 @@ public class ActivityDatabaseHandler extends SQLiteOpenHelper implements DBHandl
* @param kind the raw activity kind of the sample * @param kind the raw activity kind of the sample
*/ */
@Override @Override
public void addGBActivitySample(int timestamp, byte provider, short intensity, short steps, byte kind) { public void addGBActivitySample(int timestamp, byte provider, short intensity, short steps, byte kind, short customShortValue) {
if (intensity < 0) { if (intensity < 0) {
LOG.error("negative intensity received, ignoring"); LOG.error("negative intensity received, ignoring");
intensity = 0; intensity = 0;
@ -127,6 +129,11 @@ public class ActivityDatabaseHandler extends SQLiteOpenHelper implements DBHandl
steps = 0; steps = 0;
} }
if (customShortValue < 0) {
LOG.error("negative short value received, ignoring");
customShortValue = 0;
}
try (SQLiteDatabase db = this.getWritableDatabase()) { try (SQLiteDatabase db = this.getWritableDatabase()) {
ContentValues values = new ContentValues(); ContentValues values = new ContentValues();
values.put(KEY_TIMESTAMP, timestamp); values.put(KEY_TIMESTAMP, timestamp);
@ -134,6 +141,7 @@ public class ActivityDatabaseHandler extends SQLiteOpenHelper implements DBHandl
values.put(KEY_INTENSITY, intensity); values.put(KEY_INTENSITY, intensity);
values.put(KEY_STEPS, steps); values.put(KEY_STEPS, steps);
values.put(KEY_TYPE, kind); values.put(KEY_TYPE, kind);
values.put(KEY_CUSTOM_SHORT, customShortValue);
db.insert(TABLE_GBACTIVITYSAMPLES, null, values); db.insert(TABLE_GBACTIVITYSAMPLES, null, values);
} }
@ -144,8 +152,8 @@ public class ActivityDatabaseHandler extends SQLiteOpenHelper implements DBHandl
try (SQLiteDatabase db = this.getWritableDatabase()) { try (SQLiteDatabase db = this.getWritableDatabase()) {
String sql = "INSERT INTO " + TABLE_GBACTIVITYSAMPLES + " (" + KEY_TIMESTAMP + "," + String sql = "INSERT INTO " + TABLE_GBACTIVITYSAMPLES + " (" + KEY_TIMESTAMP + "," +
KEY_PROVIDER + "," + KEY_INTENSITY + "," + KEY_STEPS + "," + KEY_TYPE + ")" + KEY_PROVIDER + "," + KEY_INTENSITY + "," + KEY_STEPS + "," + KEY_TYPE + "," + KEY_CUSTOM_SHORT + ")" +
" VALUES (?,?,?,?,?);"; " VALUES (?,?,?,?,?,?);";
SQLiteStatement statement = db.compileStatement(sql); SQLiteStatement statement = db.compileStatement(sql);
db.beginTransaction(); db.beginTransaction();
@ -156,6 +164,7 @@ public class ActivityDatabaseHandler extends SQLiteOpenHelper implements DBHandl
statement.bindLong(3, activitySample.getRawIntensity()); statement.bindLong(3, activitySample.getRawIntensity());
statement.bindLong(4, activitySample.getSteps()); statement.bindLong(4, activitySample.getSteps());
statement.bindLong(5, activitySample.getRawKind()); statement.bindLong(5, activitySample.getRawKind());
statement.bindLong(6, activitySample.getCustomShortValue());
statement.execute(); statement.execute();
} }
db.setTransactionSuccessful(); db.setTransactionSuccessful();
@ -216,7 +225,8 @@ public class ActivityDatabaseHandler extends SQLiteOpenHelper implements DBHandl
cursor.getInt(cursor.getColumnIndex(KEY_TIMESTAMP)), cursor.getInt(cursor.getColumnIndex(KEY_TIMESTAMP)),
cursor.getShort(cursor.getColumnIndex(KEY_INTENSITY)), cursor.getShort(cursor.getColumnIndex(KEY_INTENSITY)),
cursor.getShort(cursor.getColumnIndex(KEY_STEPS)), cursor.getShort(cursor.getColumnIndex(KEY_STEPS)),
(byte) cursor.getShort(cursor.getColumnIndex(KEY_TYPE))); (byte) cursor.getShort(cursor.getColumnIndex(KEY_TYPE)),
cursor.getShort(cursor.getColumnIndex(KEY_CUSTOM_SHORT)));
samples.add(sample); samples.add(sample);
} while (cursor.moveToNext()); } while (cursor.moveToNext());
} }

View File

@ -10,5 +10,6 @@ public class DBConstants {
public static final String KEY_PROVIDER = "provider"; public static final String KEY_PROVIDER = "provider";
public static final String KEY_INTENSITY = "intensity"; public static final String KEY_INTENSITY = "intensity";
public static final String KEY_STEPS = "steps"; public static final String KEY_STEPS = "steps";
public static final String KEY_CUSTOM_SHORT = "customShort";
public static final String KEY_TYPE = "type"; public static final String KEY_TYPE = "type";
} }

View File

@ -24,7 +24,7 @@ public interface DBHandler {
List<ActivitySample> getSleepSamples(int tsFrom, int tsTo, SampleProvider provider); List<ActivitySample> getSleepSamples(int tsFrom, int tsTo, SampleProvider provider);
void addGBActivitySample(int timestamp, byte provider, short intensity, short steps, byte kind); void addGBActivitySample(int timestamp, byte provider, short intensity, short steps, byte kind, short heartrate);
void addGBActivitySamples(ActivitySample[] activitySamples); void addGBActivitySamples(ActivitySample[] activitySamples);

View File

@ -5,27 +5,25 @@ import android.database.sqlite.SQLiteDatabase;
import nodomain.freeyourgadget.gadgetbridge.database.DBHelper; import nodomain.freeyourgadget.gadgetbridge.database.DBHelper;
import nodomain.freeyourgadget.gadgetbridge.database.DBUpdateScript; import nodomain.freeyourgadget.gadgetbridge.database.DBUpdateScript;
import static nodomain.freeyourgadget.gadgetbridge.database.DBConstants.KEY_CUSTOM_SHORT;
import static nodomain.freeyourgadget.gadgetbridge.database.DBConstants.KEY_PROVIDER; import static nodomain.freeyourgadget.gadgetbridge.database.DBConstants.KEY_PROVIDER;
import static nodomain.freeyourgadget.gadgetbridge.database.DBConstants.KEY_STEPS; import static nodomain.freeyourgadget.gadgetbridge.database.DBConstants.KEY_STEPS;
import static nodomain.freeyourgadget.gadgetbridge.database.DBConstants.KEY_TIMESTAMP; import static nodomain.freeyourgadget.gadgetbridge.database.DBConstants.KEY_TIMESTAMP;
import static nodomain.freeyourgadget.gadgetbridge.database.DBConstants.TABLE_GBACTIVITYSAMPLES;
import static nodomain.freeyourgadget.gadgetbridge.database.DBConstants.TABLE_STEPS_PER_DAY; import static nodomain.freeyourgadget.gadgetbridge.database.DBConstants.TABLE_STEPS_PER_DAY;
/** /**
* Adds a table "STEPS_PER_DAY". * Adds a column "customShort" to the table "GBActivitySamples"
*/ */
public class ActivityDBUpdate_6 implements DBUpdateScript { public class ActivityDBUpdate_6 implements DBUpdateScript {
@Override @Override
public void upgradeSchema(SQLiteDatabase db) { public void upgradeSchema(SQLiteDatabase db) {
String CREATE_STEPS_PER_DAY_TABLE = "CREATE TABLE IF NOT EXISTS " + TABLE_STEPS_PER_DAY + " (" String ADD_COLUMN_CUSTOM_SHORT = "ALTER TABLE " + TABLE_GBACTIVITYSAMPLES + " ADD COLUMN "
+ KEY_TIMESTAMP + " INT," + KEY_CUSTOM_SHORT + " INT;";
+ KEY_PROVIDER + " TINYINT," db.execSQL(ADD_COLUMN_CUSTOM_SHORT);
+ KEY_STEPS + " MEDIUMINT,"
+ " PRIMARY KEY (" + KEY_TIMESTAMP + "," + KEY_PROVIDER + ") ON CONFLICT REPLACE)" + DBHelper.getWithoutRowId();
db.execSQL(CREATE_STEPS_PER_DAY_TABLE);
} }
@Override @Override
public void downgradeSchema(SQLiteDatabase db) { public void downgradeSchema(SQLiteDatabase db) {
DBHelper.dropTable(TABLE_STEPS_PER_DAY, db);
} }
} }

View File

@ -0,0 +1,31 @@
package nodomain.freeyourgadget.gadgetbridge.database.schema;
import android.database.sqlite.SQLiteDatabase;
import nodomain.freeyourgadget.gadgetbridge.database.DBHelper;
import nodomain.freeyourgadget.gadgetbridge.database.DBUpdateScript;
import static nodomain.freeyourgadget.gadgetbridge.database.DBConstants.KEY_PROVIDER;
import static nodomain.freeyourgadget.gadgetbridge.database.DBConstants.KEY_STEPS;
import static nodomain.freeyourgadget.gadgetbridge.database.DBConstants.KEY_TIMESTAMP;
import static nodomain.freeyourgadget.gadgetbridge.database.DBConstants.TABLE_STEPS_PER_DAY;
/**
* Adds a table "STEPS_PER_DAY".
*/
public class ActivityDBUpdate_X implements DBUpdateScript {
@Override
public void upgradeSchema(SQLiteDatabase db) {
String CREATE_STEPS_PER_DAY_TABLE = "CREATE TABLE IF NOT EXISTS " + TABLE_STEPS_PER_DAY + " ("
+ KEY_TIMESTAMP + " INT,"
+ KEY_PROVIDER + " TINYINT,"
+ KEY_STEPS + " MEDIUMINT,"
+ " PRIMARY KEY (" + KEY_TIMESTAMP + "," + KEY_PROVIDER + ") ON CONFLICT REPLACE)" + DBHelper.getWithoutRowId();
db.execSQL(CREATE_STEPS_PER_DAY_TABLE);
}
@Override
public void downgradeSchema(SQLiteDatabase db) {
DBHelper.dropTable(TABLE_STEPS_PER_DAY, db);
}
}

View File

@ -9,19 +9,19 @@ public class GBActivitySample implements ActivitySample {
private final SampleProvider provider; private final SampleProvider provider;
private final short intensity; private final short intensity;
private final short steps; private final short steps;
private final short heartrate;
private final byte type; private final byte type;
private final short customShortValue;
public GBActivitySample(SampleProvider provider, int timestamp, short intensity, short steps, byte type) { public GBActivitySample(SampleProvider provider, int timestamp, short intensity, short steps, byte type) {
this(provider, timestamp, intensity, steps, (short) 0, type); this(provider, timestamp, intensity, steps, type, (short) 0);
} }
public GBActivitySample(SampleProvider provider, int timestamp, short intensity, short steps, short heartrate, byte type) { public GBActivitySample(SampleProvider provider, int timestamp, short intensity, short steps, byte type, short customShortValue) {
this.timestamp = timestamp; this.timestamp = timestamp;
this.provider = provider; this.provider = provider;
this.intensity = intensity; this.intensity = intensity;
this.steps = steps; this.steps = steps;
this.heartrate = heartrate; this.customShortValue = customShortValue;
this.type = type; this.type = type;
validate(); validate();
} }
@ -36,8 +36,8 @@ public class GBActivitySample implements ActivitySample {
if (timestamp < 0) { if (timestamp < 0) {
throw new IllegalArgumentException("timestamp must be >= 0"); throw new IllegalArgumentException("timestamp must be >= 0");
} }
if (heartrate < 0) { if (customShortValue < 0) {
throw new IllegalArgumentException("heartrate must be >= 0"); throw new IllegalArgumentException("customShortValue must be >= 0");
} }
} }
@ -77,8 +77,8 @@ public class GBActivitySample implements ActivitySample {
} }
@Override @Override
public short getHeartRate() { public short getCustomShortValue() {
return heartrate; return customShortValue;
} }
@Override @Override
@ -87,7 +87,7 @@ public class GBActivitySample implements ActivitySample {
"timestamp=" + DateTimeUtils.formatDateTime(DateTimeUtils.parseTimeStamp(timestamp)) + "timestamp=" + DateTimeUtils.formatDateTime(DateTimeUtils.parseTimeStamp(timestamp)) +
", intensity=" + getIntensity() + ", intensity=" + getIntensity() +
", steps=" + getSteps() + ", steps=" + getSteps() +
", heartrate=" + getHeartRate() + ", customShortValue=" + getCustomShortValue() +
", type=" + getKind() + ", type=" + getKind() +
'}'; '}';
} }

View File

@ -42,5 +42,5 @@ public interface ActivitySample {
*/ */
short getSteps(); short getSteps();
short getHeartRate(); short getCustomShortValue();
} }

View File

@ -305,7 +305,7 @@ public class FetchActivityOperation extends AbstractMiBandOperation {
} }
int bpm = getBytesPerMinuteOfActivityData(); int bpm = getBytesPerMinuteOfActivityData();
LOG.debug("flushing activity data samples: " + activityStruct.activityDataHolderProgress / bpm); LOG.debug("flushing activity data samples: " + activityStruct.activityDataHolderProgress / bpm);
byte category, intensity, steps, heartrate; byte category, intensity, steps, heartrate = 0;
DBHandler dbHandler = null; DBHandler dbHandler = null;
try { try {
@ -334,7 +334,8 @@ public class FetchActivityOperation extends AbstractMiBandOperation {
timestampInSeconds, timestampInSeconds,
(short) (intensity & 0xff), (short) (intensity & 0xff),
(short) (steps & 0xff), (short) (steps & 0xff),
category); category,
(short) (heartrate & 0xff));
// next minute // next minute
minutes++; minutes++;

View File

@ -55,7 +55,7 @@ public class AppMessageHandlerGBPebble extends AppMessageHandler {
byte type = (byte) ((sample & 0xe000) >>> 13); byte type = (byte) ((sample & 0xe000) >>> 13);
byte intensity = (byte) ((sample & 0x1f80) >>> 7); byte intensity = (byte) ((sample & 0x1f80) >>> 7);
byte steps = (byte) (sample & 0x007f); byte steps = (byte) (sample & 0x007f);
db.addGBActivitySample(timestamp + offset_seconds, SampleProvider.PROVIDER_PEBBLE_GADGETBRIDGE, (short) (intensity & 0xff), (short) (steps & 0xff), type); db.addGBActivitySample(timestamp + offset_seconds, SampleProvider.PROVIDER_PEBBLE_GADGETBRIDGE, (short) (intensity & 0xff), (short) (steps & 0xff), type, (short)0);
offset_seconds += 60; offset_seconds += 60;
} }
} catch (GBException e) { } catch (GBException e) {

View File

@ -93,7 +93,7 @@ public class AppMessageHandlerMorpheuz extends AppMessageHandler {
DBHandler db = null; DBHandler db = null;
try { try {
db = GBApplication.acquireDB(); db = GBApplication.acquireDB();
db.addGBActivitySample(recording_base_timestamp + index * 600, SampleProvider.PROVIDER_PEBBLE_MORPHEUZ, intensity, (byte) 0, type); db.addGBActivitySample(recording_base_timestamp + index * 600, SampleProvider.PROVIDER_PEBBLE_MORPHEUZ, intensity, (byte) 0, type, (short)0);
} catch (GBException e) { } catch (GBException e) {
LOG.error("Error acquiring database", e); LOG.error("Error acquiring database", e);
} finally { } finally {

View File

@ -11,7 +11,7 @@
android:layout_weight="40"> android:layout_weight="40">
</com.github.mikephil.charting.charts.PieChart> </com.github.mikephil.charting.charts.PieChart>
<com.github.mikephil.charting.charts.BarChart <com.github.mikephil.charting.charts.CombinedChart
android:id="@+id/sleepchart" android:id="@+id/sleepchart"
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="fill_parent" android:layout_height="fill_parent"

View File

@ -3,7 +3,7 @@
android:layout_height="match_parent" android:layout_height="match_parent"
tools:context="nodomain.freeyourgadget.gadgetbridge.activities.charts.ChartsActivity$PlaceholderFragment"> tools:context="nodomain.freeyourgadget.gadgetbridge.activities.charts.ChartsActivity$PlaceholderFragment">
<com.github.mikephil.charting.charts.BarChart <com.github.mikephil.charting.charts.CombinedChart
android:id="@+id/activitysleepchart" android:id="@+id/activitysleepchart"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"

View File

@ -11,7 +11,7 @@
android:layout_weight="20"> android:layout_weight="20">
</com.github.mikephil.charting.charts.PieChart> </com.github.mikephil.charting.charts.PieChart>
<com.github.mikephil.charting.charts.BarChart <com.github.mikephil.charting.charts.CombinedChart
android:id="@+id/sleepchart" android:id="@+id/sleepchart"
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="fill_parent" android:layout_height="fill_parent"

View File

@ -11,6 +11,7 @@
<color name="secondarytext" type="color">#ff808080</color> <color name="secondarytext" type="color">#ff808080</color>
<color name="divider" type="color">#1f000000</color> <color name="divider" type="color">#1f000000</color>
<color name="chart_heartrate" type="color">#b40000</color>
<color name="chart_deep_sleep_light" type="color">#0071b7</color> <color name="chart_deep_sleep_light" type="color">#0071b7</color>
<color name="chart_deep_sleep_dark" type="color">#4c5aff</color> <color name="chart_deep_sleep_dark" type="color">#4c5aff</color>