From 656c912e97a02bf2dafd6315e844aea466132de9 Mon Sep 17 00:00:00 2001 From: krzys-h Date: Sat, 28 Dec 2019 14:11:42 +0100 Subject: [PATCH] Da Fit: Add device settings --- .../devices/dafit/DaFitConstants.java | 11 + .../devices/dafit/DaFitDeviceCoordinator.java | 59 ++- .../devices/dafit/settings/DaFitEnum.java | 21 + .../settings/DaFitEnumDeviceVersion.java | 33 ++ .../dafit/settings/DaFitEnumDominantHand.java | 33 ++ .../dafit/settings/DaFitEnumLanguage.java | 56 +++ .../dafit/settings/DaFitEnumMetricSystem.java | 33 ++ .../dafit/settings/DaFitEnumTimeSystem.java | 33 ++ .../devices/dafit/settings/DaFitSetting.java | 32 ++ .../dafit/settings/DaFitSettingBool.java | 37 ++ .../dafit/settings/DaFitSettingByte.java | 35 ++ .../dafit/settings/DaFitSettingEnum.java | 54 +++ .../dafit/settings/DaFitSettingInt.java | 43 ++ .../dafit/settings/DaFitSettingLanguage.java | 63 +++ .../settings/DaFitSettingRemindersToMove.java | 74 ++++ .../dafit/settings/DaFitSettingTimeRange.java | 76 ++++ .../dafit/settings/DaFitSettingUserInfo.java | 44 ++ .../devices/dafit/DaFitDeviceSupport.java | 402 +++++++++++++++++- .../devices/dafit/QuerySettingsOperation.java | 137 ++++++ .../res/drawable/ic_measurement_system.xml | 5 + app/src/main/res/drawable/ic_sitting.xml | 5 + app/src/main/res/values/arrays.xml | 32 ++ app/src/main/res/values/strings.xml | 7 + .../devicesettings_dafit_device_version.xml | 10 + .../res/xml/devicesettings_dafit_language.xml | 9 + ...evicesettings_dafit_sedentary_reminder.xml | 61 +++ .../xml/devicesettings_dafit_watchface.xml | 11 + ...devicesettings_donotdisturb_no_auto_v2.xml | 39 ++ .../xml/devicesettings_measurementsystem.xml | 12 + .../res/xml/devicesettings_personalinfo.xml | 13 + 30 files changed, 1477 insertions(+), 3 deletions(-) create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/dafit/settings/DaFitEnum.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/dafit/settings/DaFitEnumDeviceVersion.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/dafit/settings/DaFitEnumDominantHand.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/dafit/settings/DaFitEnumLanguage.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/dafit/settings/DaFitEnumMetricSystem.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/dafit/settings/DaFitEnumTimeSystem.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/dafit/settings/DaFitSetting.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/dafit/settings/DaFitSettingBool.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/dafit/settings/DaFitSettingByte.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/dafit/settings/DaFitSettingEnum.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/dafit/settings/DaFitSettingInt.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/dafit/settings/DaFitSettingLanguage.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/dafit/settings/DaFitSettingRemindersToMove.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/dafit/settings/DaFitSettingTimeRange.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/dafit/settings/DaFitSettingUserInfo.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/dafit/QuerySettingsOperation.java create mode 100644 app/src/main/res/drawable/ic_measurement_system.xml create mode 100644 app/src/main/res/drawable/ic_sitting.xml create mode 100644 app/src/main/res/xml/devicesettings_dafit_device_version.xml create mode 100644 app/src/main/res/xml/devicesettings_dafit_language.xml create mode 100644 app/src/main/res/xml/devicesettings_dafit_sedentary_reminder.xml create mode 100644 app/src/main/res/xml/devicesettings_dafit_watchface.xml create mode 100644 app/src/main/res/xml/devicesettings_donotdisturb_no_auto_v2.xml create mode 100644 app/src/main/res/xml/devicesettings_measurementsystem.xml create mode 100644 app/src/main/res/xml/devicesettings_personalinfo.xml diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/dafit/DaFitConstants.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/dafit/DaFitConstants.java index 32d4021de..9115247d3 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/dafit/DaFitConstants.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/dafit/DaFitConstants.java @@ -369,4 +369,15 @@ public class DaFitConstants { return DaFitConstants.WEATHER_HAZE; } } + + + public static final String PREF_WATCH_FACE = "dafit_watch_face"; + public static final String PREF_LANGUAGE = "dafit_language"; + public static final String PREF_LANGUAGE_SUPPORT = "dafit_language_supported"; + public static final String PREF_DEVICE_VERSION = "dafit_device_version"; + public static final String PREF_SEDENTARY_REMINDER = "sedentary_reminder"; + public static final String PREF_SEDENTARY_REMINDER_PERIOD = "sedentary_reminder_period"; + public static final String PREF_SEDENTARY_REMINDER_STEPS = "sedentary_reminder_steps"; + public static final String PREF_SEDENTARY_REMINDER_START = "sedentary_reminder_start"; + public static final String PREF_SEDENTARY_REMINDER_END = "sedentary_reminder_end"; } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/dafit/DaFitDeviceCoordinator.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/dafit/DaFitDeviceCoordinator.java index a46a76d4d..a4bd39b7a 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/dafit/DaFitDeviceCoordinator.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/dafit/DaFitDeviceCoordinator.java @@ -31,9 +31,22 @@ import java.util.Collection; import java.util.Collections; import nodomain.freeyourgadget.gadgetbridge.GBException; +import nodomain.freeyourgadget.gadgetbridge.R; import nodomain.freeyourgadget.gadgetbridge.devices.AbstractDeviceCoordinator; import nodomain.freeyourgadget.gadgetbridge.devices.InstallHandler; import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider; +import nodomain.freeyourgadget.gadgetbridge.devices.dafit.settings.DaFitEnumDeviceVersion; +import nodomain.freeyourgadget.gadgetbridge.devices.dafit.settings.DaFitEnumMetricSystem; +import nodomain.freeyourgadget.gadgetbridge.devices.dafit.settings.DaFitEnumTimeSystem; +import nodomain.freeyourgadget.gadgetbridge.devices.dafit.settings.DaFitSetting; +import nodomain.freeyourgadget.gadgetbridge.devices.dafit.settings.DaFitSettingBool; +import nodomain.freeyourgadget.gadgetbridge.devices.dafit.settings.DaFitSettingByte; +import nodomain.freeyourgadget.gadgetbridge.devices.dafit.settings.DaFitSettingEnum; +import nodomain.freeyourgadget.gadgetbridge.devices.dafit.settings.DaFitSettingInt; +import nodomain.freeyourgadget.gadgetbridge.devices.dafit.settings.DaFitSettingLanguage; +import nodomain.freeyourgadget.gadgetbridge.devices.dafit.settings.DaFitSettingRemindersToMove; +import nodomain.freeyourgadget.gadgetbridge.devices.dafit.settings.DaFitSettingTimeRange; +import nodomain.freeyourgadget.gadgetbridge.devices.dafit.settings.DaFitSettingUserInfo; import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession; import nodomain.freeyourgadget.gadgetbridge.entities.Device; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; @@ -187,8 +200,52 @@ public class DaFitDeviceCoordinator extends AbstractDeviceCoordinator { @Override public boolean supportsUnicodeEmojis() { return false; } + private static final DaFitSetting[] DAFIT_SETTINGS = new DaFitSetting[] { + new DaFitSettingUserInfo("USER_INFO", DaFitConstants.CMD_SET_USER_INFO), + new DaFitSettingByte("STEP_LENGTH", (byte)-1, DaFitConstants.CMD_SET_STEP_LENGTH), + // (*) new DaFitSettingEnum<>("DOMINANT_HAND", DaFitConstants.CMD_QUERY_DOMINANT_HAND, DaFitConstants.CMD_SET_DOMINANT_HAND, DaFitEnumDominantHand.class), + new DaFitSettingInt("GOAL_STEP", DaFitConstants.CMD_QUERY_GOAL_STEP, DaFitConstants.CMD_SET_GOAL_STEP), + + new DaFitSettingEnum<>("DEVICE_VERSION", DaFitConstants.CMD_QUERY_DEVICE_VERSION, DaFitConstants.CMD_SET_DEVICE_VERSION, DaFitEnumDeviceVersion.class), + new DaFitSettingLanguage("DEVICE_LANGUAGE", DaFitConstants.CMD_QUERY_DEVICE_LANGUAGE, DaFitConstants.CMD_SET_DEVICE_LANGUAGE), + new DaFitSettingEnum<>("TIME_SYSTEM", DaFitConstants.CMD_QUERY_TIME_SYSTEM, DaFitConstants.CMD_SET_TIME_SYSTEM, DaFitEnumTimeSystem.class), + new DaFitSettingEnum<>("METRIC_SYSTEM", DaFitConstants.CMD_QUERY_METRIC_SYSTEM, DaFitConstants.CMD_SET_METRIC_SYSTEM, DaFitEnumMetricSystem.class), + + // (*) new DaFitSetting("DISPLAY_DEVICE_FUNCTION", DaFitConstants.CMD_QUERY_DISPLAY_DEVICE_FUNCTION, DaFitConstants.CMD_SET_DISPLAY_DEVICE_FUNCTION), + // (*) new DaFitSetting("SUPPORT_WATCH_FACE", DaFitConstants.CMD_QUERY_SUPPORT_WATCH_FACE, (byte)-1), + // (*) new DaFitSetting("WATCH_FACE_LAYOUT", DaFitConstants.CMD_QUERY_WATCH_FACE_LAYOUT, DaFitConstants.CMD_SET_WATCH_FACE_LAYOUT), + new DaFitSettingByte("DISPLAY_WATCH_FACE", DaFitConstants.CMD_QUERY_DISPLAY_WATCH_FACE, DaFitConstants.CMD_SET_DISPLAY_WATCH_FACE), + new DaFitSettingBool("OTHER_MESSAGE_STATE", DaFitConstants.CMD_QUERY_OTHER_MESSAGE_STATE, DaFitConstants.CMD_SET_OTHER_MESSAGE_STATE), + + new DaFitSettingBool("QUICK_VIEW", DaFitConstants.CMD_QUERY_QUICK_VIEW, DaFitConstants.CMD_SET_QUICK_VIEW), + new DaFitSettingTimeRange("QUICK_VIEW_TIME", DaFitConstants.CMD_QUERY_QUICK_VIEW_TIME, DaFitConstants.CMD_SET_QUICK_VIEW_TIME), + new DaFitSettingBool("SEDENTARY_REMINDER", DaFitConstants.CMD_QUERY_SEDENTARY_REMINDER, DaFitConstants.CMD_SET_SEDENTARY_REMINDER), + new DaFitSettingRemindersToMove("REMINDERS_TO_MOVE_PERIOD", DaFitConstants.CMD_QUERY_REMINDERS_TO_MOVE_PERIOD, DaFitConstants.CMD_SET_REMINDERS_TO_MOVE_PERIOD), + new DaFitSettingTimeRange("DO_NOT_DISTURB_TIME", DaFitConstants.CMD_QUERY_DO_NOT_DISTURB_TIME, DaFitConstants.CMD_SET_DO_NOT_DISTURB_TIME), + // (*) new DaFitSetting("PSYCHOLOGICAL_PERIOD", DaFitConstants.CMD_QUERY_PSYCHOLOGICAL_PERIOD, DaFitConstants.CMD_SET_PSYCHOLOGICAL_PERIOD), + + new DaFitSettingBool("BREATHING_LIGHT", DaFitConstants.CMD_QUERY_BREATHING_LIGHT, DaFitConstants.CMD_SET_BREATHING_LIGHT) + }; + @Override public int[] getSupportedDeviceSpecificSettings(GBDevice device) { - return null; + return new int[]{ + R.xml.devicesettings_personalinfo, + //R.xml.devicesettings_steplength, // TODO is this needed? does it work? write-only so hard to tell + R.xml.devicesettings_dafit_device_version, + R.xml.devicesettings_dafit_language, + R.xml.devicesettings_timeformat, + R.xml.devicesettings_measurementsystem, + R.xml.devicesettings_dafit_watchface, + //R.xml.devicesettings_dafit_othermessage, // not implemented because this doesn't really do anything on the watch side, only enables/disables sending of "other" notifications in the app (no idea why they store the setting on the watch) + R.xml.devicesettings_liftwrist_display, + R.xml.devicesettings_dafit_sedentary_reminder, + R.xml.devicesettings_donotdisturb_no_auto_v2, + //R.xml.devicesettings_dafit_breathinglight, // No idea what this does but it doesn't seem to change anything + }; + } + + public DaFitSetting[] getSupportedSettings() { + return DAFIT_SETTINGS; } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/dafit/settings/DaFitEnum.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/dafit/settings/DaFitEnum.java new file mode 100644 index 000000000..33f3bdc3e --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/dafit/settings/DaFitEnum.java @@ -0,0 +1,21 @@ +/* Copyright (C) 2019 krzys_h + + This file is part of Gadgetbridge. + + Gadgetbridge is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Gadgetbridge is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . */ +package nodomain.freeyourgadget.gadgetbridge.devices.dafit.settings; + +public interface DaFitEnum { + byte value(); +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/dafit/settings/DaFitEnumDeviceVersion.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/dafit/settings/DaFitEnumDeviceVersion.java new file mode 100644 index 000000000..b33ca49ae --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/dafit/settings/DaFitEnumDeviceVersion.java @@ -0,0 +1,33 @@ +/* Copyright (C) 2019 krzys_h + + This file is part of Gadgetbridge. + + Gadgetbridge is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Gadgetbridge is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . */ +package nodomain.freeyourgadget.gadgetbridge.devices.dafit.settings; + +public enum DaFitEnumDeviceVersion implements DaFitEnum { + CHINESE_EDITION((byte)0), + INTERNATIONAL_EDITION((byte)1); + + public final byte value; + + DaFitEnumDeviceVersion(byte value) { + this.value = value; + } + + @Override + public byte value() { + return value; + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/dafit/settings/DaFitEnumDominantHand.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/dafit/settings/DaFitEnumDominantHand.java new file mode 100644 index 000000000..c05ceabc1 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/dafit/settings/DaFitEnumDominantHand.java @@ -0,0 +1,33 @@ +/* Copyright (C) 2019 krzys_h + + This file is part of Gadgetbridge. + + Gadgetbridge is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Gadgetbridge is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . */ +package nodomain.freeyourgadget.gadgetbridge.devices.dafit.settings; + +public enum DaFitEnumDominantHand implements DaFitEnum { + LEFT_HAND((byte)0), + RIGHT_HAND((byte)1); + + public final byte value; + + DaFitEnumDominantHand(byte value) { + this.value = value; + } + + @Override + public byte value() { + return value; + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/dafit/settings/DaFitEnumLanguage.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/dafit/settings/DaFitEnumLanguage.java new file mode 100644 index 000000000..5b94f1736 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/dafit/settings/DaFitEnumLanguage.java @@ -0,0 +1,56 @@ +/* Copyright (C) 2019 krzys_h + + This file is part of Gadgetbridge. + + Gadgetbridge is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Gadgetbridge is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . */ +package nodomain.freeyourgadget.gadgetbridge.devices.dafit.settings; + +public enum DaFitEnumLanguage implements DaFitEnum { + LANGUAGE_ENGLISH((byte)0), + LANGUAGE_CHINESE((byte)1), + LANGUAGE_JAPANESE((byte)2), + LANGUAGE_KOREAN((byte)3), + LANGUAGE_GERMAN((byte)4), + LANGUAGE_FRENCH((byte)5), + LANGUAGE_SPANISH((byte)6), + LANGUAGE_ARABIC((byte)7), + LANGUAGE_RUSSIAN((byte)8), + LANGUAGE_TRADITIONAL((byte)9), + LANGUAGE_UKRAINIAN((byte)10), + LANGUAGE_ITALIAN((byte)11), + LANGUAGE_PORTUGUESE((byte)12), + LANGUAGE_DUTCH((byte)13), + LANGUAGE_POLISH((byte)14), + LANGUAGE_SWEDISH((byte)15), + LANGUAGE_FINNISH((byte)16), + LANGUAGE_DANISH((byte)17), + LANGUAGE_NORWEGIAN((byte)18), + LANGUAGE_HUNGARIAN((byte)19), + LANGUAGE_CZECH((byte)20), + LANGUAGE_BULGARIAN((byte)21), + LANGUAGE_ROMANIAN((byte)22), + LANGUAGE_SLOVAK_LANGUAGE((byte)23), + LANGUAGE_LATVIAN((byte)24); + + public final byte value; + + DaFitEnumLanguage(byte value) { + this.value = value; + } + + @Override + public byte value() { + return value; + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/dafit/settings/DaFitEnumMetricSystem.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/dafit/settings/DaFitEnumMetricSystem.java new file mode 100644 index 000000000..570343968 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/dafit/settings/DaFitEnumMetricSystem.java @@ -0,0 +1,33 @@ +/* Copyright (C) 2019 krzys_h + + This file is part of Gadgetbridge. + + Gadgetbridge is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Gadgetbridge is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . */ +package nodomain.freeyourgadget.gadgetbridge.devices.dafit.settings; + +public enum DaFitEnumMetricSystem implements DaFitEnum { + METRIC_SYSTEM((byte)0), + IMPERIAL_SYSTEM((byte)1); + + public final byte value; + + DaFitEnumMetricSystem(byte value) { + this.value = value; + } + + @Override + public byte value() { + return value; + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/dafit/settings/DaFitEnumTimeSystem.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/dafit/settings/DaFitEnumTimeSystem.java new file mode 100644 index 000000000..68e5a26dd --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/dafit/settings/DaFitEnumTimeSystem.java @@ -0,0 +1,33 @@ +/* Copyright (C) 2019 krzys_h + + This file is part of Gadgetbridge. + + Gadgetbridge is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Gadgetbridge is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . */ +package nodomain.freeyourgadget.gadgetbridge.devices.dafit.settings; + +public enum DaFitEnumTimeSystem implements DaFitEnum { + TIME_SYSTEM_12((byte)0), + TIME_SYSTEM_24((byte)1); + + public final byte value; + + DaFitEnumTimeSystem(byte value) { + this.value = value; + } + + @Override + public byte value() { + return value; + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/dafit/settings/DaFitSetting.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/dafit/settings/DaFitSetting.java new file mode 100644 index 000000000..5638a5ab2 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/dafit/settings/DaFitSetting.java @@ -0,0 +1,32 @@ +/* Copyright (C) 2019 krzys_h + + This file is part of Gadgetbridge. + + Gadgetbridge is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Gadgetbridge is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . */ +package nodomain.freeyourgadget.gadgetbridge.devices.dafit.settings; + +public abstract class DaFitSetting { + public final String name; + public final byte cmdQuery; + public final byte cmdSet; + + public DaFitSetting(String name, byte cmdQuery, byte cmdSet) { + this.name = name; + this.cmdQuery = cmdQuery; + this.cmdSet = cmdSet; + } + + public abstract byte[] encode(T value); + public abstract T decode(byte[] data); +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/dafit/settings/DaFitSettingBool.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/dafit/settings/DaFitSettingBool.java new file mode 100644 index 000000000..515aa6b67 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/dafit/settings/DaFitSettingBool.java @@ -0,0 +1,37 @@ +/* Copyright (C) 2019 krzys_h + + This file is part of Gadgetbridge. + + Gadgetbridge is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Gadgetbridge is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . */ +package nodomain.freeyourgadget.gadgetbridge.devices.dafit.settings; + +public class DaFitSettingBool extends DaFitSetting { + public DaFitSettingBool(String name, byte cmdQuery, byte cmdSet) { + super(name, cmdQuery, cmdSet); + } + + @Override + public byte[] encode(Boolean value) { + return new byte[] { value ? (byte)1 : (byte)0 }; + } + + @Override + public Boolean decode(byte[] data) { + if (data.length != 1) + throw new IllegalArgumentException("Wrong data length, should be 1, was " + data.length); + if (data[0] != 0 && data[0] != 1) + throw new IllegalArgumentException("Expected a boolean, got " + data[0]); + return data[0] != 0; + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/dafit/settings/DaFitSettingByte.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/dafit/settings/DaFitSettingByte.java new file mode 100644 index 000000000..fb5fd6849 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/dafit/settings/DaFitSettingByte.java @@ -0,0 +1,35 @@ +/* Copyright (C) 2019 krzys_h + + This file is part of Gadgetbridge. + + Gadgetbridge is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Gadgetbridge is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . */ +package nodomain.freeyourgadget.gadgetbridge.devices.dafit.settings; + +public class DaFitSettingByte extends DaFitSetting { + public DaFitSettingByte(String name, byte cmdQuery, byte cmdSet) { + super(name, cmdQuery, cmdSet); + } + + @Override + public byte[] encode(Byte value) { + return new byte[] { value }; + } + + @Override + public Byte decode(byte[] data) { + if (data.length != 1) + throw new IllegalArgumentException("Wrong data length, should be 1, was " + data.length); + return data[0]; + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/dafit/settings/DaFitSettingEnum.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/dafit/settings/DaFitSettingEnum.java new file mode 100644 index 000000000..50791f735 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/dafit/settings/DaFitSettingEnum.java @@ -0,0 +1,54 @@ +/* Copyright (C) 2019 krzys_h + + This file is part of Gadgetbridge. + + Gadgetbridge is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Gadgetbridge is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . */ +package nodomain.freeyourgadget.gadgetbridge.devices.dafit.settings; + +public class DaFitSettingEnum & DaFitEnum> extends DaFitSetting { + protected final Class clazz; + + public DaFitSettingEnum(String name, byte cmdQuery, byte cmdSet, Class clazz) { + super(name, cmdQuery, cmdSet); + this.clazz = clazz; + } + + public T findByValue(byte value) + { + for (T e : clazz.getEnumConstants()) { + if (e.value() == value) { + return e; + } + } + + throw new IllegalArgumentException("No enum value for " + value); + } + + @Override + public byte[] encode(T value) { + return new byte[] { value.value() }; + } + + @Override + public T decode(byte[] data) { + if (data.length != 1) + throw new IllegalArgumentException("Wrong data length, should be 1, was " + data.length); + + return findByValue(data[0]); + } + + public T[] decodeSupportedValues(byte[] data) { + return clazz.getEnumConstants(); + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/dafit/settings/DaFitSettingInt.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/dafit/settings/DaFitSettingInt.java new file mode 100644 index 000000000..1ba6b0aed --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/dafit/settings/DaFitSettingInt.java @@ -0,0 +1,43 @@ +/* Copyright (C) 2019 krzys_h + + This file is part of Gadgetbridge. + + Gadgetbridge is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Gadgetbridge is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . */ +package nodomain.freeyourgadget.gadgetbridge.devices.dafit.settings; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +public class DaFitSettingInt extends DaFitSetting { + public DaFitSettingInt(String name, byte cmdQuery, byte cmdSet) { + super(name, cmdQuery, cmdSet); + } + + @Override + public byte[] encode(Integer value) { + ByteBuffer buffer = ByteBuffer.allocate(4); + buffer.order(ByteOrder.BIG_ENDIAN); // <- this is what happens when somebody in China designs a communication protocol + buffer.putInt(value); + return buffer.array(); + } + + @Override + public Integer decode(byte[] data) { + if (data.length != 4) + throw new IllegalArgumentException("Wrong data length, should be 4, was " + data.length); + ByteBuffer buffer = ByteBuffer.wrap(data); + buffer.order(ByteOrder.LITTLE_ENDIAN); // <- yes, it's different here + return buffer.getInt(); + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/dafit/settings/DaFitSettingLanguage.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/dafit/settings/DaFitSettingLanguage.java new file mode 100644 index 000000000..b3158133e --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/dafit/settings/DaFitSettingLanguage.java @@ -0,0 +1,63 @@ +/* Copyright (C) 2019 krzys_h + + This file is part of Gadgetbridge. + + Gadgetbridge is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Gadgetbridge is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . */ +package nodomain.freeyourgadget.gadgetbridge.devices.dafit.settings; + +import android.util.Pair; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; + +public class DaFitSettingLanguage extends DaFitSettingEnum { + public DaFitSettingLanguage(String name, byte cmdQuery, byte cmdSet) { + super(name, cmdQuery, cmdSet, DaFitEnumLanguage.class); + } + + private Pair decodeData(byte[] data) { + if (data.length != 5) + throw new IllegalArgumentException("Wrong data length, should be 5, was " + data.length); + + byte[] current = new byte[] { data[0] }; + byte[] supported = new byte[] { data[1], data[2], data[3], data[4] }; + + ByteBuffer buffer = ByteBuffer.wrap(supported); + int supportedNum = buffer.getInt(); + String supportedStr = new StringBuffer(Integer.toBinaryString(supportedNum)).reverse().toString(); + + DaFitEnumLanguage currentLanguage = super.decode(current); + List supportedLanguages = new ArrayList<>(); + for (DaFitEnumLanguage e : clazz.getEnumConstants()) { + if (e.value() >= supportedStr.length()) + continue; + if (Integer.parseInt(supportedStr.substring(e.value(), e.value() + 1)) != 0) + supportedLanguages.add(e); + } + + DaFitEnumLanguage[] supportedLanguagesArr = new DaFitEnumLanguage[supportedLanguages.size()]; + return Pair.create(currentLanguage, supportedLanguages.toArray(supportedLanguagesArr)); + } + + @Override + public DaFitEnumLanguage decode(byte[] data) { + return decodeData(data).first; + } + + @Override + public DaFitEnumLanguage[] decodeSupportedValues(byte[] data) { + return decodeData(data).second; + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/dafit/settings/DaFitSettingRemindersToMove.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/dafit/settings/DaFitSettingRemindersToMove.java new file mode 100644 index 000000000..765ad24d6 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/dafit/settings/DaFitSettingRemindersToMove.java @@ -0,0 +1,74 @@ +/* Copyright (C) 2019 krzys_h + + This file is part of Gadgetbridge. + + Gadgetbridge is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Gadgetbridge is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . */ +package nodomain.freeyourgadget.gadgetbridge.devices.dafit.settings; + +import java.nio.ByteBuffer; + +public class DaFitSettingRemindersToMove extends DaFitSetting { + public static class RemindersToMove { + public byte period; + public byte steps; + public byte start_h; + public byte end_h; + + public RemindersToMove() { + } + + public RemindersToMove(byte period, byte steps, byte start_h, byte end_h) { + this.period = period; + this.steps = steps; + this.start_h = start_h; + this.end_h = end_h; + } + + @Override + public String toString() { + return "RemindersToMove{" + + "period=" + period + + ", steps=" + steps + + ", start_h=" + start_h + + ", end_h=" + end_h + + '}'; + } + } + + public DaFitSettingRemindersToMove(String name, byte cmdQuery, byte cmdSet) { + super(name, cmdQuery, cmdSet); + } + + @Override + public byte[] encode(RemindersToMove value) { + ByteBuffer buffer = ByteBuffer.allocate(4); + buffer.put(value.period); + buffer.put(value.steps); + buffer.put(value.start_h); + buffer.put(value.end_h); + return buffer.array(); + } + + @Override + public RemindersToMove decode(byte[] data) { + if (data.length != 4) + throw new IllegalArgumentException("Wrong data length, should be 4, was " + data.length); + ByteBuffer buffer = ByteBuffer.wrap(data); + byte period = buffer.get(); + byte steps = buffer.get(); + byte start_h = buffer.get(); + byte end_h = buffer.get(); + return new RemindersToMove(period, steps, start_h, end_h); + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/dafit/settings/DaFitSettingTimeRange.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/dafit/settings/DaFitSettingTimeRange.java new file mode 100644 index 000000000..6e7fadeef --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/dafit/settings/DaFitSettingTimeRange.java @@ -0,0 +1,76 @@ +/* Copyright (C) 2019 krzys_h + + This file is part of Gadgetbridge. + + Gadgetbridge is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Gadgetbridge is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . */ +package nodomain.freeyourgadget.gadgetbridge.devices.dafit.settings; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +public class DaFitSettingTimeRange extends DaFitSetting { + public static class TimeRange { + public byte start_h; + public byte start_m; + public byte end_h; + public byte end_m; + + public TimeRange() { + } + + public TimeRange(byte start_h, byte start_m, byte end_h, byte end_m) { + this.start_h = start_h; + this.start_m = start_m; + this.end_h = end_h; + this.end_m = end_m; + } + + @Override + public String toString() { + return "TimeRange{" + + "start_h=" + start_h + + ", start_m=" + start_m + + ", end_h=" + end_h + + ", end_m=" + end_m + + '}'; + } + } + + public DaFitSettingTimeRange(String name, byte cmdQuery, byte cmdSet) { + super(name, cmdQuery, cmdSet); + } + + // Yes, these are different. Was somebody drunk when designing this? + + @Override + public byte[] encode(TimeRange value) { + ByteBuffer buffer = ByteBuffer.allocate(4); + buffer.put(value.start_h); + buffer.put(value.start_m); + buffer.put(value.end_h); + buffer.put(value.end_m); + return buffer.array(); + } + + @Override + public TimeRange decode(byte[] data) { + if (data.length != 4) + throw new IllegalArgumentException("Wrong data length, should be 4, was " + data.length); + ByteBuffer buffer = ByteBuffer.wrap(data); + buffer.order(ByteOrder.LITTLE_ENDIAN); + short start = buffer.getShort(); + short end = buffer.getShort(); + return new TimeRange((byte)(start / 60), (byte)(start % 60), (byte)(end / 60), (byte)(start % 60)); + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/dafit/settings/DaFitSettingUserInfo.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/dafit/settings/DaFitSettingUserInfo.java new file mode 100644 index 000000000..1e55e7714 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/dafit/settings/DaFitSettingUserInfo.java @@ -0,0 +1,44 @@ +/* Copyright (C) 2019 krzys_h + + This file is part of Gadgetbridge. + + Gadgetbridge is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Gadgetbridge is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . */ +package nodomain.freeyourgadget.gadgetbridge.devices.dafit.settings; + +import org.apache.commons.lang3.NotImplementedException; + +import java.nio.ByteBuffer; + +import nodomain.freeyourgadget.gadgetbridge.model.ActivityUser; + +public class DaFitSettingUserInfo extends DaFitSetting { + public DaFitSettingUserInfo(String name, byte cmdSet) { + super(name, (byte)-1, cmdSet); + } + + @Override + public byte[] encode(ActivityUser value) { + ByteBuffer buffer = ByteBuffer.allocate(4); + buffer.put((byte)value.getHeightCm()); + buffer.put((byte)value.getWeightKg()); + buffer.put((byte)value.getAge()); + buffer.put((byte)value.getGender()); + return buffer.array(); + } + + @Override + public ActivityUser decode(byte[] data) { + throw new NotImplementedException("decode"); + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/dafit/DaFitDeviceSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/dafit/DaFitDeviceSupport.java index 95ec2f948..3830e1a42 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/dafit/DaFitDeviceSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/dafit/DaFitDeviceSupport.java @@ -19,8 +19,10 @@ package nodomain.freeyourgadget.gadgetbridge.service.devices.dafit; import android.bluetooth.BluetoothGatt; import android.bluetooth.BluetoothGattCharacteristic; import android.content.Intent; +import android.content.SharedPreferences; import android.net.Uri; import android.os.Handler; +import android.util.ArrayMap; import android.util.Log; import android.util.Pair; import android.widget.Toast; @@ -32,29 +34,51 @@ import org.slf4j.LoggerFactory; import java.io.IOException; import java.nio.ByteBuffer; +import java.text.ParseException; +import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; +import java.util.HashSet; +import java.util.Locale; +import java.util.Map; import java.util.Objects; +import java.util.Set; import java.util.UUID; import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.Logging; +import nodomain.freeyourgadget.gadgetbridge.R; +import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst; import nodomain.freeyourgadget.gadgetbridge.database.DBHandler; import nodomain.freeyourgadget.gadgetbridge.database.DBHelper; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventBatteryInfo; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventCallControl; +import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventConfigurationRead; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventMusicControl; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventVersionInfo; import nodomain.freeyourgadget.gadgetbridge.devices.dafit.DaFitConstants; import nodomain.freeyourgadget.gadgetbridge.devices.dafit.DaFitWeatherForecast; import nodomain.freeyourgadget.gadgetbridge.devices.dafit.DaFitWeatherToday; +import nodomain.freeyourgadget.gadgetbridge.devices.dafit.DaFitDeviceCoordinator; import nodomain.freeyourgadget.gadgetbridge.devices.dafit.DaFitSampleProvider; +import nodomain.freeyourgadget.gadgetbridge.devices.dafit.settings.DaFitEnumDeviceVersion; +import nodomain.freeyourgadget.gadgetbridge.devices.dafit.settings.DaFitEnumLanguage; +import nodomain.freeyourgadget.gadgetbridge.devices.dafit.settings.DaFitEnumMetricSystem; +import nodomain.freeyourgadget.gadgetbridge.devices.dafit.settings.DaFitEnumTimeSystem; +import nodomain.freeyourgadget.gadgetbridge.devices.dafit.settings.DaFitSetting; +import nodomain.freeyourgadget.gadgetbridge.devices.dafit.settings.DaFitSettingEnum; +import nodomain.freeyourgadget.gadgetbridge.devices.dafit.settings.DaFitSettingLanguage; +import nodomain.freeyourgadget.gadgetbridge.devices.dafit.settings.DaFitSettingRemindersToMove; +import nodomain.freeyourgadget.gadgetbridge.devices.dafit.settings.DaFitSettingTimeRange; +import nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiConst; +import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst; import nodomain.freeyourgadget.gadgetbridge.entities.Device; import nodomain.freeyourgadget.gadgetbridge.entities.DaFitActivitySample; import nodomain.freeyourgadget.gadgetbridge.entities.User; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample; +import nodomain.freeyourgadget.gadgetbridge.model.ActivityUser; import nodomain.freeyourgadget.gadgetbridge.model.Alarm; import nodomain.freeyourgadget.gadgetbridge.model.CalendarEventSpec; import nodomain.freeyourgadget.gadgetbridge.model.CallSpec; @@ -75,8 +99,10 @@ import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.battery.Batter import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.deviceinfo.DeviceInfo; import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.deviceinfo.DeviceInfoProfile; import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.heartrate.HeartRateProfile; +import nodomain.freeyourgadget.gadgetbridge.util.DeviceHelper; import nodomain.freeyourgadget.gadgetbridge.util.GB; import nodomain.freeyourgadget.gadgetbridge.util.NotificationUtils; +import nodomain.freeyourgadget.gadgetbridge.util.Prefs; import nodomain.freeyourgadget.gadgetbridge.util.StringUtils; // TODO: figure out the training data @@ -139,6 +165,8 @@ public class DaFitDeviceSupport extends AbstractBTLEDeviceSupport { builder.notify(getCharacteristic(DaFitConstants.UUID_CHARACTERISTIC_DATA_IN), true); deviceInfoProfile.requestDeviceInfo(builder); setTime(builder); + sendSetting(builder, getSetting("USER_INFO"), new ActivityUser()); // these settings are write-only, so write them just in case because there is no way to know if they desynced somehow + sendSetting(builder, getSetting("GOAL_STEP"), new ActivityUser().getStepsGoal()); batteryInfoProfile.requestBatteryInfo(builder); batteryInfoProfile.enableNotify(builder); heartRateProfile.enableNotify(builder); @@ -331,6 +359,17 @@ public class DaFitDeviceSupport extends AbstractBTLEDeviceSupport { return true; } + for (DaFitSetting setting : queriedSettings) + { + if (setting.cmdQuery == packetType) + { + Object value = setting.decode(payload); + onReadConfigurationDone(setting, value, payload); + queriedSettings.remove(setting); + return true; + } + } + LOG.warn("Unhandled packet " + packetType + ": " + Logging.formatBytes(payload)); return false; } @@ -938,18 +977,377 @@ public class DaFitDeviceSupport extends AbstractBTLEDeviceSupport { throw new UnsupportedOperationException(); } + @SuppressWarnings("unchecked") + private T getSetting(String id) { + DaFitDeviceCoordinator coordinator = (DaFitDeviceCoordinator) DeviceHelper.getInstance().getCoordinator(getDevice()); + for(DaFitSetting setting : coordinator.getSupportedSettings()) + { + if (setting.name.equals(id)) + return (T) setting; + } + throw new IllegalArgumentException("No such setting: " + id); + } + + private static Calendar getTimePref(Prefs prefs, String key, String defaultValue) { + String timePref = prefs.getString(key, defaultValue); + Date time = null; + try { + time = new SimpleDateFormat("HH:mm").parse(timePref); + } catch (ParseException e) { + e.printStackTrace(); + } + Calendar cal = Calendar.getInstance(); + cal.setTime(time); + return cal; + } + + private void sendSetting(TransactionBuilder builder, DaFitSetting setting, T newValue) + { + sendPacket(builder, DaFitPacketOut.buildPacket(setting.cmdSet, setting.encode(newValue))); + } + + private void sendSetting(DaFitSetting setting, T newValue) + { + try { + TransactionBuilder builder = performInitialized("sendSetting"); + sendSetting(builder, setting, newValue); + builder.queue(getQueue()); + } catch (IOException e) { + e.printStackTrace(); + } + } + + private Set queriedSettings = new HashSet<>(); + + private void querySetting(DaFitSetting setting) + { + if (queriedSettings.contains(setting)) + return; + + try { + TransactionBuilder builder = performInitialized("querySetting"); + sendPacket(builder, DaFitPacketOut.buildPacket(setting.cmdQuery, new byte[0])); + builder.queue(getQueue()); + queriedSettings.add(setting); + } catch (IOException e) { + e.printStackTrace(); + } + } + @Override public void onSendConfiguration(String config) { - // TODO + Log.i("OOOOOOOOOOOOOOOOsend", config); + + Prefs prefs = new Prefs(GBApplication.getDeviceSpecificSharedPrefs(getDevice().getAddress())); + switch (config) { + case ActivityUser.PREF_USER_HEIGHT_CM: + case ActivityUser.PREF_USER_WEIGHT_KG: + case ActivityUser.PREF_USER_YEAR_OF_BIRTH: + case ActivityUser.PREF_USER_GENDER: + sendSetting(getSetting("USER_INFO"), new ActivityUser()); + break; + + case ActivityUser.PREF_USER_STEPS_GOAL: + sendSetting(getSetting("GOAL_STEP"), new ActivityUser().getStepsGoal()); + break; + + case DeviceSettingsPreferenceConst.PREF_TIMEFORMAT: + String timeSystemPref = prefs.getString(DeviceSettingsPreferenceConst.PREF_TIMEFORMAT, getContext().getString(R.string.p_timeformat_24h)); + + DaFitEnumTimeSystem timeSystem; + if (timeSystemPref.equals(getContext().getString(R.string.p_timeformat_24h))) + timeSystem = DaFitEnumTimeSystem.TIME_SYSTEM_24; + else if (timeSystemPref.equals(getContext().getString(R.string.p_timeformat_am_pm))) + timeSystem = DaFitEnumTimeSystem.TIME_SYSTEM_12; + else + throw new IllegalArgumentException(); + + sendSetting(getSetting("TIME_SYSTEM"), timeSystem); + break; + + case DeviceSettingsPreferenceConst.PREF_MEASUREMENTSYSTEM: + String metricSystemPref = prefs.getString(DeviceSettingsPreferenceConst.PREF_MEASUREMENTSYSTEM, getContext().getString(R.string.p_unit_metric)); + + DaFitEnumMetricSystem metricSystem; + if (metricSystemPref.equals(getContext().getString(R.string.p_unit_metric))) + metricSystem = DaFitEnumMetricSystem.METRIC_SYSTEM; + else if (metricSystemPref.equals(getContext().getString(R.string.p_unit_imperial))) + metricSystem = DaFitEnumMetricSystem.IMPERIAL_SYSTEM; + else + throw new IllegalArgumentException(); + + sendSetting(getSetting("METRIC_SYSTEM"), metricSystem); + break; + + case DaFitConstants.PREF_WATCH_FACE: + String watchFacePref = prefs.getString(DaFitConstants.PREF_WATCH_FACE, String.valueOf(1)); + byte watchFace = Byte.valueOf(watchFacePref); + sendSetting(getSetting("DISPLAY_WATCH_FACE"), watchFace); + break; + + case DaFitConstants.PREF_LANGUAGE: + String languagePref = prefs.getString(DaFitConstants.PREF_LANGUAGE, + String.valueOf(DaFitEnumLanguage.LANGUAGE_ENGLISH.value())); + byte languageNum = Byte.valueOf(languagePref); + DaFitSettingEnum languageSetting = getSetting("DEVICE_LANGUAGE"); + sendSetting(languageSetting, languageSetting.findByValue(languageNum)); + break; + + case DaFitConstants.PREF_DEVICE_VERSION: + String versionPref = prefs.getString(DaFitConstants.PREF_DEVICE_VERSION, + String.valueOf(DaFitEnumDeviceVersion.INTERNATIONAL_EDITION.value())); + byte versionNum = Byte.valueOf(versionPref); + DaFitSettingEnum versionSetting = getSetting("DEVICE_VERSION"); + sendSetting(versionSetting, versionSetting.findByValue(versionNum)); + break; + + case MiBandConst.PREF_DO_NOT_DISTURB: + case MiBandConst.PREF_DO_NOT_DISTURB_START: + case MiBandConst.PREF_DO_NOT_DISTURB_END: + String doNotDisturbPref = prefs.getString(MiBandConst.PREF_DO_NOT_DISTURB, MiBandConst.PREF_DO_NOT_DISTURB_OFF); + boolean doNotDisturbEnabled = !MiBandConst.PREF_DO_NOT_DISTURB_OFF.equals(doNotDisturbPref); + + Calendar doNotDisturbStart = getTimePref(prefs, MiBandConst.PREF_DO_NOT_DISTURB_START, "01:00"); + Calendar doNotDisturbEnd = getTimePref(prefs, MiBandConst.PREF_DO_NOT_DISTURB_END, "06:00"); + + DaFitSettingTimeRange.TimeRange doNotDisturb; + if (doNotDisturbEnabled) + doNotDisturb = new DaFitSettingTimeRange.TimeRange( + (byte) doNotDisturbStart.get(Calendar.HOUR_OF_DAY), (byte) doNotDisturbStart.get(Calendar.MINUTE), + (byte) doNotDisturbEnd.get(Calendar.HOUR_OF_DAY), (byte) doNotDisturbEnd.get(Calendar.MINUTE)); + else + doNotDisturb = new DaFitSettingTimeRange.TimeRange((byte)0, (byte)0, (byte)0, (byte)0); + + sendSetting(getSetting("DO_NOT_DISTURB_TIME"), doNotDisturb); + break; + + case HuamiConst.PREF_ACTIVATE_DISPLAY_ON_LIFT: + case HuamiConst.PREF_DISPLAY_ON_LIFT_START: + case HuamiConst.PREF_DISPLAY_ON_LIFT_END: + String quickViewPref = prefs.getString(HuamiConst.PREF_ACTIVATE_DISPLAY_ON_LIFT, MiBandConst.PREF_DO_NOT_DISTURB_OFF); + boolean quickViewEnabled = !quickViewPref.equals(getContext().getString(R.string.p_off)); + boolean quickViewScheduled = quickViewPref.equals(getContext().getString(R.string.p_scheduled)); + + Calendar quickViewStart = getTimePref(prefs, HuamiConst.PREF_DISPLAY_ON_LIFT_START, "00:00"); + Calendar quickViewEnd = getTimePref(prefs, HuamiConst.PREF_DISPLAY_ON_LIFT_END, "00:00"); + + DaFitSettingTimeRange.TimeRange quickViewTime; + if (quickViewEnabled && quickViewScheduled) + quickViewTime = new DaFitSettingTimeRange.TimeRange( + (byte) quickViewStart.get(Calendar.HOUR_OF_DAY), (byte) quickViewStart.get(Calendar.MINUTE), + (byte) quickViewEnd.get(Calendar.HOUR_OF_DAY), (byte) quickViewEnd.get(Calendar.MINUTE)); + else + quickViewTime = new DaFitSettingTimeRange.TimeRange((byte)0, (byte)0, (byte)0, (byte)0); + + sendSetting(getSetting("QUICK_VIEW"), quickViewEnabled); + sendSetting(getSetting("QUICK_VIEW_TIME"), quickViewTime); + break; + + case DaFitConstants.PREF_SEDENTARY_REMINDER: + String sedentaryReminderPref = prefs.getString(DaFitConstants.PREF_SEDENTARY_REMINDER, "off"); + boolean sedentaryReminderEnabled = !sedentaryReminderPref.equals("off"); + sendSetting(getSetting("SEDENTARY_REMINDER"), sedentaryReminderEnabled); + break; + + case DaFitConstants.PREF_SEDENTARY_REMINDER_PERIOD: + case DaFitConstants.PREF_SEDENTARY_REMINDER_STEPS: + case DaFitConstants.PREF_SEDENTARY_REMINDER_START: + case DaFitConstants.PREF_SEDENTARY_REMINDER_END: + byte sedentaryPeriod = (byte) prefs.getInt(DaFitConstants.PREF_SEDENTARY_REMINDER_PERIOD, 30); + byte sedentarySteps = (byte) prefs.getInt(DaFitConstants.PREF_SEDENTARY_REMINDER_STEPS, 100); + byte sedentaryStart = (byte) prefs.getInt(DaFitConstants.PREF_SEDENTARY_REMINDER_START, 10); + byte sedentaryEnd = (byte) prefs.getInt(DaFitConstants.PREF_SEDENTARY_REMINDER_END, 22); + sendSetting(getSetting("REMINDERS_TO_MOVE_PERIOD"), + new DaFitSettingRemindersToMove.RemindersToMove(sedentaryPeriod, sedentarySteps, sedentaryStart, sedentaryEnd)); + break; + } + + // Query the setting to make sure the configuration got actually applied + // TODO: breaks sedentary + //onReadConfiguration(config); } @Override public void onReadConfiguration(String config) { - // TODO + Log.i("OOOOOOOOOOOOOOOOread", config); + + switch (config) { + /* These use the global Gadgetbridge configuration and are always forced on device upon connection + case ActivityUser.PREF_USER_HEIGHT_CM: + case ActivityUser.PREF_USER_WEIGHT_KG: + case ActivityUser.PREF_USER_YEAR_OF_BIRTH: + case ActivityUser.PREF_USER_GENDER: + querySetting(getSetting("USER_INFO")); + break; + + case ActivityUser.PREF_USER_STEPS_GOAL: + querySetting(getSetting("GOAL_STEP")); + break;*/ + + case DeviceSettingsPreferenceConst.PREF_TIMEFORMAT: + querySetting(getSetting("TIME_SYSTEM")); + break; + + case DeviceSettingsPreferenceConst.PREF_MEASUREMENTSYSTEM: + querySetting(getSetting("METRIC_SYSTEM")); + break; + + case DaFitConstants.PREF_WATCH_FACE: + querySetting(getSetting("DISPLAY_WATCH_FACE")); + break; + + case DaFitConstants.PREF_LANGUAGE: + querySetting(getSetting("DEVICE_LANGUAGE")); + break; + + case DaFitConstants.PREF_DEVICE_VERSION: + querySetting(getSetting("DEVICE_VERSION")); + break; + + case MiBandConst.PREF_DO_NOT_DISTURB: + case MiBandConst.PREF_DO_NOT_DISTURB_START: + case MiBandConst.PREF_DO_NOT_DISTURB_END: + querySetting(getSetting("DO_NOT_DISTURB_TIME")); + break; + + case HuamiConst.PREF_ACTIVATE_DISPLAY_ON_LIFT: + case HuamiConst.PREF_DISPLAY_ON_LIFT_START: + case HuamiConst.PREF_DISPLAY_ON_LIFT_END: + querySetting(getSetting("QUICK_VIEW")); + querySetting(getSetting("QUICK_VIEW_TIME")); + break; + + case DaFitConstants.PREF_SEDENTARY_REMINDER: + querySetting(getSetting("SEDENTARY_REMINDER")); + break; + + case DaFitConstants.PREF_SEDENTARY_REMINDER_PERIOD: + case DaFitConstants.PREF_SEDENTARY_REMINDER_STEPS: + case DaFitConstants.PREF_SEDENTARY_REMINDER_START: + case DaFitConstants.PREF_SEDENTARY_REMINDER_END: + querySetting(getSetting("REMINDERS_TO_MOVE_PERIOD")); + break; + default: + return; + } + + GBDeviceEventConfigurationRead configReadEvent = new GBDeviceEventConfigurationRead(); + configReadEvent.config = config; + configReadEvent.event = GBDeviceEventConfigurationRead.Event.IN_PROGRESS; + evaluateGBDeviceEvent(configReadEvent); + } + + public void onReadConfigurationDone(DaFitSetting setting, Object value, byte[] data) + { + Log.i("CONFIG", setting.name + " = " + value); + Prefs prefs = new Prefs(GBApplication.getDeviceSpecificSharedPrefs(getDevice().getAddress())); + Map changedProperties = new ArrayMap<>(); + SharedPreferences.Editor prefsEditor = prefs.getPreferences().edit(); + switch (setting.name) { + case "TIME_SYSTEM": + DaFitEnumTimeSystem timeSystem = (DaFitEnumTimeSystem) value; + if (timeSystem == DaFitEnumTimeSystem.TIME_SYSTEM_24) + changedProperties.put(DeviceSettingsPreferenceConst.PREF_TIMEFORMAT, getContext().getString(R.string.p_timeformat_24h)); + else if (timeSystem == DaFitEnumTimeSystem.TIME_SYSTEM_12) + changedProperties.put(DeviceSettingsPreferenceConst.PREF_TIMEFORMAT, getContext().getString(R.string.p_timeformat_am_pm)); + else + throw new IllegalArgumentException("Invalid value"); + break; + + case "METRIC_SYSTEM": + DaFitEnumMetricSystem metricSystem = (DaFitEnumMetricSystem) value; + if (metricSystem == DaFitEnumMetricSystem.METRIC_SYSTEM) + changedProperties.put(DeviceSettingsPreferenceConst.PREF_MEASUREMENTSYSTEM, getContext().getString(R.string.p_unit_metric)); + else if (metricSystem == DaFitEnumMetricSystem.IMPERIAL_SYSTEM) + changedProperties.put(DeviceSettingsPreferenceConst.PREF_MEASUREMENTSYSTEM, getContext().getString(R.string.p_unit_imperial)); + else + throw new IllegalArgumentException("Invalid value"); + break; + + case "DISPLAY_WATCH_FACE": + byte watchFace = (Byte) value; + changedProperties.put(DaFitConstants.PREF_WATCH_FACE, String.valueOf(watchFace)); + break; + + case "DEVICE_LANGUAGE": + DaFitEnumLanguage language = (DaFitEnumLanguage) value; + changedProperties.put(DaFitConstants.PREF_LANGUAGE, String.valueOf(language.value())); + DaFitEnumLanguage[] supportedLanguages = ((DaFitSettingLanguage) setting).decodeSupportedValues(data); + Set supportedLanguagesList = new HashSet<>(); + for(DaFitEnumLanguage supportedLanguage : supportedLanguages) + supportedLanguagesList.add(String.valueOf(supportedLanguage.value())); + prefsEditor.putStringSet(DaFitConstants.PREF_LANGUAGE_SUPPORT, supportedLanguagesList); + break; + + case "DEVICE_VERSION": + DaFitEnumDeviceVersion deviceVersion = (DaFitEnumDeviceVersion) value; + changedProperties.put(DaFitConstants.PREF_DEVICE_VERSION, String.valueOf(deviceVersion.value())); + break; + + case "DO_NOT_DISTURB_TIME": + DaFitSettingTimeRange.TimeRange doNotDisturb = (DaFitSettingTimeRange.TimeRange) value; + if (doNotDisturb.start_h == 0 && doNotDisturb.start_m == 0 && + doNotDisturb.end_h == 0 && doNotDisturb.end_m == 0) + changedProperties.put(MiBandConst.PREF_DO_NOT_DISTURB, MiBandConst.PREF_DO_NOT_DISTURB_OFF); + else + changedProperties.put(MiBandConst.PREF_DO_NOT_DISTURB, MiBandConst.PREF_DO_NOT_DISTURB_SCHEDULED); + changedProperties.put(MiBandConst.PREF_DO_NOT_DISTURB_START, String.format(Locale.ROOT, "%02d:%02d", doNotDisturb.start_h, doNotDisturb.start_m)); + changedProperties.put(MiBandConst.PREF_DO_NOT_DISTURB_END, String.format(Locale.ROOT, "%02d:%02d", doNotDisturb.end_h, doNotDisturb.end_m)); + break; + + case "QUICK_VIEW": + boolean quickViewEnabled = (Boolean) value; + boolean quickViewScheduled = prefs.getString(HuamiConst.PREF_ACTIVATE_DISPLAY_ON_LIFT, getContext().getString(R.string.p_off)).equals(getContext().getString(R.string.p_scheduled)); + changedProperties.put(HuamiConst.PREF_ACTIVATE_DISPLAY_ON_LIFT, quickViewEnabled ? (quickViewScheduled ? getContext().getString(R.string.p_scheduled) : getContext().getString(R.string.p_on)) : getContext().getString(R.string.p_off)); + break; + + case "QUICK_VIEW_TIME": + boolean quickViewEnabled2 = !prefs.getString(HuamiConst.PREF_ACTIVATE_DISPLAY_ON_LIFT, getContext().getString(R.string.p_off)).equals(getContext().getString(R.string.p_off)); + DaFitSettingTimeRange.TimeRange quickViewTime = (DaFitSettingTimeRange.TimeRange) value; + if (quickViewEnabled2) + { + if (quickViewTime.start_h == 0 && quickViewTime.start_m == 0 && + quickViewTime.end_h == 0 && quickViewTime.end_m == 0) + changedProperties.put(HuamiConst.PREF_ACTIVATE_DISPLAY_ON_LIFT, getContext().getString(R.string.p_on)); + else + changedProperties.put(HuamiConst.PREF_ACTIVATE_DISPLAY_ON_LIFT, getContext().getString(R.string.p_scheduled)); + } + changedProperties.put(HuamiConst.PREF_DISPLAY_ON_LIFT_START, String.format(Locale.ROOT, "%02d:%02d", quickViewTime.start_h, quickViewTime.start_m)); + changedProperties.put(HuamiConst.PREF_DISPLAY_ON_LIFT_END, String.format(Locale.ROOT, "%02d:%02d", quickViewTime.end_h, quickViewTime.end_m)); + break; + + case "SEDENTARY_REMINDER": + boolean sedentaryReminderEnabled = (Boolean) value; + changedProperties.put(DaFitConstants.PREF_SEDENTARY_REMINDER, sedentaryReminderEnabled ? "on": "off"); + break; + + case "REMINDERS_TO_MOVE_PERIOD": + DaFitSettingRemindersToMove.RemindersToMove remindersToMove = (DaFitSettingRemindersToMove.RemindersToMove) value; + changedProperties.put(DaFitConstants.PREF_SEDENTARY_REMINDER_PERIOD, String.valueOf(remindersToMove.period)); + changedProperties.put(DaFitConstants.PREF_SEDENTARY_REMINDER_STEPS, String.valueOf(remindersToMove.steps)); + changedProperties.put(DaFitConstants.PREF_SEDENTARY_REMINDER_START, String.valueOf(remindersToMove.start_h)); + changedProperties.put(DaFitConstants.PREF_SEDENTARY_REMINDER_END, String.valueOf(remindersToMove.end_h)); + break; + } + for (Map.Entry property : changedProperties.entrySet()) + prefsEditor.putString(property.getKey(), property.getValue()); + prefsEditor.apply(); + for (Map.Entry property : changedProperties.entrySet()) + { + GBDeviceEventConfigurationRead configReadEvent = new GBDeviceEventConfigurationRead(); + configReadEvent.config = property.getKey(); + configReadEvent.event = GBDeviceEventConfigurationRead.Event.SUCCESS; + evaluateGBDeviceEvent(configReadEvent); + } } @Override public void onTestNewFunction() { + try { + new QuerySettingsOperation(this).perform(); + } catch (IOException e) { + e.printStackTrace(); + } } @Override diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/dafit/QuerySettingsOperation.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/dafit/QuerySettingsOperation.java new file mode 100644 index 000000000..35ecec657 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/dafit/QuerySettingsOperation.java @@ -0,0 +1,137 @@ +/* Copyright (C) 2019 krzys_h + + This file is part of Gadgetbridge. + + Gadgetbridge is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Gadgetbridge is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . */ +package nodomain.freeyourgadget.gadgetbridge.service.devices.dafit; + +import android.bluetooth.BluetoothGatt; +import android.bluetooth.BluetoothGattCharacteristic; +import android.util.Log; +import android.util.Pair; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.util.UUID; + +import nodomain.freeyourgadget.gadgetbridge.devices.dafit.DaFitConstants; +import nodomain.freeyourgadget.gadgetbridge.devices.dafit.DaFitDeviceCoordinator; +import nodomain.freeyourgadget.gadgetbridge.devices.dafit.settings.DaFitSetting; +import nodomain.freeyourgadget.gadgetbridge.service.btle.AbstractBTLEOperation; +import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder; +import nodomain.freeyourgadget.gadgetbridge.service.devices.miband.operations.OperationStatus; +import nodomain.freeyourgadget.gadgetbridge.util.DeviceHelper; + +public class QuerySettingsOperation extends AbstractBTLEOperation { + + private static final Logger LOG = LoggerFactory.getLogger(QuerySettingsOperation.class); + + private final DaFitSetting[] settingsToQuery; + private boolean[] received; + + private DaFitPacketIn packetIn = new DaFitPacketIn(); + + public QuerySettingsOperation(DaFitDeviceSupport support, DaFitSetting[] settingsToQuery) { + super(support); + this.settingsToQuery = settingsToQuery; + } + + public QuerySettingsOperation(DaFitDeviceSupport support) { + super(support); + DaFitDeviceCoordinator coordinator = (DaFitDeviceCoordinator) DeviceHelper.getInstance().getCoordinator(getDevice()); + this.settingsToQuery = coordinator.getSupportedSettings(); + } + + @Override + protected void prePerform() { + getDevice().setBusyTask("Querying settings"); // mark as busy quickly to avoid interruptions from the outside + getDevice().sendDeviceUpdateIntent(getContext()); + } + + @Override + protected void doPerform() throws IOException { + received = new boolean[settingsToQuery.length]; + TransactionBuilder builder = performInitialized("QuerySettingsOperation"); + for (DaFitSetting setting : settingsToQuery) + { + if (setting.cmdQuery == -1) + continue; + + getSupport().sendPacket(builder, DaFitPacketOut.buildPacket(setting.cmdQuery, new byte[0])); + } + builder.queue(getQueue()); + } + + @Override + public boolean onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { + if (!isOperationRunning()) + { + LOG.error("onCharacteristicChanged but operation is not running!"); + } + else + { + UUID charUuid = characteristic.getUuid(); + if (charUuid.equals(DaFitConstants.UUID_CHARACTERISTIC_DATA_IN)) + { + if (packetIn.putFragment(characteristic.getValue())) { + Pair packet = DaFitPacketIn.parsePacket(packetIn.getPacket()); + packetIn = new DaFitPacketIn(); + if (packet != null) { + byte packetType = packet.first; + byte[] payload = packet.second; + + if (handlePacket(packetType, payload)) + return true; + } + } + } + } + + return super.onCharacteristicChanged(gatt, characteristic); + } + + private boolean handlePacket(byte packetType, byte[] payload) { + boolean handled = false; + boolean receivedEverything = true; + for(int i = 0; i < settingsToQuery.length; i++) + { + DaFitSetting setting = settingsToQuery[i]; + if (setting.cmdQuery == -1) + continue; + if (setting.cmdQuery == packetType) + { + Object value = setting.decode(payload); + Log.i("SETTING QUERY", setting.name + " = " + value.toString()); + received[i] = true; + handled = true; + } + else if (!received[i]) + receivedEverything = false; + } + if (receivedEverything) + operationFinished(); + + return handled; + } + + @Override + protected void operationFinished() { + operationStatus = OperationStatus.FINISHED; + if (getDevice() != null && getDevice().isConnected()) { + unsetBusy(); + } + } +} diff --git a/app/src/main/res/drawable/ic_measurement_system.xml b/app/src/main/res/drawable/ic_measurement_system.xml new file mode 100644 index 000000000..18c9e5f55 --- /dev/null +++ b/app/src/main/res/drawable/ic_measurement_system.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/ic_sitting.xml b/app/src/main/res/drawable/ic_sitting.xml new file mode 100644 index 000000000..c46d270f1 --- /dev/null +++ b/app/src/main/res/drawable/ic_sitting.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index 9e2875dda..45d240227 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -366,6 +366,16 @@ @string/p_scheduled + + @string/off + @string/on + + + + @string/p_off + @string/p_on + + @string/mi2_dnd_off @string/mi2_dnd_automatic @@ -2624,6 +2634,28 @@ ru_RU + + Watch face 1 + Watch face 2 + Watch face 3 + + + + 1 + 2 + 3 + + + + Chinese edition + International edition + + + + 0 + 1 + + @string/off diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index daf5a1720..2f76ee222 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -436,6 +436,13 @@ Visible only if no device is added New Auth Protocol Enable if your device no longer connects after a firmware upgrade + Watch face + Device version + Sedentary reminder + Time period (minutes) + Minimum steps + Start time (hour) + End time (hour) Units Time format diff --git a/app/src/main/res/xml/devicesettings_dafit_device_version.xml b/app/src/main/res/xml/devicesettings_dafit_device_version.xml new file mode 100644 index 000000000..b50f003ad --- /dev/null +++ b/app/src/main/res/xml/devicesettings_dafit_device_version.xml @@ -0,0 +1,10 @@ + + + + diff --git a/app/src/main/res/xml/devicesettings_dafit_language.xml b/app/src/main/res/xml/devicesettings_dafit_language.xml new file mode 100644 index 000000000..6eda64262 --- /dev/null +++ b/app/src/main/res/xml/devicesettings_dafit_language.xml @@ -0,0 +1,9 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/xml/devicesettings_dafit_sedentary_reminder.xml b/app/src/main/res/xml/devicesettings_dafit_sedentary_reminder.xml new file mode 100644 index 000000000..b89487633 --- /dev/null +++ b/app/src/main/res/xml/devicesettings_dafit_sedentary_reminder.xml @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/xml/devicesettings_dafit_watchface.xml b/app/src/main/res/xml/devicesettings_dafit_watchface.xml new file mode 100644 index 000000000..731e0d49e --- /dev/null +++ b/app/src/main/res/xml/devicesettings_dafit_watchface.xml @@ -0,0 +1,11 @@ + + + + diff --git a/app/src/main/res/xml/devicesettings_donotdisturb_no_auto_v2.xml b/app/src/main/res/xml/devicesettings_donotdisturb_no_auto_v2.xml new file mode 100644 index 000000000..486bde81d --- /dev/null +++ b/app/src/main/res/xml/devicesettings_donotdisturb_no_auto_v2.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/xml/devicesettings_measurementsystem.xml b/app/src/main/res/xml/devicesettings_measurementsystem.xml new file mode 100644 index 000000000..f324f3fa4 --- /dev/null +++ b/app/src/main/res/xml/devicesettings_measurementsystem.xml @@ -0,0 +1,12 @@ + + + + + diff --git a/app/src/main/res/xml/devicesettings_personalinfo.xml b/app/src/main/res/xml/devicesettings_personalinfo.xml new file mode 100644 index 000000000..014fcbf60 --- /dev/null +++ b/app/src/main/res/xml/devicesettings_personalinfo.xml @@ -0,0 +1,13 @@ + + + + + + + +