Huawei: health feature config experimental support.

This commit is contained in:
Me7c7
2025-10-11 23:46:38 +02:00
committed by José Rebelo
parent 3fd826cd79
commit a17c553255
12 changed files with 516 additions and 29 deletions
@@ -20,6 +20,7 @@ import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.net.Uri;
import android.text.TextUtils;
import java.nio.ByteBuffer;
import java.util.List;
@@ -368,6 +369,10 @@ public class HuaweiCoordinator {
deviceSpecificSettings.addRootScreen(R.xml.devicesettings_musicmanagement);
}
if(supportsSendCountryCode()) {
deviceSpecificSettings.addRootScreen(R.xml.devicesettings_huawei_country_code);
}
// Time
if (supportsDateFormat()) {
final List<Integer> dateTime = deviceSpecificSettings.addRootScreen(DeviceSpecificSettingsScreen.DATE_TIME);
@@ -895,6 +900,18 @@ public class HuaweiCoordinator {
return false;
}
public boolean supportsSendCountryCode() {
if (supportsExpandCapability())
return supportsExpandCapability(30);
return false;
}
public boolean supportsSendSiteId() {
if (supportsExpandCapability())
return supportsExpandCapability(170);
return false;
}
public boolean supportsPromptPushMessage () {
// do not ask for capabilities under specific condition
// if (deviceType == 10 && deviceVersion == 73617766697368 && deviceSoftVersion == 372E312E31) -> leo device
@@ -1147,4 +1164,14 @@ public class HuaweiCoordinator {
public HeartRateZonesSpec getHeartRateZonesSpec(@NonNull GBDevice device) {
return new HuaweiHeartRateZonesSpec(device, this);
}
public String getCountryCode(GBDevice gbDevice) {
return getDeviceSpecificSharedPreferences(gbDevice).getString("pref_huawei_country_code", "");
}
public boolean getSendCountryCodeEnabled(GBDevice gbDevice) {
return getDeviceSpecificSharedPreferences(gbDevice).getBoolean("pref_huawei_country_code_enable", false) && !TextUtils.isEmpty(getCountryCode(gbDevice));
}
}
@@ -648,6 +648,8 @@ public class HuaweiPacket {
return new AccountRelated.SendAccountToDevice.Response(paramsProvider).fromPacket(this);
case AccountRelated.SendExtendedAccountToDevice.id:
return new AccountRelated.SendExtendedAccountToDevice.Response(paramsProvider).fromPacket(this);
case AccountRelated.SendCountryCodeToDevice.id:
return new AccountRelated.SendCountryCodeToDevice.Response(paramsProvider).fromPacket(this);
default:
this.isEncrypted = this.attemptDecrypt(); // Helps with debugging
return this;
@@ -25,6 +25,7 @@ import androidx.preference.ListPreference;
import androidx.preference.Preference;
import androidx.preference.SwitchPreferenceCompat;
import java.util.Map;
import java.util.Set;
import java.util.Collections;
@@ -76,10 +77,14 @@ public class HuaweiSettingsCustomizer implements DeviceSpecificSettingsCustomize
SharedPreferences sharedPrefs = GBApplication.getDeviceSpecificSharedPrefs(device.getAddress());
boolean statusLiftWrist = sharedPrefs.getBoolean(PREF_LIFTWRIST_NOSHED, false);
dndStart.setEnabled(dndState.equals("scheduled"));
dndEnd.setEnabled(dndState.equals("scheduled"));
dndLifWrist.setEnabled(statusLiftWrist && !dndState.equals("off"));
dndNotWear.setEnabled(dndState.equals("off"));
if (dndStart != null)
dndStart.setEnabled(dndState.equals("scheduled"));
if (dndEnd != null)
dndEnd.setEnabled(dndState.equals("scheduled"));
if (dndLifWrist != null)
dndLifWrist.setEnabled(statusLiftWrist && !dndState.equals("off"));
if (dndNotWear != null)
dndNotWear.setEnabled(dndState.equals("off"));
}
if (preference.getKey().equals("huawei_reparse_workout_data")) {
if (((SwitchPreferenceCompat) preference).isChecked()) {
@@ -141,17 +146,21 @@ public class HuaweiSettingsCustomizer implements DeviceSpecificSettingsCustomize
boolean supportsSpO2 = this.coordinator.supportsSPo2();
forceOptions.setVisible(!supportsSmartAlarm || !supportsWearLocation || !supportsHeartRate || !supportsSpO2);
final SwitchPreferenceCompat forceSmartAlarm = handler.findPreference(PREF_FORCE_ENABLE_SMART_ALARM);
forceSmartAlarm.setVisible(!supportsSmartAlarm);
if(forceSmartAlarm != null)
forceSmartAlarm.setVisible(!supportsSmartAlarm);
final SwitchPreferenceCompat forceWearLocation = handler.findPreference(PREF_FORCE_ENABLE_WEAR_LOCATION);
forceWearLocation.setVisible(!supportsWearLocation);
if(forceWearLocation != null)
forceWearLocation.setVisible(!supportsWearLocation);
final SwitchPreferenceCompat forceHeartRate = handler.findPreference(PREF_FORCE_ENABLE_HEARTRATE_SUPPORT);
forceHeartRate.setVisible(!supportsHeartRate);
if(forceHeartRate != null)
forceHeartRate.setVisible(!supportsHeartRate);
final SwitchPreferenceCompat forceSpO2 = handler.findPreference(PREF_FORCE_ENABLE_SPO2_SUPPORT);
forceSpO2.setVisible(!supportsSpO2);
if(forceSpO2 != null)
forceSpO2.setVisible(!supportsSpO2);
}
final SwitchPreferenceCompat sleepBreath = handler.findPreference(PREF_HUAWEI_SLEEP_BREATH);
if(sleepBreath != null && !coordinator.supportsSleepBreath()) {
if (sleepBreath != null && !coordinator.supportsSleepBreath()) {
sleepBreath.setVisible(false);
}
@@ -188,6 +197,13 @@ public class HuaweiSettingsCustomizer implements DeviceSpecificSettingsCustomize
if (calendarLookahead != null) {
calendarLookahead.setVisible(false);
}
final ListPreference countryCodeList = handler.findPreference("pref_huawei_country_code");
if (countryCodeList != null) {
Map<String, String> countries = HuaweiUtil.getCountriesMap();
countryCodeList.setEntries(countries.keySet().toArray(new String[0]));
countryCodeList.setEntryValues(countries.values().toArray(new String[0]));
}
}
@Override
@@ -206,7 +222,7 @@ public class HuaweiSettingsCustomizer implements DeviceSpecificSettingsCustomize
}
public static final Creator<HuaweiSettingsCustomizer> CREATOR= new Creator<HuaweiSettingsCustomizer>() {
public static final Creator<HuaweiSettingsCustomizer> CREATOR = new Creator<>() {
@Override
public HuaweiSettingsCustomizer createFromParcel(Parcel parcel) {
@@ -16,13 +16,21 @@
along with this program. If not, see <https://www.gnu.org/licenses/>. */
package nodomain.freeyourgadget.gadgetbridge.devices.huawei;
import android.text.TextUtils;
import androidx.annotation.NonNull;
import java.nio.ByteBuffer;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.TreeMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -30,6 +38,46 @@ import org.slf4j.LoggerFactory;
public class HuaweiUtil {
private static final Logger LOG = LoggerFactory.getLogger(HuaweiUtil.class);
// NOTE: List can be incomplete
private static final Map<Integer, String[]> regions = new HashMap<>();
static {
// China
regions.put(1, new String[] {"CN"});
// Asia, Africa, Latin America
regions.put(5, new String[] {"AE","AG","AI","AM","AR","AW","AZ","BD","BF","BH","BI","BJ","BN","BO","BR","BW","BY","BZ","CD","CF","CG","CI","CK","CL","CM","CO","CR","CV","DJ","DO","DZ","EC","EG","ER","ET","FJ","GA","GD","GE","GF","GH","GM","GN","GP","GQ","GT","GW","GY","HK","HN","ID","IN","IQ","JM","JO","JP","KE","KG","KH","KM","KR","KW","KY","KZ","LA","LB","LC","LK","LR","LS","MA","MG","ML","MM","MN","MO","MQ","MR","MS","MU","MV","MW","MX","MY","MZ","NA","NE","NG","NI","NP","NR","OM","PA","PE","PF","PG","PH","PK","PR","PS","PY","QA","RE","SA","SB","SC","SG","SL","SN","SO","SR","ST","SV","SZ","TD","TG","TH","TJ","TN","TO","TT","TW","TZ","UG","UY","UZ","VE","VG","VN","YT","ZA","ZM","ZW"});
// Europe
regions.put(7, new String[] {"AD","AL","AT","AU","BA","BE","BG","CA","CH","CY","CZ","DE","DK","EE","ES","FI","FO","FR","GB","GL","GR","HR","HU","IE","IS","IT","LI","LT","LU","LV","MC","MD","ME","MK","MT","NL","NO","NZ","PL","PT","RO","RS","SE","SI","SK","SM","TR","UA","VA"});
// ru
regions.put(8, new String[] {"RU"});
}
public static int getSiteIdByCountryCode(final String countryCode) {
if(TextUtils.isEmpty(countryCode)) {
return 0;
}
for(Map.Entry<Integer, String[]> r: regions.entrySet()) {
if(Arrays.asList(r.getValue()).contains(countryCode)) {
return r.getKey();
}
}
return 0;
}
@NonNull
public static Map<String, String> getCountriesMap() {
Map<String,String> countries = new TreeMap<>();
Locale[] locales = Locale.getAvailableLocales();
for (Locale locale : locales) {
String country = locale.getDisplayCountry();
String countryCode = locale.getCountry();
if (!country.trim().isEmpty() && countryCode.matches("^[A-Z][A-Z]$") && !countries.containsKey(country)) {
countries.put(country + " (" + countryCode + ")", countryCode);
}
}
return countries;
}
public static byte[] timeToByte(String time) {
Calendar calendar = Calendar.getInstance();
DateFormat df = new SimpleDateFormat("HH:mm", Locale.ENGLISH);
@@ -79,4 +79,31 @@ public class AccountRelated {
}
}
}
public static class SendCountryCodeToDevice {
public static final byte id = 0x0a;
public static class Request extends HuaweiPacket {
public Request (ParamsProvider paramsProvider, String countryCode, Byte siteId) {
super(paramsProvider);
this.serviceId = AccountRelated.id;
this.commandId = id;
this.tlv = new HuaweiTLV();
tlv.put(0x01, countryCode);
if(siteId != null) {
tlv.put(0x02, siteId);
}
this.complete = true;
}
}
public static class Response extends HuaweiPacket {
public Response (ParamsProvider paramsProvider) {
super(paramsProvider);
}
}
}
}
@@ -135,6 +135,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
import nodomain.freeyourgadget.gadgetbridge.model.RecordedDataTypes;
import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.datasync.HuaweiDataSyncFeatureManager;
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.datasync.HuaweiDataSyncEmotion;
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.datasync.HuaweiDataSyncFindDevice;
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.datasync.HuaweiDataSyncGoals;
@@ -158,6 +159,7 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.GetW
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.GetWorkoutCapability;
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.GetWorkoutTotalsRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SendCameraRemoteSetupEvent;
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SendCountryCodeRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SendDeviceReportThreshold;
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SendExtendedAccountRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SendFitnessUserInfoRequest;
@@ -203,7 +205,6 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.GetB
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.GetConnectStatusRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.GetDeviceStatusRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.GetDndLiftWristTypeRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.GetExpandCapabilityRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.GetLinkParamsRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.GetPincodeRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.GetProductInformationRequest;
@@ -296,6 +297,8 @@ public class HuaweiSupportProvider {
protected HuaweiDataSyncManager huaweiDataSyncManager = new HuaweiDataSyncManager(this);
private HuaweiDataSyncFeatureManager huaweiDataSyncFeatureManager = null;
private HuaweiDataSyncGoals huaweiDataSyncTreeCircleGoals = null;
private HuaweiDataSyncFindDevice huaweiDataSyncFindDevice = null;
@@ -845,9 +848,26 @@ public class HuaweiSupportProvider {
*/
public void initializeDynamicServices() {
try {
// NOTE: register all DAta Sync handlers on the early stage. We can receive requests from the watch during initialization.
if(getHuaweiCoordinator().getSendCountryCodeEnabled(getDevice())) {
huaweiDataSyncFeatureManager = new HuaweiDataSyncFeatureManager(HuaweiSupportProvider.this);
}
if (getHuaweiCoordinator().supportsThreeCircle() || getHuaweiCoordinator().supportsThreeCircleLite()) {
huaweiDataSyncTreeCircleGoals = new HuaweiDataSyncGoals(HuaweiSupportProvider.this);
}
if (getHuaweiCoordinator().supportsFindDeviceAbility()) {
huaweiDataSyncFindDevice = new HuaweiDataSyncFindDevice(HuaweiSupportProvider.this);
}
if (getHuaweiCoordinator().supportsEmotion()) {
huaweiDataSyncEmotion = new HuaweiDataSyncEmotion(HuaweiSupportProvider.this);
}
// All of the below check that they are supported and otherwise they skip themselves
final List<Request> initRequestQueue = new ArrayList<>();
initRequestQueue.add(new GetExpandCapabilityRequest(this));
initRequestQueue.add(new SendExtendedAccountRequest(this));
initRequestQueue.add(new GetSettingRelatedRequest(this));
initRequestQueue.add(new AcceptAgreementsRequest(this));
@@ -890,6 +910,7 @@ public class HuaweiSupportProvider {
initRequestQueue.add(new GetContactsCount(this));
initRequestQueue.add(new SendOTASetAutoUpdate(this));
initRequestQueue.add(new GetOTAChangeLog(this));
initRequestQueue.add(new SendCountryCodeRequest(this));
initRequestQueue.add(new GetWorkoutCapability(this));
initRequestQueue.add(new GetEventAlarmList(this));
initRequestQueue.add(new GetSmartAlarmList(this));
@@ -951,18 +972,6 @@ public class HuaweiSupportProvider {
}
}
}
if (getHuaweiCoordinator().supportsThreeCircle() || getHuaweiCoordinator().supportsThreeCircleLite()) {
huaweiDataSyncTreeCircleGoals = new HuaweiDataSyncGoals(HuaweiSupportProvider.this);
}
if (getHuaweiCoordinator().supportsFindDeviceAbility()) {
huaweiDataSyncFindDevice = new HuaweiDataSyncFindDevice(HuaweiSupportProvider.this);
}
if (getHuaweiCoordinator().supportsEmotion()) {
huaweiDataSyncEmotion = new HuaweiDataSyncEmotion(HuaweiSupportProvider.this);
}
}
});
@@ -0,0 +1,250 @@
package nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.datasync;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.HuaweiSupportProvider;
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.HuaweiUploadManager;
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SendFileUploadInfo;
import nodomain.freeyourgadget.gadgetbridge.util.GB;
public class HuaweiDataSyncFeatureManager implements HuaweiDataSyncCommon.DataCallback {
private final Logger LOG = LoggerFactory.getLogger(HuaweiDataSyncFeatureManager.class);
private final HuaweiSupportProvider support;
// Increase each time when futures changed
private static final int version = 1;
public static final String SRC_PKG_NAME = "hw.unitedevice.configManager";
public static final String PKG_NAME = "featureManager";
public HuaweiDataSyncFeatureManager(HuaweiSupportProvider support) {
LOG.info("HuaweiDataSyncFeatureManager");
this.support = support;
this.support.getHuaweiDataSyncManager().registerCallback(PKG_NAME, this);
}
private boolean sendCommonFeaturesData(byte configAction, byte[] configData) {
LOG.info("HuaweiDataSyncFeatureManager sendCommonFeaturesData");
HuaweiDataSyncCommon.ConfigCommandData data = new HuaweiDataSyncCommon.ConfigCommandData();
HuaweiDataSyncCommon.ConfigData featuresConfigData = new HuaweiDataSyncCommon.ConfigData();
featuresConfigData.configId = 900100007;
featuresConfigData.configAction = configAction;
featuresConfigData.configData = configData;
List<HuaweiDataSyncCommon.ConfigData> list = new ArrayList<>();
list.add(featuresConfigData);
data.setConfigDataList(list);
return this.support.getHuaweiDataSyncManager().sendConfigCommand(SRC_PKG_NAME, PKG_NAME, data);
}
private JsonObject getPwvDetectionFeature() {
JsonObject res = new JsonObject();
res.addProperty("devPackageName", "com.huawei.health.pwvdetection");
res.addProperty("support", 1);
JsonObject extInfo = new JsonObject();
extInfo.addProperty("medical", false);
res.add("extInfo", extInfo);
return res;
}
private JsonObject getBloodPressureFeature() {
JsonObject res = new JsonObject();
res.addProperty("devPackageName", "com.huawei.health.bloodpressure");
res.addProperty("support", 1);
JsonObject extInfo = new JsonObject();
JsonArray ABPM = new JsonArray();
ABPM.add(135);
ABPM.add(85);
ABPM.add(120);
ABPM.add(70);
ABPM.add(130);
ABPM.add(80);
extInfo.add("ABPM", ABPM);
extInfo.addProperty("local", 2);
res.add("extInfo", extInfo);
return res;
}
private JsonObject getEcgAnalysisFeature() {
JsonObject res = new JsonObject();
res.addProperty("devPackageName", "com.huawei.watch.health.ecganalysis");
res.addProperty("support", 1);
JsonObject extInfo = new JsonObject();
extInfo.addProperty("medical", false);
res.add("extInfo", extInfo);
return res;
}
private JsonObject getHealthCheckFeature() {
JsonObject res = new JsonObject();
res.addProperty("devPackageName", "com.huawei.health.healthcheck");
res.addProperty("support", 1);
JsonObject extInfo = new JsonObject();
extInfo.addProperty("checkItem", 23);
res.add("extInfo", extInfo);
return res;
}
private JsonObject getEmotionalFeature() {
JsonObject res = new JsonObject();
res.addProperty("devPackageName", "com.huawei.hmos.watch.emotional");
res.addProperty("support", 1);
return res;
}
private JsonObject getPlateauCareFeature() {
JsonObject res = new JsonObject();
res.addProperty("devPackageName", "com.huawei.hmos.watch.plateaucare");
res.addProperty("support", 1);
JsonObject extInfo = new JsonObject();
extInfo.addProperty("medical", false);
res.add("extInfo", extInfo);
return res;
}
private JsonObject getArrhythmiaFeature() {
JsonObject res = new JsonObject();
res.addProperty("devPackageName", "com.huawei.watch.health.arrhythmia");
res.addProperty("support", 1);
JsonObject extInfo = new JsonObject();
extInfo.addProperty("medical", false);
res.add("extInfo", extInfo);
return res;
}
private String getFeaturesFileContent(final String countryCode) {
JsonArray featureList = new JsonArray();
featureList.add(getPwvDetectionFeature());
featureList.add(getBloodPressureFeature());
featureList.add(getEcgAnalysisFeature());
featureList.add(getHealthCheckFeature());
featureList.add(getEmotionalFeature());
featureList.add(getPlateauCareFeature());
featureList.add(getArrhythmiaFeature());
JsonObject featureData = new JsonObject();
featureData.add("featureList", featureList);
featureData.addProperty("country", countryCode);
featureData.addProperty("ver", version);
featureData.addProperty("name", String.format(Locale.ROOT, "feature_%s_device", countryCode));
return new Gson().toJson(featureData);
}
private String getNotifyJsonData(final String countryCode) {
JsonArray filterCondition = new JsonArray();
JsonObject filterConditionItem = new JsonObject();
filterConditionItem.addProperty("filterCountry", countryCode);
filterCondition.add(filterConditionItem);
JsonArray fileData = new JsonArray();
JsonObject fileDataItem = new JsonObject();
fileDataItem.addProperty("version", version);
fileDataItem.addProperty("fileName", String.format(Locale.ROOT, "feature_%s_device.txt", countryCode));
fileData.add(fileDataItem);
JsonObject responseData = new JsonObject();
responseData.add("filterCondition", filterCondition);
responseData.addProperty("configName", "com.huawei.health_deviceFeature_config");
responseData.add("fileData", fileData);
return new Gson().toJson(responseData);
}
private void sendFeaturesFile() {
LOG.info("HuaweiDataSyncFeatureManager Send feature file upload info");
final String countryCode = support.getHuaweiCoordinator().getCountryCode(support.getDevice());
final String json = getFeaturesFileContent(countryCode);
LOG.info("feature file content: {}", json);
HuaweiUploadManager.FileUploadInfo fileInfo = new HuaweiUploadManager.FileUploadInfo();
fileInfo.setFileType((byte) 0x0f);
fileInfo.setFileName(String.format(Locale.ROOT, "feature_%s_device.txt", countryCode));
fileInfo.setBytes(json.getBytes(StandardCharsets.UTF_8));
fileInfo.setFileUploadCallback(new HuaweiUploadManager.FileUploadCallback() {
@Override
public void onUploadStart() {
}
@Override
public void onUploadProgress(int progress) {
}
@Override
public void onUploadComplete() {
final String json = getNotifyJsonData(countryCode);
LOG.info("Notify file content: {}", json);
sendCommonFeaturesData((byte) 1, json.getBytes(StandardCharsets.UTF_8));
}
@Override
public void onError(int code) {
if (support.getDevice().isBusy()) {
support.getDevice().unsetBusyTask();
support.getDevice().sendDeviceUpdateIntent(support.getContext());
}
}
});
HuaweiUploadManager huaweiUploadManager = support.getUploadManager();
huaweiUploadManager.setFileUploadInfo(fileInfo);
try {
SendFileUploadInfo sendFileUploadInfo = new SendFileUploadInfo(support, huaweiUploadManager);
sendFileUploadInfo.doPerform();
} catch (IOException e) {
LOG.error("Failed to send file upload info", e);
}
}
@Override
public void onConfigCommand(HuaweiDataSyncCommon.ConfigCommandData data) {
//TODO: handle this
LOG.info("HuaweiDataSyncConfigManager code: {}", data.getCode());
if (data.getConfigDataList() != null && !data.getConfigDataList().isEmpty()) {
HuaweiDataSyncCommon.ConfigData dt = data.getConfigDataList().get(0);
LOG.info("HuaweiDataSyncConfigManager config Action: {}, ID: {}, Data: {}", dt.configAction, dt.configId, GB.hexdump(dt.configData));
if (dt.configAction == 2) {
if (sendCommonFeaturesData((byte) 2, new byte[]{0x30, 0x31})) {
sendFeaturesFile();
}
}
}
}
@Override
public void onEventCommand(HuaweiDataSyncCommon.EventCommandData data) {
}
@Override
public void onDataCommand(HuaweiDataSyncCommon.DataCommandData data) {
}
@Override
public void onDictDataCommand(HuaweiDataSyncCommon.DictDataCommandData data) {
}
}
@@ -40,10 +40,6 @@ public class GetExpandCapabilityRequest extends Request {
this.commandId = DeviceConfig.ExpandCapability.id;
}
@Override
protected boolean requestSupported() {
return supportProvider.getHuaweiCoordinator().supportsExpandCapability();
}
@Override
protected List<byte[]> createRequest() throws RequestCreationException {
@@ -55,6 +51,13 @@ public class GetExpandCapabilityRequest extends Request {
}
}
RequestCallback dynamicServicesReq = new RequestCallback() {
@Override
public void call() {
supportProvider.initializeDynamicServices();
}
};
@Override
protected void processResponse() throws ResponseParseException {
LOG.debug("handle Expand Capability");
@@ -63,5 +66,7 @@ public class GetExpandCapabilityRequest extends Request {
throw new ResponseTypeMismatchException(receivedPacket, DeviceConfig.ExpandCapability.Response.class);
supportProvider.getHuaweiCoordinator().saveExpandCapabilities(((DeviceConfig.ExpandCapability.Response) receivedPacket).expandCapabilities);
dynamicServicesReq.call();
}
}
@@ -93,7 +93,12 @@ public class GetSupportedCommandsRequest extends Request {
this.nextRequest(nextRequest);
} else {
supportProvider.getHuaweiCoordinator().printCommandsPerService();
dynamicServicesReq.call();
if(supportProvider.getHuaweiCoordinator().supportsExpandCapability()) {
GetExpandCapabilityRequest nextRequest = new GetExpandCapabilityRequest(supportProvider);
this.nextRequest(nextRequest);
} else {
dynamicServicesReq.call();
}
}
}
}
@@ -0,0 +1,50 @@
package nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiPacket;
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiUtil;
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.AccountRelated;
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.HuaweiSupportProvider;
public class SendCountryCodeRequest extends Request {
private static final Logger LOG = LoggerFactory.getLogger(SendCountryCodeRequest.class);
public SendCountryCodeRequest(HuaweiSupportProvider support) {
super(support);
this.serviceId = AccountRelated.id;
this.commandId = AccountRelated.SendCountryCodeToDevice.id;
}
@Override
protected boolean requestSupported() {
return supportProvider.getHuaweiCoordinator().supportsSendCountryCode() && supportProvider.getHuaweiCoordinator().getSendCountryCodeEnabled(supportProvider.getDevice());
}
@Override
protected List<byte[]> createRequest() throws Request.RequestCreationException {
try {
final String countryCode = supportProvider.getHuaweiCoordinator().getCountryCode(supportProvider.getDevice());
Byte siteId = null;
if(supportProvider.getHuaweiCoordinator().supportsSendSiteId()) {
siteId = (byte) HuaweiUtil.getSiteIdByCountryCode(countryCode);
}
return new AccountRelated.SendCountryCodeToDevice.Request(
paramsProvider,
countryCode,
siteId)
.serialize();
} catch (HuaweiPacket.CryptoException e) {
throw new Request.RequestCreationException(e);
}
}
@Override
protected void processResponse() throws Request.ResponseParseException {
LOG.debug("handle Send Country code to Device");
}
}
+9
View File
@@ -4372,4 +4372,13 @@
<string name="hr_settings_zones_lactate_threshold_hr">Lactate threshold heart rate</string>
<string name="hr_settings_zones_remove_all">Reset all</string>
<string name="hr_settings_zones_remove_all_description">Are you sure you want to delete the heart rate zones and limits for all posture configurations and reset them to default?</string>
<string name="pref_huawei_health_features_config_title">Health features config</string>
<string name="pref_huawei_health_features_config_summary">Configure extended health features.</string>
<string name="pref_huawei_features_config_info_title">Enable additional health features</string>
<string name="pref_huawei_features_config_info_summary">Enabling the settings below will activate additional health features on your device. For example, emotional or ECG.\nNOTE: The available features depend on the device.</string>
<string name="pref_huawei_features_config_warning_title">Send country code and features config to the device.</string>
<string name="pref_huawei_features_config_warning_summary">Warning: Enabling these settings when both Gadgetbridge and the vendor app are in use can cause issues with the vendor app and device functionality or can not affect current device abilities at all. Enable at your own risk.\nDevice reconnect is required.</string>
<string name="pref_huawei_send_country_code_title">Send country code</string>
<string name="pref_huawei_send_country_code_summary">Send country code to the device.\n Attention: country code should be set</string>
<string name="pref_huawei_country_code_title">Country code</string>
</resources>
@@ -0,0 +1,39 @@
<?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_extension"
android:key="screen_huawei_features_config"
android:persistent="false"
android:summary="@string/pref_huawei_health_features_config_summary"
android:title="@string/pref_huawei_health_features_config_title">
<PreferenceScreen
android:icon="@drawable/ic_info"
android:key="screen_huawei_features_config_info"
android:persistent="false"
android:selectable="false"
android:summary="@string/pref_huawei_features_config_info_summary"
android:title="@string/pref_huawei_features_config_info_title" />
<PreferenceScreen
android:icon="@drawable/ic_warning"
android:key="screen_huawei_features_config_warning"
android:persistent="false"
android:selectable="false"
android:summary="@string/pref_huawei_features_config_warning_summary"
android:title="@string/pref_huawei_features_config_warning_title" />
<SwitchPreferenceCompat
android:defaultValue="false"
android:key="pref_huawei_country_code_enable"
android:layout="@layout/preference_checkbox"
android:summary="@string/pref_huawei_send_country_code_title"
android:title="@string/pref_huawei_send_country_code_title" />
<ListPreference
android:dependency="pref_huawei_country_code_enable"
android:key="pref_huawei_country_code"
android:title="@string/pref_huawei_country_code_title"
app:useSimpleSummaryProvider="true" />
</PreferenceScreen>
</androidx.preference.PreferenceScreen>