mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge
synced 2024-11-26 20:06:52 +01:00
Da Fit: Add device settings
This commit is contained in:
parent
5b0c2a9b69
commit
ea58fd3f0d
@ -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";
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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 <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.devices.dafit.settings;
|
||||
|
||||
public interface DaFitEnum {
|
||||
byte value();
|
||||
}
|
@ -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 <http://www.gnu.org/licenses/>. */
|
||||
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;
|
||||
}
|
||||
}
|
@ -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 <http://www.gnu.org/licenses/>. */
|
||||
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;
|
||||
}
|
||||
}
|
@ -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 <http://www.gnu.org/licenses/>. */
|
||||
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;
|
||||
}
|
||||
}
|
@ -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 <http://www.gnu.org/licenses/>. */
|
||||
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;
|
||||
}
|
||||
}
|
@ -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 <http://www.gnu.org/licenses/>. */
|
||||
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;
|
||||
}
|
||||
}
|
@ -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 <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.devices.dafit.settings;
|
||||
|
||||
public abstract class DaFitSetting<T> {
|
||||
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);
|
||||
}
|
@ -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 <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.devices.dafit.settings;
|
||||
|
||||
public class DaFitSettingBool extends DaFitSetting<Boolean> {
|
||||
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;
|
||||
}
|
||||
}
|
@ -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 <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.devices.dafit.settings;
|
||||
|
||||
public class DaFitSettingByte extends DaFitSetting<Byte> {
|
||||
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];
|
||||
}
|
||||
}
|
@ -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 <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.devices.dafit.settings;
|
||||
|
||||
public class DaFitSettingEnum<T extends Enum <?> & DaFitEnum> extends DaFitSetting<T> {
|
||||
protected final Class<T> clazz;
|
||||
|
||||
public DaFitSettingEnum(String name, byte cmdQuery, byte cmdSet, Class<T> 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();
|
||||
}
|
||||
}
|
@ -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 <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.devices.dafit.settings;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
public class DaFitSettingInt extends DaFitSetting<Integer> {
|
||||
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();
|
||||
}
|
||||
}
|
@ -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 <http://www.gnu.org/licenses/>. */
|
||||
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<DaFitEnumLanguage> {
|
||||
public DaFitSettingLanguage(String name, byte cmdQuery, byte cmdSet) {
|
||||
super(name, cmdQuery, cmdSet, DaFitEnumLanguage.class);
|
||||
}
|
||||
|
||||
private Pair<DaFitEnumLanguage, DaFitEnumLanguage[]> 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<DaFitEnumLanguage> 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;
|
||||
}
|
||||
}
|
@ -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 <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.devices.dafit.settings;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
public class DaFitSettingRemindersToMove extends DaFitSetting<DaFitSettingRemindersToMove.RemindersToMove> {
|
||||
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);
|
||||
}
|
||||
}
|
@ -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 <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.devices.dafit.settings;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
public class DaFitSettingTimeRange extends DaFitSetting<DaFitSettingTimeRange.TimeRange> {
|
||||
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));
|
||||
}
|
||||
}
|
@ -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 <http://www.gnu.org/licenses/>. */
|
||||
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<ActivityUser> {
|
||||
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");
|
||||
}
|
||||
}
|
@ -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 extends DaFitSetting> 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 <T> void sendSetting(TransactionBuilder builder, DaFitSetting<T> setting, T newValue)
|
||||
{
|
||||
sendPacket(builder, DaFitPacketOut.buildPacket(setting.cmdSet, setting.encode(newValue)));
|
||||
}
|
||||
|
||||
private <T> void sendSetting(DaFitSetting<T> setting, T newValue)
|
||||
{
|
||||
try {
|
||||
TransactionBuilder builder = performInitialized("sendSetting");
|
||||
sendSetting(builder, setting, newValue);
|
||||
builder.queue(getQueue());
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private Set<DaFitSetting> 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<DaFitEnumLanguage> 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<DaFitEnumDeviceVersion> 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<String, String> 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<String> 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<String, String> property : changedProperties.entrySet())
|
||||
prefsEditor.putString(property.getKey(), property.getValue());
|
||||
prefsEditor.apply();
|
||||
for (Map.Entry<String, String> 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
|
||||
|
@ -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 <http://www.gnu.org/licenses/>. */
|
||||
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<DaFitDeviceSupport> {
|
||||
|
||||
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<Byte, byte[]> 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();
|
||||
}
|
||||
}
|
||||
}
|
5
app/src/main/res/drawable/ic_measurement_system.xml
Normal file
5
app/src/main/res/drawable/ic_measurement_system.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<vector android:height="24dp" android:tint="#7E7E7E"
|
||||
android:viewportHeight="24.0" android:viewportWidth="24.0"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="#FF000000" android:pathData="M8,19h3v4h2v-4h3l-4,-4 -4,4zM16,5h-3L13,1h-2v4L8,5l4,4 4,-4zM4,11v2h16v-2L4,11z"/>
|
||||
</vector>
|
5
app/src/main/res/drawable/ic_sitting.xml
Normal file
5
app/src/main/res/drawable/ic_sitting.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<vector android:height="24dp" android:tint="#7E7E7E"
|
||||
android:viewportHeight="24.0" android:viewportWidth="24.0"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="#FF000000" android:pathData="M4,18v3h3v-3h10v3h3v-6L4,15zM19,10h3v3h-3zM2,10h3v3L2,13zM17,13L7,13L7,5c0,-1.1 0.9,-2 2,-2h6c1.1,0 2,0.9 2,2v8z"/>
|
||||
</vector>
|
@ -366,6 +366,16 @@
|
||||
<item>@string/p_scheduled</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="sedentary_reminder">
|
||||
<item>@string/off</item>
|
||||
<item>@string/on</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="sedentary_reminder_values">
|
||||
<item>@string/p_off</item>
|
||||
<item>@string/p_on</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="mi2_do_not_disturb">
|
||||
<item>@string/mi2_dnd_off</item>
|
||||
<item>@string/mi2_dnd_automatic</item>
|
||||
@ -2624,6 +2634,28 @@
|
||||
<item>ru_RU</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="pref_dafit_watch_face">
|
||||
<item>Watch face 1</item>
|
||||
<item>Watch face 2</item>
|
||||
<item>Watch face 3</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="pref_dafit_watch_face_values">
|
||||
<item>1</item>
|
||||
<item>2</item>
|
||||
<item>3</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="pref_dafit_device_version">
|
||||
<item>Chinese edition</item>
|
||||
<item>International edition</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="pref_dafit_device_version_values">
|
||||
<item>0</item>
|
||||
<item>1</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="prefs_heartrate_measurement_interval">
|
||||
<!-- This will be filled dynamically by HeartRateCapability -->
|
||||
<item name="0">@string/off</item>
|
||||
|
@ -436,6 +436,13 @@
|
||||
<string name="pref_display_add_device_fab_off">Visible only if no device is added</string>
|
||||
<string name="pref_title_huami_force_new_protocol">New Auth Protocol</string>
|
||||
<string name="pref_summary_huami_force_new_protocol">Enable if your device no longer connects after a firmware upgrade</string>
|
||||
<string name="pref_watch_face">Watch face</string>
|
||||
<string name="pref_device_version">Device version</string>
|
||||
<string name="pref_sedentary_reminder">Sedentary reminder</string>
|
||||
<string name="pref_sedentary_reminder_period">Time period (minutes)</string>
|
||||
<string name="pref_sedentary_reminder_steps">Minimum steps</string>
|
||||
<string name="pref_sedentary_reminder_start">Start time (hour)</string>
|
||||
<string name="pref_sedentary_reminder_end">End time (hour)</string>
|
||||
<!-- HPlus Preferences -->
|
||||
<string name="pref_title_unit_system">Units</string>
|
||||
<string name="pref_title_timeformat">Time format</string>
|
||||
|
10
app/src/main/res/xml/devicesettings_dafit_device_version.xml
Normal file
10
app/src/main/res/xml/devicesettings_dafit_device_version.xml
Normal file
@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<ListPreference
|
||||
android:defaultValue="1"
|
||||
android:entries="@array/pref_dafit_device_version"
|
||||
android:entryValues="@array/pref_dafit_device_version_values"
|
||||
android:key="dafit_device_version"
|
||||
android:summary="%s"
|
||||
android:title="@string/pref_device_version" />
|
||||
</androidx.preference.PreferenceScreen>
|
9
app/src/main/res/xml/devicesettings_dafit_language.xml
Normal file
9
app/src/main/res/xml/devicesettings_dafit_language.xml
Normal file
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<ListPreference
|
||||
android:icon="@drawable/ic_language"
|
||||
android:defaultValue="0"
|
||||
android:key="dafit_language"
|
||||
android:summary="%s"
|
||||
android:title="@string/pref_title_language" />
|
||||
</androidx.preference.PreferenceScreen>
|
@ -0,0 +1,61 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<PreferenceScreen
|
||||
android:icon="@drawable/ic_sitting"
|
||||
android:key="screen_sedentary_reminder"
|
||||
android:persistent="false"
|
||||
android:title="@string/pref_sedentary_reminder">
|
||||
|
||||
<!-- workaround for missing toolbar -->
|
||||
<PreferenceCategory android:title="@string/pref_sedentary_reminder" />
|
||||
|
||||
<nodomain.freeyourgadget.gadgetbridge.util.XListPreference
|
||||
android:defaultValue="@string/p_off"
|
||||
android:entries="@array/sedentary_reminder"
|
||||
android:entryValues="@array/sedentary_reminder_values"
|
||||
android:key="sedentary_reminder"
|
||||
android:summary="%s"
|
||||
app:dependentValue="@string/p_on"
|
||||
android:title="@string/pref_sedentary_reminder" />
|
||||
|
||||
<androidx.preference.EditTextPreference
|
||||
android:defaultValue="30"
|
||||
android:inputType="number"
|
||||
android:key="sedentary_reminder_period"
|
||||
android:maxLength="3"
|
||||
app:useSimpleSummaryProvider="true"
|
||||
android:dependency="sedentary_reminder"
|
||||
android:title="@string/pref_sedentary_reminder_period" />
|
||||
|
||||
<androidx.preference.EditTextPreference
|
||||
android:defaultValue="100"
|
||||
android:inputType="number"
|
||||
android:key="sedentary_reminder_steps"
|
||||
android:maxLength="3"
|
||||
app:useSimpleSummaryProvider="true"
|
||||
android:dependency="sedentary_reminder"
|
||||
android:title="@string/pref_sedentary_reminder_steps" />
|
||||
|
||||
<androidx.preference.EditTextPreference
|
||||
android:defaultValue="10"
|
||||
android:inputType="number"
|
||||
android:key="sedentary_reminder_start"
|
||||
android:maxLength="2"
|
||||
app:useSimpleSummaryProvider="true"
|
||||
android:dependency="sedentary_reminder"
|
||||
android:title="@string/pref_sedentary_reminder_start" />
|
||||
|
||||
<androidx.preference.EditTextPreference
|
||||
android:defaultValue="22"
|
||||
android:inputType="number"
|
||||
android:key="sedentary_reminder_end"
|
||||
android:maxLength="2"
|
||||
app:useSimpleSummaryProvider="true"
|
||||
android:dependency="sedentary_reminder"
|
||||
android:title="@string/pref_sedentary_reminder_end" />
|
||||
|
||||
</PreferenceScreen>
|
||||
|
||||
|
||||
</androidx.preference.PreferenceScreen>
|
11
app/src/main/res/xml/devicesettings_dafit_watchface.xml
Normal file
11
app/src/main/res/xml/devicesettings_dafit_watchface.xml
Normal file
@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<ListPreference
|
||||
android:icon="@drawable/ic_widgets"
|
||||
android:defaultValue="1"
|
||||
android:entries="@array/pref_dafit_watch_face"
|
||||
android:entryValues="@array/pref_dafit_watch_face_values"
|
||||
android:key="dafit_watch_face"
|
||||
android:summary="%s"
|
||||
android:title="@string/pref_watch_face" />
|
||||
</androidx.preference.PreferenceScreen>
|
@ -0,0 +1,39 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- FIXME: A better version of _no_auto because the other one changes the IDs so the change notification does not work... -->
|
||||
<androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<PreferenceScreen
|
||||
android:icon="@drawable/ic_block"
|
||||
android:key="screen_do_not_disturb"
|
||||
android:persistent="false"
|
||||
android:summary="@string/mi2_prefs_do_not_disturb_summary"
|
||||
android:title="@string/mi2_prefs_do_not_disturb">
|
||||
|
||||
<!-- workaround for missing toolbar -->
|
||||
<PreferenceCategory android:title="@string/mi2_prefs_do_not_disturb" />
|
||||
|
||||
<nodomain.freeyourgadget.gadgetbridge.util.XListPreference
|
||||
android:defaultValue="@string/p_off"
|
||||
android:entries="@array/do_not_disturb_no_auto"
|
||||
android:entryValues="@array/do_not_disturb_no_auto_values"
|
||||
android:key="do_not_disturb"
|
||||
android:summary="%s"
|
||||
app:dependentValue="@string/p_scheduled"
|
||||
android:title="@string/mi2_prefs_do_not_disturb" />
|
||||
|
||||
<nodomain.freeyourgadget.gadgetbridge.util.XTimePreference
|
||||
android:defaultValue="01:00"
|
||||
android:key="do_not_disturb_start"
|
||||
android:dependency="do_not_disturb"
|
||||
android:title="@string/mi2_prefs_do_not_disturb_start" />
|
||||
|
||||
<nodomain.freeyourgadget.gadgetbridge.util.XTimePreference
|
||||
android:defaultValue="06:00"
|
||||
android:key="do_not_disturb_end"
|
||||
android:dependency="do_not_disturb"
|
||||
android:title="@string/mi2_prefs_do_not_disturb_end" />
|
||||
|
||||
</PreferenceScreen>
|
||||
|
||||
|
||||
</androidx.preference.PreferenceScreen>
|
12
app/src/main/res/xml/devicesettings_measurementsystem.xml
Normal file
12
app/src/main/res/xml/devicesettings_measurementsystem.xml
Normal file
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<ListPreference
|
||||
android:icon="@drawable/ic_measurement_system"
|
||||
android:defaultValue="metric"
|
||||
android:entries="@array/pref_entries_unit_system"
|
||||
android:entryValues="@array/pref_values_unit_system"
|
||||
android:key="measurement_system"
|
||||
android:summary="%s"
|
||||
android:title="@string/pref_title_unit_system" />
|
||||
|
||||
</androidx.preference.PreferenceScreen>
|
13
app/src/main/res/xml/devicesettings_personalinfo.xml
Normal file
13
app/src/main/res/xml/devicesettings_personalinfo.xml
Normal file
@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<Preference
|
||||
android:icon="@drawable/ic_person"
|
||||
android:key="personal_info"
|
||||
android:title="@string/activity_prefs_about_you">
|
||||
<intent
|
||||
android:targetPackage="nodomain.freeyourgadget.gadgetbridge"
|
||||
android:targetClass="nodomain.freeyourgadget.gadgetbridge.activities.SettingsActivity" />
|
||||
<!-- TODO: link this to proper subscreen -->
|
||||
</Preference>
|
||||
|
||||
</androidx.preference.PreferenceScreen>
|
Loading…
Reference in New Issue
Block a user