From 55cdc6d1c551162cec4dc756c8a5f30f5b000678 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Tue, 24 Oct 2017 22:01:25 +0200 Subject: [PATCH] Amazfit Cor: Untested firmware update support (refactor stuff along the way) --- .../devices/huami/HuamiFWHelper.java | 79 ++++++++++++++ .../huami/amazfitbip/AmazfitBipFWHelper.java | 52 +-------- .../amazfitcor/AmazfitCorCoordinator.java | 3 +- .../huami/amazfitcor/AmazfitCorFWHelper.java | 43 ++++++++ .../AmazfitCorFWInstallHandler.java | 56 ++++++++++ .../huami/miband2/MiBand2FWHelper.java | 51 +-------- .../service/DeviceSupportFactory.java | 5 +- .../amazfitbip/AmazfitBipFirmwareInfo.java | 19 ++-- .../devices/amazfitbip/AmazfitBipSupport.java | 24 ++--- .../devices/huami/HuamiFirmwareInfo.java | 100 ++++++++++++++++++ .../amazfitcor/AmazfitCorFirmwareInfo.java | 74 +++++++++++++ .../amazfitcor/AmazfitCorSupport.java} | 21 ++-- .../devices/miband2/Mi2FirmwareInfo.java | 64 ++--------- .../devices/miband2/MiBand2Support.java | 8 +- .../operations/UpdateFirmwareOperation.java | 14 +-- app/src/main/res/values/strings.xml | 2 + 16 files changed, 416 insertions(+), 199 deletions(-) create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huami/HuamiFWHelper.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huami/amazfitcor/AmazfitCorFWHelper.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huami/amazfitcor/AmazfitCorFWInstallHandler.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/HuamiFirmwareInfo.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/amazfitcor/AmazfitCorFirmwareInfo.java rename app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/{amazfitbip/operations/AmazfitBipUpdateFirmwareOperation.java => huami/amazfitcor/AmazfitCorSupport.java} (55%) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huami/HuamiFWHelper.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huami/HuamiFWHelper.java new file mode 100644 index 000000000..927044d6f --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huami/HuamiFWHelper.java @@ -0,0 +1,79 @@ +/* Copyright (C) 2016-2017 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; + +import android.content.Context; +import android.net.Uri; + +import java.io.IOException; + +import nodomain.freeyourgadget.gadgetbridge.devices.miband.AbstractMiBandFWHelper; +import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; +import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.HuamiFirmwareInfo; + +public abstract class HuamiFWHelper extends AbstractMiBandFWHelper { + protected HuamiFirmwareInfo firmwareInfo; + + public HuamiFWHelper(Uri uri, Context context) throws IOException { + super(uri, context); + } + + @Override + public String format(int version) { + return firmwareInfo.toVersion(version); + } + + @Override + public int getFirmwareVersion() { + return firmwareInfo.getFirmwareVersion(); + } + + @Override + public int getFirmware2Version() { + return 0; + } + + @Override + public String getHumanFirmwareVersion2() { + return ""; + } + + @Override + protected int[] getWhitelistedFirmwareVersions() { + return firmwareInfo.getWhitelistedVersions(); + } + + @Override + public boolean isFirmwareGenerallyCompatibleWith(GBDevice device) { + return firmwareInfo.isGenerallyCompatibleWith(device); + } + + @Override + public boolean isSingleFirmware() { + return true; + } + + @Override + public void checkValid() throws IllegalArgumentException { + firmwareInfo.checkValid(); + } + + public HuamiFirmwareInfo getFirmwareInfo() { + return firmwareInfo; + } + +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huami/amazfitbip/AmazfitBipFWHelper.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huami/amazfitbip/AmazfitBipFWHelper.java index 8d81e2b46..bac1b4aae 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huami/amazfitbip/AmazfitBipFWHelper.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huami/amazfitbip/AmazfitBipFWHelper.java @@ -22,53 +22,15 @@ import android.support.annotation.NonNull; import java.io.IOException; -import nodomain.freeyourgadget.gadgetbridge.devices.miband.AbstractMiBandFWHelper; -import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; +import nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiFWHelper; import nodomain.freeyourgadget.gadgetbridge.service.devices.amazfitbip.AmazfitBipFirmwareInfo; -public class AmazfitBipFWHelper extends AbstractMiBandFWHelper { +public class AmazfitBipFWHelper extends HuamiFWHelper { public AmazfitBipFWHelper(Uri uri, Context context) throws IOException { super(uri, context); } - private AmazfitBipFirmwareInfo firmwareInfo; - - @Override - public String format(int version) { - return AmazfitBipFirmwareInfo.toVersion(version); - } - - @Override - public int getFirmwareVersion() { - return firmwareInfo.getFirmwareVersion(); - } - - @Override - public int getFirmware2Version() { - return 0; - } - - @Override - public String getHumanFirmwareVersion2() { - return ""; - } - - @Override - protected int[] getWhitelistedFirmwareVersions() { - return AmazfitBipFirmwareInfo.getWhitelistedVersions(); - } - - @Override - public boolean isFirmwareGenerallyCompatibleWith(GBDevice device) { - return firmwareInfo.isGenerallyCompatibleWith(device); - } - - @Override - public boolean isSingleFirmware() { - return true; - } - @NonNull @Override protected void determineFirmwareInfo(byte[] wholeFirmwareBytes) { @@ -77,14 +39,4 @@ public class AmazfitBipFWHelper extends AbstractMiBandFWHelper { throw new IllegalArgumentException("Not a an Amazifit Bip firmware"); } } - - @Override - public void checkValid() throws IllegalArgumentException { - firmwareInfo.checkValid(); - } - - public AmazfitBipFirmwareInfo getFirmwareInfo() { - return firmwareInfo; - } - } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huami/amazfitcor/AmazfitCorCoordinator.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huami/amazfitcor/AmazfitCorCoordinator.java index a57085372..978c27333 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huami/amazfitcor/AmazfitCorCoordinator.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huami/amazfitcor/AmazfitCorCoordinator.java @@ -55,7 +55,8 @@ public class AmazfitCorCoordinator extends HuamiCoordinator { @Override public InstallHandler findInstallHandler(Uri uri, Context context) { - return null; + AmazfitCorFWInstallHandler handler = new AmazfitCorFWInstallHandler(uri, context); + return handler.isValid() ? handler : null; } @Override diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huami/amazfitcor/AmazfitCorFWHelper.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huami/amazfitcor/AmazfitCorFWHelper.java new file mode 100644 index 000000000..a0a63d205 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huami/amazfitcor/AmazfitCorFWHelper.java @@ -0,0 +1,43 @@ +/* Copyright (C) 2016-2017 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.amazfitcor; + +import android.content.Context; +import android.net.Uri; +import android.support.annotation.NonNull; + +import java.io.IOException; + +import nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiFWHelper; +import nodomain.freeyourgadget.gadgetbridge.service.devices.amazfitbip.AmazfitBipFirmwareInfo; +import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.amazfitcor.AmazfitCorFirmwareInfo; + +public class AmazfitCorFWHelper extends HuamiFWHelper { + + public AmazfitCorFWHelper(Uri uri, Context context) throws IOException { + super(uri, context); + } + + @NonNull + @Override + protected void determineFirmwareInfo(byte[] wholeFirmwareBytes) { + firmwareInfo = new AmazfitCorFirmwareInfo(wholeFirmwareBytes); + if (!firmwareInfo.isHeaderValid()) { + throw new IllegalArgumentException("Not a an Amazifit Bip firmware"); + } + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huami/amazfitcor/AmazfitCorFWInstallHandler.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huami/amazfitcor/AmazfitCorFWInstallHandler.java new file mode 100644 index 000000000..dc6ddfa4b --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huami/amazfitcor/AmazfitCorFWInstallHandler.java @@ -0,0 +1,56 @@ +/* Copyright (C) 2015-2017 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.amazfitcor; + +import android.content.Context; +import android.net.Uri; + +import java.io.IOException; + +import nodomain.freeyourgadget.gadgetbridge.R; +import nodomain.freeyourgadget.gadgetbridge.devices.huami.amazfitbip.AmazfitBipFWHelper; +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; +import nodomain.freeyourgadget.gadgetbridge.model.GenericItem; + +class AmazfitCorFWInstallHandler extends AbstractMiBandFWInstallHandler { + AmazfitCorFWInstallHandler(Uri uri, Context context) { + super(uri, context); + } + + @Override + protected GenericItem createInstallItem() { + return new GenericItem(mContext.getString(R.string.amazfitcor_firmware, helper.getHumanFirmwareVersion())); + } + + @Override + protected String getFwUpgradeNotice() { + return mContext.getString(R.string.fw_upgrade_notice_amazfitcor, helper.getHumanFirmwareVersion()); + } + + @Override + protected AbstractMiBandFWHelper createHelper(Uri uri, Context context) throws IOException { + return new AmazfitBipFWHelper(uri, context); + } + + @Override + protected boolean isSupportedDeviceType(GBDevice device) { + return device.getType() == DeviceType.AMAZFITCOR; + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huami/miband2/MiBand2FWHelper.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huami/miband2/MiBand2FWHelper.java index c0a555f32..05595f020 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huami/miband2/MiBand2FWHelper.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huami/miband2/MiBand2FWHelper.java @@ -22,52 +22,15 @@ import android.support.annotation.NonNull; import java.io.IOException; -import nodomain.freeyourgadget.gadgetbridge.devices.miband.AbstractMiBandFWHelper; -import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; +import nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiFWHelper; import nodomain.freeyourgadget.gadgetbridge.service.devices.miband2.Mi2FirmwareInfo; -public class MiBand2FWHelper extends AbstractMiBandFWHelper { - private Mi2FirmwareInfo firmwareInfo; +public class MiBand2FWHelper extends HuamiFWHelper { public MiBand2FWHelper(Uri uri, Context context) throws IOException { super(uri, context); } - @Override - public String format(int version) { - return Mi2FirmwareInfo.toVersion(version); - } - - @Override - public int getFirmwareVersion() { - return firmwareInfo.getFirmwareVersion(); - } - - @Override - public int getFirmware2Version() { - return 0; - } - - @Override - public String getHumanFirmwareVersion2() { - return ""; - } - - @Override - protected int[] getWhitelistedFirmwareVersions() { - return Mi2FirmwareInfo.getWhitelistedVersions(); - } - - @Override - public boolean isFirmwareGenerallyCompatibleWith(GBDevice device) { - return firmwareInfo.isGenerallyCompatibleWith(device); - } - - @Override - public boolean isSingleFirmware() { - return true; - } - @NonNull @Override protected void determineFirmwareInfo(byte[] wholeFirmwareBytes) { @@ -76,14 +39,4 @@ public class MiBand2FWHelper extends AbstractMiBandFWHelper { throw new IllegalArgumentException("Not a Mi Band 2 firmware"); } } - - @Override - public void checkValid() throws IllegalArgumentException { - firmwareInfo.checkValid(); - } - - public Mi2FirmwareInfo getFirmwareInfo() { - return firmwareInfo; - } - } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceSupportFactory.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceSupportFactory.java index 0d94ffed7..8c5a1acc9 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceSupportFactory.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceSupportFactory.java @@ -29,6 +29,7 @@ import nodomain.freeyourgadget.gadgetbridge.GBException; import nodomain.freeyourgadget.gadgetbridge.R; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.model.DeviceType; +import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.amazfitcor.AmazfitCorSupport; import nodomain.freeyourgadget.gadgetbridge.service.devices.liveview.LiveviewSupport; import nodomain.freeyourgadget.gadgetbridge.service.devices.miband2.MiBand2Support; import nodomain.freeyourgadget.gadgetbridge.service.devices.amazfitbip.AmazfitBipSupport; @@ -114,9 +115,11 @@ public class DeviceSupportFactory { deviceSupport = new ServiceDeviceSupport(new MiBand2Support(), EnumSet.of(ServiceDeviceSupport.Flags.THROTTLING, ServiceDeviceSupport.Flags.BUSY_CHECKING)); break; case AMAZFITBIP: - case AMAZFITCOR: deviceSupport = new ServiceDeviceSupport(new AmazfitBipSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING)); break; + case AMAZFITCOR: + deviceSupport = new ServiceDeviceSupport(new AmazfitCorSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING)); + break; case VIBRATISSIMO: deviceSupport = new ServiceDeviceSupport(new VibratissimoSupport(), EnumSet.of(ServiceDeviceSupport.Flags.THROTTLING, ServiceDeviceSupport.Flags.BUSY_CHECKING)); break; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/amazfitbip/AmazfitBipFirmwareInfo.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/amazfitbip/AmazfitBipFirmwareInfo.java index 744dcdd3b..61c0e552c 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/amazfitbip/AmazfitBipFirmwareInfo.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/amazfitbip/AmazfitBipFirmwareInfo.java @@ -16,13 +16,16 @@ along with this program. If not, see . */ package nodomain.freeyourgadget.gadgetbridge.service.devices.amazfitbip; +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.service.devices.miband2.Mi2FirmwareInfo; import nodomain.freeyourgadget.gadgetbridge.util.ArrayUtils; -public class AmazfitBipFirmwareInfo extends Mi2FirmwareInfo { +public class AmazfitBipFirmwareInfo extends HuamiFirmwareInfo { // total crap maybe private static final byte[] GPS_HEADER = new byte[]{ (byte) 0xcb, 0x51, (byte) 0xc1, 0x30, 0x41, (byte) 0x9e, 0x5e, (byte) 0xd3, @@ -37,10 +40,6 @@ public class AmazfitBipFirmwareInfo extends Mi2FirmwareInfo { private static final int FW_HEADER_OFFSET = 0x9330; - private static final byte[] RES_HEADER = new byte[]{ // HMRES resources file (*.res) - 0x48, 0x4d, 0x52, 0x45, 0x53 - }; - private static final byte[] GPS_ALMANAC_HEADER = new byte[]{ // probably wrong (byte) 0xa0, (byte) 0x80, 0x08, 0x00, (byte) 0x8b, 0x07 }; @@ -49,6 +48,7 @@ public class AmazfitBipFirmwareInfo extends Mi2FirmwareInfo { 0x2a, 0x12, (byte) 0xa0, 0x02 }; + private static Map crcToVersion = new HashMap<>(); static { // firmware crcToVersion.put(25257, "0.0.8.74"); @@ -75,6 +75,9 @@ public class AmazfitBipFirmwareInfo extends Mi2FirmwareInfo { @Override protected HuamiFirmwareType determineFirmwareType(byte[] bytes) { if (ArrayUtils.startsWith(bytes, RES_HEADER)) { + if (bytes.length > 500000) { // dont know how to distinguish from Cor .res + return HuamiFirmwareType.INVALID; + } return HuamiFirmwareType.RES; } if (ArrayUtils.startsWith(bytes, GPS_HEADER)) { @@ -98,4 +101,8 @@ public class AmazfitBipFirmwareInfo extends Mi2FirmwareInfo { return isHeaderValid() && device.getType() == DeviceType.AMAZFITBIP; } + @Override + protected Map getCrcMap() { + return crcToVersion; + } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/amazfitbip/AmazfitBipSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/amazfitbip/AmazfitBipSupport.java index d716bedfc..f590c6a4c 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/amazfitbip/AmazfitBipSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/amazfitbip/AmazfitBipSupport.java @@ -18,8 +18,8 @@ package nodomain.freeyourgadget.gadgetbridge.service.devices.amazfitbip; import android.bluetooth.BluetoothGatt; import android.bluetooth.BluetoothGattCharacteristic; +import android.content.Context; import android.net.Uri; -import android.widget.Toast; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -31,10 +31,11 @@ import java.util.Locale; import java.util.SimpleTimeZone; import java.util.UUID; -import nodomain.freeyourgadget.gadgetbridge.devices.huami.amazfitbip.AmazfitBipService; +import nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiFWHelper; 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.MiBand2Service; -import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.HuamiIcon; import nodomain.freeyourgadget.gadgetbridge.model.CallSpec; import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec; import nodomain.freeyourgadget.gadgetbridge.model.NotificationType; @@ -44,10 +45,9 @@ import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.alertnotificat import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.alertnotification.AlertNotificationProfile; import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.alertnotification.NewAlert; import nodomain.freeyourgadget.gadgetbridge.service.devices.amazfitbip.operations.AmazfitBipFetchLogsOperation; -import nodomain.freeyourgadget.gadgetbridge.service.devices.amazfitbip.operations.AmazfitBipUpdateFirmwareOperation; +import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.HuamiIcon; import nodomain.freeyourgadget.gadgetbridge.service.devices.miband.NotificationStrategy; import nodomain.freeyourgadget.gadgetbridge.service.devices.miband2.MiBand2Support; -import nodomain.freeyourgadget.gadgetbridge.util.GB; import nodomain.freeyourgadget.gadgetbridge.util.StringUtils; import nodomain.freeyourgadget.gadgetbridge.util.Version; @@ -120,15 +120,6 @@ public class AmazfitBipSupport extends MiBand2Support { // ignore } - @Override - public void onInstallApp(Uri uri) { - try { - new AmazfitBipUpdateFirmwareOperation(uri, this).perform(); - } catch (IOException ex) { - GB.toast(getContext(), "Firmware cannot be installed: " + ex.getMessage(), Toast.LENGTH_LONG, GB.ERROR, ex); - } - } - @Override public void onSendWeather(WeatherSpec weatherSpec) { if (gbDevice.getFirmwareVersion() == null) { @@ -258,4 +249,9 @@ public class AmazfitBipSupport extends MiBand2Support { setLanguage(builder); requestGPSVersion(builder); } + + @Override + public HuamiFWHelper createFWHelper(Uri uri, Context context) throws IOException { + return new AmazfitBipFWHelper(uri, context); + } } 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 new file mode 100644 index 000000000..80a7e0f2d --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/HuamiFirmwareInfo.java @@ -0,0 +1,100 @@ +/* Copyright (C) 2016-2017 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; + +import java.util.Map; + +import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; +import nodomain.freeyourgadget.gadgetbridge.util.ArrayUtils; +import nodomain.freeyourgadget.gadgetbridge.util.CheckSums; + + +public abstract class HuamiFirmwareInfo { + + protected static final byte[] RES_HEADER = new byte[]{ // HMRES resources file (*.res) + 0x48, 0x4d, 0x52, 0x45, 0x53 + }; + + protected static final byte[] FT_HEADER = new byte[]{ // HMZK font file (*.ft, *.ft.xx) + 0x48, + 0x4d, + 0x5a, + 0x4b + }; + + private HuamiFirmwareType firmwareType = HuamiFirmwareType.FIRMWARE; + + public String toVersion(int crc16) { + return getCrcMap().get(crc16); + } + + public int[] getWhitelistedVersions() { + return ArrayUtils.toIntArray(getCrcMap().keySet()); + } + + private final int crc16; + + private byte[] bytes; + + private String firmwareVersion; + + public HuamiFirmwareInfo(byte[] bytes) { + this.bytes = bytes; + crc16 = CheckSums.getCRC16(bytes); + firmwareVersion = getCrcMap().get(crc16); + firmwareType = determineFirmwareType(bytes); + } + + public abstract boolean isGenerallyCompatibleWith(GBDevice device); + + public boolean isHeaderValid() { + return getFirmwareType() != HuamiFirmwareType.INVALID; + } + + public void checkValid() throws IllegalArgumentException { + } + + /** + * Returns the size of the firmware in number of bytes. + * + * @return + */ + public int getSize() { + return bytes.length; + } + + public byte[] getBytes() { + return bytes; + } + + public int getCrc16() { + return crc16; + } + + public int getFirmwareVersion() { + return getCrc16(); // HACK until we know how to determine the version from the fw bytes + } + + public HuamiFirmwareType getFirmwareType() { + return firmwareType; + } + + protected abstract Map getCrcMap(); + + protected abstract HuamiFirmwareType determineFirmwareType(byte[] bytes); +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/amazfitcor/AmazfitCorFirmwareInfo.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/amazfitcor/AmazfitCorFirmwareInfo.java new file mode 100644 index 000000000..41ad891bf --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/amazfitcor/AmazfitCorFirmwareInfo.java @@ -0,0 +1,74 @@ +/* Copyright (C) 2017 Andreas Shimokawa + + 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.amazfitcor; + +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 AmazfitCorFirmwareInfo extends HuamiFirmwareInfo { + // guessed - at least it is the same accross current versions and different from other devices + private static final byte[] FW_HEADER = new byte[]{ + (byte) 0x06, (byte) 0x48, (byte) 0x00, (byte) 0x47, (byte) 0xfe, (byte) 0xe7, (byte) 0xfe, (byte) 0xe7, + (byte) 0xfe, (byte) 0xe7, (byte) 0xfe, (byte) 0xe7, (byte) 0xfe, (byte) 0xe7, (byte) 0xfe, (byte) 0xe7 + }; + + private static final int FW_HEADER_OFFSET = 0x9330; + + private static Map crcToVersion = new HashMap<>(); + + static { + // firmware + crcToVersion.put(39948, "1.0.5.60"); + + // resources + crcToVersion.put(46341, "RES 1.0.5.60"); + } + + public AmazfitCorFirmwareInfo(byte[] bytes) { + super(bytes); + } + + @Override + protected HuamiFirmwareType determineFirmwareType(byte[] bytes) { + if (ArrayUtils.startsWith(bytes, RES_HEADER)) { + if (bytes.length < 700000) { // dont know how to distinguish from Bip .res + return HuamiFirmwareType.INVALID; + } + return HuamiFirmwareType.RES; + } else if (ArrayUtils.equals(bytes, FW_HEADER, FW_HEADER_OFFSET)) { + // TODO: this is certainly not a correct validation, but it works for now + return HuamiFirmwareType.FIRMWARE; + } + return HuamiFirmwareType.INVALID; + } + + @Override + public boolean isGenerallyCompatibleWith(GBDevice device) { + return isHeaderValid() && device.getType() == DeviceType.AMAZFITCOR; + } + + @Override + protected Map getCrcMap() { + return crcToVersion; + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/amazfitbip/operations/AmazfitBipUpdateFirmwareOperation.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/amazfitcor/AmazfitCorSupport.java similarity index 55% rename from app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/amazfitbip/operations/AmazfitBipUpdateFirmwareOperation.java rename to app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/amazfitcor/AmazfitCorSupport.java index 1b7dcc685..5a9961897 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/amazfitbip/operations/AmazfitBipUpdateFirmwareOperation.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/amazfitcor/AmazfitCorSupport.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2017 Andreas Shimokawa, Carsten Pfeiffer +/* Copyright (C) 2017 Andreas Shimokawa This file is part of Gadgetbridge. @@ -14,26 +14,21 @@ 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.amazfitbip.operations; +package nodomain.freeyourgadget.gadgetbridge.service.devices.huami.amazfitcor; import android.content.Context; import android.net.Uri; import java.io.IOException; -import nodomain.freeyourgadget.gadgetbridge.devices.huami.amazfitbip.AmazfitBipFWHelper; +import nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiFWHelper; +import nodomain.freeyourgadget.gadgetbridge.devices.huami.amazfitcor.AmazfitCorFWHelper; import nodomain.freeyourgadget.gadgetbridge.service.devices.amazfitbip.AmazfitBipSupport; -import nodomain.freeyourgadget.gadgetbridge.service.devices.miband2.Mi2FirmwareInfo; -import nodomain.freeyourgadget.gadgetbridge.service.devices.miband2.operations.UpdateFirmwareOperation; -public class AmazfitBipUpdateFirmwareOperation extends UpdateFirmwareOperation { - public AmazfitBipUpdateFirmwareOperation(Uri uri, AmazfitBipSupport support) { - super(uri, support); - } +public class AmazfitCorSupport extends AmazfitBipSupport { - - protected Mi2FirmwareInfo createFwInfo(Uri uri, Context context) throws IOException { - AmazfitBipFWHelper fwHelper = new AmazfitBipFWHelper(uri, getContext()); - return fwHelper.getFirmwareInfo(); + @Override + public HuamiFWHelper createFWHelper(Uri uri, Context context) throws IOException { + return new AmazfitCorFWHelper(uri, context); } } 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 afd7a9716..014792bfe 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 @@ -21,11 +21,11 @@ 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; -import nodomain.freeyourgadget.gadgetbridge.util.CheckSums; -public class Mi2FirmwareInfo { +public class Mi2FirmwareInfo extends HuamiFirmwareInfo { private static final byte[] FW_HEADER = new byte[]{ (byte) 0xa3, (byte) 0x68, @@ -47,13 +47,6 @@ public class Mi2FirmwareInfo { 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 - }; - protected static Map crcToVersion = new HashMap<>(); static { // firmware @@ -68,30 +61,12 @@ public class Mi2FirmwareInfo { crcToVersion.put(6377, "Font (En)"); } - private HuamiFirmwareType firmwareType = HuamiFirmwareType.FIRMWARE; - - public static String toVersion(int crc16) { - return crcToVersion.get(crc16); - } - - public static int[] getWhitelistedVersions() { - return ArrayUtils.toIntArray(crcToVersion.keySet()); - } - - private final int crc16; - - private byte[] bytes; - private String firmwareVersion; - public Mi2FirmwareInfo(byte[] bytes) { - this.bytes = bytes; - crc16 = CheckSums.getCRC16(bytes); - firmwareVersion = crcToVersion.get(crc16); - firmwareType = determineFirmwareType(bytes); + super(bytes); } protected HuamiFirmwareType determineFirmwareType(byte[] bytes) { - if (ArrayUtils.startsWith(bytes, FT_HEADER)) { + if (ArrayUtils.startsWith(bytes, HuamiFirmwareInfo.FT_HEADER)) { return HuamiFirmwareType.FONT; } if (ArrayUtils.equals(bytes, FW_HEADER, FW_HEADER_OFFSET)) { @@ -105,34 +80,7 @@ public class Mi2FirmwareInfo { return isHeaderValid() && device.getType() == DeviceType.MIBAND2; } - public boolean isHeaderValid() { - return getFirmwareType() != HuamiFirmwareType.INVALID; - } - - public void checkValid() throws IllegalArgumentException { - } - - /** - * Returns the size of the firmware in number of bytes. - * @return - */ - public int getSize() { - return bytes.length; - } - - public byte[] getBytes() { - return bytes; - } - - public int getCrc16() { - return crc16; - } - - public int getFirmwareVersion() { - return getCrc16(); // HACK until we know how to determine the version from the fw bytes - } - - public HuamiFirmwareType getFirmwareType() { - return firmwareType; + protected Map getCrcMap() { + return crcToVersion; } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband2/MiBand2Support.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband2/MiBand2Support.java index 99bd8baca..a83ba843f 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband2/MiBand2Support.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband2/MiBand2Support.java @@ -55,9 +55,11 @@ import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventBatteryInf import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventCallControl; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventVersionInfo; import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider; +import nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiCoordinator; +import nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiFWHelper; +import nodomain.freeyourgadget.gadgetbridge.devices.huami.miband2.MiBand2FWHelper; import nodomain.freeyourgadget.gadgetbridge.devices.miband.DateTimeDisplay; import nodomain.freeyourgadget.gadgetbridge.devices.miband.DoNotDisturb; -import nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiCoordinator; import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBand2SampleProvider; import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBand2Service; import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst; @@ -1539,4 +1541,8 @@ public class MiBand2Support extends AbstractBTLEDeviceSupport { setInactivityWarnings(builder); setHeartrateSleepSupport(builder); } + + public HuamiFWHelper createFWHelper(Uri uri, Context context) throws IOException { + return new MiBand2FWHelper(uri, context); + } } 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 34d1ffede..8647880e8 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 @@ -32,12 +32,14 @@ import java.util.UUID; import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.R; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventDisplayMessage; +import nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiFWHelper; import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBand2Service; import nodomain.freeyourgadget.gadgetbridge.devices.huami.miband2.MiBand2FWHelper; 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.btle.actions.SetProgressAction; +import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.HuamiFirmwareInfo; import nodomain.freeyourgadget.gadgetbridge.service.devices.miband2.AbstractMiBand2Operation; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.HuamiFirmwareType; import nodomain.freeyourgadget.gadgetbridge.service.devices.miband2.Mi2FirmwareInfo; @@ -52,7 +54,7 @@ public class UpdateFirmwareOperation extends AbstractMiBand2Operation { protected final BluetoothGattCharacteristic fwCControlChar; protected final BluetoothGattCharacteristic fwCDataChar; protected final Prefs prefs = GBApplication.getPrefs(); - protected Mi2FirmwareInfo firmwareInfo; + protected HuamiFirmwareInfo firmwareInfo; public UpdateFirmwareOperation(Uri uri, MiBand2Support support) { super(support); @@ -80,8 +82,8 @@ public class UpdateFirmwareOperation extends AbstractMiBand2Operation { //the firmware will be sent by the notification listener if the band confirms that the metadata are ok. } - protected Mi2FirmwareInfo createFwInfo(Uri uri, Context context) throws IOException { - MiBand2FWHelper fwHelper = new MiBand2FWHelper(uri, context); + protected HuamiFirmwareInfo createFwInfo(Uri uri, Context context) throws IOException { + HuamiFWHelper fwHelper = getSupport().createFWHelper(uri, context); return fwHelper.getFirmwareInfo(); } @@ -229,7 +231,7 @@ public class UpdateFirmwareOperation extends AbstractMiBand2Operation { * @return whether the transfer succeeded or not. Only a BT layer exception will cause the transmission to fail. * @see #handleNotificationNotif */ - private boolean sendFirmwareData(Mi2FirmwareInfo info) { + private boolean sendFirmwareData(HuamiFirmwareInfo info) { byte[] fwbytes = info.getBytes(); int len = fwbytes.length; final int packetLength = 20; @@ -276,7 +278,7 @@ public class UpdateFirmwareOperation extends AbstractMiBand2Operation { } - private void sendChecksum(Mi2FirmwareInfo firmwareInfo) throws IOException { + private void sendChecksum(HuamiFirmwareInfo firmwareInfo) throws IOException { TransactionBuilder builder = performInitialized("send firmware checksum"); int crc16 = firmwareInfo.getCrc16(); byte[] bytes = BLETypeConversions.fromUint16(crc16); @@ -288,7 +290,7 @@ public class UpdateFirmwareOperation extends AbstractMiBand2Operation { builder.queue(getQueue()); } - private Mi2FirmwareInfo getFirmwareInfo() { + private HuamiFirmwareInfo getFirmwareInfo() { return firmwareInfo; } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 10da34ad6..d62753284 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -55,6 +55,7 @@ FW/App installer You are about to install firmware %s instead of the one currently on your Mi Band. You are about to install firmware %s instead of the one currently on your Amazfit Bip.\n\nPlease make sure to install the .gps firmware, then the .res file, and finally the .fw 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\nEXPERIMENTAL, PROCEED AT YOUR OWN RISK + You are about to install firmware %s instead of the one currently on your Amazfit Cor.\n\nPlease make sure to install the .res file, and after that the .fw 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\nEXPERIMENTAL, PROCEED AT YOUR OWN RISK You are about to install firmwares %1$s and %2$s 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 NOT encouraged to flash it to your Mi Band!" @@ -308,6 +309,7 @@ File cannot be installed, device not ready. Mi Band Firmware %1$s Amazfit Bip Firmware %1$s + Amazfit Cor Firmware %1$s Compatible version Untested version! Connection to device: %1$s