diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/amazfitbip/AmazfitBipCooordinator.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/amazfitbip/AmazfitBipCooordinator.java index 3490a454..a8141a5a 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/amazfitbip/AmazfitBipCooordinator.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/amazfitbip/AmazfitBipCooordinator.java @@ -52,10 +52,9 @@ public class AmazfitBipCooordinator extends MiBand2Coordinator { return DeviceType.UNKNOWN; } - @Override public InstallHandler findInstallHandler(Uri uri, Context context) { - return null; // not supported yet + AmazfitBipFWInstallHandler handler = new AmazfitBipFWInstallHandler(uri, context); + return handler.isValid() ? handler : null; } - } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/amazfitbip/AmazfitBipFWHelper.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/amazfitbip/AmazfitBipFWHelper.java new file mode 100644 index 00000000..c601c41d --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/amazfitbip/AmazfitBipFWHelper.java @@ -0,0 +1,90 @@ +/* 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.amazfitbip; + +import android.content.Context; +import android.net.Uri; +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.service.devices.amazfitbip.AmazfitBipFirmwareInfo; + +public class AmazfitBipFWHelper extends AbstractMiBandFWHelper { + + 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) { + firmwareInfo = new AmazfitBipFirmwareInfo(wholeFirmwareBytes); + if (!firmwareInfo.isHeaderValid()) { + 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/amazfitbip/AmazfitBipFWInstallHandler.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/amazfitbip/AmazfitBipFWInstallHandler.java new file mode 100644 index 00000000..9c496f5e --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/amazfitbip/AmazfitBipFWInstallHandler.java @@ -0,0 +1,43 @@ +/* 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.amazfitbip; + +import android.content.Context; +import android.net.Uri; + +import java.io.IOException; + +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 AmazfitBipFWInstallHandler extends AbstractMiBandFWInstallHandler { + AmazfitBipFWInstallHandler(Uri uri, Context context) { + super(uri, context); + } + + @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.AMAZFITBIP; + } +} 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 new file mode 100644 index 00000000..50a8c5bb --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/amazfitbip/AmazfitBipFirmwareInfo.java @@ -0,0 +1,79 @@ +/* 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.amazfitbip; + +import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; +import nodomain.freeyourgadget.gadgetbridge.model.DeviceType; +import nodomain.freeyourgadget.gadgetbridge.service.devices.miband2.FirmwareType; +import nodomain.freeyourgadget.gadgetbridge.service.devices.miband2.Mi2FirmwareInfo; +import nodomain.freeyourgadget.gadgetbridge.util.ArrayUtils; + +public class AmazfitBipFirmwareInfo extends Mi2FirmwareInfo { + // total crap maybe + private static final byte[] GPS_HEADER = new byte[]{ + (byte) 0xcb, 0x51, (byte) 0xc1, 0x30, 0x41, (byte) 0x9e, 0x5e, (byte) 0xd3, + 0x51, 0x35, (byte) 0xdf, 0x66, (byte) 0xed, (byte) 0xd9, 0x5f, (byte) 0xa7 + }; + + // guessed - at least it is the same accross current versions and different from other devices + private static final byte[] FW_HEADER = new byte[]{ + 0x3f, 0x34, 0x00, 0x20, 0x27, 0x35, 0x00, 0x20, + 0x0d, 0x31, 0x03, 0x00, 0x15, 0x35, 0x00, 0x20 + }; + + private static final int FW_HEADER_OFFSET = 0x40; + + private static final byte[] RES_HEADER = new byte[]{ // HMRES resources file (*.res) + 0x48, 0x4d, 0x52, 0x45, 0x53 + }; + + + static { + // firmware + crcToVersion.put(25257, "0.0.8.74"); + + // resources + crcToVersion.put(12586, "0.0.8.74 (RES)"); + + // gps + } + + public AmazfitBipFirmwareInfo(byte[] bytes) { + super(bytes); + } + + @Override + protected FirmwareType determineFirmwareType(byte[] bytes) { + if (ArrayUtils.startsWith(bytes, RES_HEADER)) { + return FirmwareType.RES; + } + if (ArrayUtils.startsWith(bytes, GPS_HEADER)) { + return FirmwareType.GPS; + } + 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; + } + + @Override + public boolean isGenerallyCompatibleWith(GBDevice device) { + return isHeaderValid() && device.getType() == DeviceType.AMAZFITBIP; + } + +} 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 c10d9b7d..c0cfa653 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 @@ -16,6 +16,9 @@ along with this program. If not, see . */ package nodomain.freeyourgadget.gadgetbridge.service.devices.amazfitbip; +import android.net.Uri; +import android.widget.Toast; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -35,8 +38,10 @@ import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder; import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.alertnotification.AlertCategory; 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.AmazfitBipUpdateFirmwareOperation; 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; public class AmazfitBipSupport extends MiBand2Support { @@ -113,6 +118,14 @@ public class AmazfitBipSupport extends MiBand2Support { } @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); + } + } + public void onSendWeather(WeatherSpec weatherSpec) { try { TransactionBuilder builder = performInitialized("Sending weather forecast"); 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 index ce9b6b7b..2abbd89d 100644 --- 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 @@ -19,8 +19,8 @@ package nodomain.freeyourgadget.gadgetbridge.service.devices.miband2; public enum FirmwareType { FIRMWARE((byte) 0), FONT((byte) 1), - UNKNOWN1((byte) 2), - UNKNOWN2((byte) 3), + RES((byte) 2), + GPS((byte) 3), INVALID(Byte.MIN_VALUE); private final byte 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 a08a27af..202e55ec 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 @@ -53,7 +53,7 @@ public class Mi2FirmwareInfo { 0x4b }; - private static Map crcToVersion = new HashMap<>(); + protected static Map crcToVersion = new HashMap<>(); static { // firmware crcToVersion.put(41899, "1.0.0.39"); @@ -89,7 +89,7 @@ public class Mi2FirmwareInfo { firmwareType = determineFirmwareType(bytes); } - private FirmwareType determineFirmwareType(byte[] bytes) { + protected FirmwareType determineFirmwareType(byte[] bytes) { if (ArrayUtils.startsWith(bytes, FT_HEADER)) { return FirmwareType.FONT; } 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 3e48640c..1516b995 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 @@ -49,10 +49,10 @@ public class UpdateFirmwareOperation extends AbstractMiBand2Operation { private static final Logger LOG = LoggerFactory.getLogger(UpdateFirmwareOperation.class); private final Uri uri; - private final BluetoothGattCharacteristic fwCControlChar; - private final BluetoothGattCharacteristic fwCDataChar; - final Prefs prefs = GBApplication.getPrefs(); - private Mi2FirmwareInfo firmwareInfo; + protected final BluetoothGattCharacteristic fwCControlChar; + protected final BluetoothGattCharacteristic fwCDataChar; + protected final Prefs prefs = GBApplication.getPrefs(); + protected Mi2FirmwareInfo firmwareInfo; public UpdateFirmwareOperation(Uri uri, MiBand2Support support) { super(support);