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
This commit is contained in:
Vitaliy Tomin
2024-07-24 19:03:41 +00:00
committed by José Rebelo
parent b8a2fc0076
commit 5c5c0a48d4
6 changed files with 49 additions and 16 deletions
@@ -567,6 +567,8 @@ public class HuaweiPacket {
return new Watchface.DeviceWatchInfo.Response(paramsProvider).fromPacket(this); return new Watchface.DeviceWatchInfo.Response(paramsProvider).fromPacket(this);
case Watchface.WatchfaceNameInfo.id: case Watchface.WatchfaceNameInfo.id:
return new Watchface.WatchfaceNameInfo.Response(paramsProvider).fromPacket(this); return new Watchface.WatchfaceNameInfo.Response(paramsProvider).fromPacket(this);
case Watchface.WatchfaceConfirm.id:
return new Watchface.WatchfaceConfirm.Response(paramsProvider).fromPacket(this);
default: default:
this.isEncrypted = this.attemptDecrypt(); // Helps with debugging this.isEncrypted = this.attemptDecrypt(); // Helps with debugging
return this; return this;
@@ -198,9 +198,18 @@ public class Watchface {
} }
public static class Response extends HuaweiPacket { public static class Response extends HuaweiPacket {
public static byte reportType = 0;
public Response (ParamsProvider paramsProvider) { public Response (ParamsProvider paramsProvider) {
super(paramsProvider); super(paramsProvider);
} }
@Override
public void parseTlv() throws HuaweiPacket.ParseException {
if(this.tlv.contains(0x03)) {
this.reportType = this.tlv.getByte(0x03);
}
}
} }
} }
@@ -457,11 +457,6 @@ public class AsynchronousResponse {
support.onUploadProgress(R.string.updatefirmwareoperation_update_complete, 100, false); support.onUploadProgress(R.string.updatefirmwareoperation_update_complete, 100, false);
SendFileUploadComplete sendFileUploadComplete = new SendFileUploadComplete(this.support, support.huaweiUploadManager.getFileType()); SendFileUploadComplete sendFileUploadComplete = new SendFileUploadComplete(this.support, support.huaweiUploadManager.getFileType());
sendFileUploadComplete.doPerform(); 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) { } catch (IOException e) {
LOG.error("Could not send fileupload result request", e); LOG.error("Could not send fileupload result request", e);
} }
@@ -473,10 +468,16 @@ public class AsynchronousResponse {
if (response.serviceId == Watchface.id) { if (response.serviceId == Watchface.id) {
if (response.commandId == Watchface.WatchfaceConfirm.id) { if (response.commandId == Watchface.WatchfaceConfirm.id) {
try { 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 sendWatchfaceConfirm = new SendWatchfaceConfirm(this.support, this.support.huaweiUploadManager.getFileName());
sendWatchfaceConfirm.doPerform(); 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) { } catch (IOException e) {
LOG.error("Could not send watchface confirm request", e); LOG.error("Could not send watchface confirm request", e);
} }
@@ -27,8 +27,10 @@ import org.slf4j.LoggerFactory;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.nio.ByteBuffer;
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.FileUpload; 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.GBZipFile;
import nodomain.freeyourgadget.gadgetbridge.util.UriHelper; import nodomain.freeyourgadget.gadgetbridge.util.UriHelper;
import nodomain.freeyourgadget.gadgetbridge.util.ZipFileException; import nodomain.freeyourgadget.gadgetbridge.util.ZipFileException;
@@ -85,13 +87,37 @@ public class HuaweiFwHelper {
final UriHelper uriHelper = UriHelper.get(uri, this.mContext); final UriHelper uriHelper = UriHelper.get(uri, this.mContext);
GBZipFile watchfacePackage = new GBZipFile(uriHelper.openInputStream()); 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); watchfaceDescription = new HuaweiWatchfaceManager.WatchfaceDescription(xmlDescription);
if (watchfacePackage.fileExists("preview/cover.jpg")) { if (watchfacePackage.fileExists("preview/cover.jpg")) {
final byte[] preview = watchfacePackage.getFileFromZip("preview/cover.jpg"); final byte[] preview = watchfacePackage.getFileFromZip("preview/cover.jpg");
watchfacePreviewBitmap = BitmapFactory.decodeByteArray(preview, 0, preview.length); 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; fileSize = fw.length;
isWatchface = true; isWatchface = true;
@@ -20,10 +20,6 @@ package nodomain.freeyourgadget.gadgetbridge.service.devices.huawei;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import android.net.Uri;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.security.MessageDigest; import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException; 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.devices.huawei.packets.FileUpload.FileUploadParams;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.util.GB; 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 { public class HuaweiUploadManager {
private static final Logger LOG = LoggerFactory.getLogger(HuaweiUploadManager.class); private static final Logger LOG = LoggerFactory.getLogger(HuaweiUploadManager.class);
@@ -82,6 +82,8 @@ public class HuaweiWatchfaceManager
} }
public String screenByThemeVersion(String themeVersion) { public String screenByThemeVersion(String themeVersion) {
if(!map.containsKey(themeVersion))
return "0x0";
String screen = map.get(themeVersion).toString(); String screen = map.get(themeVersion).toString();
return screen; return screen;
} }