diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 6117c508..2303ffda 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -89,6 +89,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -142,6 +162,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband2/FirmwareType.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband2/FirmwareType.java
new file mode 100644
index 00000000..4b36d21f
--- /dev/null
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband2/FirmwareType.java
@@ -0,0 +1,19 @@
+package nodomain.freeyourgadget.gadgetbridge.service.devices.miband2;
+
+public enum FirmwareType {
+ FIRMWARE((byte) 0),
+ FONT((byte) 1),
+ UNKNOWN1((byte) 2),
+ UNKNOWN2((byte) 3),
+ INVALID(Byte.MIN_VALUE);
+
+ private final byte value;
+
+ FirmwareType(byte value) {
+ this.value = value;
+ }
+
+ public byte getValue() {
+ return value;
+ }
+}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband2/Mi2FirmwareInfo.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband2/Mi2FirmwareInfo.java
index 4dbf595e..08b2e35b 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband2/Mi2FirmwareInfo.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband2/Mi2FirmwareInfo.java
@@ -27,13 +27,23 @@ public class Mi2FirmwareInfo {
(byte) 0xf3,
(byte) 0xe7,
};
+
private static final int FW_HEADER_OFFSET = 0x150;
+ private static final byte[] FT_HEADER = new byte[] { // HMZK font file (*.ft, *.ft.xx)
+ 0x48,
+ 0x4d,
+ 0x5a,
+ 0x4b
+ };
+
private static Map crcToVersion = new HashMap<>();
static {
crcToVersion.put(41899, "1.0.0.39");
}
+ private FirmwareType firmwareType = FirmwareType.FIRMWARE;
+
public static String toVersion(int crc16) {
return crcToVersion.get(crc16);
}
@@ -51,6 +61,18 @@ public class Mi2FirmwareInfo {
this.bytes = bytes;
crc16 = CheckSums.getCRC16(bytes);
firmwareVersion = crcToVersion.get(crc16);
+ firmwareType = determineFirmwareType(bytes);
+ }
+
+ private FirmwareType determineFirmwareType(byte[] bytes) {
+ if (ArrayUtils.startsWith(bytes, FT_HEADER)) {
+ return FirmwareType.FONT;
+ }
+ if (ArrayUtils.equals(bytes, FW_HEADER, FW_HEADER_OFFSET)) {
+ // TODO: this is certainly not a correct validation, but it works for now
+ return FirmwareType.FIRMWARE;
+ }
+ return FirmwareType.INVALID;
}
public boolean isGenerallyCompatibleWith(GBDevice device) {
@@ -58,8 +80,7 @@ public class Mi2FirmwareInfo {
}
public boolean isHeaderValid() {
- // TODO: this is certainly not a correct validation, but it works for now
- return ArrayUtils.equals(bytes, FW_HEADER, FW_HEADER_OFFSET);
+ return getFirmwareType() != FirmwareType.INVALID;
}
public void checkValid() throws IllegalArgumentException {
@@ -84,4 +105,8 @@ public class Mi2FirmwareInfo {
public int getFirmwareVersion() {
return getCrc16(); // HACK until we know how to determine the version from the fw bytes
}
+
+ public FirmwareType getFirmwareType() {
+ return firmwareType;
+ }
}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband2/operations/UpdateFirmwareOperation.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband2/operations/UpdateFirmwareOperation.java
index dfb2d0cd..dc5fa9b9 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband2/operations/UpdateFirmwareOperation.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband2/operations/UpdateFirmwareOperation.java
@@ -23,6 +23,7 @@ import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.SetDeviceBusyAction;
import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.SetProgressAction;
import nodomain.freeyourgadget.gadgetbridge.service.devices.miband2.AbstractMiBand2Operation;
+import nodomain.freeyourgadget.gadgetbridge.service.devices.miband2.FirmwareType;
import nodomain.freeyourgadget.gadgetbridge.service.devices.miband2.Mi2FirmwareInfo;
import nodomain.freeyourgadget.gadgetbridge.service.devices.miband2.MiBand2Support;
import nodomain.freeyourgadget.gadgetbridge.util.GB;
@@ -113,7 +114,12 @@ public class UpdateFirmwareOperation extends AbstractMiBand2Operation {
break;
}
case MiBand2Service.COMMAND_FIRMWARE_CHECKSUM: {
- sendApplyReboot(getFirmwareInfo());
+ if (getFirmwareInfo().getFirmwareType() == FirmwareType.FIRMWARE) {
+ getSupport().onReboot();
+ } else {
+ GB.updateInstallNotification(getContext().getString(R.string.updatefirmwareoperation_update_complete), false, 100, getContext());
+ done();
+ }
break;
}
case MiBand2Service.COMMAND_FIRMWARE_REBOOT: {
@@ -152,12 +158,20 @@ public class UpdateFirmwareOperation extends AbstractMiBand2Operation {
builder.add(new SetDeviceBusyAction(getDevice(), getContext().getString(R.string.updating_firmware), getContext()));
int fwSize = getFirmwareInfo().getSize();
byte[] sizeBytes = BLETypeConversions.fromUint24(fwSize);
- byte[] bytes = new byte[]{
- MiBand2Service.COMMAND_FIRMWARE_INIT,
- sizeBytes[0],
- sizeBytes[1],
- sizeBytes[2],
- };
+ int arraySize = 4;
+ boolean isFirmwareCode = getFirmwareInfo().getFirmwareType() == FirmwareType.FIRMWARE;
+ if (!isFirmwareCode) {
+ arraySize++;
+ }
+ byte[] bytes = new byte[arraySize];
+ int i = 0;
+ bytes[i++] = MiBand2Service.COMMAND_FIRMWARE_INIT;
+ bytes[i++] = sizeBytes[0];
+ bytes[i++] = sizeBytes[1];
+ bytes[i++] = sizeBytes[2];
+ if (!isFirmwareCode) {
+ bytes[i++] = getFirmwareInfo().getFirmwareType().getValue();
+ }
builder.write(fwCControlChar, bytes);
builder.queue(getQueue());
@@ -237,12 +251,6 @@ public class UpdateFirmwareOperation extends AbstractMiBand2Operation {
builder.queue(getQueue());
}
- private void sendApplyReboot(Mi2FirmwareInfo firmwareInfo) throws IOException {
- TransactionBuilder builder = performInitialized("send firmware reboot");
- builder.write(fwCControlChar, new byte[] { MiBand2Service.COMMAND_FIRMWARE_REBOOT});
- builder.queue(getQueue());
- }
-
private Mi2FirmwareInfo getFirmwareInfo() {
return firmwareInfo;
}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/ArrayUtils.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/ArrayUtils.java
index d0bee577..a380b8a0 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/ArrayUtils.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/ArrayUtils.java
@@ -52,4 +52,14 @@ public class ArrayUtils {
}
return result;
}
+
+ /**
+ * Returns true if the given byte array starts with the given values
+ * @param array the array to check
+ * @param values the values which the other array is checked to start with
+ * @return
+ */
+ public static boolean startsWith(byte[] array, byte[] values) {
+ return equals(array, values, 0);
+ }
}
diff --git a/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/test/ArrayUtilsTest.java b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/test/ArrayUtilsTest.java
index d6bc5bca..71064f5a 100644
--- a/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/test/ArrayUtilsTest.java
+++ b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/test/ArrayUtilsTest.java
@@ -111,6 +111,46 @@ public class ArrayUtilsTest extends TestBase {
assertFalse(ArrayUtils.equals(DATA_5, new byte[] {3, 4, 6}, 2));
}
+ @Test
+ public void testStartsWith1() throws Exception {
+ assertTrue(ArrayUtils.startsWith(DATA_5, new byte[] {1}));
+ }
+
+ @Test
+ public void testStartsWith2() throws Exception {
+ assertTrue(ArrayUtils.startsWith(DATA_5, new byte[] {1, 2}));
+ }
+
+ @Test
+ public void testStartsWithAll() throws Exception {
+ assertTrue(ArrayUtils.startsWith(DATA_5, DATA_5.clone()));
+ }
+
+ @Test
+ public void testStartsWithEmpty() throws Exception {
+ assertTrue(ArrayUtils.startsWith(DATA_5, EMPTY));
+ }
+
+ @Test
+ public void testStartsWithFail1() throws Exception {
+ try {
+ ArrayUtils.startsWith(DATA_5, null);
+ fail("should have thrown an exception");
+ } catch (IllegalArgumentException ex) {
+ // expected
+ }
+ }
+
+ @Test
+ public void testStartsWithFail3() throws Exception {
+ assertFalse(ArrayUtils.startsWith(DATA_5, new byte[] {2, 3}));
+ }
+
+ @Test
+ public void testStartsWithFail4() throws Exception {
+ assertFalse(ArrayUtils.startsWith(DATA_5, new byte[] {1, 2, 3, 4, 5, 6}));
+ }
+
private byte[] b(int b) {
return new byte[] {(byte) b};
}