From 5c5c0a48d4009535d758a67084d9985e6e340135 Mon Sep 17 00:00:00 2001 From: Vitaliy Tomin Date: Sun, 21 Jul 2024 14:22:55 +0800 Subject: [PATCH] Huawei: Improve watchface install support * there are newer watchface files, which need to unpack inner com.huawei.watchface as zip file and install watchface.bin * also some description.xml has BOM which cause issue parsing as xml --- .../devices/huawei/HuaweiPacket.java | 2 ++ .../devices/huawei/packets/Watchface.java | 9 ++++++ .../devices/huawei/AsynchronousResponse.java | 15 +++++----- .../devices/huawei/HuaweiFwHelper.java | 30 +++++++++++++++++-- .../devices/huawei/HuaweiUploadManager.java | 7 ----- .../huawei/HuaweiWatchfaceManager.java | 2 ++ 6 files changed, 49 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/HuaweiPacket.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/HuaweiPacket.java index 6efedb934..e42621ced 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/HuaweiPacket.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/HuaweiPacket.java @@ -567,6 +567,8 @@ public class HuaweiPacket { return new Watchface.DeviceWatchInfo.Response(paramsProvider).fromPacket(this); case Watchface.WatchfaceNameInfo.id: return new Watchface.WatchfaceNameInfo.Response(paramsProvider).fromPacket(this); + case Watchface.WatchfaceConfirm.id: + return new Watchface.WatchfaceConfirm.Response(paramsProvider).fromPacket(this); default: this.isEncrypted = this.attemptDecrypt(); // Helps with debugging return this; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/packets/Watchface.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/packets/Watchface.java index 39b0aaf8b..a7742fb6b 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/packets/Watchface.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/packets/Watchface.java @@ -198,9 +198,18 @@ public class Watchface { } public static class Response extends HuaweiPacket { + public static byte reportType = 0; public Response (ParamsProvider paramsProvider) { super(paramsProvider); } + + @Override + public void parseTlv() throws HuaweiPacket.ParseException { + if(this.tlv.contains(0x03)) { + this.reportType = this.tlv.getByte(0x03); + } + } + } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/AsynchronousResponse.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/AsynchronousResponse.java index 8a3412504..9ae56ad36 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/AsynchronousResponse.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/AsynchronousResponse.java @@ -457,11 +457,6 @@ public class AsynchronousResponse { support.onUploadProgress(R.string.updatefirmwareoperation_update_complete, 100, false); SendFileUploadComplete sendFileUploadComplete = new SendFileUploadComplete(this.support, support.huaweiUploadManager.getFileType()); sendFileUploadComplete.doPerform(); - if (support.huaweiUploadManager.getFileType() == FileUpload.Filetype.watchface) { - //make uploaded watchface active - SendWatchfaceOperation sendWatchfaceOperation = new SendWatchfaceOperation(this.support, support.huaweiUploadManager.getFileName(), Watchface.WatchfaceOperation.operationActive); - sendWatchfaceOperation.doPerform(); - } } catch (IOException e) { LOG.error("Could not send fileupload result request", e); } @@ -473,10 +468,16 @@ public class AsynchronousResponse { if (response.serviceId == Watchface.id) { if (response.commandId == Watchface.WatchfaceConfirm.id) { try { + if (!(response instanceof Watchface.WatchfaceConfirm.Response)) + throw new Request.ResponseTypeMismatchException(response, Watchface.WatchfaceConfirm.class); + Watchface.WatchfaceConfirm.Response resp = (Watchface.WatchfaceConfirm.Response) response; SendWatchfaceConfirm sendWatchfaceConfirm = new SendWatchfaceConfirm(this.support, this.support.huaweiUploadManager.getFileName()); sendWatchfaceConfirm.doPerform(); - - + if (resp.reportType == 0x02) { + //make uploaded watchface active + SendWatchfaceOperation sendWatchfaceOperation = new SendWatchfaceOperation(this.support, support.huaweiUploadManager.getFileName(), Watchface.WatchfaceOperation.operationActive); + sendWatchfaceOperation.doPerform(); + } } catch (IOException e) { LOG.error("Could not send watchface confirm request", e); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiFwHelper.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiFwHelper.java index f1e8427ac..1f39dca4d 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiFwHelper.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiFwHelper.java @@ -27,8 +27,10 @@ import org.slf4j.LoggerFactory; import java.io.FileNotFoundException; import java.io.IOException; +import java.nio.ByteBuffer; import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.FileUpload; +import nodomain.freeyourgadget.gadgetbridge.util.GB; import nodomain.freeyourgadget.gadgetbridge.util.GBZipFile; import nodomain.freeyourgadget.gadgetbridge.util.UriHelper; import nodomain.freeyourgadget.gadgetbridge.util.ZipFileException; @@ -85,13 +87,37 @@ public class HuaweiFwHelper { final UriHelper uriHelper = UriHelper.get(uri, this.mContext); GBZipFile watchfacePackage = new GBZipFile(uriHelper.openInputStream()); - String xmlDescription = new String(watchfacePackage.getFileFromZip("description.xml")); + byte[] bytesDescription = watchfacePackage.getFileFromZip("description.xml"); + + // check if description file contents BOM + ByteBuffer bb = ByteBuffer.wrap(bytesDescription); + byte[] bom = new byte[3]; + // get the first 3 bytes + bb.get(bom, 0, bom.length); + String content = new String(GB.hexdump(bom)); + String xmlDescription = null; + if ("efbbbf".equalsIgnoreCase(content)) { + byte[] contentAfterFirst3Bytes = new byte[bytesDescription.length - 3]; + bb.get(contentAfterFirst3Bytes, 0, contentAfterFirst3Bytes.length); + xmlDescription = new String(contentAfterFirst3Bytes); + } else { + xmlDescription = new String(bytesDescription); + } + watchfaceDescription = new HuaweiWatchfaceManager.WatchfaceDescription(xmlDescription); if (watchfacePackage.fileExists("preview/cover.jpg")) { final byte[] preview = watchfacePackage.getFileFromZip("preview/cover.jpg"); watchfacePreviewBitmap = BitmapFactory.decodeByteArray(preview, 0, preview.length); } - fw = watchfacePackage.getFileFromZip("com.huawei.watchface"); + + byte[] watchfaceZip = watchfacePackage.getFileFromZip("com.huawei.watchface"); + try { + GBZipFile watchfaceBinZip = new GBZipFile(watchfaceZip); + fw = watchfaceBinZip.getFileFromZip("watchface.bin"); + } catch (ZipFileException e) { + LOG.error("Unable to get watchfaceZip, it seems older already watchface.bin"); + fw = watchfaceZip; + } fileSize = fw.length; isWatchface = true; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiUploadManager.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiUploadManager.java index 4aa12abdc..45af727d9 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiUploadManager.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiUploadManager.java @@ -20,10 +20,6 @@ package nodomain.freeyourgadget.gadgetbridge.service.devices.huawei; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import android.net.Uri; - -import java.io.FileNotFoundException; -import java.io.IOException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; @@ -31,9 +27,6 @@ import nodomain.freeyourgadget.gadgetbridge.R; import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.FileUpload.FileUploadParams; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.util.GB; -import nodomain.freeyourgadget.gadgetbridge.util.GBZipFile; -import nodomain.freeyourgadget.gadgetbridge.util.UriHelper; -import nodomain.freeyourgadget.gadgetbridge.util.ZipFileException; public class HuaweiUploadManager { private static final Logger LOG = LoggerFactory.getLogger(HuaweiUploadManager.class); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiWatchfaceManager.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiWatchfaceManager.java index aa548d043..b6650136d 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiWatchfaceManager.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiWatchfaceManager.java @@ -82,6 +82,8 @@ public class HuaweiWatchfaceManager } public String screenByThemeVersion(String themeVersion) { + if(!map.containsKey(themeVersion)) + return "0x0"; String screen = map.get(themeVersion).toString(); return screen; }