mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge.git
synced 2025-02-10 15:57:00 +01:00
Moyoung: Code and settings improvements
This commit is contained in:
parent
bff6fcca56
commit
487afa6814
@ -23,13 +23,18 @@ import android.os.ParcelUuid;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import de.greenrobot.dao.query.QueryBuilder;
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBException;
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.AbstractDeviceCoordinator;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpecificSettings;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpecificSettingsScreen;
|
||||
import nodomain.freeyourgadget.gadgetbridge.capabilities.HeartRateCapability;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.AbstractBLEDeviceCoordinator;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.TimeSampleProvider;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.moyoung.samples.MoyoungActivitySampleProvider;
|
||||
@ -58,7 +63,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.Spo2Sample;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.DeviceSupport;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.moyoung.MoyoungDeviceSupport;
|
||||
|
||||
public abstract class AbstractMoyoungDeviceCoordinator extends AbstractDeviceCoordinator {
|
||||
public abstract class AbstractMoyoungDeviceCoordinator extends AbstractBLEDeviceCoordinator {
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
@ -160,11 +165,12 @@ public abstract class AbstractMoyoungDeviceCoordinator extends AbstractDeviceCoo
|
||||
return true;
|
||||
}
|
||||
|
||||
private static final MoyoungSetting[] MOYOUNG_SETTINGS = new MoyoungSetting[] {
|
||||
private static final MoyoungSetting[] MOYOUNG_SETTINGS = {
|
||||
new MoyoungSettingUserInfo("USER_INFO", MoyoungConstants.CMD_SET_USER_INFO),
|
||||
new MoyoungSettingByte("STEP_LENGTH", (byte)-1, MoyoungConstants.CMD_SET_STEP_LENGTH),
|
||||
// (*) new MoyoungSettingEnum<>("DOMINANT_HAND", MoyoungConstants.CMD_QUERY_DOMINANT_HAND, MoyoungConstants.CMD_SET_DOMINANT_HAND, MoyoungEnumDominantHand.class),
|
||||
new MoyoungSettingInt("GOAL_STEP", MoyoungConstants.CMD_QUERY_GOAL_STEP, MoyoungConstants.CMD_SET_GOAL_STEP),
|
||||
new MoyoungSettingByte("HR_AUTO_INTERVAL", MoyoungConstants.CMD_QUERY_TIMING_MEASURE_HEART_RATE, MoyoungConstants.CMD_SET_TIMING_MEASURE_HEART_RATE),
|
||||
|
||||
new MoyoungSettingEnum<>("DEVICE_VERSION", MoyoungConstants.CMD_QUERY_DEVICE_VERSION, MoyoungConstants.CMD_SET_DEVICE_VERSION, MoyoungEnumDeviceVersion.class),
|
||||
new MoyoungSettingLanguage("DEVICE_LANGUAGE", MoyoungConstants.CMD_QUERY_DEVICE_LANGUAGE, MoyoungConstants.CMD_SET_DEVICE_LANGUAGE),
|
||||
@ -187,24 +193,43 @@ public abstract class AbstractMoyoungDeviceCoordinator extends AbstractDeviceCoo
|
||||
new MoyoungSettingBool("BREATHING_LIGHT", MoyoungConstants.CMD_QUERY_BREATHING_LIGHT, MoyoungConstants.CMD_SET_BREATHING_LIGHT)
|
||||
};
|
||||
|
||||
|
||||
@Override
|
||||
public int[] getSupportedDeviceSpecificSettings(GBDevice device) {
|
||||
return new int[]{
|
||||
//R.xml.devicesettings_steplength, // TODO is this needed? does it work? write-only so hard to tell
|
||||
R.xml.devicesettings_moyoung_device_version,
|
||||
R.xml.devicesettings_moyoung_language,
|
||||
R.xml.devicesettings_timeformat,
|
||||
R.xml.devicesettings_measurementsystem,
|
||||
R.xml.devicesettings_moyoung_watchface,
|
||||
//R.xml.devicesettings_moyoung_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_moyoung_sedentary_reminder,
|
||||
R.xml.devicesettings_donotdisturb_no_auto,
|
||||
//R.xml.devicesettings_moyoung_breathinglight, // No idea what this does but it doesn't seem to change anything
|
||||
R.xml.devicesettings_world_clocks,
|
||||
public DeviceSpecificSettings getDeviceSpecificSettings(final GBDevice device) {
|
||||
final DeviceSpecificSettings deviceSpecificSettings = new DeviceSpecificSettings();
|
||||
final List<Integer> generic = deviceSpecificSettings.addRootScreen(DeviceSpecificSettingsScreen.GENERIC);
|
||||
generic.add(R.xml.devicesettings_moyoung_device_version);
|
||||
generic.add(R.xml.devicesettings_colmi_r0x);
|
||||
generic.add(R.xml.devicesettings_timeformat);
|
||||
generic.add(R.xml.devicesettings_measurementsystem);
|
||||
generic.add(R.xml.devicesettings_moyoung_watchface);
|
||||
generic.add(R.xml.devicesettings_liftwrist_display);
|
||||
generic.add(R.xml.devicesettings_moyoung_sedentary_reminder);
|
||||
generic.add(R.xml.devicesettings_donotdisturb_no_auto);
|
||||
generic.add(R.xml.devicesettings_world_clocks);
|
||||
generic.add(R.xml.devicesettings_sync_calendar);
|
||||
return deviceSpecificSettings;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getSupportedLanguageSettings(GBDevice device) {
|
||||
return new String[]{
|
||||
"en_US",
|
||||
"nl_NL",
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<HeartRateCapability.MeasurementInterval> getHeartRateMeasurementIntervals() {
|
||||
return Arrays.asList(
|
||||
HeartRateCapability.MeasurementInterval.OFF,
|
||||
HeartRateCapability.MeasurementInterval.MINUTES_5,
|
||||
HeartRateCapability.MeasurementInterval.MINUTES_10,
|
||||
HeartRateCapability.MeasurementInterval.MINUTES_15,
|
||||
HeartRateCapability.MeasurementInterval.MINUTES_30
|
||||
);
|
||||
}
|
||||
|
||||
public MoyoungSetting[] getSupportedSettings() {
|
||||
return MOYOUNG_SETTINGS;
|
||||
}
|
||||
|
@ -145,6 +145,12 @@ public class MoyoungConstants {
|
||||
public static final byte CMD_SET_TIMING_MEASURE_HEART_RATE = 31; // (*) {i}, i >= 0, 0 is disabled
|
||||
public static final byte CMD_START_STOP_MEASURE_DYNAMIC_RATE = 104; // (*) {enabled ? 0 : -1}
|
||||
|
||||
public static final byte HR_INTERVAL_OFF = 0;
|
||||
public static final byte HR_INTERVAL_5MIN = 1;
|
||||
public static final byte HR_INTERVAL_10MIN = 2;
|
||||
public static final byte HR_INTERVAL_20MIN = 4;
|
||||
public static final byte HR_INTERVAL_30MIN = 6;
|
||||
|
||||
public static final byte CMD_TRIGGER_MEASURE_BLOOD_PRESSURE = 105; // (?) {0, 0, 0} to start, {-1, -1, -1} to stop -> {unused?, num1, num2}
|
||||
public static final byte CMD_TRIGGER_MEASURE_BLOOD_OXYGEN = 107; // (?) {start ? 0 : -1} -> {num}
|
||||
public static final byte CMD_TRIGGER_MEASURE_HEARTRATE = 109; // {start ? 0 : -1} -> {bpm}
|
||||
|
@ -42,8 +42,8 @@ public class MoyoungSettingEnum<T extends Enum <?> & MoyoungEnum> extends Moyoun
|
||||
|
||||
@Override
|
||||
public T decode(byte[] data) {
|
||||
if (data.length != 1)
|
||||
throw new IllegalArgumentException("Wrong data length, should be 1, was " + data.length);
|
||||
if (data.length < 1)
|
||||
throw new IllegalArgumentException("Wrong data length, should be at least 1, was " + data.length);
|
||||
|
||||
return findByValue(data[0]);
|
||||
}
|
||||
|
@ -18,18 +18,25 @@ package nodomain.freeyourgadget.gadgetbridge.devices.moyoung.settings;
|
||||
|
||||
import android.util.Pair;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.moyoung.QuerySettingsOperation;
|
||||
|
||||
public class MoyoungSettingLanguage extends MoyoungSettingEnum<MoyoungEnumLanguage> {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(MoyoungSettingLanguage.class);
|
||||
|
||||
public MoyoungSettingLanguage(String name, byte cmdQuery, byte cmdSet) {
|
||||
super(name, cmdQuery, cmdSet, MoyoungEnumLanguage.class);
|
||||
}
|
||||
|
||||
private Pair<MoyoungEnumLanguage, MoyoungEnumLanguage[]> decodeData(byte[] data) {
|
||||
if (data.length != 5)
|
||||
throw new IllegalArgumentException("Wrong data length, should be 5, was " + data.length);
|
||||
if (data.length < 5)
|
||||
throw new IllegalArgumentException("Wrong data length, should be at least 5, was " + data.length);
|
||||
|
||||
byte[] current = new byte[] { data[0] };
|
||||
byte[] supported = new byte[] { data[1], data[2], data[3], data[4] };
|
||||
@ -48,6 +55,7 @@ public class MoyoungSettingLanguage extends MoyoungSettingEnum<MoyoungEnumLangua
|
||||
}
|
||||
|
||||
MoyoungEnumLanguage[] supportedLanguagesArr = new MoyoungEnumLanguage[supportedLanguages.size()];
|
||||
LOG.debug("Supported languages: {}", supportedLanguages);
|
||||
return Pair.create(currentLanguage, supportedLanguages.toArray(supportedLanguagesArr));
|
||||
}
|
||||
|
||||
|
@ -212,6 +212,14 @@ public class BLETypeConversions {
|
||||
return (short) (bytes[0] & 0xff | ((bytes[1] & 0xff) << 8));
|
||||
}
|
||||
|
||||
public static int toUint24(byte... bytes) {
|
||||
return (bytes[0] & 0xff) | ((bytes[1] & 0xff) << 8) | ((bytes[2] & 0xff) << 16);
|
||||
}
|
||||
|
||||
public static int toUint24(byte[] bytes, int offset) {
|
||||
return (bytes[offset + 0] & 0xff) | ((bytes[offset + 1] & 0xff) << 8) | ((bytes[offset + 2] & 0xff) << 16);
|
||||
}
|
||||
|
||||
public static int toUint32(byte... bytes) {
|
||||
return (bytes[0] & 0xff) | ((bytes[1] & 0xff) << 8) | ((bytes[2] & 0xff) << 16) | ((bytes[3] & 0xff) << 24);
|
||||
}
|
||||
|
@ -92,6 +92,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.RecordedDataTypes;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.AbstractBTLEDeviceSupport;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.BLETypeConversions;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.GattService;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.SetDeviceStateAction;
|
||||
@ -117,20 +118,17 @@ public class MoyoungDeviceSupport extends AbstractBTLEDeviceSupport {
|
||||
private final HeartRateProfile<MoyoungDeviceSupport> heartRateProfile;
|
||||
private final GBDeviceEventVersionInfo versionCmd = new GBDeviceEventVersionInfo();
|
||||
private final GBDeviceEventBatteryInfo batteryCmd = new GBDeviceEventBatteryInfo();
|
||||
private final IntentListener mListener = new IntentListener() {
|
||||
@Override
|
||||
public void notify(Intent intent) {
|
||||
String s = intent.getAction();
|
||||
if (Objects.equals(s, DeviceInfoProfile.ACTION_DEVICE_INFO)) {
|
||||
handleDeviceInfo((DeviceInfo) intent.getParcelableExtra(DeviceInfoProfile.EXTRA_DEVICE_INFO));
|
||||
}
|
||||
if (Objects.equals(s, BatteryInfoProfile.ACTION_BATTERY_INFO)) {
|
||||
handleBatteryInfo((BatteryInfo) intent.getParcelableExtra(BatteryInfoProfile.EXTRA_BATTERY_INFO));
|
||||
}
|
||||
private final IntentListener mListener = intent -> {
|
||||
String s = intent.getAction();
|
||||
if (Objects.equals(s, DeviceInfoProfile.ACTION_DEVICE_INFO)) {
|
||||
handleDeviceInfo(intent.getParcelableExtra(DeviceInfoProfile.EXTRA_DEVICE_INFO));
|
||||
}
|
||||
if (Objects.equals(s, BatteryInfoProfile.ACTION_BATTERY_INFO)) {
|
||||
handleBatteryInfo(intent.getParcelableExtra(BatteryInfoProfile.EXTRA_BATTERY_INFO));
|
||||
}
|
||||
};
|
||||
|
||||
private Handler idleUpdateHandler = new Handler();
|
||||
private final Handler idleUpdateHandler = new Handler();
|
||||
|
||||
private int mtu = 20;
|
||||
private MoyoungPacketIn packetIn = new MoyoungPacketIn();
|
||||
@ -437,30 +435,6 @@ public class MoyoungDeviceSupport extends AbstractBTLEDeviceSupport {
|
||||
return false;
|
||||
}
|
||||
|
||||
private void addGBActivitySample(MoyoungActivitySample sample) {
|
||||
addGBActivitySamples(new MoyoungActivitySample[] { sample });
|
||||
}
|
||||
|
||||
private void addGBActivitySamples(MoyoungActivitySample[] samples) {
|
||||
try (DBHandler dbHandler = GBApplication.acquireDB()) {
|
||||
User user = DBHelper.getUser(dbHandler.getDaoSession());
|
||||
Device device = DBHelper.getDevice(getDevice(), dbHandler.getDaoSession());
|
||||
|
||||
MoyoungActivitySampleProvider provider = new MoyoungActivitySampleProvider(getDevice(), dbHandler.getDaoSession());
|
||||
|
||||
for (MoyoungActivitySample sample : samples) {
|
||||
sample.setDevice(device);
|
||||
sample.setUser(user);
|
||||
sample.setProvider(provider);
|
||||
provider.addGBActivitySample(sample);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
LOG.error("Error saving samples: ", ex);
|
||||
GB.toast(getContext(), "Error saving samples: " + ex.getLocalizedMessage(), Toast.LENGTH_LONG, GB.ERROR);
|
||||
GB.updateTransferNotification(null, "Data transfer failed", false, 0, getContext());
|
||||
}
|
||||
}
|
||||
|
||||
private void broadcastSample(MoyoungActivitySample sample) {
|
||||
Intent intent = new Intent(DeviceService.ACTION_REALTIME_SAMPLES)
|
||||
.putExtra(DeviceService.EXTRA_REALTIME_SAMPLE, sample)
|
||||
@ -659,12 +633,6 @@ public class MoyoungDeviceSupport extends AbstractBTLEDeviceSupport {
|
||||
}
|
||||
}
|
||||
|
||||
private static int BytesToInt24(byte[] bArr) {
|
||||
if (bArr.length != 3)
|
||||
throw new IllegalArgumentException();
|
||||
return ((bArr[2] << 24) >>> 8) | ((bArr[1] << 8) & 0xFF00) | (bArr[0] & 0xFF);
|
||||
}
|
||||
|
||||
private Runnable updateIdleStepsRunnable = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
@ -777,13 +745,13 @@ public class MoyoungDeviceSupport extends AbstractBTLEDeviceSupport {
|
||||
|
||||
byte[] bArr2 = new byte[3];
|
||||
System.arraycopy(data, 0, bArr2, 0, 3);
|
||||
int steps = BytesToInt24(bArr2);
|
||||
int steps = BLETypeConversions.toUint24(bArr2);
|
||||
System.arraycopy(data, 3, bArr2, 0, 3);
|
||||
int distance = BytesToInt24(bArr2);
|
||||
int distance = BLETypeConversions.toUint24(bArr2);
|
||||
System.arraycopy(data, 6, bArr2, 0, 3);
|
||||
int calories = BytesToInt24(bArr2);
|
||||
int calories = BLETypeConversions.toUint24(bArr2);
|
||||
|
||||
LOG.info("steps[" + daysAgo + "] steps=" + steps + ", distance=" + distance + ", calories=" + calories);
|
||||
LOG.info("steps[{}] steps={}, distance={}, calories={}", daysAgo, steps, distance, calories);
|
||||
|
||||
try (DBHandler dbHandler = GBApplication.acquireDB()) {
|
||||
User user = DBHelper.getUser(dbHandler.getDaoSession());
|
||||
@ -833,7 +801,7 @@ public class MoyoungDeviceSupport extends AbstractBTLEDeviceSupport {
|
||||
|
||||
if (newSteps < 0 || newDistance < 0 || newCalories < 0)
|
||||
{
|
||||
LOG.warn("Ignoring a sample that would generate negative values: steps += " + newSteps + ", distance +=" + newDistance + ", calories += " + newCalories);
|
||||
LOG.warn("Ignoring a sample that would generate negative values: steps += {}, distance +={}, calories += {}", newSteps, newDistance, newCalories);
|
||||
}
|
||||
else if (newSteps != 0 || newDistance != 0 || newCalories != 0 || daysAgo == 0)
|
||||
{
|
||||
@ -857,7 +825,7 @@ public class MoyoungDeviceSupport extends AbstractBTLEDeviceSupport {
|
||||
broadcastSample(sample);
|
||||
}
|
||||
|
||||
LOG.info("Adding a sample: " + sample.toString());
|
||||
LOG.info("Adding a sample: {}", sample);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
LOG.error("Error saving samples: ", ex);
|
||||
@ -1084,22 +1052,6 @@ public class MoyoungDeviceSupport extends AbstractBTLEDeviceSupport {
|
||||
}
|
||||
}
|
||||
|
||||
private void addGBActivitySampleIfNotExists(MoyoungActivitySampleProvider provider, MoyoungActivitySample sample)
|
||||
{
|
||||
boolean alreadyHaveThisSample = false;
|
||||
for (MoyoungActivitySample sample2 : provider.getAllActivitySamples(sample.getTimestamp() - 1, sample.getTimestamp() + 1))
|
||||
{
|
||||
if (sample2.getTimestamp() == sample2.getTimestamp() && sample2.getRawKind() == sample.getRawKind())
|
||||
alreadyHaveThisSample = true;
|
||||
}
|
||||
|
||||
if (!alreadyHaveThisSample)
|
||||
{
|
||||
provider.addGBActivitySample(sample);
|
||||
LOG.info("Adding a sample: " + sample.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReset(int flags) {
|
||||
// TODO: this shuts down the watch, rather than rebooting it - perhaps add a new operation type?
|
||||
@ -1231,7 +1183,7 @@ public class MoyoungDeviceSupport extends AbstractBTLEDeviceSupport {
|
||||
public void onSendConfiguration(String config) {
|
||||
LOG.info("Send configuration: " + config);
|
||||
|
||||
Prefs prefs = new Prefs(GBApplication.getDeviceSpecificSharedPrefs(getDevice().getAddress()));
|
||||
Prefs prefs = getDevicePrefs();
|
||||
switch (config) {
|
||||
case ActivityUser.PREF_USER_HEIGHT_CM:
|
||||
case ActivityUser.PREF_USER_WEIGHT_KG:
|
||||
@ -1433,7 +1385,7 @@ public class MoyoungDeviceSupport extends AbstractBTLEDeviceSupport {
|
||||
public void onReadConfigurationDone(MoyoungSetting setting, Object value, byte[] data)
|
||||
{
|
||||
LOG.info("CONFIG " + setting.name + " = " + value);
|
||||
Prefs prefs = new Prefs(GBApplication.getDeviceSpecificSharedPrefs(getDevice().getAddress()));
|
||||
Prefs prefs = getDevicePrefs();
|
||||
Map<String, String> changedProperties = new ArrayMap<>();
|
||||
SharedPreferences.Editor prefsEditor = prefs.getPreferences().edit();
|
||||
switch (setting.name) {
|
||||
|
@ -111,8 +111,12 @@ public class QuerySettingsOperation extends AbstractBTLEOperation<MoyoungDeviceS
|
||||
continue;
|
||||
if (setting.cmdQuery == packetType)
|
||||
{
|
||||
Object value = setting.decode(payload);
|
||||
LOG.info("SETTING QUERY " + setting.name + " = " + value.toString());
|
||||
try {
|
||||
Object value = setting.decode(payload);
|
||||
LOG.info("SETTING QUERY " + setting.name + " = " + value.toString());
|
||||
} catch (Exception e) {
|
||||
LOG.error("Parse error in packet for setting " + setting.name + ": ", e);
|
||||
}
|
||||
received[i] = true;
|
||||
handled = true;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user