From f33413111924d915766814507532b58a917c065c Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Mon, 11 Apr 2016 19:57:54 +0200 Subject: [PATCH 01/19] Updated gradle to 2.12 --- gradle/wrapper/gradle-wrapper.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 0ecc9c01..4e749a60 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.11-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-2.12-all.zip From 7ab31514dc62e81dc191da1a900f1585af8f6b70 Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Mon, 11 Apr 2016 23:18:12 +0200 Subject: [PATCH 02/19] Rework charts to completely fix crash in charts activity #277 --- .../charts/AbstractChartFragment.java | 46 +++++++--- .../charts/ActivitySleepChartFragment.java | 9 +- .../activities/charts/ChartsData.java | 4 + .../charts/LiveActivityFragment.java | 8 +- .../activities/charts/SleepChartFragment.java | 60 +++++++++++-- .../charts/WeekStepsChartFragment.java | 88 +++++++++++++------ 6 files changed, 167 insertions(+), 48 deletions(-) create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ChartsData.java diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/AbstractChartFragment.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/AbstractChartFragment.java index f163ba65..c32752d3 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/AbstractChartFragment.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/AbstractChartFragment.java @@ -335,6 +335,8 @@ public abstract class AbstractChartFragment extends AbstractGBFragment { } protected void configureChartDefaults(Chart chart) { + chart.setDescription(""); + // if enabled, the chart will always start at zero on the y-axis chart.setNoDataText(getString(R.string.chart_no_data_synchronize)); @@ -343,6 +345,8 @@ public abstract class AbstractChartFragment extends AbstractGBFragment { // enable touch gestures chart.setTouchEnabled(true); + + setupLegend(chart); } protected void configureBarLineChartDefaults(BarLineChartBase chart) { @@ -380,9 +384,9 @@ public abstract class AbstractChartFragment extends AbstractGBFragment { /** * This method reads the data from the database, analyzes and prepares it for * the charts. This will be called from a background task, so there must not be - * any UI access. #renderCharts will be automatically called after this method. + * any UI access. #updateChartsInUIThread and #renderCharts will be automatically called after this method. */ - protected abstract void refreshInBackground(DBHandler db, GBDevice device); + protected abstract ChartsData refreshInBackground(ChartsHost chartsHost, DBHandler db, GBDevice device); /** * Triggers the actual (re-) rendering of the chart. @@ -390,7 +394,7 @@ public abstract class AbstractChartFragment extends AbstractGBFragment { */ protected abstract void renderCharts(); - protected void refresh(GBDevice gbDevice, BarLineChartBase chart, List samples) { + protected DefaultChartsData refresh(GBDevice gbDevice, List samples) { Calendar cal = GregorianCalendar.getInstance(); cal.clear(); Date date; @@ -398,6 +402,7 @@ public abstract class AbstractChartFragment extends AbstractGBFragment { String dateStringTo = ""; LOG.info("" + getTitle() + ": number of samples:" + samples.size()); + CombinedData combinedData; if (samples.size() > 1) { boolean annotate = true; boolean use_steps_as_movement; @@ -486,11 +491,11 @@ public abstract class AbstractChartFragment extends AbstractGBFragment { xLabels.add(xLabel); } - chart.getXAxis().setValues(xLabels); +// chart.getXAxis().setValues(xLabels); BarDataSet activitySet = createActivitySet(activityEntries, colors, "Activity"); // create a data object with the datasets - CombinedData combinedData = new CombinedData(xLabels); + combinedData = new CombinedData(xLabels); List list = new ArrayList<>(); list.add(activitySet); BarData barData = new BarData(xLabels, list); @@ -503,17 +508,13 @@ public abstract class AbstractChartFragment extends AbstractGBFragment { combinedData.setData(lineData); } - chart.setDescription(""); // chart.setDescription(getString(R.string.sleep_activity_date_range, dateStringFrom, dateStringTo)); // chart.setDescriptionPosition(?, ?); - - setupLegend(chart); - - chart.setData(combinedData); } else { - CombinedData data = new CombinedData(Collections.emptyList()); - chart.setData(data); + combinedData = new CombinedData(Collections.emptyList()); } + + return new DefaultChartsData(combinedData); } protected boolean isValidHeartRateValue(int value) { @@ -622,6 +623,8 @@ public abstract class AbstractChartFragment extends AbstractGBFragment { } public class RefreshTask extends DBAccess { + private ChartsData chartsData; + public RefreshTask(String task, Context context) { super(task, context); } @@ -630,7 +633,9 @@ public abstract class AbstractChartFragment extends AbstractGBFragment { protected void doInBackground(DBHandler db) { ChartsHost chartsHost = getChartsHost(); if (chartsHost != null) { - refreshInBackground(db, chartsHost.getDevice()); + chartsData = refreshInBackground(chartsHost, db, chartsHost.getDevice()); + } else { + cancel(true); } } @@ -639,6 +644,7 @@ public abstract class AbstractChartFragment extends AbstractGBFragment { super.onPostExecute(o); FragmentActivity activity = getActivity(); if (activity != null && !activity.isFinishing() && !activity.isDestroyed()) { + updateChartsnUIThread(chartsData); renderCharts(); } else { LOG.info("Not rendering charts because activity is not available anymore"); @@ -646,6 +652,8 @@ public abstract class AbstractChartFragment extends AbstractGBFragment { } } + protected abstract void updateChartsnUIThread(ChartsData chartsData); + /** * Returns true if the date was successfully shifted, and false if the shift * was ignored, e.g. when the to-value is in the future. @@ -689,4 +697,16 @@ public abstract class AbstractChartFragment extends AbstractGBFragment { private int toTimestamp(Date date) { return (int) ((date.getTime() / 1000)); } + + public static class DefaultChartsData extends ChartsData{ + private final CombinedData combinedData; + + public DefaultChartsData(CombinedData combinedData) { + this.combinedData = combinedData; + } + + public CombinedData getCombinedData() { + return combinedData; + } + } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ActivitySleepChartFragment.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ActivitySleepChartFragment.java index cd45452d..7c58693e 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ActivitySleepChartFragment.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ActivitySleepChartFragment.java @@ -106,11 +106,16 @@ public class ActivitySleepChartFragment extends AbstractChartFragment { } @Override - protected void refreshInBackground(DBHandler db, GBDevice device) { + protected ChartsData refreshInBackground(ChartsHost chartsHost, DBHandler db, GBDevice device) { List samples = getSamples(db, device); - refresh(device, mChart, samples); + return refresh(device, samples); + } + @Override + protected void updateChartsnUIThread(ChartsData chartsData) { + DefaultChartsData dcd = (DefaultChartsData) chartsData; mChart.getLegend().setTextColor(LEGEND_TEXT_COLOR); + mChart.setData(dcd.getCombinedData()); } protected void renderCharts() { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ChartsData.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ChartsData.java new file mode 100644 index 00000000..4285951f --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ChartsData.java @@ -0,0 +1,4 @@ +package nodomain.freeyourgadget.gadgetbridge.activities.charts; + +public abstract class ChartsData { +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/LiveActivityFragment.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/LiveActivityFragment.java index d7b2ca24..f69e2ae5 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/LiveActivityFragment.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/LiveActivityFragment.java @@ -402,7 +402,13 @@ public class LiveActivityFragment extends AbstractChartFragment { } @Override - protected void refreshInBackground(DBHandler db, GBDevice device) { + protected ChartsData refreshInBackground(ChartsHost chartsHost, DBHandler db, GBDevice device) { + throw new UnsupportedOperationException(); + } + + @Override + protected void updateChartsnUIThread(ChartsData chartsData) { + throw new UnsupportedOperationException(); } @Override diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/SleepChartFragment.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/SleepChartFragment.java index b0836eeb..4f18495d 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/SleepChartFragment.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/SleepChartFragment.java @@ -48,14 +48,16 @@ public class SleepChartFragment extends AbstractChartFragment { private int mSmartAlarmGoneOff = -1; @Override - protected void refreshInBackground(DBHandler db, GBDevice device) { + protected ChartsData refreshInBackground(ChartsHost chartsHost, DBHandler db, GBDevice device) { List samples = getSamples(db, device); - refresh(device, mActivityChart, samples); - refreshSleepAmounts(device, mSleepAmountChart, samples); + MySleepChartsData mySleepChartsData = refreshSleepAmounts(device, samples); + DefaultChartsData chartsData = refresh(device, samples); + + return new MyChartsData(mySleepChartsData, chartsData); } - private void refreshSleepAmounts(GBDevice mGBDevice, PieChart pieChart, List samples) { + private MySleepChartsData refreshSleepAmounts(GBDevice mGBDevice, List samples) { ActivityAnalysis analysis = new ActivityAnalysis(); ActivityAmounts amounts = analysis.calculateActivityAmounts(samples); PieData data = new PieData(); @@ -73,7 +75,6 @@ public class SleepChartFragment extends AbstractChartFragment { } } String totalSleep = DateTimeUtils.formatDurationHoursMinutes(totalSeconds, TimeUnit.SECONDS); - pieChart.setCenterText(totalSleep); PieDataSet set = new PieDataSet(entries, ""); set.setValueFormatter(new ValueFormatter() { @Override @@ -83,10 +84,18 @@ public class SleepChartFragment extends AbstractChartFragment { }); set.setColors(colors); data.setDataSet(set); - pieChart.setData(data); - pieChart.getLegend().setEnabled(false); //setupLegend(pieChart); + return new MySleepChartsData(totalSleep, data); + } + + @Override + protected void updateChartsnUIThread(ChartsData chartsData) { + MyChartsData mcd = (MyChartsData) chartsData; + mSleepAmountChart.setCenterText(mcd.getPieData().getTotalSleep()); + mSleepAmountChart.setData(mcd.getPieData().getPieData()); + + mActivityChart.setData(mcd.getChartsData().getCombinedData()); } @Override @@ -132,6 +141,7 @@ public class SleepChartFragment extends AbstractChartFragment { mSleepAmountChart.setDescription(""); mSleepAmountChart.setNoDataTextDescription(""); mSleepAmountChart.setNoDataText(""); + mSleepAmountChart.getLegend().setEnabled(false); } private void setupActivityChart() { @@ -194,4 +204,40 @@ public class SleepChartFragment extends AbstractChartFragment { mActivityChart.animateX(ANIM_TIME, Easing.EasingOption.EaseInOutQuart); mSleepAmountChart.invalidate(); } + + private static class MySleepChartsData extends ChartsData { + private String totalSleep; + private final PieData pieData; + + public MySleepChartsData(String totalSleep, PieData pieData) { + this.totalSleep = totalSleep; + this.pieData = pieData; + } + + public PieData getPieData() { + return pieData; + } + + public CharSequence getTotalSleep() { + return totalSleep; + } + } + + private static class MyChartsData extends ChartsData { + private final DefaultChartsData chartsData; + private final MySleepChartsData pieData; + + public MyChartsData(MySleepChartsData pieData, DefaultChartsData chartsData) { + this.pieData = pieData; + this.chartsData = chartsData; + } + + public MySleepChartsData getPieData() { + return pieData; + } + + public DefaultChartsData getChartsData() { + return chartsData; + } + } } \ No newline at end of file diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/WeekStepsChartFragment.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/WeekStepsChartFragment.java index 927a499b..2e271f28 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/WeekStepsChartFragment.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/WeekStepsChartFragment.java @@ -42,19 +42,30 @@ public class WeekStepsChartFragment extends AbstractChartFragment { private Locale mLocale; private int mTargetSteps = 10000; - private CombinedChart mWeekStepsChart; private PieChart mTodayStepsChart; + private CombinedChart mWeekStepsChart; @Override - protected void refreshInBackground(DBHandler db, GBDevice device) { - ChartsHost chartsHost = getChartsHost(); - if (chartsHost != null) { - Calendar day = Calendar.getInstance(); - day.setTime(chartsHost.getEndDate()); - //NB: we could have omitted the day, but this way we can move things to the past easily - refreshDaySteps(db, mTodayStepsChart, day, device); - refreshWeekBeforeSteps(db, mWeekStepsChart, day, device); - } + protected ChartsData refreshInBackground(ChartsHost chartsHost, DBHandler db, GBDevice device) { + Calendar day = Calendar.getInstance(); + day.setTime(chartsHost.getEndDate()); + //NB: we could have omitted the day, but this way we can move things to the past easily + DaySteps daySteps = refreshDaySteps(db, day, device); + DefaultChartsData weekBeforeStepsData = refreshWeekBeforeSteps(db, mWeekStepsChart, day, device); + + return new MyChartsData(daySteps, weekBeforeStepsData); + } + + @Override + protected void updateChartsnUIThread(ChartsData chartsData) { + MyChartsData mcd = (MyChartsData) chartsData; + +// setupLegend(mWeekStepsChart); + mTodayStepsChart.setCenterText(NumberFormat.getNumberInstance(mLocale).format(mcd.getDaySteps().totalSteps)); + mTodayStepsChart.setData(mcd.getDaySteps().data); + + mWeekStepsChart.setData(mcd.getWeekBeforeStepsData().getCombinedData()); + mWeekStepsChart.getLegend().setEnabled(false); } @Override @@ -63,7 +74,7 @@ public class WeekStepsChartFragment extends AbstractChartFragment { mTodayStepsChart.invalidate(); } - private void refreshWeekBeforeSteps(DBHandler db, CombinedChart combinedChart, Calendar day, GBDevice device) { + private DefaultChartsData refreshWeekBeforeSteps(DBHandler db, CombinedChart combinedChart, Calendar day, GBDevice device) { ActivityAnalysis analysis = new ActivityAnalysis(); @@ -90,18 +101,16 @@ public class WeekStepsChartFragment extends AbstractChartFragment { CombinedData combinedData = new CombinedData(labels); combinedData.setData(barData); - - setupLegend(combinedChart); - combinedChart.setData(combinedData); - combinedChart.getLegend().setEnabled(false); + return new DefaultChartsData(combinedData); } - private void refreshDaySteps(DBHandler db, PieChart pieChart, Calendar day, GBDevice device) { + + + private DaySteps refreshDaySteps(DBHandler db, Calendar day, GBDevice device) { ActivityAnalysis analysis = new ActivityAnalysis(); int totalSteps = analysis.calculateTotalSteps(getSamplesOfDay(db, day, device)); - pieChart.setCenterText(NumberFormat.getNumberInstance(mLocale).format(totalSteps)); PieData data = new PieData(); List entries = new ArrayList<>(); List colors = new ArrayList<>(); @@ -123,9 +132,8 @@ public class WeekStepsChartFragment extends AbstractChartFragment { data.setDataSet(set); //this hides the values (numeric) added to the set. These would be shown aside the strings set with addXValue above data.setDrawValues(false); - pieChart.setData(data); - pieChart.getLegend().setEnabled(false); + return new DaySteps(data, totalSteps); } @Override @@ -164,6 +172,8 @@ public class WeekStepsChartFragment extends AbstractChartFragment { mTodayStepsChart.setDescription(getContext().getString(R.string.weeksteps_today_steps_description, mTargetSteps)); mTodayStepsChart.setNoDataTextDescription(""); mTodayStepsChart.setNoDataText(""); + mTodayStepsChart.getLegend().setEnabled(false); +// setupLegend(mTodayStepsChart); } private void setupWeekStepsChart() { @@ -196,12 +206,12 @@ public class WeekStepsChartFragment extends AbstractChartFragment { } protected void setupLegend(Chart chart) { - List legendColors = new ArrayList<>(1); - List legendLabels = new ArrayList<>(1); - legendColors.add(akActivity.color); - legendLabels.add(getContext().getString(R.string.chart_steps)); - chart.getLegend().setCustom(legendColors, legendLabels); - chart.getLegend().setTextColor(LEGEND_TEXT_COLOR); +// List legendColors = new ArrayList<>(1); +// List legendLabels = new ArrayList<>(1); +// legendColors.add(akActivity.color); +// legendLabels.add(getContext().getString(R.string.chart_steps)); +// chart.getLegend().setCustom(legendColors, legendLabels); +// chart.getLegend().setTextColor(LEGEND_TEXT_COLOR); } private List getSamplesOfDay(DBHandler db, Calendar day, GBDevice device) { @@ -226,4 +236,32 @@ public class WeekStepsChartFragment extends AbstractChartFragment { protected List getSamples(DBHandler db, GBDevice device, int tsFrom, int tsTo) { return super.getAllSamples(db, device, tsFrom, tsTo); } + + private static class DaySteps { + private final PieData data; + private final int totalSteps; + + public DaySteps(PieData data, int totalSteps) { + this.data = data; + this.totalSteps = totalSteps; + } + } + + private static class MyChartsData extends ChartsData { + private final DefaultChartsData weekBeforeStepsData; + private final DaySteps daySteps; + + public MyChartsData(DaySteps daySteps, DefaultChartsData weekBeforeStepsData) { + this.daySteps = daySteps; + this.weekBeforeStepsData = weekBeforeStepsData; + } + + public DaySteps getDaySteps() { + return daySteps; + } + + public DefaultChartsData getWeekBeforeStepsData() { + return weekBeforeStepsData; + } + } } From 58d90c2a662760cfad7e4bb46e7a79fa8b29c40a Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Tue, 12 Apr 2016 13:04:28 +0200 Subject: [PATCH 03/19] remove obsolete Holo theming --- app/src/main/res/values/styles.xml | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 31de7354..1bcf060c 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -1,25 +1,10 @@ - - - - - From f15a97d9947ea60548bb058c9683c6a91576d5cc Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Tue, 12 Apr 2016 23:12:15 +0200 Subject: [PATCH 04/19] Initial live heartrate measurement in the live activity tab #178 --- .../activities/HeartRateUtils.java | 6 + .../charts/AbstractChartFragment.java | 5 +- .../charts/ActivitySleepChartFragment.java | 5 +- .../charts/LiveActivityFragment.java | 118 ++++++++++++++---- .../activities/charts/SleepChartFragment.java | 5 +- .../gadgetbridge/devices/EventHandler.java | 2 + .../gadgetbridge/impl/GBDeviceService.java | 7 ++ .../gadgetbridge/model/DeviceService.java | 3 + .../gadgetbridge/model/Measurement.java | 33 +++++ .../service/DeviceCommunicationService.java | 6 + .../service/ServiceDeviceSupport.java | 8 ++ .../service/devices/miband/MiBandSupport.java | 31 ++++- .../serial/AbstractSerialDeviceSupport.java | 6 + .../service/serial/GBDeviceProtocol.java | 2 + app/src/main/res/values/colors.xml | 1 + app/src/main/res/values/strings.xml | 1 + .../service/TestDeviceSupport.java | 5 + 17 files changed, 213 insertions(+), 31 deletions(-) create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/HeartRateUtils.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/Measurement.java diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/HeartRateUtils.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/HeartRateUtils.java new file mode 100644 index 00000000..9ac085d7 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/HeartRateUtils.java @@ -0,0 +1,6 @@ +package nodomain.freeyourgadget.gadgetbridge.activities; + +public class HeartRateUtils { + public static final int MAX_HEART_RATE_VALUE = 250; + public static final int MIN_HEART_RATE_VALUE = 0; +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/AbstractChartFragment.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/AbstractChartFragment.java index c32752d3..75a3c13e 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/AbstractChartFragment.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/AbstractChartFragment.java @@ -39,6 +39,7 @@ import java.util.Set; import nodomain.freeyourgadget.gadgetbridge.R; import nodomain.freeyourgadget.gadgetbridge.activities.AbstractGBFragment; +import nodomain.freeyourgadget.gadgetbridge.activities.HeartRateUtils; import nodomain.freeyourgadget.gadgetbridge.database.DBAccess; import nodomain.freeyourgadget.gadgetbridge.database.DBHandler; import nodomain.freeyourgadget.gadgetbridge.devices.DeviceCoordinator; @@ -116,6 +117,7 @@ public abstract class AbstractChartFragment extends AbstractGBFragment { protected int CHART_TEXT_COLOR; protected int LEGEND_TEXT_COLOR; protected int HEARTRATE_COLOR; + protected int HEARTRATE_FILL_COLOR; protected int AK_ACTIVITY_COLOR; protected int AK_DEEP_SLEEP_COLOR; protected int AK_LIGHT_SLEEP_COLOR; @@ -152,6 +154,7 @@ public abstract class AbstractChartFragment extends AbstractGBFragment { CHART_TEXT_COLOR = getResources().getColor(R.color.secondarytext); LEGEND_TEXT_COLOR = getResources().getColor(R.color.primarytext); HEARTRATE_COLOR = getResources().getColor(R.color.chart_heartrate); + HEARTRATE_FILL_COLOR = getResources().getColor(R.color.chart_heartrate_fill); AK_ACTIVITY_COLOR = getResources().getColor(R.color.chart_activity_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); @@ -518,7 +521,7 @@ public abstract class AbstractChartFragment extends AbstractGBFragment { } protected boolean isValidHeartRateValue(int value) { - return value > 0 && value < 255; + return value > HeartRateUtils.MIN_HEART_RATE_VALUE && value < HeartRateUtils.MAX_HEART_RATE_VALUE; } /** diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ActivitySleepChartFragment.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ActivitySleepChartFragment.java index 7c58693e..7260a205 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ActivitySleepChartFragment.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ActivitySleepChartFragment.java @@ -20,6 +20,7 @@ import java.util.ArrayList; import java.util.List; import nodomain.freeyourgadget.gadgetbridge.R; +import nodomain.freeyourgadget.gadgetbridge.activities.HeartRateUtils; import nodomain.freeyourgadget.gadgetbridge.database.DBHandler; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample; @@ -83,8 +84,8 @@ public class ActivitySleepChartFragment extends AbstractChartFragment { yAxisRight.setDrawLabels(true); yAxisRight.setDrawTopYLabelEntry(true); yAxisRight.setTextColor(CHART_TEXT_COLOR); - yAxisRight.setAxisMaxValue(250); - yAxisRight.setAxisMinValue(0); + yAxisRight.setAxisMaxValue(HeartRateUtils.MAX_HEART_RATE_VALUE); + yAxisRight.setAxisMinValue(HeartRateUtils.MIN_HEART_RATE_VALUE); // refresh immediately instead of use refreshIfVisible(), for perceived performance refresh(); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/LiveActivityFragment.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/LiveActivityFragment.java index f69e2ae5..cd014362 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/LiveActivityFragment.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/LiveActivityFragment.java @@ -23,6 +23,7 @@ import com.github.mikephil.charting.components.YAxis; import com.github.mikephil.charting.data.BarData; import com.github.mikephil.charting.data.BarDataSet; import com.github.mikephil.charting.data.BarEntry; +import com.github.mikephil.charting.data.ChartData; import com.github.mikephil.charting.data.Entry; import com.github.mikephil.charting.data.LineData; import com.github.mikephil.charting.data.LineDataSet; @@ -39,10 +40,12 @@ import java.util.concurrent.TimeUnit; import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.R; +import nodomain.freeyourgadget.gadgetbridge.activities.HeartRateUtils; import nodomain.freeyourgadget.gadgetbridge.database.DBHandler; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample; import nodomain.freeyourgadget.gadgetbridge.model.DeviceService; +import nodomain.freeyourgadget.gadgetbridge.model.Measurement; import nodomain.freeyourgadget.gadgetbridge.util.GB; public class LiveActivityFragment extends AbstractChartFragment { @@ -63,6 +66,9 @@ public class LiveActivityFragment extends AbstractChartFragment { private final Steps mSteps = new Steps(); private ScheduledExecutorService pulseScheduler; private int maxStepsResetCounter; + private List heartRateValues; + private LineDataSet mHeartRateSet; + private int mHeartRate; private class Steps { private int initialSteps; @@ -145,16 +151,36 @@ public class LiveActivityFragment extends AbstractChartFragment { public void onReceive(Context context, Intent intent) { String action = intent.getAction(); switch (action) { - case DeviceService.ACTION_REALTIME_STEPS: + case DeviceService.ACTION_REALTIME_STEPS: { int steps = intent.getIntExtra(DeviceService.EXTRA_REALTIME_STEPS, 0); long timestamp = intent.getLongExtra(DeviceService.EXTRA_TIMESTAMP, System.currentTimeMillis()); - refreshCurrentSteps(steps, timestamp); + addEntries(steps, timestamp); break; + } + case DeviceService.ACTION_HEARTRATE_MEASUREMENT: { + int heartRate = intent.getIntExtra(DeviceService.EXTRA_HEART_RATE_VALUE, 0); + long timestamp = intent.getLongExtra(DeviceService.EXTRA_TIMESTAMP, System.currentTimeMillis()); + if (isValidHeartRateValue(heartRate)) { + setCurrentHeartRate(heartRate, timestamp); + } + break; + } } } }; - private void refreshCurrentSteps(int steps, long timestamp) { + private void setCurrentHeartRate(int heartRate, long timestamp) { + addHistoryDataSet(true); + mHeartRate = heartRate; + } + + private int getCurrentHeartRate() { + int result = mHeartRate; + mHeartRate = -1; + return result; + } + + private void addEntries(int steps, long timestamp) { mSteps.updateCurrentSteps(steps, timestamp); if (++maxStepsResetCounter > RESET_COUNT) { maxStepsResetCounter = 0; @@ -163,10 +189,10 @@ public class LiveActivityFragment extends AbstractChartFragment { // Or: count down the steps until goal reached? And then flash GOAL REACHED -> Set stretch goal LOG.info("Steps: " + steps + ", total: " + mSteps.getTotalSteps() + ", current: " + mSteps.getStepsPerMinute(false)); -// refreshCurrentSteps(); +// addEntries(); } - private void refreshCurrentSteps() { + private void addEntries() { mTotalStepsChart.setSingleEntryYValue(mSteps.getTotalSteps()); YAxis stepsPerMinuteCurrentYAxis = mStepsPerMinuteCurrentChart.getAxisLeft(); int maxStepsPerMinute = mSteps.getMaxStepsPerMinute(); @@ -180,24 +206,36 @@ public class LiveActivityFragment extends AbstractChartFragment { int stepsPerMinute = mSteps.getStepsPerMinute(true); mStepsPerMinuteCurrentChart.setSingleEntryYValue(stepsPerMinute); - if (mStepsPerMinuteHistoryChart.getData() == null) { - if (mSteps.getTotalSteps() == 0) { - return; // ignore the first default value to keep the "no-data-description" visible - } - LineData data = new LineData(); - mStepsPerMinuteHistoryChart.setData(data); - data.addDataSet(mHistorySet); + if (!addHistoryDataSet(false)) { + return; } - LineData historyData = (LineData) mStepsPerMinuteHistoryChart.getData(); - historyData.addXValue(""); - historyData.addEntry(new Entry(stepsPerMinute, mHistorySet.getEntryCount()), 0); + ChartData data = mStepsPerMinuteHistoryChart.getData(); + data.addXValue(""); + if (stepsPerMinute < 0) { + stepsPerMinute = 0; + } + mHistorySet.addEntry(new Entry(stepsPerMinute, data.getXValCount() - 1)); + int hr = getCurrentHeartRate(); + if (hr < 0) { + hr = 0; + } + mHeartRateSet.addEntry(new Entry(hr, data.getXValCount() - 1)); + } - mTotalStepsData.notifyDataSetChanged(); - mStepsPerMinuteData.notifyDataSetChanged(); - mStepsPerMinuteHistoryChart.notifyDataSetChanged(); - - renderCharts(); + private boolean addHistoryDataSet(boolean force) { + if (mStepsPerMinuteHistoryChart.getData() == null) { + // ignore the first default value to keep the "no-data-description" visible + if (force || mSteps.getTotalSteps() > 0) { + LineData data = new LineData(); + data.addDataSet(mHistorySet); + data.addDataSet(mHeartRateSet); + mStepsPerMinuteHistoryChart.setData(data); + return true; + } + return false; + } + return true; } @Nullable @@ -205,6 +243,8 @@ public class LiveActivityFragment extends AbstractChartFragment { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { IntentFilter filterLocal = new IntentFilter(); filterLocal.addAction(DeviceService.ACTION_REALTIME_STEPS); + filterLocal.addAction(DeviceService.ACTION_HEARTRATE_MEASUREMENT); + heartRateValues = new ArrayList<>(); View rootView = inflater.inflate(R.layout.fragment_live_activity, container, false); @@ -262,7 +302,22 @@ public class LiveActivityFragment extends AbstractChartFragment { * Called in the UI thread. */ private void pulse() { - refreshCurrentSteps(); + addEntries(); + + LineData historyData = (LineData) mStepsPerMinuteHistoryChart.getData(); + if (historyData == null) { + return; + } + + historyData.notifyDataChanged(); + mTotalStepsData.notifyDataSetChanged(); + mStepsPerMinuteData.notifyDataSetChanged(); + mStepsPerMinuteHistoryChart.notifyDataSetChanged(); + + renderCharts(); + + // have to enable it again and again to keep it measureing + GBApplication.deviceService().onEnableRealtimeHeartRateMeasurement(true); } private long getPulseIntervalMillis() { @@ -272,6 +327,7 @@ public class LiveActivityFragment extends AbstractChartFragment { @Override protected void onMadeVisibleInActivity() { GBApplication.deviceService().onEnableRealtimeSteps(true); + GBApplication.deviceService().onEnableRealtimeHeartRateMeasurement(true); super.onMadeVisibleInActivity(); if (getActivity() != null) { getActivity().getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); @@ -281,6 +337,7 @@ public class LiveActivityFragment extends AbstractChartFragment { @Override protected void onMadeInvisibleInActivity() { GBApplication.deviceService().onEnableRealtimeSteps(false); + GBApplication.deviceService().onEnableRealtimeHeartRateMeasurement(false); if (getActivity() != null) { getActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); } @@ -346,6 +403,7 @@ public class LiveActivityFragment extends AbstractChartFragment { private void setupHistoryChart(BarLineChartBase chart) { configureBarLineChartDefaults(chart); + chart.setTouchEnabled(false); // no zooming or anything, because it's updated all the time chart.setBackgroundColor(BACKGROUND_COLOR); chart.setDescriptionColor(DESCRIPTION_COLOR); chart.setDescription(getString(R.string.live_activity_steps_per_minute_history)); @@ -367,22 +425,34 @@ public class LiveActivityFragment extends AbstractChartFragment { y.setDrawGridLines(false); y.setDrawTopYLabelEntry(false); y.setTextColor(CHART_TEXT_COLOR); - y.setEnabled(true); + y.setAxisMinValue(0); YAxis yAxisRight = chart.getAxisRight(); yAxisRight.setDrawGridLines(false); - yAxisRight.setEnabled(false); - yAxisRight.setDrawLabels(false); + yAxisRight.setEnabled(true); + yAxisRight.setDrawLabels(true); yAxisRight.setDrawTopYLabelEntry(false); yAxisRight.setTextColor(CHART_TEXT_COLOR); + yAxisRight.setAxisMaxValue(HeartRateUtils.MAX_HEART_RATE_VALUE); + yAxisRight.setAxisMinValue(HeartRateUtils.MIN_HEART_RATE_VALUE); mHistorySet = new LineDataSet(new ArrayList(), getString(R.string.live_activity_steps_history)); + mHistorySet.setAxisDependency(YAxis.AxisDependency.LEFT); mHistorySet.setColor(akActivity.color); mHistorySet.setDrawCircles(false); mHistorySet.setDrawCubic(true); mHistorySet.setDrawFilled(true); mHistorySet.setDrawValues(false); + + mHeartRateSet = new LineDataSet(new ArrayList(), getString(R.string.live_activity_heart_rate)); + mHeartRateSet.setAxisDependency(YAxis.AxisDependency.RIGHT); + mHeartRateSet.setColor(HEARTRATE_COLOR); + mHeartRateSet.setDrawCircles(false); + mHeartRateSet.setDrawCubic(true); + mHeartRateSet.setDrawFilled(false); +// mHeartRateSet.setFillColor(HEARTRATE_FILL_COLOR); + mHeartRateSet.setDrawValues(false); } @Override diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/SleepChartFragment.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/SleepChartFragment.java index 4f18495d..48ff18f8 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/SleepChartFragment.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/SleepChartFragment.java @@ -27,6 +27,7 @@ import java.util.List; import java.util.concurrent.TimeUnit; import nodomain.freeyourgadget.gadgetbridge.R; +import nodomain.freeyourgadget.gadgetbridge.activities.HeartRateUtils; import nodomain.freeyourgadget.gadgetbridge.database.DBHandler; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.model.ActivityAmount; @@ -174,8 +175,8 @@ public class SleepChartFragment extends AbstractChartFragment { yAxisRight.setDrawLabels(true); yAxisRight.setDrawTopYLabelEntry(true); yAxisRight.setTextColor(CHART_TEXT_COLOR); - yAxisRight.setAxisMaxValue(250); - yAxisRight.setAxisMinValue(0); + yAxisRight.setAxisMaxValue(HeartRateUtils.MAX_HEART_RATE_VALUE); + yAxisRight.setAxisMinValue(HeartRateUtils.MIN_HEART_RATE_VALUE); } protected void setupLegend(Chart chart) { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/EventHandler.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/EventHandler.java index 5ddad49e..a6dd21bf 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/EventHandler.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/EventHandler.java @@ -44,6 +44,8 @@ public interface EventHandler { void onHeartRateTest(); + void onEnableRealtimeHeartRateMeasurement(boolean enable); + void onFindDevice(boolean start); void onScreenshotReq(); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDeviceService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDeviceService.java index add9f676..61af3fcb 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDeviceService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDeviceService.java @@ -216,4 +216,11 @@ public class GBDeviceService implements DeviceService { .putExtra(EXTRA_BOOLEAN_ENABLE, enable); invokeService(intent); } + + @Override + public void onEnableRealtimeHeartRateMeasurement(boolean enable) { + Intent intent = createIntent().setAction(ACTION_ENABLE_REALTIME_HEARTRATE_MEASUREMENT) + .putExtra(EXTRA_BOOLEAN_ENABLE, enable); + invokeService(intent); + } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/DeviceService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/DeviceService.java index 7c38088f..2cf979cd 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/DeviceService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/DeviceService.java @@ -33,7 +33,9 @@ public interface DeviceService extends EventHandler { String ACTION_SET_ALARMS = PREFIX + ".action.set_alarms"; String ACTION_ENABLE_REALTIME_STEPS = PREFIX + ".action.enable_realtime_steps"; String ACTION_REALTIME_STEPS = PREFIX + ".action.realtime_steps"; + String ACTION_ENABLE_REALTIME_HEARTRATE_MEASUREMENT = PREFIX + ".action.realtime_hr_measurement"; String ACTION_ENABLE_HEARTRATE_SLEEP_SUPPORT = PREFIX + ".action.enable_heartrate_sleep_support"; + String ACTION_HEARTRATE_MEASUREMENT = PREFIX + ".action.hr_measurement"; String EXTRA_DEVICE_ADDRESS = "device_address"; String EXTRA_NOTIFICATION_BODY = "notification_body"; String EXTRA_NOTIFICATION_FLAGS = "notification_flags"; @@ -62,6 +64,7 @@ public interface DeviceService extends EventHandler { String EXTRA_BOOLEAN_ENABLE = "enable_realtime_steps"; String EXTRA_REALTIME_STEPS = "realtime_steps"; String EXTRA_TIMESTAMP = "timestamp"; + String EXTRA_HEART_RATE_VALUE = "hr_value"; void start(); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/Measurement.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/Measurement.java new file mode 100644 index 00000000..f841da00 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/Measurement.java @@ -0,0 +1,33 @@ +package nodomain.freeyourgadget.gadgetbridge.model; + +public class Measurement { + private final int value; + private final long timestamp; + + public Measurement(int value, long timestamp) { + this.value = value; + this.timestamp = timestamp; + } + + public int getValue() { + return value; + } + + public long getTimestamp() { + return timestamp; + } + + @Override + public int hashCode() { + return (int) (71 ^ value ^ timestamp); + } + + @Override + public boolean equals(Object o) { + if (o instanceof Measurement) { + Measurement m = (Measurement) o; + return timestamp == m.timestamp && value == m.value; + } + return super.equals(o); + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java index 6ade401d..85e3ceb7 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java @@ -46,6 +46,7 @@ import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_CO import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_DELETEAPP; import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_DISCONNECT; import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_ENABLE_HEARTRATE_SLEEP_SUPPORT; +import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_ENABLE_REALTIME_HEARTRATE_MEASUREMENT; import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_ENABLE_REALTIME_STEPS; import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_FETCH_ACTIVITY_DATA; import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_FIND_DEVICE; @@ -349,6 +350,11 @@ public class DeviceCommunicationService extends Service { mDeviceSupport.onEnableHeartRateSleepSupport(enable); break; } + case ACTION_ENABLE_REALTIME_HEARTRATE_MEASUREMENT: { + boolean enable = intent.getBooleanExtra(EXTRA_BOOLEAN_ENABLE, false); + mDeviceSupport.onEnableRealtimeHeartRateMeasurement(enable); + break; + } } return START_STICKY; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/ServiceDeviceSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/ServiceDeviceSupport.java index e54e61bd..2a0de20e 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/ServiceDeviceSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/ServiceDeviceSupport.java @@ -250,4 +250,12 @@ public class ServiceDeviceSupport implements DeviceSupport { } delegate.onEnableHeartRateSleepSupport(enable); } + + @Override + public void onEnableRealtimeHeartRateMeasurement(boolean enable) { + if (checkBusy("enable realtime heart rate measurement: " + enable)) { + return; + } + delegate.onEnableRealtimeHeartRateMeasurement(enable); + } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/MiBandSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/MiBandSupport.java index 37b22591..9eec7cf5 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/MiBandSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/MiBandSupport.java @@ -603,7 +603,6 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport { TransactionBuilder builder = performInitialized("HeartRateTest"); builder.write(getCharacteristic(MiBandService.UUID_CHARACTERISTIC_HEART_RATE_CONTROL_POINT), stopHeartMeasurementContinuous); builder.write(getCharacteristic(MiBandService.UUID_CHARACTERISTIC_HEART_RATE_CONTROL_POINT), stopHeartMeasurementManual); - builder.write(getCharacteristic(MiBandService.UUID_CHARACTERISTIC_HEART_RATE_CONTROL_POINT), stopHeartMeasurementSleep); builder.write(getCharacteristic(MiBandService.UUID_CHARACTERISTIC_HEART_RATE_CONTROL_POINT), startHeartMeasurementManual); builder.queue(getQueue()); } catch (IOException ex) { @@ -614,6 +613,25 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport { } } + @Override + public void onEnableRealtimeHeartRateMeasurement(boolean enable) { + if (supportsHeartRate()) { + try { + TransactionBuilder builder = performInitialized("EnableRealtimeHeartRateMeasurement"); + if (enable) { + builder.write(getCharacteristic(MiBandService.UUID_CHARACTERISTIC_HEART_RATE_CONTROL_POINT), stopHeartMeasurementManual); + builder.write(getCharacteristic(MiBandService.UUID_CHARACTERISTIC_HEART_RATE_CONTROL_POINT), stopHeartMeasurementSleep); + builder.write(getCharacteristic(MiBandService.UUID_CHARACTERISTIC_HEART_RATE_CONTROL_POINT), startHeartMeasurementContinuous); + } else { + builder.write(getCharacteristic(MiBandService.UUID_CHARACTERISTIC_HEART_RATE_CONTROL_POINT), stopHeartMeasurementContinuous); + } + builder.queue(getQueue()); + } catch (IOException ex) { + LOG.error("Unable to enable realtime heart rate measurement in MI1S", ex); + } + } + } + public boolean supportsHeartRate() { return getDeviceInfo() != null && getDeviceInfo().supportsHeartrate(); } @@ -745,7 +763,7 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport { } else if (MiBandService.UUID_CHARACTERISTIC_REALTIME_STEPS.equals(characteristicUUID)) { handleRealtimeSteps(characteristic.getValue()); } else if (MiBandService.UUID_CHARACTERISTIC_HEART_RATE_MEASUREMENT.equals(characteristicUUID)) { - logHeartrate(characteristic.getValue()); + handleHeartrate(characteristic.getValue()); } else { LOG.info("Unhandled characteristic changed: " + characteristicUUID); logMessageContent(characteristic.getValue()); @@ -814,6 +832,15 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport { } } + private void handleHeartrate(byte[] value) { + if (value.length == 2 && value[0] == 6) { + int hrValue = (value[1] & 0xff); + Intent intent = new Intent(DeviceService.ACTION_HEARTRATE_MEASUREMENT) + .putExtra(DeviceService.EXTRA_HEART_RATE_VALUE, hrValue) + .putExtra(DeviceService.EXTRA_TIMESTAMP, System.currentTimeMillis()); + LocalBroadcastManager.getInstance(getContext()).sendBroadcast(intent); + } + } private void handleRealtimeSteps(byte[] value) { int steps = 0xff & value[0] | (0xff & value[1]) << 8; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/AbstractSerialDeviceSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/AbstractSerialDeviceSupport.java index aa78a393..5dfa8b2a 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/AbstractSerialDeviceSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/AbstractSerialDeviceSupport.java @@ -181,4 +181,10 @@ public abstract class AbstractSerialDeviceSupport extends AbstractDeviceSupport byte[] bytes = gbDeviceProtocol.encodeEnableHeartRateSleepSupport(enable); sendToDevice(bytes); } + + @Override + public void onEnableRealtimeHeartRateMeasurement(boolean enable) { + byte[] bytes = gbDeviceProtocol.encodeEnableRealtimeHeartRateMeasurement(enable); + sendToDevice(bytes); + } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/GBDeviceProtocol.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/GBDeviceProtocol.java index 2aa1fb66..bdf1b101 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/GBDeviceProtocol.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/GBDeviceProtocol.java @@ -63,6 +63,8 @@ public abstract class GBDeviceProtocol { return null; } + public byte[] encodeEnableRealtimeHeartRateMeasurement(boolean enable) { return null; } + public GBDeviceEvent[] decodeResponse(byte[] responseData) { return null; } diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 82744a0c..5f53994c 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -12,6 +12,7 @@ #1f000000 #ffab40 + #fadab1 #0071b7 #4c5aff diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index beac2a5d..fa365a9b 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -240,5 +240,6 @@ Firmware update in progress Firmware not sent Heart Rate + Heart Rate diff --git a/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/TestDeviceSupport.java b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/TestDeviceSupport.java index 19fd1810..9d486bc0 100644 --- a/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/TestDeviceSupport.java +++ b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/TestDeviceSupport.java @@ -129,4 +129,9 @@ public class TestDeviceSupport extends AbstractDeviceSupport { public void onEnableHeartRateSleepSupport(boolean enable) { } + + @Override + public void onEnableRealtimeHeartRateMeasurement(boolean enable) { + + } } From 78bf51689752d7db755e43406b6f082efee40977 Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Tue, 12 Apr 2016 23:25:12 +0200 Subject: [PATCH 05/19] Disabling sleep measurement for continuous measurement is not necessary Looks like they don't interfere, after all. #178 --- .../gadgetbridge/service/devices/miband/MiBandSupport.java | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/MiBandSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/MiBandSupport.java index 9eec7cf5..97357ccf 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/MiBandSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/MiBandSupport.java @@ -620,7 +620,6 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport { TransactionBuilder builder = performInitialized("EnableRealtimeHeartRateMeasurement"); if (enable) { builder.write(getCharacteristic(MiBandService.UUID_CHARACTERISTIC_HEART_RATE_CONTROL_POINT), stopHeartMeasurementManual); - builder.write(getCharacteristic(MiBandService.UUID_CHARACTERISTIC_HEART_RATE_CONTROL_POINT), stopHeartMeasurementSleep); builder.write(getCharacteristic(MiBandService.UUID_CHARACTERISTIC_HEART_RATE_CONTROL_POINT), startHeartMeasurementContinuous); } else { builder.write(getCharacteristic(MiBandService.UUID_CHARACTERISTIC_HEART_RATE_CONTROL_POINT), stopHeartMeasurementContinuous); From ae5d9089d884fbc9c1ec24d4b82e79930a1e1304 Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Wed, 13 Apr 2016 21:21:10 +0200 Subject: [PATCH 06/19] Slight improvement to hr charts #178 --- .../activities/charts/AbstractChartFragment.java | 12 ++++-------- .../activities/charts/LiveActivityFragment.java | 8 +------- 2 files changed, 5 insertions(+), 15 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/AbstractChartFragment.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/AbstractChartFragment.java index 75a3c13e..60c6dfa0 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/AbstractChartFragment.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/AbstractChartFragment.java @@ -565,23 +565,19 @@ public abstract class AbstractChartFragment extends AbstractGBFragment { protected LineDataSet createHeartrateSet(List values, String label) { LineDataSet set1 = new LineDataSet(values, label); + set1.setLineWidth(0.8f); set1.setColor(HEARTRATE_COLOR); -// set1.setColors(colors); set1.setDrawCubic(true); set1.setCubicIntensity(0.1f); -// //set1.setDrawFilled(true); -// set1.setDrawCircles(false); -// set1.setLineWidth(2f); - set1.setDrawCircles(false); // set1.setCircleRadius(2f); // set1.setDrawFilled(true); - - set1.setLineWidth(0.8f); +// set1.setColor(getResources().getColor(android.R.color.background_light)); +// set1.setCircleColor(HEARTRATE_COLOR); // set1.setFillColor(ColorTemplate.getHoloBlue()); - set1.setDrawValues(true); // set1.setHighLightColor(Color.rgb(128, 0, 255)); // set1.setColor(Color.rgb(89, 178, 44)); + set1.setDrawValues(true); set1.setValueTextColor(CHART_TEXT_COLOR); set1.setAxisDependency(YAxis.AxisDependency.RIGHT); return set1; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/LiveActivityFragment.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/LiveActivityFragment.java index cd014362..ef1dcd07 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/LiveActivityFragment.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/LiveActivityFragment.java @@ -445,13 +445,7 @@ public class LiveActivityFragment extends AbstractChartFragment { mHistorySet.setDrawFilled(true); mHistorySet.setDrawValues(false); - mHeartRateSet = new LineDataSet(new ArrayList(), getString(R.string.live_activity_heart_rate)); - mHeartRateSet.setAxisDependency(YAxis.AxisDependency.RIGHT); - mHeartRateSet.setColor(HEARTRATE_COLOR); - mHeartRateSet.setDrawCircles(false); - mHeartRateSet.setDrawCubic(true); - mHeartRateSet.setDrawFilled(false); -// mHeartRateSet.setFillColor(HEARTRATE_FILL_COLOR); + mHeartRateSet = createHeartrateSet(new ArrayList(), getString(R.string.live_activity_heart_rate)); mHeartRateSet.setDrawValues(false); } From f52126ed36013970c8e0e423c18ae36f8bbf46f3 Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Wed, 13 Apr 2016 21:21:25 +0200 Subject: [PATCH 07/19] Update dependencies --- app/build.gradle | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index b87fb8a0..b58658fa 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -46,12 +46,12 @@ dependencies { testCompile "org.mockito:mockito-core:1.9.5" compile fileTree(dir: 'libs', include: ['*.jar']) - compile 'com.android.support:appcompat-v7:23.1.1' - compile 'com.android.support:support-v4:23.1.1' + compile 'com.android.support:appcompat-v7:23.3.0' + compile 'com.android.support:support-v4:23.3.0' compile 'com.android.support:design:23.3.0' compile 'com.github.tony19:logback-android-classic:1.1.1-4' compile 'org.slf4j:slf4j-api:1.7.7' - compile 'com.github.PhilJay:MPAndroidChart:v2.2.3' + compile 'com.github.PhilJay:MPAndroidChart:v2.2.4' compile 'com.github.pfichtner:durationformatter:0.1.1' compile 'de.cketti.library.changelog:ckchangelog:1.2.2' } From e87a357bede59fe35439c2c86eeaa0dc610efd57 Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Wed, 13 Apr 2016 21:38:35 +0200 Subject: [PATCH 08/19] Show separate curves when the time between two measurements is too long #273 --- .../gadgetbridge/activities/HeartRateUtils.java | 8 ++++++++ .../activities/charts/AbstractChartFragment.java | 7 +++++++ 2 files changed, 15 insertions(+) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/HeartRateUtils.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/HeartRateUtils.java index 9ac085d7..a4d39925 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/HeartRateUtils.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/HeartRateUtils.java @@ -3,4 +3,12 @@ package nodomain.freeyourgadget.gadgetbridge.activities; public class HeartRateUtils { public static final int MAX_HEART_RATE_VALUE = 250; public static final int MIN_HEART_RATE_VALUE = 0; + /** + * The maxiumum gap between two hr measurements in which + * we interpolate between the measurements. Otherwise, two + * distinct measurements will be shown. + * + * Value is in minutes + */ + public static final int MAX_HR_MEASUREMENTS_GAP_MINUTES = 10; } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/AbstractChartFragment.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/AbstractChartFragment.java index 60c6dfa0..c8cb4d7c 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/AbstractChartFragment.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/AbstractChartFragment.java @@ -421,6 +421,7 @@ public abstract class AbstractChartFragment extends AbstractGBFragment { boolean hr = supportsHeartrate(); List heartrateEntries = hr ? new ArrayList(numEntries) : null; List colors = new ArrayList<>(numEntries); // this is kinda inefficient... + int lastHrSampleIndex = -1; for (int i = 0; i < numEntries; i++) { ActivitySample sample = samples.get(i); @@ -463,7 +464,13 @@ public abstract class AbstractChartFragment extends AbstractGBFragment { } activityEntries.add(createBarEntry(value, i)); if (hr && isValidHeartRateValue(sample.getCustomValue())) { + if (lastHrSampleIndex > -1 && i - lastHrSampleIndex > HeartRateUtils.MAX_HR_MEASUREMENTS_GAP_MINUTES) { + heartrateEntries.add(createLineEntry(0, lastHrSampleIndex + 1)); + heartrateEntries.add(createLineEntry(0, i - 1)); + } + heartrateEntries.add(createLineEntry(sample.getCustomValue(), i)); + lastHrSampleIndex = i; } String xLabel = ""; From b25a47c3987dc63bd86b08535076f78a67c1ab86 Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Wed, 13 Apr 2016 23:36:14 +0200 Subject: [PATCH 09/19] Immediately disable hr reading and activity tracking when leaving the tab #273 --- .../activities/charts/LiveActivityFragment.java | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/LiveActivityFragment.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/LiveActivityFragment.java index ef1dcd07..7b201372 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/LiveActivityFragment.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/LiveActivityFragment.java @@ -267,16 +267,12 @@ public class LiveActivityFragment extends AbstractChartFragment { @Override public void onPause() { super.onPause(); - if (pulseScheduler != null) { - pulseScheduler.shutdownNow(); - pulseScheduler = null; - } + stopActivityPulse(); } @Override public void onResume() { super.onResume(); - pulseScheduler = startActivityPulse(); } private ScheduledExecutorService startActivityPulse() { @@ -298,6 +294,13 @@ public class LiveActivityFragment extends AbstractChartFragment { return service; } + private void stopActivityPulse() { + if (pulseScheduler != null) { + pulseScheduler.shutdownNow(); + pulseScheduler = null; + } + } + /** * Called in the UI thread. */ @@ -332,10 +335,12 @@ public class LiveActivityFragment extends AbstractChartFragment { if (getActivity() != null) { getActivity().getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); } + pulseScheduler = startActivityPulse(); } @Override protected void onMadeInvisibleInActivity() { + stopActivityPulse(); GBApplication.deviceService().onEnableRealtimeSteps(false); GBApplication.deviceService().onEnableRealtimeHeartRateMeasurement(false); if (getActivity() != null) { From 24cc3725d2b985748f250d54a62b059fb7d75b6e Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Thu, 14 Apr 2016 11:07:44 +0200 Subject: [PATCH 10/19] equalize size of connected and disconnected device icons --- .../ic_device_miband_disabled.png | Bin 971 -> 1281 bytes .../ic_device_pebble_disabled.png | Bin 1008 -> 1316 bytes .../ic_device_miband_disabled.png | Bin 584 -> 961 bytes .../ic_device_pebble_disabled.png | Bin 650 -> 1021 bytes .../ic_device_miband_disabled.png | Bin 1415 -> 1706 bytes .../ic_device_pebble_disabled.png | Bin 1351 -> 1653 bytes .../ic_device_miband_disabled.png | Bin 2316 -> 2593 bytes .../ic_device_pebble_disabled.png | Bin 2273 -> 2417 bytes 8 files changed, 0 insertions(+), 0 deletions(-) diff --git a/app/src/main/res/drawable-hdpi/ic_device_miband_disabled.png b/app/src/main/res/drawable-hdpi/ic_device_miband_disabled.png index 43cabe9b459b62ea347e293f62499b12728a780a..f9f7be9c705f2a0cffb739ef23c7ae77b9f3434f 100644 GIT binary patch literal 1281 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 T(_a&O00000NkvXXu0mjfAsyC3 diff --git a/app/src/main/res/drawable-mdpi/ic_device_miband_disabled.png b/app/src/main/res/drawable-mdpi/ic_device_miband_disabled.png index c1d9e92abf1cb4639867084c5f34e3ff9f64d5d5..9d9f007a908867cf9a80bd5a060241938917228d 100644 GIT binary patch literal 961 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA0wn)(8}a}tmUKs7M+SzC{oH>NS%G|}ByV>Y zhX3vTXZ8bmoCO|{#S9D*%R!jY)6RA;P>{XE)7O>#0Sg}|t2IxOn>|pIxTlL_NW|f{ z(;d4nJBS?rpFgQ*ZeHtBZtZugHY^C@=c;S^`bhkPa>d6duJ(=h9c(z8()Ay)-{`Jm zQdFpp;MeNaxU@kp`gV%iXPYISm#<#g!s)c|z0sLH5C6~po;GPF`noI_W7ts zpwsqj2D^eo%6ds%NlR8d=d*cwVG>8$`7GfV!Pc%jg1>*R{x$RN%8BzjJJ)}D*laGT z6s@gU^~rKyNW2_F%KxwP@-K&UmUsl7zskGD&UA0_qIDTCh%qmJTUqGjn!di6rY4S_l85u1Q;0c4 z$>4r$ORi$m_nsXme;wc{-7;~-oEJ}6E$;?hw$S5f(u+rC0E=o--$t+7v1}e(WE7r>|O4rZHOis-! zPA%3?s?^O()-6udH`X)IzsDl=6lk3)$hwrol2j|O)>H-~14C0?0}EY4;}8P_D^n9I zLkn#KBP#=g-RB(&Q8eV{r(~v8;?{6#(vP!14U!-mg7ec#%7Kn$C@(M9%goCzPEIUH x1-WkaI~ysWB0-R%kj#>tR0iKnr^LJz1<&OCyrnUEz}&{b;OXk;vd$@?2>^Y~g<${y delta 570 zcmV-A0>%Bo2gn4F8Gi-<00374`G)`i0uM<yy|H!0Yv13xd$14Zv|+mjJvvoz7b*Cffo) z)wxL~lkFn_=zqCfE(@tlcL;z02!H?xa9jYjT21Qr`_gbY+)1z&d{6-xkH^wtv5=O_ z%w{ubGMW6I%yc?kN#1Gr4c^(b7JMSW z$y_1OXf#soBL-hsM)98*0T2KI5C8%GHnxrgpzC(K-+z=gwisx26M!ad0G{VN1mFoa zR7q=5&$8^fD2jF30D>SiVE17@p}0dGjYi|CREk>i5IYu&@$1esqf=^;NW>Tphk5dB zhC-oEAQ0#UgTZgDMPhb|+9YPe@AsSb9Wfc;{*fwhPmc1LJk46l;c&cIt=31VI&h8E zn3b)D9WyX5fF3=-Xeo#R1!SE(qf^P`sUdSfsWzoVL;KJ60~_X3&B}UO`2YX_07*qo IM6N<$g0NZzy8r+H diff --git a/app/src/main/res/drawable-mdpi/ic_device_pebble_disabled.png b/app/src/main/res/drawable-mdpi/ic_device_pebble_disabled.png index 675a26a7f67a2a73f579abc02303abac38ecec79..924fcb587ec11408245283bfa955275dcdc9c497 100644 GIT binary patch literal 1021 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA0wn)(8}a}tmUKs7M+SzC{oH>NS%G|}ByV>Y zhX3vTXZ8bmoCO|{#S9D*%R!jY)6RA;P>{XE)7O>#0Sg}|t2IxOn>|odu&0Y-NW|f* z)6ZuMJBl3NpPyEKMoo8$!oL+tZx>#g{J_;FV%I{vZF+uNajaIrf7qxb-w z2>vQTrg>E>FNqx4aV2S1N_zRc_P2RKx9|FF5?**e*eL(`@0pePMzh)Hludj(W9^PR zJxpFNs#p(%`|UWsct)TxSH{)fPuV9eb20esc0Bj*aUQ{Y27f-St4kEqUh+I3DcrW^ zgPwCr_R@xVb=`X5+u0emelFXYdMTu{L}NjyzjZ{d*4`cRF@eQQQy5>&y3nP4i|?qw z=M`&DC@`BSu6%F(nLUB&;s0q4aZlu~uAcMnF~dnE-@X%VLdzM{mR-51U7f?5&0zPi z*71*79@CEwepR`p44j+}eVyG#-9-+oKJN$=*qJargG@TwT1}g(r!N$#c4C@O6 z1Tr5?fMxVHqX*rGw;+@$Mj8{lbNnJ1;u>s$|*ZR1kX z7JF~SeSp74uj5QOtBMDMO7f$p&sU0U=sbJrr1TAm-OYa#Jj(yqG6uYx#{4Uf(QSr^ z5`#jE(Ug$QHd=B=3h(y3dBCk)bW{FFtZjyh;A{fc)-9Z$E+nZIa4 z;y3y0^De8hzs~2Mm-BkfOxc%Qv$nkYyJj`pe8VEE?98OMvPbT|57hr(DD!gi)QE2j zlh&JsE7d^H~@?I#(ZBf8jOD9ivk%taJZ8{Qm6AKaR_5|M>r9)jqTC z{^Y+M-+(EOr^Gd)#Idv_Bfp5Dq97x$qW-~~GeGfVkhpVxL1j^9dPWI@v$KL@Nl8&= zQfWzMex9yhex7rFZfrx_(Y(a%x_2YO#J&rEXrbZgHZ%v7UkcJr=2_KSs57YKJQS7q9HdwB{QuOw}w-bew+nrkObKfoS#-w4sBu34#=bWR~QlG6bY1CFP_lcqZrPb?s;P3zTH=boFyt I=akR{0LcWN7ytkO delta 636 zcmV-?0)zei2Z{xd8Gi-<00374`G)`i0#QjsK~#9!?U~7L;y@6F!I_QBa?3)j5^vUINeQ`RSj$;aacz?a#&yh&v!;2v*m5QU) zY6*=-`3P#_}oT`rdeh=nt{8g^Vl zxXBf%;GZPR@(s`Pr$)CFhkFqw_ecX|v)Ox($MX{*_A8+eARG>Vl_cqwG=LxoBLKMY z`~BZBndk+;tbg+@m&@Hz0H6c{0T*PZAEpC9mQbhDsisb+qdTZ}yM34kS&kgQU@%a3 zyPc--c&r;hQIx|xyayEki^W3icDuTSW2pmpuBZUmZnx@sy;fJNl`i2}oI?%3X0uUC zrIPM<0LS7S>Hsji%;)oe3dc|jFdPp5yXSEXGXS&MOn(!z0F%i?6Vm|rwZp1OwIE6TJkrDc}AWqSk{ W{?KvS332-X0000T-OgI#DO{ z5zazH>70C=4k{m!SH3!=^)7J;rxVlG@y`3#d;WO;c%J9F@9Vy=`}ym6E(Q2`8S0zq z0{~#?O(X=VXY^L-LDZdC)OlY$AaOWf8~`*G7^tY)YOERK<3#{Aa|;GK)d|AHhrP-`o z>(*Y_T^MdVs#WznWj}*b)c|i@7?b#rg&&4n?~xZqBpy9ulAzE-*?l?Lu!Qo0W3z7v5wCc zss@_B=s#0aIyQ0}$O-un{yoWf41yh1a`n>MH(OviRN1}MxwP0QmHrd`&UnTVM# z|LC+l^rcjjOiDtXE{0692)Na@~5`A%ql`&m6Ts*`k)VP zB-63*#r|d4mWBE?@y5x@c-6UY!g_=5yd9s>YR)HP2it`2hqV0BoBhxEvu;IXP0wH` z%=ch`<5l;UA^!_hmf9hw`gCI8lV81e4p-+7O)Jn}OHv_(+7|t5PJ221cgiyj-d`0f znr%rXC4atN2U?ma6I8@M!o#gJ0sO$T?R!sy!v`?MwTv!{vcKNwK*EP*O-~!1-&@8S zeQc9BNN&hQF&!B@fUv6v_uk+?*q^gNoVc_w_U^Q-e`Xg9+D*E0{qCf_3)}o9#bk>4 z%jlBpYIUfsOPbCBBRkQtwulZv*Tkbwl$L0V$@c-|Hy_#qp~Ho($PL+I#r@@*p^1vwcnNwrqfjZ@{9#LlN1&j-9B zS6%$$tXn(naD}J$>z}Z3W#*ZxV4son<`z8l;i64nyANMGp!pf4^yZn++g}32(?6!{ z=)dr}M!E~{Gey%FsWilnmz$^}Uk|N>oL`MZyONaiRWa8$0m+N0edKo(d-ZwT26~2p zI3dX7@_{5ClarJ=yEvfcX>nt741VNq)5=rCJsURznPE(7x9DzNTABSYKXmpN%E0gcL|Z*5oh5o@Lv?c5TDus}8)@MYnt aoLIOwjmxP%W3PTI0O0NEM`*xDpZgETcJ=N6 literal 1415 zcmai!{Xf$Q0LQ{&Jmuj$l!wZ_ zQVv&n$d+t6=AjrVA{XXb<2*D%=U(^2{dV_yeIEXR&+GHfc0K1HBdID00Dz3+8C$|$ zlm9kcd@tXZUNQ#&@SLNqH8F8gP}zTezn3EWN*y2Xa%Ssx5ykl-BwL2yZs%Wv3wLra zX!JYOQyjLf0MjCi>5Gn&rQpZXz%w)a9r212KM+Bq#FMLP zdU&hMH^BZE_-aQnrmM>5@zyGwU)Mu^5spMMDTk@MEl<6c6N4FxL&;YiRPM+ zuyLQ{Ie~;TSe)aSQ3blRv8m~LdR<*zUTkcvrLrvjHpoKjT3BrMtgWqmo(+ZDu0bCA zHFaoeY9ccj2US(KsAMwcogm?qKq&lbLpN9y2$Gfi(~zibxvi=FiRs*_dFS)4Hbd6x6HaM{?#{QW9x;l_$PUIKrUS~vu6d?D}h@? zWx?u!K9<8}-pI&`t+dr=0F}<;@$P7d9=Yl1A*`!*bXl%9UJEwp(0rxV*O4hIxooVh z@>@jlyGKR3?sGjY>TO1M6_|+B_V#uSqt(I;O9vgYg(Q_VCT5j0tC5?VI~4OBbP?fm zpLa8)#lpjR;6Xk}I;2r@>t_&X4-XHoHZ?Ihc{o)87#ka-QV6OpI_`wCXMgj5i*S`> za*w4pG&Gz-%)qQXJUlLYdU__=+q2Cm8;7A*iwPOVKz;~pStoU1U_b(f>eB8z4Zy7a zOO0YPaVP3uyl@PsQtfTOjsiL&F z$E~ieZ^9XjfP)nc5ON83aPVwqW@aOTLE5LlPRMr7QUhvhYY7;XtN(J(vx#j+cLL<7 zfq^53!)XLln+*&NFQA!AOG_Eh*tj^YsHiB%j*gD#D?LMaJpPwKnv9S|TTwwj(P7{9 z2GITt-uSq79!Jx~#pT6*>hBS7y6Efr%Fb&SCE-d^S8Ut&Bh)NF1Hfc0K$xMMbW3k9 z1W?_ptxG{nPERuy6saCuqT$cFV%x;~V% z+fs3%HQH`~%XKuo=@e)-7o&OIY%URBo`S>x(ErnVyi-tjjTvNgbkxtc8}o#!f)D8e zXNuvB^1ieOO3~ipfKDO*)%^TC6eqw#Tz!3gkEDIAWRXSkh3;;^VtE$t`p0q+Hg#)j z3%!UA#Z?G{Vkre|z0qHdA>TG5Cj=XTd!qv-!7%kHEu$~Rk@~IhEzbfpj&+Kh%;Xtq)krgPY@( zm6h!>mUOgHsUa5IjYelUR6KtZiL1SPHQ-t#ytS z_~7N~X^GX>r@8t0`5hs85{bkB5-BV@o|RWnP~cTxU*D^I?Sn8UCkN`5w5!Xw6v+QD zpWFjyd;u=;XA%!)Y!XvATj+}}e>QCVN?0KMLc+h5XfXGp#Wu!;I) zsx68iY@rZ?f6O!LycKkBNiXSZv7C?czew|++=Y;HH43d>R;lj+7I3sXXWMj|oc0&J CCupqz diff --git a/app/src/main/res/drawable-xhdpi/ic_device_pebble_disabled.png b/app/src/main/res/drawable-xhdpi/ic_device_pebble_disabled.png index 705aad25e230438695bf0cdb5eae70775ca696c5..f231da8ec84dcb4df0b68be1c7e45c3d319c61ba 100644 GIT binary patch literal 1653 zcmZ`(ZCujl8h#*rK~s-TYr1Jnt4#$#&GHaxBnH+`%~F1*mLdKHM8M#WqEJJRuaxgg zOOKkZrJ~c!UPeiJ&X!76Dyb}OW~Q6Ad^?+E=H{Sp`*1$o&-J^n=eq9udcHgbheN3r zW)5Zm0E=K6<%k|n8p;%g?}iX?~U^h3#4tjw791;u6Qx~Yy1W>h<#}#?#uVhe~<@k%^#}FrpwQ)PFYqu ziuW6Ie|s7so6{QYw~>#T(w;1jkC<%(*dnJEZWt!)e&uARoeg05g*9Fthw`eg z&Zg?bDosphuYa!T^1V`|)>i3qT)k!ja-U$V7BWv9t;lux*P)vCRT)iwtSRQ!?LQ5k zm|h)I;>>1SHYtq8dpuPM5mAvKtHIV~GC%Bbh;RsLJGdoi_(-kCUM<#D=Sz>lO=|}! zl}US@|8d@H!Jhh>O;=JsJ-ehh{^^AWNH!AfQ((Gu9VBP9McW`VZRHc`=k8m2io&mF zaZO8xhmY@k@#M!*E8m)H>qvhE?{pqVP`d}Pdv5I%^d-ETieQoM!<8pX1Y(GaM0b+5=W^ z`E8P`at_S-PlO~7T;5yb+U-VXrAt7Y+#u =@dqcisE$0cPkcck?A`YkgtESWM#^ zpo*HUaow8czNw_wdH#m-L!hI3GJKZ<=G_`LMuf;!bnizM>=)&+k7GZ)Zgf~DzqD<< zYMpU0;oT8%Pd!u+CWt!II2JP-i8>q^{0Yrk^OS{>x5BF=)2?)<89QLD#AZQ{a;3sA z_DPKP$)0|+bFqPR#tQscZuiN>q>TLfHJdkISFA{=GF4TUb7s`slESCFsL(td zw$0rg?S*?EA+x`#*cr1A*?ztMKQCY1M7*5VsM#7)M-7Gke5Snw#qK{lAdxbjYUYRf zst=w_$(WS2_eaYRQ}(BuF3NbaYxP}Z@eymQ8MOb#^6ku1HgB8G#U8BNJrdBGL(;LpjqJTa60j*%zK(7~G|DX}4XOu02Lw(rByQ zwDn0%G;6zG>KKj+cDS~~13zZjpxfyC3a-QQ!hLB{h1p_REaEF{$9YTEFC)b=*Y0C< zbzY%%?TH_{9vbE%4&-f-wvqq&zr2aMsc((T=e_qvrlxx7F8*mU&DV6+Q~#XM|8$$- zpeUFuhS>rkkfgBrk}oG;Kh*O~10N_zNf&ZhY#0OvV#qKoClzAqMFPIaLm*_~lQ~R?FM>q)_;ehfi4!sK z-W~+}1j=DXzix+NT>=A!h##yF@FIBn;0V4rPwxlP(FOj{UxMJEP)h6mlUaWOG8EQV delta 1343 zcmV-F1;G0C495zP8Gi-<0082ccQ^n51rA9>K~#9!?VZa{8&?#@v6H6nG$HAWQi3tX z1|&8}O%-*4+N3Q_Nvc-i;l?&EgIJh{02#3`2oNuUE%6eFe}DxmX8{{nutUHC1RHj& z5C{}lu}M9>-*`-o`;^JGvHczC69%D~Ip=rJopU`iXHrsVG=Cb6Mx)VaG#ZUYqtW8h zbei-DE?tPORPb?d*NTdYu0w@|g>OLl`S~~ESwTM__yr%sKwO>R;~+CLGv7)}OM9oF zpx|BMzCcV&UM z^#TChtbeSm4;mXApAtX-Kut}JRSZg_$z)2)$jG>jZvtcixE=)1+}!*#0R#Y4S6AEe z^768Ca&kTsqdye@w681V06>}%z(oMLxw&5uKhD1v92^ipGy#NbZf=eM2q3`$;EsmSX@^q~7h(iJ00ck) z1V8`;KmfcT!%LF9B*}~N1V8{0+?a)%rxq6%rHD6X@zz8FAOHg30~!RtN0bPF00!Y05F+M z@3*wHl(1=E06<+`okaxyp21-F7=u$P0CY`6YesfW{1ZS!L&G!li!+w5wS0KjyN;G>%)M!(GV_G%Vj2OS+94|{rgk{*DF!K>ER)?)NhMSt)^ znzrg?0Z<``Dd@i2?N0jU-694rMFuV`$3n@t=KYWJoh(SsWU+$x3g2Ul>AXHpcRrS~?RNXGm6eqxqV)V){Ozvn>E?e`Mwt7s`a=zj zF5*}bijz?W`YDUD%nzX diff --git a/app/src/main/res/drawable-xxhdpi/ic_device_miband_disabled.png b/app/src/main/res/drawable-xxhdpi/ic_device_miband_disabled.png index db5603a27cc7b117ec5792ced887e53da4d2d627..94dd2c1282ceceec85460c6f1b062b2630b3b136 100644 GIT binary patch literal 2593 zcmb_edpOg58~^3dm>d$qqZ%U7m~)n7Y%_;pn`265#^$hTR&%ICDk`>+gqSm7=wa;RsX_pkSl_n-HA|G2;Rb$_nU=eqCfd)?Rdx#Jw|t;E5KU;qHb ztuaVEKXZ0NM2P=l9W?d%Nyra@MF2oKTWp&s%&!H!ZLN^NuiNa-dVVDujByVE0PEG= z*h4uket-{xnATVnXi`W*bgxMpg4qiIA}nhp!YOoY;c*XJ)k?Od{^^t2h370kBZ+D? zFo%qim#3QF$EYX^h^ch!i4*LIkA!@7n3QZ4J$`JmK~^|U5bvUbkaBC-b8~;~DNGyM z)=?zG_p*M)H!2$>pq_w!SMN8Vl0_-Xs@Fv^Kq)k%04mG?T%w#<>P`mk zhM@3N=~7&}i$qRQtyJ2q;Qr#poMMl(#@W0(>N0~P6^Il)%_45}zEI`Q^CV}ffYS1U z_L^crl&8?4nKmrqd{VlscTN<+`^|AVpT~V$89VTV<|oARPxBI1`@93e)Z8cudM!|FxNrV+Hg?)%dJ_52%bDc zG$-pc(X%Cu8`D{fKdc+;1*u;7w!P7qdulFMX#bK;e|X`!ag^CN#jfj$-Hq>le$hYE z22xdYRBpfbz!F;dY?D#<{HppYa5^w|yWxP2E;$)*Q+DmoW6}nx>pn37>jjS<>d4=T zc=n+_a5z4{u0YQGwwkjjJXMaD4tm(l%dE@kRx|p;-S}Zw4Y3_PRiqbvwzai?@3cC- zvld)Y5WzdNFdEdMZu}dQJ0pVN{}uX=ukxAet366+=$+ib%Rzo_eTaR|NJq43Z_;Sk zg`d_Oq|$0m&4NRWaV&fOMv*WiDnFsE%S8Xj$O%oGFuU^jrUD~l;V9{S#uYZg0m(Q7 zw$XM!LOmhJQ^w;tc0kueT#m8#qRie$7Q6fapz6nVvg_ez_=`u58%o|Gz`d$p!ct_*T#*VLAS;V_NNR5e!x!$;AL%!$Z zB$d?feZtpNb65j~zNd8WLR)WSi;;>&$gI`jyK&MOYYZl?nA>@&* zXS&ZNz0XE3`T>Y$UV`?Ulhad0DbhkFBGF1h2#IJ22*J4lX+=nVhKMkv{s$Pz_C(5N zz4BX@@BVaj;v;GPy~smzwUnH~SqoKXnO;3oLj#ppypdvdug%kc+Na9y&df0Y}sqccz6 z*X_W5u6h)4V6f@n7f5c}rH%2t&)8l+`@W2U$$`Ti-P3fY;TR^_~vv_ zBUlc7^azo~aIKDXt^}mS%-mNBbJBd=zJ&uly3$ zdun66t)}SZE$q|jFi*yx2@;uE<1Y4Z#JBrG9!-qoeP}pzB|zft+N=6ykL{6&V*Su3 z%SW~a*q`*Yy{2OhZ_Q7cO`P5)*N=v-1>aNGa$k=Dxi8S1moTlD&e9vPO%x_l{e+OgP}7=Yjhg zHXg}wr{x@)E+LfoSzUPuJ(J(3=s?=evEpA;77Mr*A zb2LF2wZ3Q*mK_-T0BN*ND3v5?_B2S~t7?kh1T5%3F0Q^Y<;p=WE=4d1^L3fon(T3w zUhDAI!dOxyb~vr@v#ZH=110yx>Z0q!{OavhC(z@S?ATx*G5W``LjU^gDv>q2d=dd> zGbtCj{^ge_6ORbul;4oG_IFd#~z{8Zx-@~>@Id*SrJ4iyuQ*M z*s>a{dcX>&P!V4yujW_@xX)v3&8_2Q0!LHMC6f~mzR^6!AV{#?b6;HEnvuwVmPTn; zz{hg}RPtqiOH%aG{hiVb=Ex|9G?^UBhn~vte`36aoomHWq8A*C%^(!ZRBz1}w=A4V zL`z5b&a&XX6eq(JybbT-Yu#i0Qo~AL2CL45=j?d9R0mtn^%uYoYE-EQZicBHBr&y! z$;pO^ndbYd^N$x#WKeLUPz*~0m5`RG-j5;>-@=X$eLY#vg-OboyIN=8Z|YA$dXu|| zkHrIjSHz1c=mt5`z_arC&YE!tPhiV%CHJqD=85xNuWZM?LK3lKtvayRy}iiRLU_;K zm#{mf;OlPj!&Q;LIU5F;@wmz;(cvPjR;wJk3-)iXCE-seu~Y<6z^i1y>ueV5YT=Z6 zses8ET}ypH|GbW^xtLq;%xK|e!d$D3!yAhZlgW8)N51dtH~#{T8hN7OBc>4kRkDwX za$_PcF)4Hg5E@LOg+@-!ck*%4E^bK=4r5ULC``c85`thd8C35}Oe&oQwWrf8=|Mqc z28l`xgc2x31{o1Z4Io1(OlB}#M~B296PeV@WD=i5r-f+K8Gbr}R1%pMLJraK4ujH2 z&=8`IzBWu}LP&9%-%f3}oez;ohW{fa19~uBLn!PdR9D{#27?{oJ2{6b`z2iX zEP}5ja7hg@!NNyi;eH`^k}tHTb6`vC2D5Hwen`*)-zX~G{X4^@%+XN`GI$ii_@xjJf^V`%8kRgdg$`w$+ zs$~clG}EbXk%X`l8GNM%oP+y28Wo~gVCe^C`U1i% zX)GtQxLELSQc_Yd^HZ3zwzf7;TlX z6i~dXaUsH2%GSwAKk07X7SI0gBiS9102`vSeyyGzz2m8%pb(XsntIXN;NIfb(TX&~ zVJ&U#GNS9d(B106d7A!oecGJY&W8|cN0e+2LP@-unDpduN zNEuU+OY$)_&K#)A1n288!b6fH%diLzsc0SCTFacz<|@9o>{nwZG{A{MT**_Kz=B=* zQQ=_AlAhnA<&m<+IjCpKzafer;~!6!9fbKK+GrDWHlr~0>uxKKtU1!9t0T8gLv>y z;#j#s<*eL>I2a0yJ|2#V|4;Vv5=6BFsO(5`HRjR8hb9klEW6m0sF>}fP{)0WBQAy=7V z4pH-?6~?{tNOleoc$KwFMM@i4upN~fr5K{be@0rM$!lwK^wF`&hZ9kfAFO2;r(#jqq#}z>w%1F^Z59uqbwXetK)$a$DE%)chy|OxI zXOH#coUpXVrip6z%GJ39SHnebIMzs`_z$me{m-ulfc3wg9VumqlL7ZokEQ#sU;M|y z{gV6_(u7n!ed@;sQWYdzmKQjCk|4opg~4E;AXPEMj^@B+oJ2;SH`rAGb#!(oM@Fn9 zxi2Ns00hVrE5l#t&5u$g@CIL#1sJM9GyvH!VR}`f(V~t&C&^uyIi2IHx{!&VhDd4Z zu5j90Xu2k#o7H-G!36TG-9n{rCC^1 zl(eiNFb_slar5KdIoR-$C?n9OZR3zm2Y$I?z+M?9-;4JJqd**81+fr3mSK)Mr`HE!@(MtzqJ!cZ3^c-(U{~*0 z^1jiHohjeN=TqAyae;s$=5HkuZwsZbgLR&8D>$^sH@lMxqew;Sa#yU*~gY%E(hvTX?FK!iVRjy3Ix3Lkg zMTyVN><~@_KN7m_T|x=U&2520t?8DR*CM5k!Ma+VK>pIf)%8wgL2*TLn?0iGr(m@H zoc*@CVZ3HN)iiV>%3VMz3FBN$qQ<-@x?3rvvSR*X*6(y$D_YUte###a8#(8(tv$tQ zFr22fW=r6TvXBvW$lr`+X78s0d&%yKA_kR$`;boG*3gAz<>`YGSDUoAS@I9lv^Il< zq>_eYP>o9JIW`6CBOSg&zcq!IxHr1Ig!cso#fje65bw&0hPr&lK~FSH^g&*0Y7cI; z-}8w7pbl{2P4dp*VnR4OLEJ;0RhwhPG2*x}pQ$JfC)S@Qhqg#Zn3wLJ^%T?UP@x4$ z6mc^bD|-^E1{X9kWz7B5=H!CLN{Xy!`hHL!G9|7X{o)@%lHB8(ZmAM`l`@0`j-IKZ L1^S7>_2|C=UW6<| diff --git a/app/src/main/res/drawable-xxhdpi/ic_device_pebble_disabled.png b/app/src/main/res/drawable-xxhdpi/ic_device_pebble_disabled.png index c1eebfd5974537b27e16dd341de28826c8d03ab9..24c8f2f56eaec676c83fb31d0b1c9826bd379829 100644 GIT binary patch literal 2417 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 T{b5;OfLo3pu_8RcyI%eW$RF$t From a9b4ea8edac1e77a46dd2056a9e43467e9a159f9 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Thu, 14 Apr 2016 15:17:08 +0200 Subject: [PATCH 11/19] bump buildToolsVersion --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index b58658fa..f8f96f42 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -8,7 +8,7 @@ tasks.withType(Test) { systemProperty 'MiFirmwareDir', System.getProperty('MiFir android { compileSdkVersion 23 - buildToolsVersion "23.0.2" + buildToolsVersion "23.0.3" defaultConfig { applicationId "nodomain.freeyourgadget.gadgetbridge" From 4bcebca7445cef5cc9037489023e10864e96c0cc Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Thu, 14 Apr 2016 15:21:25 +0200 Subject: [PATCH 12/19] Work towards dark theme, remove -v21 specific theme definition --- .../gadgetbridge/GBApplication.java | 4 +++ .../gadgetbridge/activities/AlarmDetails.java | 3 +- .../activities/AndroidPairingActivity.java | 3 +- .../activities/AppBlacklistActivity.java | 3 +- .../activities/AppManagerActivity.java | 3 +- .../activities/ConfigureAlarms.java | 3 +- .../activities/ControlCenter.java | 3 +- .../activities/DebugActivity.java | 3 +- .../activities/DiscoveryActivity.java | 3 +- .../activities/ExternalPebbleJSActivity.java | 3 +- .../activities/FwAppInstallerActivity.java | 3 +- .../gadgetbridge/activities/GBActivity.java | 22 +++++++++++++ .../charts/AbstractChartFragment.java | 4 +-- app/src/main/res/values-v21/styles.xml | 32 ------------------- app/src/main/res/values/colors.xml | 3 +- app/src/main/res/values/styles.xml | 23 +++++++++++-- 16 files changed, 61 insertions(+), 57 deletions(-) create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/GBActivity.java delete mode 100644 app/src/main/res/values-v21/styles.xml diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBApplication.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBApplication.java index 20e79bed..a9ffd273 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBApplication.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBApplication.java @@ -305,4 +305,8 @@ public class GBApplication extends Application { public static LimitedQueue getIDSenderLookup() { return mIDSenderLookup; } + + public static boolean isDarkThemeEnabled() { + return false; + } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AlarmDetails.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AlarmDetails.java index 9bfe1295..7b3342ae 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AlarmDetails.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AlarmDetails.java @@ -2,7 +2,6 @@ package nodomain.freeyourgadget.gadgetbridge.activities; import android.os.Bundle; import android.os.Parcelable; -import android.support.v7.app.AppCompatActivity; import android.text.format.DateFormat; import android.view.MenuItem; import android.widget.CheckBox; @@ -12,7 +11,7 @@ import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.R; import nodomain.freeyourgadget.gadgetbridge.impl.GBAlarm; -public class AlarmDetails extends AppCompatActivity { +public class AlarmDetails extends GBActivity { private GBAlarm alarm; private TimePicker timePicker; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AndroidPairingActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AndroidPairingActivity.java index f85d3ca0..e7900e44 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AndroidPairingActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AndroidPairingActivity.java @@ -1,11 +1,10 @@ package nodomain.freeyourgadget.gadgetbridge.activities; import android.os.Bundle; -import android.support.v7.app.AppCompatActivity; import nodomain.freeyourgadget.gadgetbridge.R; -public class AndroidPairingActivity extends AppCompatActivity { +public class AndroidPairingActivity extends GBActivity { @Override protected void onCreate(Bundle savedInstanceState) { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppBlacklistActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppBlacklistActivity.java index 06021c08..21e8393a 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppBlacklistActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppBlacklistActivity.java @@ -11,7 +11,6 @@ import android.os.Bundle; import android.preference.PreferenceManager; import android.support.v4.app.NavUtils; import android.support.v4.content.LocalBroadcastManager; -import android.support.v7.app.AppCompatActivity; import android.view.LayoutInflater; import android.view.MenuItem; import android.view.View; @@ -34,7 +33,7 @@ import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.R; -public class AppBlacklistActivity extends AppCompatActivity { +public class AppBlacklistActivity extends GBActivity { private static final Logger LOG = LoggerFactory.getLogger(AppBlacklistActivity.class); private final BroadcastReceiver mReceiver = new BroadcastReceiver() { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppManagerActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppManagerActivity.java index f5182ee3..5be4f6f0 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppManagerActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppManagerActivity.java @@ -10,7 +10,6 @@ import android.os.Bundle; import android.preference.PreferenceManager; import android.support.v4.app.NavUtils; import android.support.v4.content.LocalBroadcastManager; -import android.support.v7.app.AppCompatActivity; import android.view.ContextMenu; import android.view.MenuItem; import android.view.View; @@ -37,7 +36,7 @@ import nodomain.freeyourgadget.gadgetbridge.util.FileUtils; import nodomain.freeyourgadget.gadgetbridge.util.PebbleUtils; -public class AppManagerActivity extends AppCompatActivity { +public class AppManagerActivity extends GBActivity { public static final String ACTION_REFRESH_APPLIST = "nodomain.freeyourgadget.gadgetbridge.appmanager.action.refresh_applist"; private static final Logger LOG = LoggerFactory.getLogger(AppManagerActivity.class); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ConfigureAlarms.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ConfigureAlarms.java index d04338cc..49f8e7a7 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ConfigureAlarms.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ConfigureAlarms.java @@ -4,7 +4,6 @@ import android.content.Intent; import android.content.SharedPreferences; import android.os.Bundle; import android.preference.PreferenceManager; -import android.support.v7.app.AppCompatActivity; import android.view.MenuItem; import android.widget.ListView; @@ -21,7 +20,7 @@ import nodomain.freeyourgadget.gadgetbridge.impl.GBAlarm; import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.PREF_MIBAND_ALARMS; -public class ConfigureAlarms extends AppCompatActivity { +public class ConfigureAlarms extends GBActivity { private static final int REQ_CONFIGURE_ALARM = 1; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ControlCenter.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ControlCenter.java index cb188ba4..b9ad4d98 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ControlCenter.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ControlCenter.java @@ -20,7 +20,6 @@ import android.support.v4.app.ActivityCompat; import android.support.v4.content.ContextCompat; import android.support.v4.content.LocalBroadcastManager; import android.support.v4.widget.SwipeRefreshLayout; -import android.support.v7.app.AppCompatActivity; import android.view.ContextMenu; import android.view.Menu; import android.view.MenuItem; @@ -48,7 +47,7 @@ import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.util.DeviceHelper; import nodomain.freeyourgadget.gadgetbridge.util.GB; -public class ControlCenter extends AppCompatActivity { +public class ControlCenter extends GBActivity { private static final Logger LOG = LoggerFactory.getLogger(ControlCenter.class); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DebugActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DebugActivity.java index 524522e2..a6eee775 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DebugActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DebugActivity.java @@ -13,7 +13,6 @@ import android.os.Bundle; import android.support.v4.app.NavUtils; import android.support.v4.app.NotificationCompat; import android.support.v4.app.RemoteInput; -import android.support.v7.app.AppCompatActivity; import android.view.MenuItem; import android.view.View; import android.widget.Button; @@ -37,7 +36,7 @@ import nodomain.freeyourgadget.gadgetbridge.util.FileUtils; import nodomain.freeyourgadget.gadgetbridge.util.GB; -public class DebugActivity extends AppCompatActivity { +public class DebugActivity extends GBActivity { private static final Logger LOG = LoggerFactory.getLogger(DebugActivity.class); private static final String EXTRA_REPLY = "reply"; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DiscoveryActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DiscoveryActivity.java index 82f2c7e5..f2ab531b 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DiscoveryActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DiscoveryActivity.java @@ -12,7 +12,6 @@ import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.os.Parcelable; -import android.support.v7.app.AppCompatActivity; import android.view.View; import android.widget.AdapterView; import android.widget.Button; @@ -33,7 +32,7 @@ import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceCandidate; import nodomain.freeyourgadget.gadgetbridge.util.DeviceHelper; import nodomain.freeyourgadget.gadgetbridge.util.GB; -public class DiscoveryActivity extends AppCompatActivity implements AdapterView.OnItemClickListener { +public class DiscoveryActivity extends GBActivity implements AdapterView.OnItemClickListener { private static final Logger LOG = LoggerFactory.getLogger(DiscoveryActivity.class); private static final long SCAN_DURATION = 60000; // 60s diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ExternalPebbleJSActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ExternalPebbleJSActivity.java index 4c18bb90..7dba008b 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ExternalPebbleJSActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ExternalPebbleJSActivity.java @@ -4,7 +4,6 @@ import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.support.v4.app.NavUtils; -import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.MenuItem; import android.webkit.ConsoleMessage; @@ -32,7 +31,7 @@ import nodomain.freeyourgadget.gadgetbridge.util.FileUtils; import nodomain.freeyourgadget.gadgetbridge.util.GB; import nodomain.freeyourgadget.gadgetbridge.util.PebbleUtils; -public class ExternalPebbleJSActivity extends AppCompatActivity { +public class ExternalPebbleJSActivity extends GBActivity { private static final Logger LOG = LoggerFactory.getLogger(ExternalPebbleJSActivity.class); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/FwAppInstallerActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/FwAppInstallerActivity.java index be79ea0a..90390a1a 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/FwAppInstallerActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/FwAppInstallerActivity.java @@ -8,7 +8,6 @@ import android.net.Uri; import android.os.Bundle; import android.support.v4.app.NavUtils; import android.support.v4.content.LocalBroadcastManager; -import android.support.v7.app.AppCompatActivity; import android.view.MenuItem; import android.view.View; import android.widget.Button; @@ -35,7 +34,7 @@ import nodomain.freeyourgadget.gadgetbridge.util.DeviceHelper; import nodomain.freeyourgadget.gadgetbridge.util.GB; -public class FwAppInstallerActivity extends AppCompatActivity implements InstallActivity { +public class FwAppInstallerActivity extends GBActivity implements InstallActivity { private static final Logger LOG = LoggerFactory.getLogger(FwAppInstallerActivity.class); private static final String ITEM_DETAILS = "details"; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/GBActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/GBActivity.java new file mode 100644 index 00000000..39c972ea --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/GBActivity.java @@ -0,0 +1,22 @@ +package nodomain.freeyourgadget.gadgetbridge.activities; + + +import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; + +import nodomain.freeyourgadget.gadgetbridge.GBApplication; +import nodomain.freeyourgadget.gadgetbridge.R; + + +public class GBActivity extends AppCompatActivity { + @Override + protected void onCreate(Bundle savedInstanceState) { + if (GBApplication.isDarkThemeEnabled()) { + setTheme(R.style.GadgetbridgeThemeDark); + } else { + setTheme(R.style.GadgetbridgeTheme); + } + + super.onCreate(savedInstanceState); + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/AbstractChartFragment.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/AbstractChartFragment.java index c8cb4d7c..9378d2a6 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/AbstractChartFragment.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/AbstractChartFragment.java @@ -150,9 +150,9 @@ public abstract class AbstractChartFragment extends AbstractGBFragment { protected void init() { BACKGROUND_COLOR = getResources().getColor(R.color.background_material_light); - DESCRIPTION_COLOR = getResources().getColor(R.color.primarytext); + DESCRIPTION_COLOR = getResources().getColor(R.color.primarytext_light); CHART_TEXT_COLOR = getResources().getColor(R.color.secondarytext); - LEGEND_TEXT_COLOR = getResources().getColor(R.color.primarytext); + LEGEND_TEXT_COLOR = getResources().getColor(R.color.primarytext_light); HEARTRATE_COLOR = getResources().getColor(R.color.chart_heartrate); HEARTRATE_FILL_COLOR = getResources().getColor(R.color.chart_heartrate_fill); AK_ACTIVITY_COLOR = getResources().getColor(R.color.chart_activity_light); diff --git a/app/src/main/res/values-v21/styles.xml b/app/src/main/res/values-v21/styles.xml deleted file mode 100644 index 80bee978..00000000 --- a/app/src/main/res/values-v21/styles.xml +++ /dev/null @@ -1,32 +0,0 @@ - - - - - diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 5f53994c..ac484db2 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -7,7 +7,8 @@ #f0f03000 #0091ea - #ff000000 + #000000 + #ffffff #ff808080 #1f000000 diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 1bcf060c..5d6ea28d 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -1,10 +1,29 @@ + + + + From 367aced03d530d5b9741f1e890697df57317d4e0 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Thu, 14 Apr 2016 15:34:53 +0200 Subject: [PATCH 13/19] also use theme in settings --- .../gadgetbridge/activities/AbstractSettingsActivity.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AbstractSettingsActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AbstractSettingsActivity.java index d9a3b1c3..2d62ce04 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AbstractSettingsActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AbstractSettingsActivity.java @@ -20,6 +20,9 @@ import android.view.ViewGroup; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import nodomain.freeyourgadget.gadgetbridge.GBApplication; +import nodomain.freeyourgadget.gadgetbridge.R; + /** * A settings activity with support for preferences directly displaying their value. * If you combine such preferences with a custom OnPreferenceChangeListener, you have @@ -86,6 +89,11 @@ public abstract class AbstractSettingsActivity extends PreferenceActivity { @Override protected void onCreate(Bundle savedInstanceState) { + if (GBApplication.isDarkThemeEnabled()) { + setTheme(R.style.GadgetbridgeThemeDark); + } else { + setTheme(R.style.GadgetbridgeTheme); + } getDelegate().installViewFactory(); getDelegate().onCreate(savedInstanceState); super.onCreate(savedInstanceState); From f76a1ba16fe490d9d01529607b27b8138c8b1185 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Thu, 14 Apr 2016 16:15:58 +0200 Subject: [PATCH 14/19] allow to switch to dark theme im settings --- .../freeyourgadget/gadgetbridge/GBApplication.java | 10 +++------- app/src/main/res/values/arrays.xml | 11 +++++++++++ app/src/main/res/values/strings.xml | 3 +++ app/src/main/res/xml/preferences.xml | 7 +++++++ 4 files changed, 24 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBApplication.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBApplication.java index a9ffd273..1aa62200 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBApplication.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBApplication.java @@ -195,11 +195,7 @@ public class GBApplication extends Application { public static void releaseDB() { dbLock.unlock(); } - - public static boolean isRunningOnKitkatOrLater() { - return VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT; - } - + public static boolean isRunningLollipopOrLater() { return VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP; } @@ -299,7 +295,7 @@ public class GBApplication extends Application { editor.putString(PREFS_VERSION, Integer.toString(CURRENT_PREFS_VERSION)); break; } - editor.commit(); + editor.apply(); } public static LimitedQueue getIDSenderLookup() { @@ -307,6 +303,6 @@ public class GBApplication extends Application { } public static boolean isDarkThemeEnabled() { - return false; + return sharedPrefs.getString("pref_key_theme", context.getString(R.string.pref_theme_value_light)).equals(context.getString(R.string.pref_theme_value_dark)); } } diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index 1f5cfa29..937c29f2 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -1,5 +1,16 @@ + + @string/pref_theme_light + @string/pref_theme_dark + + + @string/pref_theme_value_light + @string/pref_theme_value_dark + + light + dark + @string/always @string/when_screen_off diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index fa365a9b..5f43f764 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -39,6 +39,9 @@ Date and Time Sync time Sync time to device when connecting and when time or timezone changes on Android + Theme + Light + Dark Notifications Repetitions diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index 60eb7c5f..4d49eba1 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -11,6 +11,13 @@ android:defaultValue="default" android:key="audio_player" android:title="@string/pref_title_audo_player" /> + Date: Thu, 14 Apr 2016 16:44:44 +0200 Subject: [PATCH 15/19] use android:summary="%s" for ListPreferences --- .../gadgetbridge/GBApplication.java | 2 +- .../activities/SettingsActivity.java | 6 ------ .../miband/MiBandPreferencesActivity.java | 6 ------ app/src/main/res/xml/miband_preferences.xml | 18 ++++++++++++------ app/src/main/res/xml/preferences.xml | 18 ++++++++++++------ 5 files changed, 25 insertions(+), 25 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBApplication.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBApplication.java index 1aa62200..f292133a 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBApplication.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBApplication.java @@ -195,7 +195,7 @@ public class GBApplication extends Application { public static void releaseDB() { dbLock.unlock(); } - + public static boolean isRunningLollipopOrLater() { return VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP; } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/SettingsActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/SettingsActivity.java index 34942ef2..d541af9c 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/SettingsActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/SettingsActivity.java @@ -133,11 +133,6 @@ public class SettingsActivity extends AbstractSettingsActivity { @Override protected String[] getPreferenceKeysWithSummary() { return new String[]{ - "audio_player", - "notification_mode_calls", - "notification_mode_sms", - "notification_mode_k9mail", - "pebble_activitytracker", "pebble_emu_addr", "pebble_emu_port", "pebble_reconnect_attempts", @@ -159,7 +154,6 @@ public class SettingsActivity extends AbstractSettingsActivity { "canned_reply_15", "canned_reply_16", PREF_USER_YEAR_OF_BIRTH, - PREF_USER_GENDER, PREF_USER_HEIGHT_CM, PREF_USER_WEIGHT_KG, PREF_USER_SLEEP_DURATION, diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandPreferencesActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandPreferencesActivity.java index 7ef19b80..919e7d2c 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandPreferencesActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandPreferencesActivity.java @@ -59,20 +59,14 @@ public class MiBandPreferencesActivity extends AbstractSettingsActivity { protected String[] getPreferenceKeysWithSummary() { return new String[]{ PREF_USER_ALIAS, - PREF_MIBAND_WEARSIDE, PREF_MIBAND_ADDRESS, PREF_MIBAND_FITNESS_GOAL, PREF_MIBAND_DONT_ACK_TRANSFER, PREF_MIBAND_RESERVE_ALARM_FOR_CALENDAR, - getNotificationPrefKey(VIBRATION_PROFILE, ORIGIN_SMS), getNotificationPrefKey(VIBRATION_COUNT, ORIGIN_SMS), - getNotificationPrefKey(VIBRATION_PROFILE, ORIGIN_INCOMING_CALL), getNotificationPrefKey(VIBRATION_COUNT, ORIGIN_INCOMING_CALL), - getNotificationPrefKey(VIBRATION_PROFILE, ORIGIN_K9MAIL), getNotificationPrefKey(VIBRATION_COUNT, ORIGIN_K9MAIL), - getNotificationPrefKey(VIBRATION_PROFILE, ORIGIN_PEBBLEMSG), getNotificationPrefKey(VIBRATION_COUNT, ORIGIN_PEBBLEMSG), - getNotificationPrefKey(VIBRATION_PROFILE, ORIGIN_GENERIC), getNotificationPrefKey(VIBRATION_COUNT, ORIGIN_GENERIC), }; } diff --git a/app/src/main/res/xml/miband_preferences.xml b/app/src/main/res/xml/miband_preferences.xml index 042cd8e1..c544d254 100644 --- a/app/src/main/res/xml/miband_preferences.xml +++ b/app/src/main/res/xml/miband_preferences.xml @@ -14,7 +14,8 @@ android:entries="@array/wearside" android:entryValues="@array/wearside_values" android:key="mi_wearside" - android:title="@string/miband_prefs_wearside" /> + android:title="@string/miband_prefs_wearside" + android:summary="%s" /> + android:title="@string/miband_prefs_vibration" + android:summary="%s" /> + android:title="@string/miband_prefs_vibration" + android:summary="%s" /> + android:title="@string/miband_prefs_vibration" + android:summary="%s" /> + android:title="@string/miband_prefs_vibration" + android:summary="%s" /> + android:title="@string/miband_prefs_vibration" + android:summary="%s" /> + android:title="@string/pref_title_audo_player" + android:summary="%s" /> + android:title="@string/pref_title_notifications_call" + android:summary="%s" /> + android:title="@string/pref_title_notifications_sms" + android:summary="%s" /> + android:title="@string/pref_title_notifications_k9mail" + android:summary="%s" /> + android:title="@string/activity_prefs_gender" + android:summary="%s" /> + android:title="@string/pref_title_pebble_activitytracker" + android:summary="%s" /> Date: Thu, 14 Apr 2016 17:04:49 +0200 Subject: [PATCH 16/19] allow dark theme in charts activity. The charts however are still the same --- .../activities/AbstractGBFragmentActivity.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AbstractGBFragmentActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AbstractGBFragmentActivity.java index b76e50c3..dcb87d89 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AbstractGBFragmentActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AbstractGBFragmentActivity.java @@ -5,6 +5,9 @@ import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentPagerAdapter; +import nodomain.freeyourgadget.gadgetbridge.GBApplication; +import nodomain.freeyourgadget.gadgetbridge.R; + /** * A base activity that supports paging through fragments by swiping. * Subclasses will have to add a ViewPager to their layout and add something @@ -31,6 +34,12 @@ public abstract class AbstractGBFragmentActivity extends FragmentActivity { @Override protected void onCreate(Bundle savedInstanceState) { + if (GBApplication.isDarkThemeEnabled()) { + setTheme(R.style.GadgetbridgeThemeDark); + } else { + setTheme(R.style.GadgetbridgeTheme); + } + super.onCreate(savedInstanceState); // Create the adapter that will return a fragment for each of the three From a9b75a63b348568b8d935906e91bac2d8e8af8c3 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Thu, 14 Apr 2016 17:16:43 +0200 Subject: [PATCH 17/19] simply derive AbstractGBFragmentActivity from GBActivity instead of FragmentActivity This fixes the Actionbar being invisible --- .../activities/AbstractGBFragmentActivity.java | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AbstractGBFragmentActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AbstractGBFragmentActivity.java index dcb87d89..ba2e5a7f 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AbstractGBFragmentActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AbstractGBFragmentActivity.java @@ -1,13 +1,9 @@ package nodomain.freeyourgadget.gadgetbridge.activities; import android.os.Bundle; -import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentPagerAdapter; -import nodomain.freeyourgadget.gadgetbridge.GBApplication; -import nodomain.freeyourgadget.gadgetbridge.R; - /** * A base activity that supports paging through fragments by swiping. * Subclasses will have to add a ViewPager to their layout and add something @@ -21,7 +17,7 @@ import nodomain.freeyourgadget.gadgetbridge.R; * * @see AbstractGBFragment */ -public abstract class AbstractGBFragmentActivity extends FragmentActivity { +public abstract class AbstractGBFragmentActivity extends GBActivity { /** * The {@link android.support.v4.view.PagerAdapter} that will provide * fragments for each of the sections. We use a @@ -34,12 +30,6 @@ public abstract class AbstractGBFragmentActivity extends FragmentActivity { @Override protected void onCreate(Bundle savedInstanceState) { - if (GBApplication.isDarkThemeEnabled()) { - setTheme(R.style.GadgetbridgeThemeDark); - } else { - setTheme(R.style.GadgetbridgeTheme); - } - super.onCreate(savedInstanceState); // Create the adapter that will return a fragment for each of the three From a9e7cdcaa7c62731aeab8728abb9ed3b791a5adc Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Thu, 14 Apr 2016 17:41:04 +0200 Subject: [PATCH 18/19] use some colors from the theme for charts activity --- .../activities/charts/AbstractChartFragment.java | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/AbstractChartFragment.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/AbstractChartFragment.java index 9378d2a6..41c61114 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/AbstractChartFragment.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/AbstractChartFragment.java @@ -4,11 +4,13 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.res.Resources; import android.os.AsyncTask; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v4.app.FragmentActivity; import android.support.v4.content.LocalBroadcastManager; +import android.util.TypedValue; import android.view.View; import com.github.mikephil.charting.charts.BarLineChartBase; @@ -149,10 +151,14 @@ public abstract class AbstractChartFragment extends AbstractGBFragment { } protected void init() { - BACKGROUND_COLOR = getResources().getColor(R.color.background_material_light); - DESCRIPTION_COLOR = getResources().getColor(R.color.primarytext_light); + TypedValue typedValue = new TypedValue(); + Resources.Theme theme = getContext().getTheme(); + theme.resolveAttribute(android.R.attr.background, typedValue, true); + BACKGROUND_COLOR = typedValue.data; + theme.resolveAttribute(android.R.attr.textColor, typedValue, true); + LEGEND_TEXT_COLOR = DESCRIPTION_COLOR = typedValue.data; + CHART_TEXT_COLOR = getResources().getColor(R.color.secondarytext); - LEGEND_TEXT_COLOR = getResources().getColor(R.color.primarytext_light); HEARTRATE_COLOR = getResources().getColor(R.color.chart_heartrate); HEARTRATE_FILL_COLOR = getResources().getColor(R.color.chart_heartrate_fill); AK_ACTIVITY_COLOR = getResources().getColor(R.color.chart_activity_light); @@ -704,7 +710,7 @@ public abstract class AbstractChartFragment extends AbstractGBFragment { return (int) ((date.getTime() / 1000)); } - public static class DefaultChartsData extends ChartsData{ + public static class DefaultChartsData extends ChartsData { private final CombinedData combinedData; public DefaultChartsData(CombinedData combinedData) { From a460049a1b56180c192444792ce1788da5bdc1b3 Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Thu, 14 Apr 2016 23:23:06 +0200 Subject: [PATCH 19/19] Sort by label and blacklist status, hopefully fast enough #275 --- .../activities/AppBlacklistActivity.java | 40 +++++++++++-------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppBlacklistActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppBlacklistActivity.java index 21e8393a..adf33ddc 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppBlacklistActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppBlacklistActivity.java @@ -27,6 +27,7 @@ import org.slf4j.LoggerFactory; import java.util.Collections; import java.util.Comparator; +import java.util.IdentityHashMap; import java.util.List; import nodomain.freeyourgadget.gadgetbridge.GBApplication; @@ -59,6 +60,29 @@ public class AppBlacklistActivity extends GBActivity { final List packageList = pm.getInstalledApplications(PackageManager.GET_META_DATA); ListView appListView = (ListView) findViewById(R.id.appListView); + // sort the package list by label and blacklist status + final IdentityHashMap nameMap = new IdentityHashMap<>(packageList.size()); + for (ApplicationInfo ai : packageList) { + CharSequence name = pm.getApplicationLabel(ai); + if (name == null) { + name = ai.packageName; + } + if (GBApplication.blacklist.contains(ai.packageName)) { + // sort blacklisted first by prefixing with a '!' + name = "!" + name; + } + nameMap.put(ai, name.toString()); + } + + Collections.sort(packageList, new Comparator() { + @Override + public int compare(ApplicationInfo ai1, ApplicationInfo ai2) { + final String s1 = nameMap.get(ai1); + final String s2 = nameMap.get(ai2); + return s1.compareTo(s2); + } + }); + final ArrayAdapter adapter = new ArrayAdapter(this, R.layout.item_with_checkbox, packageList) { @Override public View getView(int position, View view, ViewGroup parent) { @@ -79,22 +103,6 @@ public class AppBlacklistActivity extends GBActivity { checkbox.setChecked(GBApplication.blacklist.contains(appInfo.packageName)); - Collections.sort(packageList, new Comparator() { - @Override - public int compare(ApplicationInfo ai1, ApplicationInfo ai2) { - boolean blacklisted1 = GBApplication.blacklist.contains(ai1.packageName); - boolean blacklisted2 = GBApplication.blacklist.contains(ai2.packageName); - - if ((blacklisted1 && blacklisted2) || (!blacklisted1 && !blacklisted2)) { - // both blacklisted or both not blacklisted = sort by alphabet - return ai1.packageName.compareTo(ai2.packageName); - } else if (blacklisted1) { - return -1; - } else { - return 1; - } - } - }); return view; } };