diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1ed089eaf..59bab8dea 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,8 @@
### Changelog
+#### Version 0.35.1
+* Mi Band 4: Support flashing watchfaces, res and firmware (.ft untested)
+
#### Version 0.35.0
* Mi Band 4: Initial support (WARNING: INITIAL SETUP NEEDS MI FIT WITH ACCOUNT AND ROOT, NOT A RECOMMENDED DEVICE FOR GADGETBRIDGE)
diff --git a/app/build.gradle b/app/build.gradle
index 76fc13d37..05eddf98b 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -25,8 +25,8 @@ android {
targetSdkVersion 27
// Note: always bump BOTH versionCode and versionName!
- versionName "0.35.0"
- versionCode 152
+ versionName "0.35.1"
+ versionCode 153
vectorDrawables.useSupportLibrary = true
}
buildTypes {
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huami/amazfitcor2/AmazfitCor2Coordinator.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huami/amazfitcor2/AmazfitCor2Coordinator.java
index 6d1bd6f49..ad5d07e65 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huami/amazfitcor2/AmazfitCor2Coordinator.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huami/amazfitcor2/AmazfitCor2Coordinator.java
@@ -80,4 +80,13 @@ public class AmazfitCor2Coordinator extends HuamiCoordinator {
public boolean supportsUnicodeEmojis() {
return true;
}
+
+ @Override
+ public int[] getSupportedDeviceSpecificSettings(GBDevice device) {
+ return new int[]{
+ R.xml.devicesettings_amazfitcor,
+ R.xml.devicesettings_liftwrist_display,
+ R.xml.devicesettings_disconnectnotification,
+ R.xml.devicesettings_pairingkey};
+ }
}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/HuamiFirmwareInfo.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/HuamiFirmwareInfo.java
index c511daa27..681c4bd93 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/HuamiFirmwareInfo.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/HuamiFirmwareInfo.java
@@ -106,12 +106,14 @@ public abstract class HuamiFirmwareInfo {
}
private final int crc16;
+ private final int crc32;
private byte[] bytes;
public HuamiFirmwareInfo(byte[] bytes) {
this.bytes = bytes;
crc16 = CheckSums.getCRC16(bytes);
+ crc32 = CheckSums.getCRC32(bytes);
firmwareType = determineFirmwareType(bytes);
}
@@ -140,6 +142,9 @@ public abstract class HuamiFirmwareInfo {
public int getCrc16() {
return crc16;
}
+ public int getCrc32() {
+ return crc32;
+ }
public int getFirmwareVersion() {
return getCrc16(); // HACK until we know how to determine the version from the fw bytes
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/HuamiSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/HuamiSupport.java
index 6bc42278e..ad7d815e1 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/HuamiSupport.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/HuamiSupport.java
@@ -113,7 +113,6 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.actions.StopNo
import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.miband2.Mi2NotificationStrategy;
import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.miband2.Mi2TextNotificationStrategy;
import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.operations.FetchActivityOperation;
-import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.operations.FetchSportsSummaryOperation;
import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.operations.InitOperation;
import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.operations.UpdateFirmwareOperation;
import nodomain.freeyourgadget.gadgetbridge.service.devices.miband.NotificationStrategy;
@@ -1000,7 +999,7 @@ public class HuamiSupport extends AbstractBTLEDeviceSupport {
@Override
public void onInstallApp(Uri uri) {
try {
- new UpdateFirmwareOperation(uri, this).perform();
+ createUpdateFirmwareOperation(uri).perform();
} catch (IOException ex) {
GB.toast(getContext(), "Firmware cannot be installed: " + ex.getMessage(), Toast.LENGTH_LONG, GB.ERROR, ex);
}
@@ -1965,4 +1964,8 @@ public class HuamiSupport extends AbstractBTLEDeviceSupport {
public HuamiFWHelper createFWHelper(Uri uri, Context context) throws IOException {
return new MiBand2FWHelper(uri, context);
}
+
+ public UpdateFirmwareOperation createUpdateFirmwareOperation(Uri uri) {
+ return new UpdateFirmwareOperation(uri, this);
+ }
}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/miband4/MiBand4Support.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/miband4/MiBand4Support.java
index 2250925a0..7e687932c 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/miband4/MiBand4Support.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/miband4/MiBand4Support.java
@@ -24,6 +24,7 @@ import java.io.IOException;
import nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiFWHelper;
import nodomain.freeyourgadget.gadgetbridge.devices.huami.miband4.MiBand4FWHelper;
import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.miband3.MiBand3Support;
+import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.operations.UpdateFirmwareOperationNew;
public class MiBand4Support extends MiBand3Support {
@@ -36,4 +37,9 @@ public class MiBand4Support extends MiBand3Support {
public HuamiFWHelper createFWHelper(Uri uri, Context context) throws IOException {
return new MiBand4FWHelper(uri, context);
}
+
+ @Override
+ public UpdateFirmwareOperationNew createUpdateFirmwareOperation(Uri uri) {
+ return new UpdateFirmwareOperationNew(uri, this);
+ }
}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/operations/UpdateFirmwareOperation.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/operations/UpdateFirmwareOperation.java
index de1178000..07ca209cd 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/operations/UpdateFirmwareOperation.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/operations/UpdateFirmwareOperation.java
@@ -50,8 +50,8 @@ public class UpdateFirmwareOperation extends AbstractHuamiOperation {
private static final Logger LOG = LoggerFactory.getLogger(UpdateFirmwareOperation.class);
protected final Uri uri;
- protected final BluetoothGattCharacteristic fwCControlChar;
- protected final BluetoothGattCharacteristic fwCDataChar;
+ final BluetoothGattCharacteristic fwCControlChar;
+ private final BluetoothGattCharacteristic fwCDataChar;
protected final Prefs prefs = GBApplication.getPrefs();
protected HuamiFirmwareInfo firmwareInfo;
@@ -81,7 +81,7 @@ public class UpdateFirmwareOperation extends AbstractHuamiOperation {
//the firmware will be sent by the notification listener if the band confirms that the metadata are ok.
}
- protected HuamiFirmwareInfo createFwInfo(Uri uri, Context context) throws IOException {
+ private HuamiFirmwareInfo createFwInfo(Uri uri, Context context) throws IOException {
HuamiFWHelper fwHelper = getSupport().createFWHelper(uri, context);
return fwHelper.getFirmwareInfo();
}
@@ -128,8 +128,8 @@ public class UpdateFirmwareOperation extends AbstractHuamiOperation {
* @param value
*/
private void handleNotificationNotif(byte[] value) {
- if (value.length != 3) {
- LOG.error("Notifications should be 3 bytes long.");
+ if (value.length != 3 && value.length != 11) {
+ LOG.error("Notifications should be 3 or 11 bytes long.");
getSupport().logMessageContent(value);
return;
}
@@ -160,7 +160,6 @@ public class UpdateFirmwareOperation extends AbstractHuamiOperation {
case HuamiService.COMMAND_FIRMWARE_REBOOT: {
LOG.info("Reboot command successfully sent.");
GB.updateInstallNotification(getContext().getString(R.string.updatefirmwareoperation_update_complete), false, 100, getContext());
-// getSupport().onReboot();
done();
break;
}
@@ -170,7 +169,6 @@ public class UpdateFirmwareOperation extends AbstractHuamiOperation {
operationFailed();
displayMessage(getContext(), getContext().getString(R.string.updatefirmwareoperation_updateproblem_do_not_reboot), Toast.LENGTH_LONG, GB.ERROR);
done();
- return;
}
}
} catch (Exception ex) {
@@ -185,7 +183,8 @@ public class UpdateFirmwareOperation extends AbstractHuamiOperation {
done();
}
}
- protected void displayMessage(Context context, String message, int duration, int severity) {
+
+ private void displayMessage(Context context, String message, int duration, int severity) {
getSupport().handleGBDeviceEvent(new GBDeviceEventDisplayMessage(message, duration, severity));
}
@@ -208,7 +207,7 @@ public class UpdateFirmwareOperation extends AbstractHuamiOperation {
bytes[i++] = sizeBytes[1];
bytes[i++] = sizeBytes[2];
if (!isFirmwareCode) {
- bytes[i++] = getFirmwareInfo().getFirmwareType().getValue();
+ bytes[i] = getFirmwareInfo().getFirmwareType().getValue();
}
builder.write(fwCControlChar, bytes);
@@ -241,10 +240,7 @@ public class UpdateFirmwareOperation extends AbstractHuamiOperation {
int firmwareProgress = 0;
TransactionBuilder builder = performInitialized("send firmware packet");
- if (prefs.getBoolean("mi_low_latency_fw_update", true)) {
- getSupport().setLowLatency(builder);
- }
- builder.write(fwCControlChar, new byte[] { HuamiService.COMMAND_FIRMWARE_START_DATA });
+ builder.write(fwCControlChar, getFirmwareStartCommand());
for (int i = 0; i < packets; i++) {
byte[] fwChunk = Arrays.copyOfRange(fwbytes, i * packetLength, i * packetLength + packetLength);
@@ -262,14 +258,13 @@ public class UpdateFirmwareOperation extends AbstractHuamiOperation {
if (firmwareProgress < len) {
byte[] lastChunk = Arrays.copyOfRange(fwbytes, packets * packetLength, len);
builder.write(fwCDataChar, lastChunk);
- firmwareProgress = len;
}
builder.write(fwCControlChar, new byte[]{HuamiService.COMMAND_FIRMWARE_UPDATE_SYNC});
builder.queue(getQueue());
} catch (IOException ex) {
- LOG.error("Unable to send fw to MI 2", ex);
+ LOG.error("Unable to send fw to device", ex);
GB.updateInstallNotification(getContext().getString(R.string.updatefirmwareoperation_firmware_not_sent), false, 0, getContext());
return false;
}
@@ -277,11 +272,11 @@ public class UpdateFirmwareOperation extends AbstractHuamiOperation {
}
- private void sendChecksum(HuamiFirmwareInfo firmwareInfo) throws IOException {
+ protected void sendChecksum(HuamiFirmwareInfo firmwareInfo) throws IOException {
TransactionBuilder builder = performInitialized("send firmware checksum");
int crc16 = firmwareInfo.getCrc16();
byte[] bytes = BLETypeConversions.fromUint16(crc16);
- builder.write(fwCControlChar, new byte[] {
+ builder.write(fwCControlChar, new byte[]{
HuamiService.COMMAND_FIRMWARE_CHECKSUM,
bytes[0],
bytes[1],
@@ -289,7 +284,11 @@ public class UpdateFirmwareOperation extends AbstractHuamiOperation {
builder.queue(getQueue());
}
- private HuamiFirmwareInfo getFirmwareInfo() {
+ HuamiFirmwareInfo getFirmwareInfo() {
return firmwareInfo;
}
-}
+
+ protected byte[] getFirmwareStartCommand() {
+ return new byte[]{HuamiService.COMMAND_FIRMWARE_START_DATA};
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/operations/UpdateFirmwareOperationNew.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/operations/UpdateFirmwareOperationNew.java
new file mode 100644
index 000000000..e2991366c
--- /dev/null
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/operations/UpdateFirmwareOperationNew.java
@@ -0,0 +1,86 @@
+/* Copyright (C) 2016-2019 Andreas Shimokawa, Carsten Pfeiffer, Daniele
+ Gobbetti
+
+ This file is part of Gadgetbridge.
+
+ Gadgetbridge is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published
+ by the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Gadgetbridge is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see . */
+package nodomain.freeyourgadget.gadgetbridge.service.devices.huami.operations;
+
+import android.net.Uri;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+
+import nodomain.freeyourgadget.gadgetbridge.R;
+import nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiService;
+import nodomain.freeyourgadget.gadgetbridge.service.btle.BLETypeConversions;
+import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
+import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.SetDeviceBusyAction;
+import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.HuamiFirmwareInfo;
+import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.HuamiSupport;
+
+public class UpdateFirmwareOperationNew extends UpdateFirmwareOperation {
+ private static final Logger LOG = LoggerFactory.getLogger(UpdateFirmwareOperationNew.class);
+
+
+ public UpdateFirmwareOperationNew(Uri uri, HuamiSupport support) {
+ super(uri, support);
+ }
+
+
+ public boolean sendFwInfo() {
+ try {
+ TransactionBuilder builder = performInitialized("send firmware info");
+ 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[10];
+ int i = 0;
+ bytes[i++] = HuamiService.COMMAND_FIRMWARE_INIT;
+ bytes[i++] = getFirmwareInfo().getFirmwareType().getValue();
+ bytes[i++] = sizeBytes[0];
+ bytes[i++] = sizeBytes[1];
+ bytes[i++] = sizeBytes[2];
+ bytes[i++] = 0; // TODO: what is that?
+ int crc32 = firmwareInfo.getCrc32();
+ byte[] crcBytes = BLETypeConversions.fromUint32(crc32);
+ bytes[i++] = crcBytes[0];
+ bytes[i++] = crcBytes[1];
+ bytes[i++] = crcBytes[2];
+ bytes[i] = crcBytes[3];
+
+
+ builder.write(fwCControlChar, bytes);
+ builder.queue(getQueue());
+ return true;
+ } catch (IOException e) {
+ LOG.error("Error sending firmware info: " + e.getLocalizedMessage(), e);
+ return false;
+ }
+ }
+
+ @Override
+ protected void sendChecksum(HuamiFirmwareInfo firmwareInfo) throws IOException {
+ TransactionBuilder builder = performInitialized("send firmware upload finished");
+ builder.write(fwCControlChar, new byte[]{HuamiService.COMMAND_FIRMWARE_CHECKSUM});
+ builder.queue(getQueue());
+ }
+
+ @Override
+ protected byte[] getFirmwareStartCommand() {
+ return new byte[]{HuamiService.COMMAND_FIRMWARE_START_DATA, 1};
+ }
+}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/CheckSums.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/CheckSums.java
index 671d79af0..f33ef49a5 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/CheckSums.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/CheckSums.java
@@ -20,6 +20,7 @@ import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.util.zip.CRC32;
public class CheckSums {
public static int getCRC8(byte[] seq) {
@@ -46,9 +47,9 @@ public class CheckSums {
public static int getCRC16(byte[] seq) {
int crc = 0xFFFF;
- for (int j = 0; j < seq.length; j++) {
+ for (byte b : seq) {
crc = ((crc >>> 8) | (crc << 8)) & 0xffff;
- crc ^= (seq[j] & 0xff);//byte to int, trunc sign
+ crc ^= (b & 0xff);//byte to int, trunc sign
crc ^= ((crc & 0xff) >> 4);
crc ^= (crc << 12) & 0xffff;
crc ^= ((crc & 0xFF) << 5) & 0xffff;
@@ -57,6 +58,12 @@ public class CheckSums {
return crc;
}
+ public static int getCRC32(byte[] seq) {
+ CRC32 crc = new CRC32();
+ crc.update(seq);
+ return (int) (crc.getValue());
+ }
+
public static void main(String[] args) throws IOException {
if (args == null || args.length == 0) {
throw new IllegalArgumentException("Pass the files to be checksummed as arguments");
diff --git a/app/src/main/res/xml/changelog_master.xml b/app/src/main/res/xml/changelog_master.xml
index c9002f075..0eff99c63 100644
--- a/app/src/main/res/xml/changelog_master.xml
+++ b/app/src/main/res/xml/changelog_master.xml
@@ -1,5 +1,8 @@
+
+ Mi Band 4: Support flashing watchfaces, res and firmware (fonts untested)
+
Mi Band 4: Initial support (WARNING: INITIAL SETUP NEEDS MI FIT WITH ACCOUNT AND ROOT, NOT A RECOMMENDED DEVICE FOR GADGETBRIDGE)
diff --git a/fastlane/metadata/android/en-US/changelogs/153.txt b/fastlane/metadata/android/en-US/changelogs/153.txt
new file mode 100644
index 000000000..bfd64ad46
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/153.txt
@@ -0,0 +1 @@
+* Mi Band 4: Support flashing watchfaces, res and firmware (.ft untested)