diff --git a/.idea/dictionaries/t.xml b/.idea/dictionaries/t.xml
index c25502eb5e..a9f3a021ad 100644
--- a/.idea/dictionaries/t.xml
+++ b/.idea/dictionaries/t.xml
@@ -161,6 +161,7 @@
trofimov
tysiak
uart
+ uihh
uint
utsob
uuids
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/UIHHContainer.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/UIHHContainer.java
index 23d51d75c3..978d271765 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/UIHHContainer.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/UIHHContainer.java
@@ -28,6 +28,7 @@ import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.List;
+import java.util.stream.Collectors;
import nodomain.freeyourgadget.gadgetbridge.service.btle.BLETypeConversions;
import nodomain.freeyourgadget.gadgetbridge.util.CheckSums;
@@ -45,6 +46,10 @@ public class UIHHContainer {
return files;
}
+ public List getFileTypes() {
+ return files.stream().map(FileEntry::getType).collect(Collectors.toList());
+ }
+
public byte[] getFile(final FileType fileType) {
for (final FileEntry file : files) {
if (file.getType() == fileType) {
@@ -91,8 +96,8 @@ public class UIHHContainer {
return null;
}
- final int crc32 = BLETypeConversions.toUint32(ArrayUtils.subarray(bytes, 12, 12 + 4));
- final int length = BLETypeConversions.toUint32(ArrayUtils.subarray(bytes, 22, 22 + 4));
+ final int crc32 = BLETypeConversions.toUint32(bytes, 12);
+ final int length = BLETypeConversions.toUint32(bytes, 22);
if (length + 32 != bytes.length) {
LOG.error("Length mismatch between header and bytes: {}/{}", length, bytes.length);
@@ -122,14 +127,14 @@ public class UIHHContainer {
final FileType type = FileType.fromValue(bytes[i]);
if (type == null) {
- LOG.error("Unknown type byte {} at position {}", String.format("0x%x", bytes[i], i));
+ LOG.error("Unknown type byte {} at position {}", String.format("0x%x", bytes[i]), i);
return null;
}
i++;
- final int fileLength = BLETypeConversions.toUint32(ArrayUtils.subarray(bytes, i, i + 4));
+ final int fileLength = BLETypeConversions.toUint32(bytes, i);
i += 4;
- final int fileCrc32 = BLETypeConversions.toUint32(ArrayUtils.subarray(bytes, i, i + 4));
+ final int fileCrc32 = BLETypeConversions.toUint32(bytes, i);
i += 4;
if (i + fileLength > bytes.length) {
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/operations/ZeppOsAgpsFile.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/operations/ZeppOsAgpsFile.java
index 9b2727af54..795c2effa1 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/operations/ZeppOsAgpsFile.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/operations/ZeppOsAgpsFile.java
@@ -21,6 +21,8 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.List;
import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.UIHHContainer;
import nodomain.freeyourgadget.gadgetbridge.util.GBZipFile;
@@ -29,18 +31,22 @@ import nodomain.freeyourgadget.gadgetbridge.util.ZipFileException;
public class ZeppOsAgpsFile {
private static final Logger LOG = LoggerFactory.getLogger(ZeppOsAgpsFile.class);
- private final byte[] zipBytes;
+ private final byte[] fileBytes;
- public ZeppOsAgpsFile(final byte[] zipBytes) {
- this.zipBytes = zipBytes;
+ public ZeppOsAgpsFile(final byte[] fileBytes) {
+ this.fileBytes = fileBytes;
}
public boolean isValid() {
- if (!GBZipFile.isZipFile(zipBytes)) {
- return false;
+ if (GBZipFile.isZipFile(fileBytes)) {
+ return isValidAsEpoZip();
+ } else {
+ return isValidAsUihh();
}
+ }
- final GBZipFile zipFile = new GBZipFile(zipBytes);
+ private boolean isValidAsEpoZip() {
+ final GBZipFile zipFile = new GBZipFile(fileBytes);
try {
final byte[] manifestBin = zipFile.getFileFromZip("META-INF/MANIFEST.MF");
@@ -61,22 +67,64 @@ public class ZeppOsAgpsFile {
LOG.error("Failed to parse read MANIFEST or check file", e);
}
- return false;
+ return true;
+ }
+
+ private boolean isValidAsUihh() {
+ final UIHHContainer uihh = UIHHContainer.fromRawBytes(fileBytes);
+ if (uihh == null) {
+ return false;
+ }
+
+ final List fileTypes = uihh.getFileTypes();
+ final List expectedFileTypes = Arrays.asList(
+ UIHHContainer.FileType.GPS_ALM_BIN,
+ UIHHContainer.FileType.GLN_ALM_BIN,
+ UIHHContainer.FileType.LLE_BDS_LLE,
+ UIHHContainer.FileType.LLE_GPS_LLE,
+ UIHHContainer.FileType.LLE_GLO_LLE,
+ UIHHContainer.FileType.LLE_GAL_LLE,
+ UIHHContainer.FileType.LLE_QZSS_LLE
+ );
+
+ if (fileTypes.size() != expectedFileTypes.size()) {
+ LOG.warn("uihh file types mismatch - expected {}, found {}", expectedFileTypes.size(), fileTypes.size());
+ return false;
+ }
+
+ for (final UIHHContainer.FileType fileType : expectedFileTypes) {
+ if (!fileTypes.contains(fileType)) {
+ LOG.warn("uihh is missing file type {}", fileType);
+ return false;
+ }
+ }
+
+ return true;
}
public byte[] getUihhBytes() {
- final UIHHContainer uihh = new UIHHContainer();
+ if (GBZipFile.isZipFile(fileBytes)) {
+ // EPO zip - repackage into UIHH
+ final UIHHContainer uihh = new UIHHContainer();
- final GBZipFile zipFile = new GBZipFile(zipBytes);
+ final GBZipFile zipFile = new GBZipFile(fileBytes);
- try {
- uihh.addFile(UIHHContainer.FileType.AGPS_EPO_GR_3, zipFile.getFileFromZip("EPO_GR_3.DAT"));
- uihh.addFile(UIHHContainer.FileType.AGPS_EPO_GAL_7, zipFile.getFileFromZip("EPO_GAL_7.DAT"));
- uihh.addFile(UIHHContainer.FileType.AGPS_EPO_BDS_3, zipFile.getFileFromZip("EPO_BDS_3.DAT"));
- } catch (final ZipFileException e) {
- throw new IllegalStateException("Failed to read file from zip", e);
+ try {
+ uihh.addFile(UIHHContainer.FileType.AGPS_EPO_GR_3, zipFile.getFileFromZip("EPO_GR_3.DAT"));
+ uihh.addFile(UIHHContainer.FileType.AGPS_EPO_GAL_7, zipFile.getFileFromZip("EPO_GAL_7.DAT"));
+ uihh.addFile(UIHHContainer.FileType.AGPS_EPO_BDS_3, zipFile.getFileFromZip("EPO_BDS_3.DAT"));
+ } catch (final ZipFileException e) {
+ throw new IllegalStateException("Failed to read file from zip", e);
+ }
+
+ return uihh.toRawBytes();
+ } else {
+ final UIHHContainer uihhContainer = UIHHContainer.fromRawBytes(fileBytes);
+ if (uihhContainer != null) {
+ return fileBytes;
+ }
}
- return uihh.toRawBytes();
+ throw new IllegalStateException("Unknown file bytes - this should never happen");
}
}
diff --git a/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/UIHHContainerTest.java b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/UIHHContainerTest.java
new file mode 100644
index 0000000000..6e1bc351a5
--- /dev/null
+++ b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/UIHHContainerTest.java
@@ -0,0 +1,19 @@
+package nodomain.freeyourgadget.gadgetbridge.service.devices.huami;
+
+import org.junit.Ignore;
+import org.junit.Test;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+
+import nodomain.freeyourgadget.gadgetbridge.test.TestBase;
+
+public class UIHHContainerTest extends TestBase {
+ @Test
+ @Ignore("helper test for development, remove this while debugging")
+ public void localTest() throws IOException {
+ byte[] bytes = Files.readAllBytes(new File("/storage/downloads/uihh.bin").toPath());
+ final UIHHContainer uihhContainer = UIHHContainer.fromRawBytes(bytes);
+ }
+}