From 8946eff8fa6c3be66b866101c091469e88dd7c8e Mon Sep 17 00:00:00 2001 From: Vitaliy Tomin Date: Sun, 28 Apr 2024 23:27:38 +0800 Subject: [PATCH] Huawei: Set user info to device * height * weight * age * year of birth * gender --- .../devices/huawei/packets/FitnessData.java | 30 +++++++- .../devices/huawei/HuaweiSupportProvider.java | 19 +++++ .../requests/SendFitnessUserInfoRequest.java | 76 +++++++++++++++++++ 3 files changed, 124 insertions(+), 1 deletion(-) create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/requests/SendFitnessUserInfoRequest.java diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/packets/FitnessData.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/packets/FitnessData.java index f32f3f26e..6f0d93509 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/packets/FitnessData.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/packets/FitnessData.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2024 Damien Gaignon, Martin.JM +/* Copyright (C) 2024 Damien Gaignon, Martin.JM, Vitalii Tomin This file is part of Gadgetbridge. @@ -71,6 +71,34 @@ public class FitnessData { } } } + + public static class UserInfo { + public static final byte id = 0x02; + public static class Request extends HuaweiPacket { + public Request(ParamsProvider paramsProvider, + int height, + int weight, + int age, + int birthdayEncoded, + byte gender) { + super(paramsProvider); + this.serviceId = FitnessData.id; + this.commandId = id; + + byte bmi1 = (byte)Math.round(0.42f * height); + byte bmi2 = (byte)Math.round(0.83f * height); + + this.tlv = new HuaweiTLV() + .put(0x01, (byte)height) + .put(0x02, (byte)weight) + .put(0x03, (byte)age) + .put(0x04, birthdayEncoded) + .put(0x05, gender) + .put(0x06, bmi1) + .put(0x07, bmi2); + } + } + } public static class MessageCount { public static final byte sleepId = 0x0C; public static final byte stepId = 0x0A; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiSupportProvider.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiSupportProvider.java index 6c7349c27..7d83a633a 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiSupportProvider.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiSupportProvider.java @@ -93,6 +93,7 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.GetS import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.GetWatchfaceParams; import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SendCameraRemoteSetupEvent; import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SendExtendedAccountRequest; +import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SendFitnessUserInfoRequest; import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SendGpsAndTimeToDeviceRequest; import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SendGpsDataRequest; import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SendFileUploadInfo; @@ -514,6 +515,7 @@ public class HuaweiSupportProvider { } onSetTime(); getBatteryLevel(); + sendUserInfo(); if (isBLE()) { assert leBuilder != null; leBuilder.add(new nodomain.freeyourgadget.gadgetbridge.service.btle.actions.SetDeviceStateAction(gbDevice, GBDevice.State.INITIALIZED, context)); @@ -986,6 +988,12 @@ public class HuaweiSupportProvider { // But it will disappear after reconnection - until it is enabled again GB.toast(context, context.getString(R.string.toast_setting_requires_reconnect), Toast.LENGTH_SHORT, GB.INFO); } + case ActivityUser.PREF_USER_WEIGHT_KG: + case ActivityUser.PREF_USER_HEIGHT_CM: + case ActivityUser.PREF_USER_GENDER: + case ActivityUser.PREF_USER_YEAR_OF_BIRTH: + sendUserInfo(); + break; } } catch (IOException e) { // TODO: Use translatable string @@ -1598,6 +1606,17 @@ public class HuaweiSupportProvider { } } + public void sendUserInfo() { + try { + SendFitnessUserInfoRequest sendFitnessUserInfoRequest = new SendFitnessUserInfoRequest(this); + sendFitnessUserInfoRequest.doPerform(); + } catch (IOException e) { + GB.toast(context, "Failed to set user info", Toast.LENGTH_SHORT, GB.ERROR, e); + LOG.error("Failed to set user info", e); + } + } + + public void setActivateOnLift() { try { SetActivateOnLiftRequest setActivateOnLiftReq = new SetActivateOnLiftRequest(this); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/requests/SendFitnessUserInfoRequest.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/requests/SendFitnessUserInfoRequest.java new file mode 100644 index 000000000..abf70fd19 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/requests/SendFitnessUserInfoRequest.java @@ -0,0 +1,76 @@ +/* Copyright (C) 2024 Vitalii Tomin + + This file is part of Gadgetbridge. + + Gadgetbridge is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Gadgetbridge is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . */ +package nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Calendar; +import java.util.Date; +import java.util.List; + +import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiPacket; +import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.FitnessData; +import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.FitnessData.UserInfo; +import nodomain.freeyourgadget.gadgetbridge.model.ActivityUser; +import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.HuaweiSupportProvider; + +public class SendFitnessUserInfoRequest extends Request { + private static final Logger LOG = LoggerFactory.getLogger(SendFitnessUserInfoRequest.class); + + public SendFitnessUserInfoRequest(HuaweiSupportProvider support) { + super(support); + this.serviceId = FitnessData.id; + this.commandId = UserInfo.id; + } + + @Override + protected List createRequest() throws RequestCreationException { + try { + // Hardcoded values till interface for goal + ActivityUser activityUser = new ActivityUser(); + byte gender = 3; + if (activityUser.getGender() == ActivityUser.GENDER_FEMALE) { + gender = 2; + } else if (activityUser.getGender() == ActivityUser.GENDER_MALE) { + gender = 1; + } + + Date birthday = activityUser.getUserBirthday(); + Calendar cal = Calendar.getInstance(); + cal.setTime(birthday); + int birthdayEncoded = cal.get(Calendar.YEAR) << 16; + birthdayEncoded += (cal.get(Calendar.MONTH)+1) << 8; + birthdayEncoded += cal.get(Calendar.DAY_OF_MONTH); + + return new UserInfo.Request(paramsProvider, + activityUser.getHeightCm(), + activityUser.getWeightKg(), + activityUser.getAge(), + birthdayEncoded, + gender + ).serialize(); + } catch (HuaweiPacket.CryptoException e) { + throw new RequestCreationException(e); + } + } + + @Override + protected void processResponse() { + LOG.debug("handle Send Fitness UserInfo Request"); + } +}