huawei: Implemented parser for WatchfaceDeviceParams

* watchface  resolution validation implemented
This commit is contained in:
Vitaliy Tomin 2024-04-03 16:53:16 +08:00
parent 3a8fbbe4d3
commit 34e9b5ceb5
6 changed files with 199 additions and 13 deletions

View File

@ -35,6 +35,7 @@ import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpec
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.Notifications;
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.Notifications.NotificationConstraintsType;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.HuaweiWatchfaceManager;
import nodomain.freeyourgadget.gadgetbridge.util.GB;
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.*;
@ -50,6 +51,8 @@ public class HuaweiCoordinator {
ByteBuffer notificationConstraints = null;
private final HuaweiCoordinatorSupplier parent;
protected HuaweiWatchfaceManager huaweiWatchfaceManager = new HuaweiWatchfaceManager();
private boolean transactionCrypted=true;
public HuaweiCoordinator(HuaweiCoordinatorSupplier parent) {
@ -75,6 +78,10 @@ public class HuaweiCoordinator {
}
}
public HuaweiWatchfaceManager getHuaweiWatchfaceManager(){
return huaweiWatchfaceManager;
}
private SharedPreferences getCapabilitiesSharedPreferences() {
return GBApplication.getContext().getSharedPreferences("huawei_coordinator_capatilities" + parent.getDeviceType().name(), Context.MODE_PRIVATE);
}

View File

@ -14,10 +14,12 @@ import java.io.IOException;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.activities.InstallActivity;
import nodomain.freeyourgadget.gadgetbridge.devices.DeviceCoordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.InstallHandler;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.model.GenericItem;
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.HuaweiWatchfaceManager;
import nodomain.freeyourgadget.gadgetbridge.util.GBZipFile;
import nodomain.freeyourgadget.gadgetbridge.util.UriHelper;
import nodomain.freeyourgadget.gadgetbridge.util.ZipFileException;
@ -28,8 +30,9 @@ public class HuaweiInstallHandler implements InstallHandler {
private final Context context;
Bitmap previewbMap;
byte[] watchfaceBin;
byte[] watchfaceSHA256;
String watchfaceDescription;
boolean valid = false;
public HuaweiInstallHandler(Uri uri, Context context) {
this.context = context;
@ -39,7 +42,7 @@ public class HuaweiInstallHandler implements InstallHandler {
uriHelper = UriHelper.get(uri, this.context);
GBZipFile watchfacePackage = new GBZipFile(uriHelper.openInputStream());
String watchfaceDescription = new String(watchfacePackage.getFileFromZip("description.xml"));
watchfaceDescription = new String(watchfacePackage.getFileFromZip("description.xml"));
final byte[] preview = watchfacePackage.getFileFromZip("preview/cover.jpg");
previewbMap = BitmapFactory.decodeByteArray(preview, 0, preview.length);
@ -61,6 +64,23 @@ public class HuaweiInstallHandler implements InstallHandler {
@Override
public void validateInstallation(InstallActivity installActivity, GBDevice device) {
final DeviceCoordinator coordinator = device.getDeviceCoordinator();
if (!(coordinator instanceof HuaweiCoordinatorSupplier)) {
LOG.warn("Coordinator is not a HuaweiCoordinatorSupplier: {}", coordinator.getClass());
installActivity.setInstallEnabled(false);
return;
}
final HuaweiCoordinatorSupplier huaweiCoordinatorSupplier = (HuaweiCoordinatorSupplier) coordinator;
HuaweiWatchfaceManager.WatchfaceDescription description = new HuaweiWatchfaceManager.WatchfaceDescription(watchfaceDescription);
HuaweiWatchfaceManager.Resolution resolution = new HuaweiWatchfaceManager.Resolution();
String deviceScreen = String.format("%d*%d",huaweiCoordinatorSupplier.getHuaweiCoordinator().getHuaweiWatchfaceManager().getHeight(),
huaweiCoordinatorSupplier.getHuaweiCoordinator().getHuaweiWatchfaceManager().getWidth());
this.valid = resolution.isValid(description.screen, deviceScreen);
installActivity.setInstallEnabled(true);
GenericItem installItem = new GenericItem();
@ -70,6 +90,8 @@ public class HuaweiInstallHandler implements InstallHandler {
installItem.setPreview(previewbMap);
}
installItem.setName(description.title);
installActivity.setInstallItem(installItem);
if (device.isBusy()) {
LOG.error("Firmware cannot be installed (device busy)");
installActivity.setInfoText("Firmware cannot be installed (device busy)");
@ -85,18 +107,22 @@ public class HuaweiInstallHandler implements InstallHandler {
return;
}
if (!isValid()) {
LOG.error("Firmware cannot be installed (not valid)");
installActivity.setInfoText("Firmware cannot be installed (not valid)");
if (!this.valid) {
LOG.error("Watchface cannot be installed");
installActivity.setInfoText("Watchface resolution doesnt match device screen. Watchface is "
+ resolution.screenByThemeVersion(description.screen) + " device screen is " + deviceScreen);
installActivity.setInstallEnabled(false);
return;
}
installItem.setName("Huawei watchface preview");
//installItem.setDetails(getVersion());
installActivity.setInfoText(context.getString(R.string.firmware_install_warning, "(unknown)"));
installActivity.setInstallItem(installItem);
installItem.setIcon(R.drawable.ic_watchface);
installActivity.setInfoText(context.getString(R.string.watchface_install_info, installItem.getName(), description.version, description.author));
LOG.debug("Initialized HuaweiInstallHandler");
}
@Override

View File

@ -33,6 +33,7 @@ import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.Alarms;
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.AccountRelated;
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.Calls;
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.GpsAndTime;
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.Watchface;
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.Weather;
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.Workout;
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.DeviceConfig;
@ -550,6 +551,14 @@ public class HuaweiPacket {
this.isEncrypted = this.attemptDecrypt(); // Helps with debugging
return this;
}
case Watchface.id:
switch (this.commandId) {
case Watchface.WatchfaceParams.id:
return new Watchface.WatchfaceParams.Response(paramsProvider).fromPacket(this);
default:
this.isEncrypted = this.attemptDecrypt(); // Helps with debugging
return this;
}
default:
this.isEncrypted = this.attemptDecrypt(); // Helps with debugging
return this;

View File

@ -6,6 +6,15 @@ import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiTLV;
public class Watchface {
public static final byte id = 0x27;
public static class WatchfaceDeviceParams {
public String maxVersion = "";
public short width = 0;
public short height = 0;
public byte supportFileType = 1;
public byte sort = 1;
public String otherWatchfaceVersions = "";
}
public static class WatchfaceParams {
public static final byte id = 0x01;
public static class Request extends HuaweiPacket {
@ -29,14 +38,36 @@ public class Watchface {
}
public static class Response extends HuaweiPacket {
public Response (ParamsProvider paramsProvider) {
super(paramsProvider);
}
public static class Response extends HuaweiPacket {
public WatchfaceDeviceParams params = new WatchfaceDeviceParams();
public Response (ParamsProvider paramsProvider) {
super(paramsProvider);
}
@Override
public void parseTlv() throws ParseException {
try {
if(this.tlv.contains(0x01))
this.params.maxVersion = this.tlv.getString(0x01);
if(this.tlv.contains(0x02))
this.params.width = this.tlv.getShort(0x02);
if(this.tlv.contains(0x03))
this.params.height = this.tlv.getShort(0x03);
if(this.tlv.contains(0x04))
this.params.supportFileType = this.tlv.getByte(0x04);
if(this.tlv.contains(0x05))
this.params.sort = this.tlv.getByte(0x05);
if(this.tlv.contains(0x06))
this.params.otherWatchfaceVersions = this.tlv.getString(0x06);
} catch (MissingTagException e) {
throw new RuntimeException(e);
}
}
}
}
}

View File

@ -0,0 +1,104 @@
package nodomain.freeyourgadget.gadgetbridge.service.devices.huawei;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;
import java.io.StringReader;
import java.util.HashMap;
import java.util.Map;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.Watchface.WatchfaceDeviceParams;
public class HuaweiWatchfaceManager
{
public static class Resolution {
Map<String, Object> map = new HashMap<>();
public Resolution() {
map.put("HWHD09", "466*466");
map.put("HWHD08", "320*320");
map.put("HWHD10", "360*320");
map.put("HWHD02", "454*454");
map.put("HWHD01", "390*390");
map.put("HWHD05", "460*188");
map.put("HWHD03", "240*120");
map.put("HWHD04", "160*80");
map.put("HWHD06", "456*280");
map.put("HWHD07", "368*194");
}
public boolean isValid(String themeVersion, String screenResolution) {
String screen = map.get(themeVersion).toString();
if (screenResolution.equals(screen)) {
return true;
} else {
return false;
}
}
public String screenByThemeVersion(String themeVersion) {
String screen = map.get(themeVersion).toString();
return screen;
}
}
public static class WatchfaceDescription {
public String title;
public String title_cn;
public String author;
public String designer;
public String screen;
public String version;
public String font;
public String font_cn;
public WatchfaceDescription(String xmlStr) {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder;
try {
builder = factory.newDocumentBuilder();
Document doc = builder.parse(new InputSource(new StringReader(
xmlStr)));
this.title = doc.getElementsByTagName("title").item(0).getTextContent();
this.title_cn = doc.getElementsByTagName("title-cn").item(0).getTextContent();
this.author = doc.getElementsByTagName("author").item(0).getTextContent();
this.designer = doc.getElementsByTagName("designer").item(0).getTextContent();
this.screen = doc.getElementsByTagName("screen").item(0).getTextContent();
this.version = doc.getElementsByTagName("version").item(0).getTextContent();
this.font = doc.getElementsByTagName("font").item(0).getTextContent();
this.font_cn = doc.getElementsByTagName("font-cn").item(0).getTextContent();
} catch (Exception e) {
e.printStackTrace();
}
}
}
private WatchfaceDeviceParams params;
public HuaweiWatchfaceManager() {
}
public void setParams(WatchfaceDeviceParams params) {
this.params = params;
}
public short getWidth() {
return params.width;
}
public short getHeight() {
return params.height;
}
}

View File

@ -28,4 +28,13 @@ public class GetWatchfaceParams extends Request{
throw new RequestCreationException(e);
}
}
@Override
protected void processResponse() throws ResponseParseException {
if (!(receivedPacket instanceof Watchface.WatchfaceParams.Response))
throw new ResponseTypeMismatchException(receivedPacket, Watchface.WatchfaceParams.Response.class);
Watchface.WatchfaceParams.Response resp = (Watchface.WatchfaceParams.Response)(receivedPacket);
supportProvider.getHuaweiCoordinator().getHuaweiWatchfaceManager().setParams(resp.params);
}
}