mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge
synced 2024-12-01 14:32:54 +01:00
Zepp OS: Support flashing zab files
This commit is contained in:
parent
594a611065
commit
dd01c77aca
@ -28,15 +28,13 @@ import nodomain.freeyourgadget.gadgetbridge.util.CheckSums;
|
|||||||
public abstract class AbstractHuamiFirmwareInfo {
|
public abstract class AbstractHuamiFirmwareInfo {
|
||||||
private byte[] bytes;
|
private byte[] bytes;
|
||||||
|
|
||||||
private final int crc16;
|
private int crc16;
|
||||||
private final int crc32;
|
private int crc32;
|
||||||
|
|
||||||
protected final HuamiFirmwareType firmwareType;
|
protected HuamiFirmwareType firmwareType;
|
||||||
|
|
||||||
public AbstractHuamiFirmwareInfo(byte[] bytes) {
|
public AbstractHuamiFirmwareInfo(byte[] bytes) {
|
||||||
this.bytes = bytes;
|
setBytes(bytes);
|
||||||
this.crc16 = CheckSums.getCRC16(bytes);
|
|
||||||
this.crc32 = CheckSums.getCRC32(bytes);
|
|
||||||
this.firmwareType = determineFirmwareType(bytes);
|
this.firmwareType = determineFirmwareType(bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,6 +68,12 @@ public abstract class AbstractHuamiFirmwareInfo {
|
|||||||
return crc32;
|
return crc32;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setBytes(final byte[] bytes) {
|
||||||
|
this.bytes = bytes;
|
||||||
|
this.crc16 = CheckSums.getCRC16(bytes);
|
||||||
|
this.crc32 = CheckSums.getCRC32(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
public int getFirmwareVersion() {
|
public int getFirmwareVersion() {
|
||||||
return getCrc16(); // HACK until we know how to determine the version from the fw bytes
|
return getCrc16(); // HACK until we know how to determine the version from the fw bytes
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,8 @@
|
|||||||
|
|
||||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.huami;
|
package nodomain.freeyourgadget.gadgetbridge.service.devices.huami;
|
||||||
|
|
||||||
|
import org.json.JSONArray;
|
||||||
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
@ -114,31 +116,96 @@ public abstract class Huami2021FirmwareInfo extends AbstractHuamiFirmwareInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Attempt to handle as an app / watchface
|
// Attempt to handle as an app / watchface
|
||||||
final JSONObject appJson = getAppJson(zipFile);
|
final JSONObject appJson = getJson(zipFile, "app.json");
|
||||||
if (appJson == null) {
|
if (appJson != null) {
|
||||||
return HuamiFirmwareType.INVALID;
|
final String appType;
|
||||||
|
try {
|
||||||
|
appType = appJson.getJSONObject("app").getString("appType");
|
||||||
|
} catch (final Exception e) {
|
||||||
|
LOG.error("Failed to get appType from app.json", e);
|
||||||
|
return HuamiFirmwareType.INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (appType) {
|
||||||
|
case "watchface":
|
||||||
|
return HuamiFirmwareType.WATCHFACE;
|
||||||
|
case "app":
|
||||||
|
return HuamiFirmwareType.APP;
|
||||||
|
default:
|
||||||
|
LOG.warn("Unknown app type {}", appType);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final String appType;
|
// Attempt to handle as a zab file
|
||||||
try {
|
final byte[] zpk = handleZabPackage(zipFile);
|
||||||
appType = appJson.getJSONObject("app").getString("appType");
|
if (zpk != null) {
|
||||||
} catch (final Exception e) {
|
setBytes(zpk);
|
||||||
LOG.error("Failed to get appType from app.json", e);
|
return handleZipPackage(zpk);
|
||||||
return HuamiFirmwareType.INVALID;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (appType) {
|
|
||||||
case "watchface":
|
|
||||||
return HuamiFirmwareType.WATCHFACE;
|
|
||||||
case "app":
|
|
||||||
return HuamiFirmwareType.APP;
|
|
||||||
default:
|
|
||||||
LOG.warn("Unknown app type {}", appType);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return HuamiFirmwareType.INVALID;
|
return HuamiFirmwareType.INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A zab package is a zip file with:
|
||||||
|
* - manifest.json
|
||||||
|
* - .sc (source code)
|
||||||
|
* - One or more zpk files
|
||||||
|
* <p>
|
||||||
|
* Right now, we only handle the first compatible zpk file that is supported by the connected device.
|
||||||
|
*/
|
||||||
|
private byte[] handleZabPackage(final ZipFile zipFile) {
|
||||||
|
final JSONObject manifest = getJson(zipFile, "manifest.json");
|
||||||
|
if (manifest == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
final JSONArray zpks;
|
||||||
|
try {
|
||||||
|
zpks = manifest.getJSONArray("zpks");
|
||||||
|
} catch (final Exception e) {
|
||||||
|
LOG.error("Failed to get zpks from manifest.json", e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iterate all zpks until a compatible one is found
|
||||||
|
for (int i = 0; i < zpks.length(); i++) {
|
||||||
|
try {
|
||||||
|
final JSONObject zpkEntry = zpks.getJSONObject(i);
|
||||||
|
final JSONArray platforms = zpkEntry.getJSONArray("platforms");
|
||||||
|
|
||||||
|
// Check if this zpk is compatible with the current device
|
||||||
|
for (int j = 0; j < platforms.length(); j++) {
|
||||||
|
final JSONObject platform = platforms.getJSONObject(j);
|
||||||
|
|
||||||
|
if (deviceName().equals(platform.getString("name"))) {
|
||||||
|
// It's compatible with the device, fetch device.zip
|
||||||
|
final String name = zpkEntry.getString("name");
|
||||||
|
final byte[] zpkBytes = zipFile.getFileFromZip(name);
|
||||||
|
if (!ZipFile.isZipFile(zpkBytes)) {
|
||||||
|
LOG.warn("bytes for {} not a zip file", name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
final ZipFile zpkFile = new ZipFile(zpkBytes);
|
||||||
|
final byte[] deviceZip = zpkFile.getFileFromZip("device.zip");
|
||||||
|
if (!ZipFile.isZipFile(zpkBytes)) {
|
||||||
|
LOG.warn("bytes for device.zip of zpk {} not a zip file", name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return deviceZip;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (final Exception e) {
|
||||||
|
LOG.warn("Failed to parse zpk", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG.warn("No compatible zpk found in zab file");
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toVersion(int crc16) {
|
public String toVersion(int crc16) {
|
||||||
final String crcMapVersion = getCrcMap().get(crc16);
|
final String crcMapVersion = getCrcMap().get(crc16);
|
||||||
@ -261,7 +328,7 @@ public abstract class Huami2021FirmwareInfo extends AbstractHuamiFirmwareInfo {
|
|||||||
// TODO check i18n section?
|
// TODO check i18n section?
|
||||||
// TODO Show preview icon?
|
// TODO Show preview icon?
|
||||||
|
|
||||||
final JSONObject appJson = getAppJson(zipFile);
|
final JSONObject appJson = getJson(zipFile, "app.json");
|
||||||
if (appJson == null) {
|
if (appJson == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -275,12 +342,12 @@ public abstract class Huami2021FirmwareInfo extends AbstractHuamiFirmwareInfo {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static JSONObject getAppJson(final ZipFile zipFile) {
|
private static JSONObject getJson(final ZipFile zipFile, final String path) {
|
||||||
final byte[] appJsonBin;
|
final byte[] appJsonBin;
|
||||||
try {
|
try {
|
||||||
appJsonBin = zipFile.getFileFromZip("app.json");
|
appJsonBin = zipFile.getFileFromZip(path);
|
||||||
} catch (final ZipFileException e) {
|
} catch (final ZipFileException e) {
|
||||||
LOG.error("Failed to read app.json", e);
|
LOG.error("Failed to read " + path, e);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -290,7 +357,7 @@ public abstract class Huami2021FirmwareInfo extends AbstractHuamiFirmwareInfo {
|
|||||||
.replace("\uFEFF", "");
|
.replace("\uFEFF", "");
|
||||||
return new JSONObject(appJsonString);
|
return new JSONObject(appJsonString);
|
||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
LOG.error("Failed to parse app.json", e);
|
LOG.error("Failed to parse " + path, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
Loading…
Reference in New Issue
Block a user