diff --git a/CHANGELOG.md b/CHANGELOG.md index ccff8844a..1ed089eaf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ ### Changelog +#### 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) + #### Version 0.34.1 * Mi Band 1: Fix crash when entering per-device settings * Mi Band 3: Allow setting date format in per-device settings diff --git a/README.md b/README.md index c30f0dcc9..df82c3e14 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,7 @@ vendor's servers. * Mi Band, Mi Band 1A, Mi Band 1S [Wiki](https://codeberg.org/Freeyourgadget/Gadgetbridge/wiki/Mi-Band) * Mi Band 2 [Wiki](https://codeberg.org/Freeyourgadget/Gadgetbridge/wiki/Mi-Band-2) * Mi Band 3 [Wiki](https://codeberg.org/Freeyourgadget/Gadgetbridge/wiki/Mi-Band-3) +* Mi Band 4 (WIP, NOT RECOMMENDED, NEEDS MI FIT WITH ACCOUNT AND ROOT ONCE) [Wiki](https://codeberg.org/Freeyourgadget/Gadgetbridge/wiki/Mi-Band-4) * Mi Scale 2 (currently only displays a toast after stepping on the scale) * NO.1 F1 (WIP) * Pebble, Pebble Steel, Pebble Time, Pebble Time Steel, Pebble Time Round [Wiki](https://codeberg.org/Freeyourgadget/Gadgetbridge/wiki/Pebble) diff --git a/app/build.gradle b/app/build.gradle index ddc3663ab..76fc13d37 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.34.1" - versionCode 151 + versionName "0.35.0" + versionCode 152 vectorDrawables.useSupportLibrary = true } buildTypes { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huami/miband4/MiBand4Coordinator.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huami/miband4/MiBand4Coordinator.java index 2a171e15c..f6bbc8461 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huami/miband4/MiBand4Coordinator.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huami/miband4/MiBand4Coordinator.java @@ -57,9 +57,11 @@ public class MiBand4Coordinator extends HuamiCoordinator { } + @Override public InstallHandler findInstallHandler(Uri uri, Context context) { - return null; + MiBand4FWInstallHandler handler = new MiBand4FWInstallHandler(uri, context); + return handler.isValid() ? handler : null; } @Override diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huami/miband4/MiBand4FWHelper.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huami/miband4/MiBand4FWHelper.java new file mode 100644 index 000000000..ed2b17821 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huami/miband4/MiBand4FWHelper.java @@ -0,0 +1,40 @@ +/* Copyright (C) 2017-2019 Andreas Shimokawa, Carsten Pfeiffer + + 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.devices.huami.miband4; + +import android.content.Context; +import android.net.Uri; + +import java.io.IOException; + +import nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiFWHelper; +import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.miband4.MiBand4FirmwareInfo; + +public class MiBand4FWHelper extends HuamiFWHelper { + + public MiBand4FWHelper(Uri uri, Context context) throws IOException { + super(uri, context); + } + + @Override + protected void determineFirmwareInfo(byte[] wholeFirmwareBytes) { + firmwareInfo = new MiBand4FirmwareInfo(wholeFirmwareBytes); + if (!firmwareInfo.isHeaderValid()) { + throw new IllegalArgumentException("Not a Mi Band 4 firmware"); + } + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huami/miband4/MiBand4FWInstallHandler.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huami/miband4/MiBand4FWInstallHandler.java new file mode 100644 index 000000000..f8f09a8cc --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huami/miband4/MiBand4FWInstallHandler.java @@ -0,0 +1,50 @@ +/* Copyright (C) 2015-2019 Andreas Shimokawa, Carsten Pfeiffer + + 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.devices.huami.miband4; + +import android.content.Context; +import android.net.Uri; + +import java.io.IOException; + +import nodomain.freeyourgadget.gadgetbridge.R; +import nodomain.freeyourgadget.gadgetbridge.devices.huami.miband3.MiBand3FWHelper; +import nodomain.freeyourgadget.gadgetbridge.devices.miband.AbstractMiBandFWHelper; +import nodomain.freeyourgadget.gadgetbridge.devices.miband.AbstractMiBandFWInstallHandler; +import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; +import nodomain.freeyourgadget.gadgetbridge.model.DeviceType; + +class MiBand4FWInstallHandler extends AbstractMiBandFWInstallHandler { + MiBand4FWInstallHandler(Uri uri, Context context) { + super(uri, context); + } + + @Override + protected String getFwUpgradeNotice() { + return mContext.getString(R.string.fw_upgrade_notice_miband4, helper.getHumanFirmwareVersion()); + } + + @Override + protected AbstractMiBandFWHelper createHelper(Uri uri, Context context) throws IOException { + return new MiBand4FWHelper(uri, context); + } + + @Override + protected boolean isSupportedDeviceType(GBDevice device) { + return device.getType() == DeviceType.MIBAND4; + } +} 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 981388a00..c511daa27 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 @@ -49,6 +49,8 @@ public abstract class HuamiFirmwareInfo { }; protected static final int FONT_TYPE_OFFSET = 0x9; + protected static final int COMPRESSED_RES_HEADER_OFFSET = 0x9; + protected static final int COMPRESSED_RES_HEADER_OFFSET_NEW = 0xd; private HuamiFirmwareType firmwareType; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/amazfitbip/AmazfitBipSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/amazfitbip/AmazfitBipSupport.java index 8e5d8dc2d..967f48076 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/amazfitbip/AmazfitBipSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/amazfitbip/AmazfitBipSupport.java @@ -44,6 +44,7 @@ import nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiWeatherConditions import nodomain.freeyourgadget.gadgetbridge.devices.huami.amazfitbip.AmazfitBipFWHelper; import nodomain.freeyourgadget.gadgetbridge.devices.huami.amazfitbip.AmazfitBipService; import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst; +import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.model.CallSpec; import nodomain.freeyourgadget.gadgetbridge.model.DeviceType; import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec; @@ -136,16 +137,25 @@ public class AmazfitBipSupport extends HuamiSupport { appSuffix = appName.getBytes(); suffixlength = appSuffix.length; } + if (gbDevice.getType() == DeviceType.MIBAND4) { + prefixlength += 4; + } byte[] rawmessage = message.getBytes(); int length = Math.min(rawmessage.length, maxLength - prefixlength); byte[] command = new byte[length + prefixlength + suffixlength]; - - command[0] = (byte) alertCategory.getId(); - command[1] = 1; + int pos = 0; + command[pos++] = (byte) alertCategory.getId(); + if (gbDevice.getType() == DeviceType.MIBAND4) { + command[pos++] = 0; // TODO + command[pos++] = 0; + command[pos++] = 0; + command[pos++] = 0; + } + command[pos++] = 1; if (alertCategory == AlertCategory.CustomHuami) { - command[2] = customIconId; + command[pos] = customIconId; } System.arraycopy(rawmessage, 0, command, prefixlength, length); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/amazfitcor2/AmazfitCor2FirmwareInfo.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/amazfitcor2/AmazfitCor2FirmwareInfo.java index 119fbb35d..3fcccc536 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/amazfitcor2/AmazfitCor2FirmwareInfo.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/amazfitcor2/AmazfitCor2FirmwareInfo.java @@ -31,9 +31,6 @@ public class AmazfitCor2FirmwareInfo extends HuamiFirmwareInfo { 0x00, (byte) 0x98, 0x00, 0x20, (byte) 0xA5, 0x04, 0x00, 0x20, (byte) 0xAD, 0x04, 0x00, 0x20, (byte) 0xC5, 0x04, 0x00, 0x20 }; - private static final int COMPRESSED_RES_HEADER_OFFSET = 0x9; - private static final int COMPRESSED_RES_HEADER_OFFSET_NEW = 0xd; - private static Map crcToVersion = new HashMap<>(); static { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/miband4/MiBand4FirmwareInfo.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/miband4/MiBand4FirmwareInfo.java new file mode 100644 index 000000000..5b7f3fcee --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/miband4/MiBand4FirmwareInfo.java @@ -0,0 +1,89 @@ +/* Copyright (C) 2017-2019 Andreas Shimokawa, Carsten Pfeiffer + + 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.miband4; + +import java.util.HashMap; +import java.util.Map; + +import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; +import nodomain.freeyourgadget.gadgetbridge.model.DeviceType; +import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.HuamiFirmwareInfo; +import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.HuamiFirmwareType; +import nodomain.freeyourgadget.gadgetbridge.util.ArrayUtils; + +public class MiBand4FirmwareInfo extends HuamiFirmwareInfo { + + private static final byte[] FW_HEADER = new byte[]{ + 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, (byte) 0x9c, (byte) 0xe3, 0x7d, 0x5c, 0x00, 0x04 + }; + + private static final int FW_HEADER_OFFSET = 16; + + private static Map crcToVersion = new HashMap<>(); + + static { + // firmware + crcToVersion.put(8969, "1.0.5.22"); + + // resources + crcToVersion.put(27412, "1.0.5.22"); + + // font + crcToVersion.put(31978, "1"); + } + + public MiBand4FirmwareInfo(byte[] bytes) { + super(bytes); + } + + @Override + protected HuamiFirmwareType determineFirmwareType(byte[] bytes) { + if (ArrayUtils.equals(bytes, RES_HEADER, COMPRESSED_RES_HEADER_OFFSET) || ArrayUtils.equals(bytes, NEWRES_HEADER, COMPRESSED_RES_HEADER_OFFSET_NEW) || ArrayUtils.equals(bytes, NEWRES_HEADER, COMPRESSED_RES_HEADER_OFFSET)) { + return HuamiFirmwareType.RES_COMPRESSED; + } + if (ArrayUtils.equals(bytes, FW_HEADER, FW_HEADER_OFFSET)) { + if (searchString32BitAligned(bytes, "Mi Smart Band 4")) { + return HuamiFirmwareType.FIRMWARE; + } + return HuamiFirmwareType.INVALID; + } + if (ArrayUtils.startsWith(bytes, WATCHFACE_HEADER)) { + return HuamiFirmwareType.WATCHFACE; + } + if (ArrayUtils.startsWith(bytes, NEWFT_HEADER)) { + if (bytes[10] == 0x03) { + return HuamiFirmwareType.FONT; + } + } + // somebody might have unpacked the compressed res + if (ArrayUtils.startsWith(bytes, RES_HEADER)) { + return HuamiFirmwareType.RES; + } + return HuamiFirmwareType.INVALID; + } + + + @Override + public boolean isGenerallyCompatibleWith(GBDevice device) { + return isHeaderValid() && device.getType() == DeviceType.MIBAND4; + } + + @Override + protected Map getCrcMap() { + return crcToVersion; + } +} 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 d7feb5b97..2250925a0 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 @@ -22,6 +22,7 @@ import android.net.Uri; 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; public class MiBand4Support extends MiBand3Support { @@ -33,6 +34,6 @@ public class MiBand4Support extends MiBand3Support { @Override public HuamiFWHelper createFWHelper(Uri uri, Context context) throws IOException { - return null; + return new MiBand4FWHelper(uri, context); } } diff --git a/app/src/main/res/values-ca/strings.xml b/app/src/main/res/values-ca/strings.xml index 4ee621515..398f607ef 100644 --- a/app/src/main/res/values-ca/strings.xml +++ b/app/src/main/res/values-ca/strings.xml @@ -8,7 +8,7 @@ Donació Sincronitza Seguiment del son (ALPHA) - Cerca un dispositiu perdut + Cerca un aparell perdut Fes una captura de pantalla Connecta… Desconnecta @@ -170,9 +170,9 @@ Això és una notificació de prova des del Gadgetbridge El Bluetooth no és compatible o no està implementat. El Bluetooth està desactivat. - Toca el dispositiu connectat per obrir el gestor d\'aplicacions - Toca el dispositiu connectat per gestionar-ne l\'activitat - Toca el dispositiu per fer-lo vibrar + Toca l\'aparell connectat per obrir el gestor d\'aplicacions + Toca l\'aparell connectat per gestionar-ne l\'activitat + Toca l\'aparell per fer-lo vibrar Toca un aparell per connectar-hi No es pot connectar. Potser la direcció Bluetooth és incorrecta\? El Gadgetbridge està funcionant @@ -290,11 +290,11 @@ Passes per setmana La vostra activitat i el vostre son El microprogramari s\'està instal·lant… - No es pot instal·lar el fitxer. El dispositiu no està preparat. + No es pot instal·lar el fitxer. L\'aparell no està preparat. %1$s: %2$s %3$s Versió compatible Versió no provada! - Connexió a dispositiu: %1$s + Connexió a l\'aparell: %1$s Microprogramari Pebble %1$s Revisió del maquinari correcta La revisió del maquinari no coincideix! diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml index cba5c589b..8aa34c8fd 100644 --- a/app/src/main/res/values-cs/strings.xml +++ b/app/src/main/res/values-cs/strings.xml @@ -710,4 +710,5 @@ Vietnamsky Portugalsky Amazfit Cor 2 + Mi Band 4 \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index c9335e026..026c922f4 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -57,7 +57,8 @@ You are about to install the %s firmware on your Amazfit Bip.\n\nPlease make sure to install the .fw file, then the .res file, and finally the .gps file. Your watch will reboot after installing the .fw file.\n\nNote: You do not have to install .res and .gps if these files are exactly the same as the ones previously installed.\n\nPROCEED AT YOUR OWN RISK! You are about to install the %s firmware on your Amazfit Cor.\n\nPlease make sure to install the .fw file, and after that the .res file. Your band will reboot after installing the .fw file.\n\nNote: You do not have to install .res if it is exactly the same as the one previously installed.\n\nPROCEED AT YOUR OWN RISK! You are about to install the %s firmware on your Amazfit Cor 2.\n\nPlease make sure to install the .fw file, and after that the .res file. Your band will reboot after installing the .fw file.\n\nNote: You do not have to install .res if it is exactly the same as the one previously installed.\n\nPROCEED AT YOUR OWN RISK!\n\nCOMPLETELY UNTESTED, PROBABLY YOU NEED TO FLASH A BEATS_W FIRMWARE IF YOUR DEVICE NAME is \"Amazfit Band 2\!" - You are about to install the %s firmware on your Mi Band 3.\n\nPlease make sure to install the .fw file, and after that the .res file. Your watch will reboot after installing the .fw file.\n\nNote: You do not have to install .res if it is exactly the same as the one previously installed.\n\nPROCEED AT YOUR OWN RISK! + You are about to install the %s firmware on your Mi Band 3.\n\nPlease make sure to install the .fw file, and after that the .res file. Your band will reboot after installing the .fw file.\n\nNote: You do not have to install .res if it is exactly the same as the one previously installed.\n\nPROCEED AT YOUR OWN RISK! + You are about to install the %s firmware on your Mi Band 4.\n\nPlease make sure to install the .fw file, and after that the .res file. Your band will reboot after installing the .fw file.\n\nNote: You do not have to install .res if it is exactly the same as the one previously installed.\n\nPROCEED AT YOUR OWN RISK! You are about to install the %1$s and %2$s firmware, instead of the ones currently on your Mi Band. This firmware has been tested and is known to be compatible with Gadgetbridge. "This firmware is untested and may not be compatible with Gadgetbridge.\n\nYou are DISCOURAGED from flashing it!" @@ -225,6 +226,10 @@ Auth Key Change the auth key to a common key on all your Android devices from which you would like to connect from. The previous default key for all devices is 0123456789@ABCDE + Heart rate alarm during sports activity + Low limit + High limit + Auto export Auto export enabled diff --git a/app/src/main/res/xml/changelog_master.xml b/app/src/main/res/xml/changelog_master.xml index b287cb27d..c9002f075 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: Initial support (WARNING: INITIAL SETUP NEEDS MI FIT WITH ACCOUNT AND ROOT, NOT A RECOMMENDED DEVICE FOR GADGETBRIDGE) + Mi Band 1: Fix crash when entering per-device settings Mi Band 3: Allow setting date format in per-device settings diff --git a/fastlane/metadata/android/en-US/changelogs/152.txt b/fastlane/metadata/android/en-US/changelogs/152.txt new file mode 100644 index 000000000..6fc4ccbd6 --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/152.txt @@ -0,0 +1 @@ +* Mi Band 4: Initial support (WARNING: INITIAL SETUP NEEDS MI FIT WITH ACCOUNT AND ROOT, NOT A RECOMMENDED DEVICE FOR GADGETBRIDGE)