mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge
synced 2024-11-28 12:56:49 +01:00
Zepp OS: Refactor config, fix health on GTR 3 and GTS 3
The config refactor in addf7ff6a
broke health settings on GTR3 and GTS3
- GTS 3 and GTR 3 health configs use protocol v1. The only difference
seems to be that the steps goal is a SHORT instead of an INT.
- It needs a refactoring from the ground up to better handle different
versions, but this is enough to get the GTR 3 and GTS 3 working.
This commit is contained in:
parent
6cc3579e9c
commit
cd59511aad
@ -37,7 +37,7 @@ import nodomain.freeyourgadget.gadgetbridge.entities.Device;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.HuamiExtendedActivitySampleDao;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryParser;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.Huami2021Config;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.services.ZeppOsConfigService;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.HuamiLanguageType;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.HuamiVibrationPatternNotificationType;
|
||||
|
||||
@ -318,14 +318,14 @@ public abstract class Huami2021Coordinator extends HuamiCoordinator {
|
||||
}
|
||||
|
||||
public boolean hasGps(final GBDevice device) {
|
||||
return supportsConfig(device, Huami2021Config.ConfigArg.WORKOUT_GPS_PRESET);
|
||||
return supportsConfig(device, ZeppOsConfigService.ConfigArg.WORKOUT_GPS_PRESET);
|
||||
}
|
||||
|
||||
public boolean supportsAutoBrightness(final GBDevice device) {
|
||||
return supportsConfig(device, Huami2021Config.ConfigArg.SCREEN_AUTO_BRIGHTNESS);
|
||||
return supportsConfig(device, ZeppOsConfigService.ConfigArg.SCREEN_AUTO_BRIGHTNESS);
|
||||
}
|
||||
|
||||
private boolean supportsConfig(final GBDevice device, final Huami2021Config.ConfigArg config) {
|
||||
return Huami2021Config.deviceHasConfig(getPrefs(device), config);
|
||||
private boolean supportsConfig(final GBDevice device, final ZeppOsConfigService.ConfigArg config) {
|
||||
return ZeppOsConfigService.deviceHasConfig(getPrefs(device), config);
|
||||
}
|
||||
}
|
||||
|
@ -22,7 +22,6 @@ public class Huami2021Service {
|
||||
*/
|
||||
public static final short CHUNKED2021_ENDPOINT_HTTP = 0x0001;
|
||||
public static final short CHUNKED2021_ENDPOINT_CALENDAR = 0x0007;
|
||||
public static final short CHUNKED2021_ENDPOINT_CONFIG = 0x000a;
|
||||
public static final short CHUNKED2021_ENDPOINT_WEATHER = 0x000e;
|
||||
public static final short CHUNKED2021_ENDPOINT_ALARMS = 0x000f;
|
||||
public static final short CHUNKED2021_ENDPOINT_CANNED_MESSAGES = 0x0013;
|
||||
@ -221,16 +220,6 @@ public class Huami2021Service {
|
||||
public static final byte MUSIC_BUTTON_VOLUME_UP = 0x05;
|
||||
public static final byte MUSIC_BUTTON_VOLUME_DOWN = 0x06;
|
||||
|
||||
/**
|
||||
* Config, for {@link Huami2021Service#CHUNKED2021_ENDPOINT_CONFIG}.
|
||||
*/
|
||||
public static final byte CONFIG_CMD_CAPABILITIES_REQUEST = 0x01;
|
||||
public static final byte CONFIG_CMD_CAPABILITIES_RESPONSE = 0x02;
|
||||
public static final byte CONFIG_CMD_REQUEST = 0x03;
|
||||
public static final byte CONFIG_CMD_RESPONSE = 0x04;
|
||||
public static final byte CONFIG_CMD_SET = 0x05;
|
||||
public static final byte CONFIG_CMD_ACK = 0x06;
|
||||
|
||||
/**
|
||||
* Reminders, for {@link Huami2021Service#CHUNKED2021_ENDPOINT_REMINDERS}.
|
||||
*/
|
||||
|
@ -37,7 +37,7 @@ import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSett
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpecificSettingsHandler;
|
||||
import nodomain.freeyourgadget.gadgetbridge.capabilities.GpsCapability;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.Huami2021Config;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.services.ZeppOsConfigService;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.HuamiVibrationPatternNotificationType;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
|
||||
|
||||
@ -57,11 +57,11 @@ public class Huami2021SettingsCustomizer extends HuamiSettingsCustomizer {
|
||||
removeUnsupportedElementsFromListPreference(HuamiConst.PREF_SHORTCUTS_SORTABLE, handler, prefs);
|
||||
removeUnsupportedElementsFromListPreference(HuamiConst.PREF_CONTROL_CENTER_SORTABLE, handler, prefs);
|
||||
|
||||
for (final Huami2021Config.ConfigArg config : Huami2021Config.ConfigArg.values()) {
|
||||
for (final ZeppOsConfigService.ConfigArg config : ZeppOsConfigService.ConfigArg.values()) {
|
||||
if (config.getPrefKey() == null) {
|
||||
continue;
|
||||
}
|
||||
switch (config.getConfigType()) {
|
||||
switch (config.getConfigType(null)) {
|
||||
case BYTE:
|
||||
case BYTE_LIST:
|
||||
case STRING_LIST:
|
||||
@ -79,96 +79,96 @@ public class Huami2021SettingsCustomizer extends HuamiSettingsCustomizer {
|
||||
}
|
||||
|
||||
// Hide all config groups that may not be mapped directly to a preference
|
||||
final Map<String, List<Huami2021Config.ConfigArg>> configScreens = new HashMap<String, List<Huami2021Config.ConfigArg>>() {{
|
||||
final Map<String, List<ZeppOsConfigService.ConfigArg>> configScreens = new HashMap<String, List<ZeppOsConfigService.ConfigArg>>() {{
|
||||
put(DeviceSettingsPreferenceConst.PREF_SCREEN_NIGHT_MODE, Arrays.asList(
|
||||
Huami2021Config.ConfigArg.NIGHT_MODE_MODE,
|
||||
Huami2021Config.ConfigArg.NIGHT_MODE_SCHEDULED_START,
|
||||
Huami2021Config.ConfigArg.NIGHT_MODE_SCHEDULED_END
|
||||
ZeppOsConfigService.ConfigArg.NIGHT_MODE_MODE,
|
||||
ZeppOsConfigService.ConfigArg.NIGHT_MODE_SCHEDULED_START,
|
||||
ZeppOsConfigService.ConfigArg.NIGHT_MODE_SCHEDULED_END
|
||||
));
|
||||
put(DeviceSettingsPreferenceConst.PREF_SCREEN_SLEEP_MODE, Arrays.asList(
|
||||
Huami2021Config.ConfigArg.SLEEP_MODE_SLEEP_SCREEN,
|
||||
Huami2021Config.ConfigArg.SLEEP_MODE_SMART_ENABLE
|
||||
ZeppOsConfigService.ConfigArg.SLEEP_MODE_SLEEP_SCREEN,
|
||||
ZeppOsConfigService.ConfigArg.SLEEP_MODE_SMART_ENABLE
|
||||
));
|
||||
put(DeviceSettingsPreferenceConst.PREF_SCREEN_LIFT_WRIST, Arrays.asList(
|
||||
Huami2021Config.ConfigArg.LIFT_WRIST_MODE,
|
||||
Huami2021Config.ConfigArg.LIFT_WRIST_SCHEDULED_START,
|
||||
Huami2021Config.ConfigArg.LIFT_WRIST_SCHEDULED_END,
|
||||
Huami2021Config.ConfigArg.LIFT_WRIST_RESPONSE_SENSITIVITY
|
||||
ZeppOsConfigService.ConfigArg.LIFT_WRIST_MODE,
|
||||
ZeppOsConfigService.ConfigArg.LIFT_WRIST_SCHEDULED_START,
|
||||
ZeppOsConfigService.ConfigArg.LIFT_WRIST_SCHEDULED_END,
|
||||
ZeppOsConfigService.ConfigArg.LIFT_WRIST_RESPONSE_SENSITIVITY
|
||||
));
|
||||
put(DeviceSettingsPreferenceConst.PREF_SCREEN_PASSWORD, Arrays.asList(
|
||||
Huami2021Config.ConfigArg.PASSWORD_ENABLED,
|
||||
Huami2021Config.ConfigArg.PASSWORD_TEXT
|
||||
ZeppOsConfigService.ConfigArg.PASSWORD_ENABLED,
|
||||
ZeppOsConfigService.ConfigArg.PASSWORD_TEXT
|
||||
));
|
||||
put(DeviceSettingsPreferenceConst.PREF_SCREEN_ALWAYS_ON_DISPLAY, Arrays.asList(
|
||||
Huami2021Config.ConfigArg.ALWAYS_ON_DISPLAY_MODE,
|
||||
Huami2021Config.ConfigArg.ALWAYS_ON_DISPLAY_SCHEDULED_START,
|
||||
Huami2021Config.ConfigArg.ALWAYS_ON_DISPLAY_SCHEDULED_END,
|
||||
Huami2021Config.ConfigArg.ALWAYS_ON_DISPLAY_FOLLOW_WATCHFACE,
|
||||
Huami2021Config.ConfigArg.ALWAYS_ON_DISPLAY_STYLE
|
||||
ZeppOsConfigService.ConfigArg.ALWAYS_ON_DISPLAY_MODE,
|
||||
ZeppOsConfigService.ConfigArg.ALWAYS_ON_DISPLAY_SCHEDULED_START,
|
||||
ZeppOsConfigService.ConfigArg.ALWAYS_ON_DISPLAY_SCHEDULED_END,
|
||||
ZeppOsConfigService.ConfigArg.ALWAYS_ON_DISPLAY_FOLLOW_WATCHFACE,
|
||||
ZeppOsConfigService.ConfigArg.ALWAYS_ON_DISPLAY_STYLE
|
||||
));
|
||||
put(DeviceSettingsPreferenceConst.PREF_SCREEN_AUTO_BRIGHTNESS, Arrays.asList(
|
||||
Huami2021Config.ConfigArg.SCREEN_AUTO_BRIGHTNESS
|
||||
ZeppOsConfigService.ConfigArg.SCREEN_AUTO_BRIGHTNESS
|
||||
));
|
||||
put(DeviceSettingsPreferenceConst.PREF_SCREEN_HEARTRATE_MONITORING, Arrays.asList(
|
||||
Huami2021Config.ConfigArg.HEART_RATE_ALL_DAY_MONITORING,
|
||||
Huami2021Config.ConfigArg.HEART_RATE_HIGH_ALERTS,
|
||||
Huami2021Config.ConfigArg.HEART_RATE_LOW_ALERTS,
|
||||
Huami2021Config.ConfigArg.HEART_RATE_ACTIVITY_MONITORING,
|
||||
Huami2021Config.ConfigArg.SLEEP_HIGH_ACCURACY_MONITORING,
|
||||
Huami2021Config.ConfigArg.SLEEP_BREATHING_QUALITY_MONITORING,
|
||||
Huami2021Config.ConfigArg.STRESS_MONITORING,
|
||||
Huami2021Config.ConfigArg.STRESS_RELAXATION_REMINDER,
|
||||
Huami2021Config.ConfigArg.SPO2_ALL_DAY_MONITORING,
|
||||
Huami2021Config.ConfigArg.SPO2_LOW_ALERT
|
||||
ZeppOsConfigService.ConfigArg.HEART_RATE_ALL_DAY_MONITORING,
|
||||
ZeppOsConfigService.ConfigArg.HEART_RATE_HIGH_ALERTS,
|
||||
ZeppOsConfigService.ConfigArg.HEART_RATE_LOW_ALERTS,
|
||||
ZeppOsConfigService.ConfigArg.HEART_RATE_ACTIVITY_MONITORING,
|
||||
ZeppOsConfigService.ConfigArg.SLEEP_HIGH_ACCURACY_MONITORING,
|
||||
ZeppOsConfigService.ConfigArg.SLEEP_BREATHING_QUALITY_MONITORING,
|
||||
ZeppOsConfigService.ConfigArg.STRESS_MONITORING,
|
||||
ZeppOsConfigService.ConfigArg.STRESS_RELAXATION_REMINDER,
|
||||
ZeppOsConfigService.ConfigArg.SPO2_ALL_DAY_MONITORING,
|
||||
ZeppOsConfigService.ConfigArg.SPO2_LOW_ALERT
|
||||
));
|
||||
put(DeviceSettingsPreferenceConst.PREF_SCREEN_INACTIVITY_EXTENDED, Arrays.asList(
|
||||
Huami2021Config.ConfigArg.INACTIVITY_WARNINGS_ENABLED,
|
||||
Huami2021Config.ConfigArg.INACTIVITY_WARNINGS_SCHEDULED_START,
|
||||
Huami2021Config.ConfigArg.INACTIVITY_WARNINGS_SCHEDULED_END,
|
||||
Huami2021Config.ConfigArg.INACTIVITY_WARNINGS_DND_ENABLED,
|
||||
Huami2021Config.ConfigArg.INACTIVITY_WARNINGS_DND_SCHEDULED_START,
|
||||
Huami2021Config.ConfigArg.INACTIVITY_WARNINGS_DND_SCHEDULED_END
|
||||
ZeppOsConfigService.ConfigArg.INACTIVITY_WARNINGS_ENABLED,
|
||||
ZeppOsConfigService.ConfigArg.INACTIVITY_WARNINGS_SCHEDULED_START,
|
||||
ZeppOsConfigService.ConfigArg.INACTIVITY_WARNINGS_SCHEDULED_END,
|
||||
ZeppOsConfigService.ConfigArg.INACTIVITY_WARNINGS_DND_ENABLED,
|
||||
ZeppOsConfigService.ConfigArg.INACTIVITY_WARNINGS_DND_SCHEDULED_START,
|
||||
ZeppOsConfigService.ConfigArg.INACTIVITY_WARNINGS_DND_SCHEDULED_END
|
||||
));
|
||||
put(DeviceSettingsPreferenceConst.PREF_HEADER_GPS, Arrays.asList(
|
||||
Huami2021Config.ConfigArg.WORKOUT_GPS_PRESET,
|
||||
Huami2021Config.ConfigArg.WORKOUT_GPS_BAND,
|
||||
Huami2021Config.ConfigArg.WORKOUT_GPS_COMBINATION,
|
||||
Huami2021Config.ConfigArg.WORKOUT_GPS_SATELLITE_SEARCH,
|
||||
Huami2021Config.ConfigArg.WORKOUT_AGPS_EXPIRY_REMINDER_ENABLED,
|
||||
Huami2021Config.ConfigArg.WORKOUT_AGPS_EXPIRY_REMINDER_TIME
|
||||
ZeppOsConfigService.ConfigArg.WORKOUT_GPS_PRESET,
|
||||
ZeppOsConfigService.ConfigArg.WORKOUT_GPS_BAND,
|
||||
ZeppOsConfigService.ConfigArg.WORKOUT_GPS_COMBINATION,
|
||||
ZeppOsConfigService.ConfigArg.WORKOUT_GPS_SATELLITE_SEARCH,
|
||||
ZeppOsConfigService.ConfigArg.WORKOUT_AGPS_EXPIRY_REMINDER_ENABLED,
|
||||
ZeppOsConfigService.ConfigArg.WORKOUT_AGPS_EXPIRY_REMINDER_TIME
|
||||
));
|
||||
put(DeviceSettingsPreferenceConst.PREF_SCREEN_SOUND_AND_VIBRATION, Arrays.asList(
|
||||
Huami2021Config.ConfigArg.VOLUME,
|
||||
Huami2021Config.ConfigArg.CROWN_VIBRATION,
|
||||
Huami2021Config.ConfigArg.ALERT_TONE,
|
||||
Huami2021Config.ConfigArg.COVER_TO_MUTE,
|
||||
Huami2021Config.ConfigArg.VIBRATE_FOR_ALERT,
|
||||
Huami2021Config.ConfigArg.TEXT_TO_SPEECH
|
||||
ZeppOsConfigService.ConfigArg.VOLUME,
|
||||
ZeppOsConfigService.ConfigArg.CROWN_VIBRATION,
|
||||
ZeppOsConfigService.ConfigArg.ALERT_TONE,
|
||||
ZeppOsConfigService.ConfigArg.COVER_TO_MUTE,
|
||||
ZeppOsConfigService.ConfigArg.VIBRATE_FOR_ALERT,
|
||||
ZeppOsConfigService.ConfigArg.TEXT_TO_SPEECH
|
||||
));
|
||||
put(DeviceSettingsPreferenceConst.PREF_SCREEN_DO_NOT_DISTURB, Arrays.asList(
|
||||
Huami2021Config.ConfigArg.DND_MODE,
|
||||
Huami2021Config.ConfigArg.DND_SCHEDULED_START,
|
||||
Huami2021Config.ConfigArg.DND_SCHEDULED_END
|
||||
ZeppOsConfigService.ConfigArg.DND_MODE,
|
||||
ZeppOsConfigService.ConfigArg.DND_SCHEDULED_START,
|
||||
ZeppOsConfigService.ConfigArg.DND_SCHEDULED_END
|
||||
));
|
||||
put(DeviceSettingsPreferenceConst.PREF_HEADER_WORKOUT_DETECTION, Arrays.asList(
|
||||
Huami2021Config.ConfigArg.WORKOUT_DETECTION_CATEGORY,
|
||||
Huami2021Config.ConfigArg.WORKOUT_DETECTION_ALERT,
|
||||
Huami2021Config.ConfigArg.WORKOUT_DETECTION_SENSITIVITY
|
||||
ZeppOsConfigService.ConfigArg.WORKOUT_DETECTION_CATEGORY,
|
||||
ZeppOsConfigService.ConfigArg.WORKOUT_DETECTION_ALERT,
|
||||
ZeppOsConfigService.ConfigArg.WORKOUT_DETECTION_SENSITIVITY
|
||||
));
|
||||
put(DeviceSettingsPreferenceConst.PREF_SCREEN_OFFLINE_VOICE, Arrays.asList(
|
||||
Huami2021Config.ConfigArg.OFFLINE_VOICE_RESPOND_TURN_WRIST,
|
||||
Huami2021Config.ConfigArg.OFFLINE_VOICE_RESPOND_SCREEN_ON,
|
||||
Huami2021Config.ConfigArg.OFFLINE_VOICE_RESPONSE_DURING_SCREEN_LIGHTING,
|
||||
Huami2021Config.ConfigArg.OFFLINE_VOICE_LANGUAGE
|
||||
ZeppOsConfigService.ConfigArg.OFFLINE_VOICE_RESPOND_TURN_WRIST,
|
||||
ZeppOsConfigService.ConfigArg.OFFLINE_VOICE_RESPOND_SCREEN_ON,
|
||||
ZeppOsConfigService.ConfigArg.OFFLINE_VOICE_RESPONSE_DURING_SCREEN_LIGHTING,
|
||||
ZeppOsConfigService.ConfigArg.OFFLINE_VOICE_LANGUAGE
|
||||
));
|
||||
}};
|
||||
|
||||
for (final Map.Entry<String, List<Huami2021Config.ConfigArg>> configScreen : configScreens.entrySet()) {
|
||||
for (final Map.Entry<String, List<ZeppOsConfigService.ConfigArg>> configScreen : configScreens.entrySet()) {
|
||||
hidePrefIfNoConfigSupported(
|
||||
handler,
|
||||
prefs,
|
||||
configScreen.getKey(),
|
||||
configScreen.getValue().toArray(new Huami2021Config.ConfigArg[0])
|
||||
configScreen.getValue().toArray(new ZeppOsConfigService.ConfigArg[0])
|
||||
);
|
||||
}
|
||||
|
||||
@ -303,7 +303,7 @@ public class Huami2021SettingsCustomizer extends HuamiSettingsCustomizer {
|
||||
}
|
||||
|
||||
// Get the list of possible values for this preference, as reported by the band
|
||||
final List<String> possibleValues = prefs.getList(Huami2021Config.getPrefPossibleValuesKey(prefKey), null);
|
||||
final List<String> possibleValues = prefs.getList(ZeppOsConfigService.getPrefPossibleValuesKey(prefKey), null);
|
||||
if (possibleValues == null || possibleValues.isEmpty()) {
|
||||
// The band hasn't reported this setting, so we don't know the possible values.
|
||||
// Hide it
|
||||
@ -360,14 +360,14 @@ public class Huami2021SettingsCustomizer extends HuamiSettingsCustomizer {
|
||||
private void hidePrefIfNoConfigSupported(final DeviceSpecificSettingsHandler handler,
|
||||
final Prefs prefs,
|
||||
final String prefToHide,
|
||||
final Huami2021Config.ConfigArg... configs) {
|
||||
final ZeppOsConfigService.ConfigArg... configs) {
|
||||
final Preference pref = handler.findPreference(prefToHide);
|
||||
if (pref == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (final Huami2021Config.ConfigArg config : configs) {
|
||||
if (Huami2021Config.deviceHasConfig(prefs, config)) {
|
||||
for (final ZeppOsConfigService.ConfigArg config : configs) {
|
||||
if (ZeppOsConfigService.deviceHasConfig(prefs, config)) {
|
||||
// This preference is supported, don't hide
|
||||
return;
|
||||
}
|
||||
|
@ -17,5 +17,5 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.huami;
|
||||
|
||||
public interface Huami2021Handler {
|
||||
void handle2021Payload(int type, byte[] payload);
|
||||
void handle2021Payload(short type, byte[] payload);
|
||||
}
|
||||
|
@ -17,32 +17,27 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.huami;
|
||||
|
||||
import static org.apache.commons.lang3.ArrayUtils.subarray;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_LANGUAGE;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_LANGUAGE_AUTO;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_TIMEFORMAT;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_TIMEFORMAT_AUTO;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.devices.huami.Huami2021Service.*;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiService.SUCCESS;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.model.ActivityUser.PREF_USER_NAME;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.service.btle.BLETypeConversions.fromUint16;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.service.btle.BLETypeConversions.fromUint8;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.service.btle.BLETypeConversions.mapTimeZone;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.service.devices.huami.Huami2021Config.ConfigArg.FITNESS_GOAL_CALORIES;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.service.devices.huami.Huami2021Config.ConfigArg.FITNESS_GOAL_FAT_BURN_TIME;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.service.devices.huami.Huami2021Config.ConfigArg.FITNESS_GOAL_SLEEP;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.service.devices.huami.Huami2021Config.ConfigArg.FITNESS_GOAL_STANDING_TIME;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.service.devices.huami.Huami2021Config.ConfigArg.FITNESS_GOAL_STEPS;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.service.devices.huami.Huami2021Config.ConfigArg.FITNESS_GOAL_WEIGHT;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.service.devices.huami.Huami2021Config.ConfigArg.HEART_RATE_ALL_DAY_MONITORING;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.service.devices.huami.Huami2021Config.ConfigArg.LANGUAGE;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.service.devices.huami.Huami2021Config.ConfigArg.LANGUAGE_FOLLOW_PHONE;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.service.devices.huami.Huami2021Config.ConfigArg.PASSWORD_ENABLED;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.service.devices.huami.Huami2021Config.ConfigArg.PASSWORD_TEXT;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.service.devices.huami.Huami2021Config.ConfigArg.SLEEP_HIGH_ACCURACY_MONITORING;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.service.devices.huami.Huami2021Config.ConfigArg.TEMPERATURE_UNIT;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.service.devices.huami.Huami2021Config.ConfigArg.TIME_FORMAT;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.service.devices.huami.Huami2021Config.ConfigGroup;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.service.devices.huami.Huami2021Config.ConfigSetter;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.services.ZeppOsConfigService.ConfigArg.FITNESS_GOAL_CALORIES;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.services.ZeppOsConfigService.ConfigArg.FITNESS_GOAL_FAT_BURN_TIME;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.services.ZeppOsConfigService.ConfigArg.FITNESS_GOAL_SLEEP;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.services.ZeppOsConfigService.ConfigArg.FITNESS_GOAL_STANDING_TIME;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.services.ZeppOsConfigService.ConfigArg.FITNESS_GOAL_STEPS;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.services.ZeppOsConfigService.ConfigArg.FITNESS_GOAL_WEIGHT;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.services.ZeppOsConfigService.ConfigArg.HEART_RATE_ALL_DAY_MONITORING;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.services.ZeppOsConfigService.ConfigArg.LANGUAGE;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.services.ZeppOsConfigService.ConfigArg.LANGUAGE_FOLLOW_PHONE;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.services.ZeppOsConfigService.ConfigArg.PASSWORD_ENABLED;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.services.ZeppOsConfigService.ConfigArg.PASSWORD_TEXT;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.services.ZeppOsConfigService.ConfigArg.SLEEP_HIGH_ACCURACY_MONITORING;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.services.ZeppOsConfigService.ConfigArg.TEMPERATURE_UNIT;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.services.ZeppOsConfigService.ConfigArg.TIME_FORMAT;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.services.ZeppOsConfigService.ConfigGroup;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.Intent;
|
||||
@ -120,6 +115,8 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.operations.Fet
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.operations.HuamiFetchDebugLogsOperation;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.operations.UpdateFirmwareOperation;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.operations.UpdateFirmwareOperation2021;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.AbstractZeppOsService;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.services.ZeppOsConfigService;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.services.ZeppOsFileUploadService;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.AlarmUtils;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.BitmapUtil;
|
||||
@ -144,6 +141,11 @@ public abstract class Huami2021Support extends HuamiSupport {
|
||||
|
||||
// Services
|
||||
private final ZeppOsFileUploadService fileUploadService = new ZeppOsFileUploadService(this);
|
||||
private final ZeppOsConfigService configService = new ZeppOsConfigService(this);
|
||||
private final Map<Short, AbstractZeppOsService> mServiceMap = new HashMap<Short, AbstractZeppOsService>() {{
|
||||
put(fileUploadService.getEndpoint(), fileUploadService);
|
||||
put(configService.getEndpoint(), configService);
|
||||
}};
|
||||
|
||||
public Huami2021Support() {
|
||||
this(LOG);
|
||||
@ -174,15 +176,15 @@ public abstract class Huami2021Support extends HuamiSupport {
|
||||
|
||||
@Override
|
||||
public void onSendConfiguration(final String config) {
|
||||
final ConfigSetter configSetter = new ConfigSetter();
|
||||
final ZeppOsConfigService.ConfigSetter configSetter = configService.newSetter();
|
||||
final Prefs prefs = getDevicePrefs();
|
||||
|
||||
try {
|
||||
if (Huami2021Config.setConfig(prefs, config, configSetter)) {
|
||||
if (configService.setConfig(prefs, config, configSetter)) {
|
||||
// If the ConfigSetter was able to set the config, just write it and return
|
||||
final TransactionBuilder builder;
|
||||
builder = performInitialized("Sending configuration for option: " + config);
|
||||
configSetter.write(this, builder);
|
||||
configSetter.write(builder);
|
||||
builder.queue(getQueue());
|
||||
|
||||
return;
|
||||
@ -453,14 +455,14 @@ public abstract class Huami2021Support extends HuamiSupport {
|
||||
final int goalFatBurnTime = GBApplication.getPrefs().getInt(ActivityUser.PREF_USER_GOAL_FAT_BURN_TIME_MINUTES, ActivityUser.defaultUserFatBurnTimeMinutes);
|
||||
LOG.info("Setting Fitness Goals to steps={}, calories={}, sleep={}, weight={}, standingTime={}, fatBurn={}", goalSteps, goalCalories, goalSleep, goalWeight, goalStandingTime, goalFatBurnTime);
|
||||
|
||||
new ConfigSetter()
|
||||
configService.newSetter()
|
||||
.setInt(FITNESS_GOAL_STEPS, goalSteps)
|
||||
.setShort(FITNESS_GOAL_CALORIES, (short) goalCalories)
|
||||
.setShort(FITNESS_GOAL_SLEEP, (short) (goalSleep * 60))
|
||||
.setShort(FITNESS_GOAL_WEIGHT, (short) goalWeight)
|
||||
.setShort(FITNESS_GOAL_STANDING_TIME, (short) (goalStandingTime))
|
||||
.setShort(FITNESS_GOAL_FAT_BURN_TIME, (short) goalFatBurnTime)
|
||||
.write(this, builder);
|
||||
.write(builder);
|
||||
|
||||
return this;
|
||||
}
|
||||
@ -529,10 +531,10 @@ public abstract class Huami2021Support extends HuamiSupport {
|
||||
return this;
|
||||
}
|
||||
|
||||
new ConfigSetter()
|
||||
configService.newSetter()
|
||||
.setBoolean(PASSWORD_ENABLED, passwordEnabled)
|
||||
.setString(PASSWORD_TEXT, password)
|
||||
.write(this, builder);
|
||||
.write(builder);
|
||||
|
||||
return this;
|
||||
}
|
||||
@ -897,9 +899,9 @@ public abstract class Huami2021Support extends HuamiSupport {
|
||||
protected Huami2021Support setHeartrateSleepSupport(final TransactionBuilder builder) {
|
||||
final boolean enableHrSleepSupport = MiBandCoordinator.getHeartrateSleepSupport(gbDevice.getAddress());
|
||||
|
||||
new ConfigSetter()
|
||||
configService.newSetter()
|
||||
.setBoolean(SLEEP_HIGH_ACCURACY_MONITORING, enableHrSleepSupport)
|
||||
.write(this, builder);
|
||||
.write(builder);
|
||||
|
||||
return this;
|
||||
}
|
||||
@ -955,10 +957,10 @@ public abstract class Huami2021Support extends HuamiSupport {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected HuamiSupport setHeartrateMeasurementInterval(TransactionBuilder builder, int minutes) {
|
||||
new ConfigSetter()
|
||||
protected HuamiSupport setHeartrateMeasurementInterval(final TransactionBuilder builder, final int minutes) {
|
||||
configService.newSetter()
|
||||
.setByte(HEART_RATE_ALL_DAY_MONITORING, (byte) minutes)
|
||||
.write(this, builder);
|
||||
.write(builder);
|
||||
|
||||
return this;
|
||||
}
|
||||
@ -1043,9 +1045,9 @@ public abstract class Huami2021Support extends HuamiSupport {
|
||||
timeFormatByte = 0x00;
|
||||
}
|
||||
|
||||
new ConfigSetter()
|
||||
configService.newSetter()
|
||||
.setByte(TIME_FORMAT, timeFormatByte)
|
||||
.write(this, builder);
|
||||
.write(builder);
|
||||
|
||||
return this;
|
||||
}
|
||||
@ -1057,7 +1059,7 @@ public abstract class Huami2021Support extends HuamiSupport {
|
||||
setDisplayItems2021(
|
||||
builder,
|
||||
DISPLAY_ITEMS_MENU,
|
||||
new ArrayList<>(prefs.getList(Huami2021Config.getPrefPossibleValuesKey(HuamiConst.PREF_DISPLAY_ITEMS_SORTABLE), Collections.emptyList())),
|
||||
new ArrayList<>(prefs.getList(ZeppOsConfigService.getPrefPossibleValuesKey(HuamiConst.PREF_DISPLAY_ITEMS_SORTABLE), Collections.emptyList())),
|
||||
new ArrayList<>(prefs.getList(HuamiConst.PREF_DISPLAY_ITEMS_SORTABLE, Collections.emptyList()))
|
||||
);
|
||||
return this;
|
||||
@ -1070,7 +1072,7 @@ public abstract class Huami2021Support extends HuamiSupport {
|
||||
setDisplayItems2021(
|
||||
builder,
|
||||
DISPLAY_ITEMS_SHORTCUTS,
|
||||
new ArrayList<>(prefs.getList(Huami2021Config.getPrefPossibleValuesKey(HuamiConst.PREF_SHORTCUTS_SORTABLE), Collections.emptyList())),
|
||||
new ArrayList<>(prefs.getList(ZeppOsConfigService.getPrefPossibleValuesKey(HuamiConst.PREF_SHORTCUTS_SORTABLE), Collections.emptyList())),
|
||||
new ArrayList<>(prefs.getList(HuamiConst.PREF_SHORTCUTS_SORTABLE, Collections.emptyList()))
|
||||
);
|
||||
return this;
|
||||
@ -1082,7 +1084,7 @@ public abstract class Huami2021Support extends HuamiSupport {
|
||||
setDisplayItems2021(
|
||||
builder,
|
||||
DISPLAY_ITEMS_CONTROL_CENTER,
|
||||
new ArrayList<>(prefs.getList(Huami2021Config.getPrefPossibleValuesKey(HuamiConst.PREF_CONTROL_CENTER_SORTABLE), Collections.emptyList())),
|
||||
new ArrayList<>(prefs.getList(ZeppOsConfigService.getPrefPossibleValuesKey(HuamiConst.PREF_CONTROL_CENTER_SORTABLE), Collections.emptyList())),
|
||||
new ArrayList<>(prefs.getList(HuamiConst.PREF_CONTROL_CENTER_SORTABLE, Collections.emptyList()))
|
||||
);
|
||||
return this;
|
||||
@ -1226,9 +1228,9 @@ public abstract class Huami2021Support extends HuamiSupport {
|
||||
break;
|
||||
}
|
||||
|
||||
new ConfigSetter()
|
||||
configService.newSetter()
|
||||
.setByte(TEMPERATURE_UNIT, unitByte)
|
||||
.write(this, builder);
|
||||
.write(builder);
|
||||
|
||||
return this;
|
||||
}
|
||||
@ -1240,10 +1242,10 @@ public abstract class Huami2021Support extends HuamiSupport {
|
||||
|
||||
LOG.info("Setting device language to {}", localeString);
|
||||
|
||||
new ConfigSetter()
|
||||
configService.newSetter()
|
||||
.setByte(LANGUAGE, getLanguageId())
|
||||
.setBoolean(LANGUAGE_FOLLOW_PHONE, localeString.equals("auto"))
|
||||
.write(this, builder);
|
||||
.write(builder);
|
||||
|
||||
return this;
|
||||
}
|
||||
@ -1361,12 +1363,8 @@ public abstract class Huami2021Support extends HuamiSupport {
|
||||
|
||||
LOG.info("2021 phase3Initialize...");
|
||||
setUserInfo(builder);
|
||||
setFitnessGoal(builder);
|
||||
|
||||
for (final ConfigGroup configGroup : ConfigGroup.values()) {
|
||||
requestConfig(builder, configGroup);
|
||||
}
|
||||
|
||||
configService.requestAllConfigs(builder);
|
||||
requestCapabilityReminders(builder);
|
||||
fileUploadService.requestCapability(builder);
|
||||
|
||||
@ -1416,7 +1414,7 @@ public abstract class Huami2021Support extends HuamiSupport {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle2021Payload(final int type, final byte[] payload) {
|
||||
public void handle2021Payload(final short type, final byte[] payload) {
|
||||
if (payload == null || payload.length == 0) {
|
||||
LOG.warn("Empty or null payload for {}", String.format("0x%04x", type));
|
||||
return;
|
||||
@ -1424,6 +1422,11 @@ public abstract class Huami2021Support extends HuamiSupport {
|
||||
|
||||
LOG.debug("Got 2021 payload for {}: {}", String.format("0x%04x", type), GB.hexdump(payload));
|
||||
|
||||
if (mServiceMap.containsKey(type)) {
|
||||
mServiceMap.get(type).handlePayload(payload);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case CHUNKED2021_ENDPOINT_ALARMS:
|
||||
handle2021Alarms(payload);
|
||||
@ -1437,12 +1440,6 @@ public abstract class Huami2021Support extends HuamiSupport {
|
||||
case CHUNKED2021_ENDPOINT_COMPAT:
|
||||
LOG.warn("Unexpected compat payload {}", GB.hexdump(payload));
|
||||
return;
|
||||
case CHUNKED2021_ENDPOINT_CONFIG:
|
||||
handle2021Config(payload);
|
||||
return;
|
||||
case ZeppOsFileUploadService.ENDPOINT:
|
||||
fileUploadService.handlePayload(payload);
|
||||
return;
|
||||
case CHUNKED2021_ENDPOINT_WEATHER:
|
||||
handle2021Weather(payload);
|
||||
return;
|
||||
@ -1660,102 +1657,6 @@ public abstract class Huami2021Support extends HuamiSupport {
|
||||
// TODO update database?
|
||||
}
|
||||
|
||||
private void requestConfig(final TransactionBuilder builder,
|
||||
final ConfigGroup config,
|
||||
final boolean includeConstraints,
|
||||
final List<Huami2021Config.ConfigArg> args) {
|
||||
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
|
||||
baos.write(CONFIG_CMD_REQUEST);
|
||||
baos.write(bool(includeConstraints));
|
||||
baos.write(config.getValue());
|
||||
baos.write(args.size());
|
||||
for (final Huami2021Config.ConfigArg arg : args) {
|
||||
baos.write(arg.getCode());
|
||||
}
|
||||
|
||||
writeToChunked2021(builder, CHUNKED2021_ENDPOINT_CONFIG, baos.toByteArray(), true);
|
||||
}
|
||||
|
||||
private void requestConfig(final TransactionBuilder builder, final ConfigGroup config) {
|
||||
requestConfig(builder, config, true, Huami2021Config.ConfigArg.getAllArgsForConfigGroup(config));
|
||||
}
|
||||
|
||||
protected void handle2021Config(final byte[] payload) {
|
||||
switch (payload[0]) {
|
||||
case CONFIG_CMD_ACK:
|
||||
LOG.info("Configuration ACK, status = {}", payload[1]);
|
||||
return;
|
||||
|
||||
case CONFIG_CMD_RESPONSE:
|
||||
if (payload[1] != 1) {
|
||||
LOG.warn("Configuration response not success: {}", payload[1]);
|
||||
return;
|
||||
}
|
||||
|
||||
handle2021ConfigResponse(payload);
|
||||
return;
|
||||
default:
|
||||
LOG.warn("Unexpected configuration payload byte {}", String.format("0x%02x", payload[0]));
|
||||
}
|
||||
}
|
||||
|
||||
private void handle2021ConfigResponse(final byte[] payload) {
|
||||
final ConfigGroup configGroup = ConfigGroup.fromValue(payload[2]);
|
||||
if (configGroup == null) {
|
||||
LOG.warn("Unknown config type {}", String.format("0x%02x", payload[2]));
|
||||
return;
|
||||
}
|
||||
|
||||
if (configGroup.getVersion() != payload[3]) {
|
||||
LOG.warn("Unexpected next byte {} for {}", String.format("0x%02x", payload[3]), configGroup);
|
||||
return;
|
||||
}
|
||||
|
||||
final boolean includesConstraints = payload[4] == 0x01;
|
||||
|
||||
int numConfigs = payload[5] & 0xff;
|
||||
|
||||
LOG.info("Got {} configs for {}", numConfigs, configGroup);
|
||||
|
||||
final Map<String, Object> prefs = new Huami2021Config.ConfigParser(configGroup, includesConstraints)
|
||||
.parse(numConfigs, subarray(payload, 6, payload.length));
|
||||
|
||||
if (prefs == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final GBDeviceEventUpdatePreferences eventUpdatePreferences = new GBDeviceEventUpdatePreferences(prefs);
|
||||
evaluateGBDeviceEvent(eventUpdatePreferences);
|
||||
|
||||
if (isInitialized()) {
|
||||
final TransactionBuilder builder;
|
||||
boolean hasAutoConfigsToSend = false;
|
||||
|
||||
try {
|
||||
builder = performInitialized("set auto band configs");
|
||||
} catch (final Exception e) {
|
||||
LOG.error("Failed to set auto band configs", e);
|
||||
return;
|
||||
}
|
||||
|
||||
if (prefs.containsKey(PREF_LANGUAGE) && prefs.get(PREF_LANGUAGE).equals(PREF_LANGUAGE_AUTO)) {
|
||||
// Band is reporting automatic language, we need to send the actual language
|
||||
setLanguage(builder);
|
||||
hasAutoConfigsToSend = true;
|
||||
}
|
||||
if (prefs.containsKey(PREF_TIMEFORMAT) && prefs.get(PREF_TIMEFORMAT).equals(PREF_TIMEFORMAT_AUTO)) {
|
||||
// Band is reporting automatic time format, we need to send the actual time format
|
||||
setTimeFormat(builder);
|
||||
hasAutoConfigsToSend = true;
|
||||
}
|
||||
|
||||
if (hasAutoConfigsToSend) {
|
||||
builder.queue(getQueue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void handle2021Workout(final byte[] payload) {
|
||||
switch (payload[0]) {
|
||||
case WORKOUT_CMD_APP_OPEN:
|
||||
@ -1838,7 +1739,7 @@ public abstract class Huami2021Support extends HuamiSupport {
|
||||
LOG.error("Unknown display items type {}", String.format("0x%x", payload[1]));
|
||||
return;
|
||||
}
|
||||
final String allScreensPrefKey = Huami2021Config.getPrefPossibleValuesKey(prefKey);
|
||||
final String allScreensPrefKey = ZeppOsConfigService.getPrefPossibleValuesKey(prefKey);
|
||||
|
||||
final boolean menuHasMoreSection;
|
||||
|
||||
|
@ -4111,7 +4111,7 @@ public abstract class HuamiSupport extends AbstractBTLEDeviceSupport implements
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle2021Payload(int type, byte[] payload) {
|
||||
public void handle2021Payload(short type, byte[] payload) {
|
||||
if (type == Huami2021Service.CHUNKED2021_ENDPOINT_COMPAT) {
|
||||
LOG.info("got configuration data");
|
||||
type = 0;
|
||||
|
@ -132,7 +132,7 @@ public class InitOperation2021 extends InitOperation implements Huami2021Handler
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle2021Payload(final int type, final byte[] payload) {
|
||||
public void handle2021Payload(final short type, final byte[] payload) {
|
||||
if (type != Huami2021Service.CHUNKED2021_ENDPOINT_AUTH) {
|
||||
this.huamiSupport.handle2021Payload(type, payload);
|
||||
return;
|
||||
|
@ -30,6 +30,10 @@ public abstract class AbstractZeppOsService {
|
||||
public abstract boolean isEncrypted();
|
||||
public abstract void handlePayload(final byte[] payload);
|
||||
|
||||
protected Huami2021Support getSupport() {
|
||||
return mSupport;
|
||||
}
|
||||
|
||||
protected void write(final String taskName, final byte[] data) {
|
||||
this.mSupport.writeToChunked2021(taskName, getEndpoint(), data, isEncrypted());
|
||||
}
|
||||
|
@ -14,13 +14,12 @@
|
||||
|
||||
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.huami;
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.services;
|
||||
|
||||
import static org.apache.commons.lang3.ArrayUtils.subarray;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.*;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.capabilities.password.PasswordCapabilityImpl.PREF_PASSWORD;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.capabilities.password.PasswordCapabilityImpl.PREF_PASSWORD_ENABLED;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.devices.huami.Huami2021Service.CHUNKED2021_ENDPOINT_CONFIG;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.devices.huami.Huami2021Service.CONFIG_CMD_SET;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiConst.PREF_EXPOSE_HR_THIRDPARTY;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.PREF_NIGHT_MODE;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.PREF_NIGHT_MODE_END;
|
||||
@ -59,6 +58,7 @@ import nodomain.freeyourgadget.gadgetbridge.activities.SettingsActivity;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst;
|
||||
import nodomain.freeyourgadget.gadgetbridge.capabilities.GpsCapability;
|
||||
import nodomain.freeyourgadget.gadgetbridge.capabilities.WorkoutDetectionCapability;
|
||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventUpdatePreferences;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.huami.ActivateDisplayOnLift;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.huami.ActivateDisplayOnLiftSensitivity;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.huami.AlwaysOnDisplay;
|
||||
@ -66,13 +66,143 @@ import nodomain.freeyourgadget.gadgetbridge.devices.miband.DoNotDisturb;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.BLETypeConversions;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.Huami2021MenuType;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.Huami2021Support;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.HuamiLanguageType;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.AbstractZeppOsService;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.MapUtils;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.StringUtils;
|
||||
|
||||
public class Huami2021Config {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(Huami2021Config.class);
|
||||
public class ZeppOsConfigService extends AbstractZeppOsService {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ZeppOsConfigService.class);
|
||||
|
||||
private static final short ENDPOINT = 0x000a;
|
||||
|
||||
private static final byte CMD_CAPABILITIES_REQUEST = 0x01;
|
||||
private static final byte CMD_CAPABILITIES_RESPONSE = 0x02;
|
||||
private static final byte CMD_REQUEST = 0x03;
|
||||
private static final byte CMD_RESPONSE = 0x04;
|
||||
private static final byte CMD_SET = 0x05;
|
||||
private static final byte CMD_ACK = 0x06;
|
||||
|
||||
private final Map<ConfigGroup, Byte> mGroupVersions = new HashMap<>();
|
||||
|
||||
public ZeppOsConfigService(final Huami2021Support support) {
|
||||
super(support);
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getEndpoint() {
|
||||
return ENDPOINT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEncrypted() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handlePayload(final byte[] payload) {
|
||||
switch (payload[0]) {
|
||||
case CMD_ACK:
|
||||
LOG.info("Configuration ACK, status = {}", payload[1]);
|
||||
return;
|
||||
|
||||
case CMD_RESPONSE:
|
||||
if (payload[1] != 1) {
|
||||
LOG.warn("Configuration response not success: {}", payload[1]);
|
||||
return;
|
||||
}
|
||||
|
||||
handle2021ConfigResponse(payload);
|
||||
return;
|
||||
default:
|
||||
LOG.warn("Unexpected configuration payload byte {}", String.format("0x%02x", payload[0]));
|
||||
}
|
||||
}
|
||||
|
||||
private boolean sentFitnessGoal = false;
|
||||
|
||||
private void handle2021ConfigResponse(final byte[] payload) {
|
||||
final ConfigGroup configGroup = ConfigGroup.fromValue(payload[2]);
|
||||
if (configGroup == null) {
|
||||
LOG.warn("Unknown config type {}", String.format("0x%02x", payload[2]));
|
||||
return;
|
||||
}
|
||||
|
||||
final byte version = payload[3];
|
||||
if (configGroup.getVersion() != version) {
|
||||
// Special case for HEALTH, where we actually support version 1 as well
|
||||
// TODO: Support multiple versions in a cleaner way...
|
||||
if (!(configGroup == ConfigGroup.HEALTH && configGroup.getVersion() == 1)) {
|
||||
LOG.warn("Unexpected version {} for {}", String.format("0x%02x", version), configGroup);
|
||||
return;
|
||||
}
|
||||
}
|
||||
mGroupVersions.put(configGroup, version);
|
||||
|
||||
final boolean includesConstraints = payload[4] == 0x01;
|
||||
|
||||
int numConfigs = payload[5] & 0xff;
|
||||
|
||||
LOG.info("Got {} configs for {} version {}", numConfigs, configGroup, version);
|
||||
|
||||
final Map<String, Object> prefs = new ZeppOsConfigService.ConfigParser(configGroup, includesConstraints)
|
||||
.parse(numConfigs, subarray(payload, 6, payload.length));
|
||||
|
||||
if (prefs == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final GBDeviceEventUpdatePreferences eventUpdatePreferences = new GBDeviceEventUpdatePreferences(prefs);
|
||||
getSupport().evaluateGBDeviceEvent(eventUpdatePreferences);
|
||||
|
||||
if (getSupport().getDevice().isInitialized()) {
|
||||
if (prefs.containsKey(PREF_LANGUAGE) && prefs.get(PREF_LANGUAGE).equals(PREF_LANGUAGE_AUTO)) {
|
||||
// Band is reporting automatic language, we need to send the actual language
|
||||
getSupport().onSendConfiguration(PREF_LANGUAGE);
|
||||
}
|
||||
if (prefs.containsKey(PREF_TIMEFORMAT) && prefs.get(PREF_TIMEFORMAT).equals(PREF_TIMEFORMAT_AUTO)) {
|
||||
// Band is reporting automatic time format, we need to send the actual time format
|
||||
getSupport().onSendConfiguration(PREF_TIMEFORMAT);
|
||||
}
|
||||
}
|
||||
|
||||
if (configGroup == ConfigGroup.HEALTH && !sentFitnessGoal) {
|
||||
// We need to send the fitness goal after we got the protocol version
|
||||
getSupport().onSendConfiguration(PREF_USER_FITNESS_GOAL);
|
||||
sentFitnessGoal = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void requestAllConfigs(final TransactionBuilder builder) {
|
||||
for (final ConfigGroup configGroup : ConfigGroup.values()) {
|
||||
requestConfig(builder, configGroup);
|
||||
}
|
||||
}
|
||||
|
||||
public void requestConfig(final TransactionBuilder builder, final ConfigGroup config) {
|
||||
requestConfig(builder, config, true, ZeppOsConfigService.ConfigArg.getAllArgsForConfigGroup(config));
|
||||
}
|
||||
|
||||
public void requestConfig(final TransactionBuilder builder,
|
||||
final ConfigGroup config,
|
||||
final boolean includeConstraints,
|
||||
final List<ZeppOsConfigService.ConfigArg> args) {
|
||||
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
|
||||
baos.write(CMD_REQUEST);
|
||||
baos.write((byte) (includeConstraints ? 1 : 0));
|
||||
baos.write(config.getValue());
|
||||
baos.write(args.size());
|
||||
for (final ZeppOsConfigService.ConfigArg arg : args) {
|
||||
baos.write(arg.getCode());
|
||||
}
|
||||
|
||||
write(builder, baos.toByteArray());
|
||||
}
|
||||
|
||||
public enum ConfigGroup {
|
||||
DISPLAY(0x01, 0x02),
|
||||
@ -201,7 +331,7 @@ public class Huami2021Config {
|
||||
SPO2_ALL_DAY_MONITORING(ConfigGroup.HEALTH, ConfigType.BOOL, 0x31, PREF_SPO2_ALL_DAY_MONITORING),
|
||||
SPO2_LOW_ALERT(ConfigGroup.HEALTH, ConfigType.BYTE, 0x32, PREF_SPO2_LOW_ALERT_THRESHOLD),
|
||||
FITNESS_GOAL_NOTIFICATION(ConfigGroup.HEALTH, ConfigType.BOOL, 0x51, PREF_USER_FITNESS_GOAL_NOTIFICATION),
|
||||
FITNESS_GOAL_STEPS(ConfigGroup.HEALTH, ConfigType.INT, 0x52, null), // TODO needs to be handled globally
|
||||
FITNESS_GOAL_STEPS(ConfigGroup.HEALTH, null /* Special case, handled below */, 0x52, null), // TODO needs to be handled globally
|
||||
FITNESS_GOAL_CALORIES(ConfigGroup.HEALTH, ConfigType.SHORT, 0x53, null), // TODO needs to be handled globally
|
||||
FITNESS_GOAL_WEIGHT(ConfigGroup.HEALTH, ConfigType.SHORT, 0x54, null), // TODO needs to be handled globally
|
||||
FITNESS_GOAL_SLEEP(ConfigGroup.HEALTH, ConfigType.SHORT, 0x55, null), // TODO needs to be handled globally
|
||||
@ -263,7 +393,27 @@ public class Huami2021Config {
|
||||
return configGroup;
|
||||
}
|
||||
|
||||
public ConfigType getConfigType() {
|
||||
public ConfigType getConfigType(@Nullable final Map<ConfigGroup, Byte> groupVersions) {
|
||||
if (this == FITNESS_GOAL_STEPS) {
|
||||
if (groupVersions == null) {
|
||||
return ConfigType.INT;
|
||||
}
|
||||
|
||||
final Byte groupVersion = groupVersions.get(getConfigGroup());
|
||||
if (groupVersion == null) {
|
||||
LOG.error("Version for {} is not known", getConfigGroup());
|
||||
return null;
|
||||
}
|
||||
|
||||
switch (groupVersion) {
|
||||
case 0x01:
|
||||
return ConfigType.SHORT;
|
||||
case 0x02:
|
||||
default:
|
||||
return ConfigType.INT;
|
||||
}
|
||||
}
|
||||
|
||||
return configType;
|
||||
}
|
||||
|
||||
@ -276,7 +426,7 @@ public class Huami2021Config {
|
||||
}
|
||||
|
||||
public static ConfigArg fromCode(final ConfigGroup configGroup, final byte code) {
|
||||
for (final Huami2021Config.ConfigArg arg : values()) {
|
||||
for (final ZeppOsConfigService.ConfigArg arg : values()) {
|
||||
if (arg.getConfigGroup().equals(configGroup) && arg.getCode() == code) {
|
||||
return arg;
|
||||
}
|
||||
@ -285,8 +435,8 @@ public class Huami2021Config {
|
||||
}
|
||||
|
||||
public static List<ConfigArg> getAllArgsForConfigGroup(final ConfigGroup configGroup) {
|
||||
final List<Huami2021Config.ConfigArg> configArgs = new ArrayList<>();
|
||||
for (final Huami2021Config.ConfigArg arg : values()) {
|
||||
final List<ZeppOsConfigService.ConfigArg> configArgs = new ArrayList<>();
|
||||
for (final ZeppOsConfigService.ConfigArg arg : values()) {
|
||||
if (arg.getConfigGroup().equals(configGroup)) {
|
||||
configArgs.add(arg);
|
||||
}
|
||||
@ -317,14 +467,14 @@ public class Huami2021Config {
|
||||
*
|
||||
* @return true if the {@link ConfigSetter} was updated for this preference key
|
||||
*/
|
||||
public static boolean setConfig(final Prefs prefs, final String key, final ConfigSetter setter) {
|
||||
public boolean setConfig(final Prefs prefs, final String key, final ConfigSetter setter) {
|
||||
final ConfigArg configArg = PREF_TO_CONFIG.get(key);
|
||||
if (configArg == null) {
|
||||
LOG.error("Unknown pref key {}", key);
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (configArg.getConfigType()) {
|
||||
switch (configArg.getConfigType(mGroupVersions)) {
|
||||
case BOOL:
|
||||
setter.setBoolean(configArg, prefs.getBoolean(key, false));
|
||||
return true;
|
||||
@ -470,11 +620,15 @@ public class Huami2021Config {
|
||||
return String.format(Locale.ROOT, "huami_2021_known_config_%s", pref.name());
|
||||
}
|
||||
|
||||
public static boolean deviceHasConfig(final Prefs devicePrefs, final Huami2021Config.ConfigArg config) {
|
||||
public static boolean deviceHasConfig(final Prefs devicePrefs, final ZeppOsConfigService.ConfigArg config) {
|
||||
return devicePrefs.getBoolean(getPrefKnownConfig(config), false);
|
||||
}
|
||||
|
||||
public static class ConfigSetter {
|
||||
public ConfigSetter newSetter() {
|
||||
return new ConfigSetter();
|
||||
}
|
||||
|
||||
public class ConfigSetter {
|
||||
private final Map<ConfigGroup, Map<ConfigArg, byte[]>> arguments = new LinkedHashMap<>();
|
||||
|
||||
public ConfigSetter() {
|
||||
@ -568,13 +722,13 @@ public class Huami2021Config {
|
||||
final Map<ConfigArg, byte[]> configArgMap = arguments.get(configGroup);
|
||||
|
||||
try {
|
||||
baos.write(CONFIG_CMD_SET);
|
||||
baos.write(CMD_SET);
|
||||
baos.write(configGroup.getValue());
|
||||
baos.write(configGroup.getVersion());
|
||||
baos.write(0x00); // ?
|
||||
baos.write(configArgMap.size());
|
||||
for (final Map.Entry<ConfigArg, byte[]> arg : configArgMap.entrySet()) {
|
||||
final ConfigType configType = arg.getKey().getConfigType();
|
||||
final ConfigType configType = arg.getKey().getConfigType(mGroupVersions);
|
||||
baos.write(arg.getKey().getCode());
|
||||
baos.write(configType.getValue());
|
||||
baos.write(arg.getValue());
|
||||
@ -586,22 +740,27 @@ public class Huami2021Config {
|
||||
return baos.toByteArray();
|
||||
}
|
||||
|
||||
public void write(final Huami2021Support support, final TransactionBuilder builder) {
|
||||
public void write(final TransactionBuilder builder) {
|
||||
// Write one command per config group
|
||||
for (final ConfigGroup configGroup : arguments.keySet()) {
|
||||
support.writeToChunked2021(builder, CHUNKED2021_ENDPOINT_CONFIG, encode(configGroup), true);
|
||||
ZeppOsConfigService.this.write(builder, encode(configGroup));
|
||||
}
|
||||
}
|
||||
|
||||
private void checkArg(final ConfigArg arg, final ConfigType expectedConfigType) {
|
||||
if (arg.getConfigType(mGroupVersions) == null) {
|
||||
// Some special cases (STEPS goal) do not have a config type
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
if (!expectedConfigType.equals(arg.getConfigType())) {
|
||||
if (!expectedConfigType.equals(arg.getConfigType(mGroupVersions))) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format(
|
||||
"Invalid arg type %s for %s, expected %s",
|
||||
expectedConfigType,
|
||||
arg,
|
||||
arg.getConfigType()
|
||||
arg.getConfigType(mGroupVersions)
|
||||
)
|
||||
);
|
||||
}
|
||||
@ -616,9 +775,7 @@ public class Huami2021Config {
|
||||
}
|
||||
}
|
||||
|
||||
public static class ConfigParser {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ConfigParser.class);
|
||||
|
||||
public class ConfigParser {
|
||||
private final ConfigGroup configGroup;
|
||||
private final boolean includesConstraints;
|
||||
|
||||
@ -640,7 +797,7 @@ public class Huami2021Config {
|
||||
}
|
||||
|
||||
final byte configArgByte = buf.get();
|
||||
final Huami2021Config.ConfigArg configArg = Huami2021Config.ConfigArg.fromCode(configGroup, configArgByte);
|
||||
final ZeppOsConfigService.ConfigArg configArg = ZeppOsConfigService.ConfigArg.fromCode(configGroup, configArgByte);
|
||||
if (configArg == null) {
|
||||
LOG.error("Unknown config {} for {}", String.format("0x%02x", configArgByte), configGroup);
|
||||
}
|
||||
@ -654,8 +811,8 @@ public class Huami2021Config {
|
||||
return prefs;
|
||||
}
|
||||
if (configArg != null) {
|
||||
if (configType != configArg.getConfigType()) {
|
||||
LOG.warn("Unexpected arg type {} for {}, expected {}", configType, configArg, configArg.getConfigType());
|
||||
if (configType != configArg.getConfigType(mGroupVersions)) {
|
||||
LOG.warn("Unexpected arg type {} for {}, expected {}", configType, configArg, configArg.getConfigType(mGroupVersions));
|
||||
}
|
||||
}
|
||||
|
||||
@ -762,7 +919,7 @@ public class Huami2021Config {
|
||||
LOG.warn("Unhandled {} pref of type {}", configType, configArg);
|
||||
}
|
||||
|
||||
if (configArg != null && argPrefs != null && configType == configArg.getConfigType()) {
|
||||
if (configArg != null && argPrefs != null && configType == configArg.getConfigType(mGroupVersions)) {
|
||||
prefs.put(getPrefKnownConfig(configArg), true);
|
||||
|
||||
// Special cases for "follow phone" preferences. We need to ensure that "auto"
|
||||
@ -787,7 +944,7 @@ public class Huami2021Config {
|
||||
return prefs;
|
||||
}
|
||||
|
||||
private static Map<String, Object> convertBooleanToPrefs(final ConfigArg configArg, final ConfigBoolean value) {
|
||||
private Map<String, Object> convertBooleanToPrefs(final ConfigArg configArg, final ConfigBoolean value) {
|
||||
// Special cases
|
||||
switch (configArg) {
|
||||
case LANGUAGE_FOLLOW_PHONE:
|
||||
@ -816,7 +973,7 @@ public class Huami2021Config {
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Map<String, Object> convertStringToPrefs(final ConfigArg configArg, final ConfigString str) {
|
||||
private Map<String, Object> convertStringToPrefs(final ConfigArg configArg, final ConfigString str) {
|
||||
// Special cases
|
||||
switch (configArg) {
|
||||
case DATE_FORMAT:
|
||||
@ -833,7 +990,7 @@ public class Huami2021Config {
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Map<String, Object> convertStringListToPrefs(final ConfigArg configArg, final ConfigStringList str) {
|
||||
private Map<String, Object> convertStringListToPrefs(final ConfigArg configArg, final ConfigStringList str) {
|
||||
final List<String> possibleValues = str.getPossibleValues();
|
||||
final boolean includesConstraints = !possibleValues.isEmpty();
|
||||
Map<String, Object> prefs = null;
|
||||
@ -861,7 +1018,7 @@ public class Huami2021Config {
|
||||
return prefs;
|
||||
}
|
||||
|
||||
private static Map<String, Object> convertShortToPrefs(final ConfigArg configArg, final ConfigShort value) {
|
||||
private Map<String, Object> convertShortToPrefs(final ConfigArg configArg, final ConfigShort value) {
|
||||
if (configArg.getPrefKey() != null) {
|
||||
// The arg maps to a number pref directly
|
||||
final Map<String, Object> prefs = singletonMap(configArg.getPrefKey(), value.getValue());
|
||||
@ -877,7 +1034,7 @@ public class Huami2021Config {
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Map<String, Object> convertIntToPrefs(final ConfigArg configArg, final ConfigInt value) {
|
||||
private Map<String, Object> convertIntToPrefs(final ConfigArg configArg, final ConfigInt value) {
|
||||
if (configArg.getPrefKey() != null) {
|
||||
// The arg maps to a number pref directly
|
||||
final Map<String, Object> prefs = singletonMap(configArg.getPrefKey(), value.getValue());
|
||||
@ -893,7 +1050,7 @@ public class Huami2021Config {
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Map<String, Object> convertDatetimeHhMmToPrefs(final ConfigArg configArg, final ConfigDatetimeHhMm hhmm) {
|
||||
private Map<String, Object> convertDatetimeHhMmToPrefs(final ConfigArg configArg, final ConfigDatetimeHhMm hhmm) {
|
||||
if (configArg.getPrefKey() != null) {
|
||||
// The arg maps to a hhmm pref directly
|
||||
return singletonMap(configArg.getPrefKey(), hhmm.getValue());
|
||||
@ -902,7 +1059,7 @@ public class Huami2021Config {
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Map<String, Object> convertByteListToPrefs(final ConfigArg configArg, final ConfigByteList value) {
|
||||
private Map<String, Object> convertByteListToPrefs(final ConfigArg configArg, final ConfigByteList value) {
|
||||
final byte[] possibleValues = value.getPossibleValues();
|
||||
final boolean includesConstraints = possibleValues != null && possibleValues.length > 0;
|
||||
Map<String, Object> prefs = null;
|
||||
@ -931,7 +1088,7 @@ public class Huami2021Config {
|
||||
return prefs;
|
||||
}
|
||||
|
||||
private static Map<String, Object> convertByteToPrefs(final ConfigArg configArg, final ConfigByte value) {
|
||||
private Map<String, Object> convertByteToPrefs(final ConfigArg configArg, final ConfigByte value) {
|
||||
final byte[] possibleValues = value.getPossibleValues();
|
||||
final boolean includesConstraints = value.getPossibleValues().length > 0;
|
||||
Map<String, Object> prefs = null;
|
||||
@ -964,7 +1121,7 @@ public class Huami2021Config {
|
||||
decoder = null;
|
||||
break;
|
||||
case HEART_RATE_ALL_DAY_MONITORING:
|
||||
decoder = Huami2021Config::decodeHeartRateAllDayMonitoring;
|
||||
decoder = ZeppOsConfigService::decodeHeartRateAllDayMonitoring;
|
||||
break;
|
||||
case SCREEN_TIMEOUT:
|
||||
case HEART_RATE_HIGH_ALERTS:
|
||||
@ -1023,7 +1180,7 @@ public class Huami2021Config {
|
||||
return prefs;
|
||||
}
|
||||
|
||||
private static List<String> decodeByteValues(final byte[] values, final ValueDecoder<Byte> decoder) {
|
||||
private List<String> decodeByteValues(final byte[] values, final ValueDecoder<Byte> decoder) {
|
||||
final List<String> decoded = new ArrayList<>(values.length);
|
||||
for (final byte b : values) {
|
||||
final String decodedByte = decoder.decode(b);
|
||||
@ -1037,7 +1194,7 @@ public class Huami2021Config {
|
||||
return decoded;
|
||||
}
|
||||
|
||||
private static String decodeStringValues(final List<String> values, final ValueDecoder<String> decoder) {
|
||||
private String decodeStringValues(final List<String> values, final ValueDecoder<String> decoder) {
|
||||
final List<String> decoded = new ArrayList<>(values.size());
|
||||
for (final String str : values) {
|
||||
final String decodedStr = decoder.decode(str);
|
||||
@ -1053,7 +1210,7 @@ public class Huami2021Config {
|
||||
return String.join(",", decoded);
|
||||
}
|
||||
|
||||
private static Map<String, Object> singletonMap(final String key, final Object value) {
|
||||
private Map<String, Object> singletonMap(final String key, final Object value) {
|
||||
if (key == null) {
|
||||
LOG.error("Null key in prefs update");
|
||||
if (BuildConfig.DEBUG) {
|
@ -35,17 +35,17 @@ import nodomain.freeyourgadget.gadgetbridge.util.CheckSums;
|
||||
public class ZeppOsFileUploadService extends AbstractZeppOsService {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ZeppOsFileUploadService.class);
|
||||
|
||||
public static final short ENDPOINT = 0x000d;
|
||||
private static final short ENDPOINT = 0x000d;
|
||||
|
||||
public static final byte CMD_CAPABILITIES_REQUEST = 0x01;
|
||||
public static final byte CMD_CAPABILITIES_RESPONSE = 0x02;
|
||||
public static final byte CMD_UPLOAD_REQUEST = 0x03;
|
||||
public static final byte CMD_UPLOAD_RESPONSE = 0x04;
|
||||
public static final byte CMD_DATA_SEND = 0x10;
|
||||
public static final byte CMD_DATA_ACK = 0x11;
|
||||
private static final byte CMD_CAPABILITIES_REQUEST = 0x01;
|
||||
private static final byte CMD_CAPABILITIES_RESPONSE = 0x02;
|
||||
private static final byte CMD_UPLOAD_REQUEST = 0x03;
|
||||
private static final byte CMD_UPLOAD_RESPONSE = 0x04;
|
||||
private static final byte CMD_DATA_SEND = 0x10;
|
||||
private static final byte CMD_DATA_ACK = 0x11;
|
||||
|
||||
public static final byte FLAG_FIRST_CHUNK = 0x01;
|
||||
public static final byte FLAG_LAST_CHUNK = 0x02;
|
||||
private static final byte FLAG_FIRST_CHUNK = 0x01;
|
||||
private static final byte FLAG_LAST_CHUNK = 0x02;
|
||||
|
||||
private final Map<Byte, FileSendRequest> mSessionRequests = new HashMap<>();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user