/* 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.devices.huawei.packets; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiPacket; import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiTLV; public class Watchface { public static final byte id = 0x27; public static class WatchfaceDeviceParams { public String maxVersion = ""; public int width = 0; public int height = 0; public byte supportFileType = 1; public byte sort = 1; public String otherWatchfaceVersions = ""; } public static class InstalledWatchfaceInfo { public String fileName = ""; public String version = ""; public byte type = 0; // bit 0 - is current // bit 1 - is factory preset // bit 2 - ??? // bit 3 - editable // bit 4 - video // bit 5 - photo // bit 6 - tryout (trial version) // bit 7 - kaleidoskop public byte expandedtype = 0; public InstalledWatchfaceInfo(HuaweiTLV tlv) throws HuaweiPacket.MissingTagException { this.fileName = tlv.getString(0x03); this.version = tlv.getString(0x04); this.type = tlv.getByte(0x05); if (tlv.contains(0x07)) // optional this.expandedtype = tlv.getByte(0x07); } public boolean isCurrent() { return (this.type & 1) == 1; } public boolean isFactory() { return ((this.type >> 1 )& 1) == 1; } public boolean isEditable() { return ((this.type >> 3 )& 1) == 1; } public boolean isVideo() { return ((this.type >> 4 )& 1) == 1; } public boolean isPhoto() { return ((this.type >> 5 )& 1) == 1; } public boolean isTryout() { return ((this.type >> 6 )& 1) == 1; } public boolean isKaleidoskop() { return ((this.type >> 7 )& 1) == 1; } } public static class WatchfaceParams { public static final byte id = 0x01; public static class Request extends HuaweiPacket { public Request(ParamsProvider paramsProvider) { super(paramsProvider); this.serviceId = Watchface.id; this.commandId = id; this.tlv = new HuaweiTLV() .put(0x01) .put(0x02) .put(0x03) .put(0x04) .put(0x05) .put(0x0e) .put(0x0f); this.complete = true; } } public static class Response extends HuaweiPacket { public WatchfaceDeviceParams params = new WatchfaceDeviceParams(); public Response (ParamsProvider paramsProvider) { super(paramsProvider); } @Override public void parseTlv() throws ParseException { this.params.maxVersion = this.tlv.getString(0x01); if (this.tlv.getBytes(0x02).length == 4) this.params.width = this.tlv.getInteger(0x02); else this.params.width = this.tlv.getShort(0x02); if (this.tlv.getBytes(0x03).length == 4) this.params.height = this.tlv.getInteger(0x03); else this.params.height = this.tlv.getShort(0x03); this.params.supportFileType = this.tlv.getByte(0x04); this.params.sort = this.tlv.getByte(0x05); if (this.tlv.contains(0x06)) this.params.otherWatchfaceVersions = this.tlv.getString(0x06); } } } public static class DeviceWatchInfo { public static final byte id = 0x02; public static class Request extends HuaweiPacket { public Request(ParamsProvider paramsProvider) { super(paramsProvider); this.serviceId = Watchface.id; this.commandId = id; this.tlv = new HuaweiTLV() .put(0x01) .put(0x06, (byte) 0x03); //3 -overseas non-test, 2 - test, 1 -null? } } public static class Response extends HuaweiPacket { public List watchfaceInfoList; public Response (ParamsProvider paramsProvider) { super(paramsProvider); } @Override public void parseTlv() throws HuaweiPacket.ParseException { watchfaceInfoList = new ArrayList<>(); if(this.tlv.contains(0x81)) { for (HuaweiTLV subTlv : this.tlv.getObject(0x81).getObjects(0x82)) { watchfaceInfoList.add(new Watchface.InstalledWatchfaceInfo(subTlv)); } } } } } public static class WatchfaceOperation { public static final byte id = 0x03; public static final byte operationActive = 1; public static final byte operationDelete = 2; public static class Request extends HuaweiPacket { public Request(ParamsProvider paramsProvider, String fileName, byte operation) { super(paramsProvider); this.serviceId = Watchface.id; this.tlv = new HuaweiTLV() .put(0x01, fileName.split("_")[0]) .put(0x02, fileName.split("_")[1]) .put(0x03, operation); this.commandId = id; } } public static class Response extends HuaweiPacket { public Response (ParamsProvider paramsProvider) { super(paramsProvider); } } } public static class WatchfaceConfirm { public static final byte id = 0x05; public static class Request extends HuaweiPacket { public Request(ParamsProvider paramsProvider, String fileName) { super(paramsProvider); this.serviceId = Watchface.id; this.commandId = id; String file = fileName.split("_")[0]; String version = ""; try { version = fileName.split("_")[1]; } catch (ArrayIndexOutOfBoundsException e) { } this.tlv = new HuaweiTLV() .put(0x01, file) .put(0x02, version) .put(0x7f, 0x000186A0); } } public static class Response extends HuaweiPacket { public static byte reportType = 0; public static String fileName; public Response (ParamsProvider paramsProvider) { super(paramsProvider); } @Override public void parseTlv() throws HuaweiPacket.ParseException { String name = this.tlv.getString(0x01); String version = this.tlv.getString(0x02); if(this.tlv.contains(0x03)) { this.reportType = this.tlv.getByte(0x03); } this.fileName = name + "_" + version; } } } public static class WatchfaceNameInfo { public static final byte id = 0x06; public static class Request extends HuaweiPacket { public Request(ParamsProvider paramsProvider, List watchfaceList) { super(paramsProvider); this.serviceId = Watchface.id; this.commandId = id; HuaweiTLV tlvList = new HuaweiTLV(); for (InstalledWatchfaceInfo watchface : watchfaceList) { //TODO: ask name only for custom watchfaces HuaweiTLV wfTlv = new HuaweiTLV().put(0x04, watchface.fileName); tlvList.put(0x83, wfTlv); } this.tlv = new HuaweiTLV() .put(0x01, (byte) 0x01) .put(0x82, tlvList); } } public static class Response extends HuaweiPacket { public HashMap watchFaceNames = new HashMap(); public Response (ParamsProvider paramsProvider) { super(paramsProvider); } @Override public void parseTlv() throws HuaweiPacket.ParseException { if(this.tlv.contains(0x82)) { for (HuaweiTLV subTlv : this.tlv.getObject(0x82).getObjects(0x83)) { watchFaceNames.put(subTlv.getString(0x04), subTlv.getString(0x05)); } } } } } }