mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge
synced 2024-09-27 00:38:01 +02:00
Support for firmware upgrade/downgrade on Mi 1A.
I hope I didn't break firmware upgrades on some Mi 1 models other than mine (my hardware revision is 2). Upgrades for Mi 1S are currently disabled, we need some brave souls who can help us test this. Closes #173 Also see: #169
This commit is contained in:
parent
6b053c4240
commit
365ce61cb6
@ -73,11 +73,8 @@
|
|||||||
</activity>
|
</activity>
|
||||||
<activity
|
<activity
|
||||||
android:name=".activities.FwAppInstallerActivity"
|
android:name=".activities.FwAppInstallerActivity"
|
||||||
android:label="@string/title_activity_fw_app_insaller">
|
android:label="@string/title_activity_fw_app_insaller"
|
||||||
<meta-data
|
android:parentActivityName=".activities.ControlCenter">
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
|
||||||
android:value=".activities.ControlCenter" />
|
|
||||||
|
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.VIEW" />
|
<action android:name="android.intent.action.VIEW" />
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
@ -25,6 +25,9 @@ public final class MiBandConst {
|
|||||||
public static final String ORIGIN_K9MAIL = "k9mail";
|
public static final String ORIGIN_K9MAIL = "k9mail";
|
||||||
public static final String ORIGIN_PEBBLEMSG = "pebblemsg";
|
public static final String ORIGIN_PEBBLEMSG = "pebblemsg";
|
||||||
public static final String ORIGIN_GENERIC = "generic";
|
public static final String ORIGIN_GENERIC = "generic";
|
||||||
|
public static final String MI_1 = "1";
|
||||||
|
public static final String MI_1A = "1A";
|
||||||
|
public static final String MI_1S = "1S";
|
||||||
|
|
||||||
public static int getNotificationPrefIntValue(String pref, String origin, SharedPreferences prefs, int defaultValue) {
|
public static int getNotificationPrefIntValue(String pref, String origin, SharedPreferences prefs, int defaultValue) {
|
||||||
String key = getNotificationPrefKey(pref, origin);
|
String key = getNotificationPrefKey(pref, origin);
|
||||||
|
@ -12,6 +12,7 @@ import java.io.IOException;
|
|||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.FileUtils;
|
import nodomain.freeyourgadget.gadgetbridge.util.FileUtils;
|
||||||
|
|
||||||
public class MiBandFWHelper {
|
public class MiBandFWHelper {
|
||||||
@ -21,10 +22,10 @@ public class MiBandFWHelper {
|
|||||||
private final ContentResolver cr;
|
private final ContentResolver cr;
|
||||||
private byte[] fw;
|
private byte[] fw;
|
||||||
|
|
||||||
private final int firmwareVersionBuild = 1056;
|
private final int offsetFirmwareVersionBuild = 1056;
|
||||||
private final int firmwareVersionRevision = 1057;
|
private final int offsetFirmwareVersionRevision = 1057;
|
||||||
private final int firmwareVersionMinor = 1058;
|
private final int offsetFirmwareVersionMinor = 1058;
|
||||||
private final int firmwareVersionMajor = 1059;
|
private final int offsetFirmwareVersionMajor = 1059;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides a different notification API which is also used on Mi1A devices.
|
* Provides a different notification API which is also used on Mi1A devices.
|
||||||
@ -57,20 +58,38 @@ public class MiBandFWHelper {
|
|||||||
|
|
||||||
try (InputStream in = new BufferedInputStream(cr.openInputStream(uri))) {
|
try (InputStream in = new BufferedInputStream(cr.openInputStream(uri))) {
|
||||||
this.fw = FileUtils.readAll(in, 1024 * 1024); // 1 MB
|
this.fw = FileUtils.readAll(in, 1024 * 1024); // 1 MB
|
||||||
if (fw.length <= firmwareVersionMajor || fw[firmwareVersionMajor] != 1) {
|
if (fw.length <= offsetFirmwareVersionMajor) {
|
||||||
throw new IOException("Firmware major version should be 1, probably this isn't a MiBand firmware.");
|
throw new IOException("This doesn't seem to be a Mi Band firmware, file size too small.");
|
||||||
}
|
}
|
||||||
|
byte firmwareVersionMajor = fw[offsetFirmwareVersionMajor];
|
||||||
|
if (!isSupportedFirmwareVersionMajor(firmwareVersionMajor)) {
|
||||||
|
throw new IOException("Firmware major version not supported, either too new or this isn't a Mi Band firmware: " + firmwareVersionMajor);
|
||||||
|
}
|
||||||
|
} catch (IOException ex) {
|
||||||
|
throw ex; // pass through
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new IOException("Error reading firmware file: " + uri.toString(), e);
|
throw new IOException("Error reading firmware file: " + uri.toString(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private byte getFirmwareVersionMajor() {
|
||||||
|
return fw[offsetFirmwareVersionMajor];
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte getFirmwareVersionMinor() {
|
||||||
|
return fw[offsetFirmwareVersionMinor];
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isSupportedFirmwareVersionMajor(byte firmwareVersionMajor) {
|
||||||
|
return firmwareVersionMajor == 1 || firmwareVersionMajor == 5;
|
||||||
|
}
|
||||||
|
|
||||||
public int getFirmwareVersion() {
|
public int getFirmwareVersion() {
|
||||||
return (fw[firmwareVersionMajor] << 24) | (fw[firmwareVersionMinor] << 16) | (fw[firmwareVersionRevision] << 8) | fw[firmwareVersionBuild];
|
return (fw[offsetFirmwareVersionMajor] << 24) | (fw[offsetFirmwareVersionMinor] << 16) | (fw[offsetFirmwareVersionRevision] << 8) | fw[offsetFirmwareVersionBuild];
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getHumanFirmwareVersion() {
|
public String getHumanFirmwareVersion() {
|
||||||
return String.format(Locale.US, "%d.%d.%d.%d", fw[firmwareVersionMajor], fw[firmwareVersionMinor], fw[firmwareVersionRevision], fw[firmwareVersionBuild]);
|
return String.format(Locale.US, "%d.%d.%d.%d", fw[offsetFirmwareVersionMajor], fw[offsetFirmwareVersionMinor], fw[offsetFirmwareVersionRevision], fw[offsetFirmwareVersionBuild]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] getFw() {
|
public byte[] getFw() {
|
||||||
@ -85,4 +104,15 @@ public class MiBandFWHelper {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isFirmwareGenerallyCompatibleWith(GBDevice device) {
|
||||||
|
String deviceHW = device.getHardwareVersion();
|
||||||
|
if (MiBandConst.MI_1.equals(deviceHW)) {
|
||||||
|
return getFirmwareVersionMajor() == 1;
|
||||||
|
}
|
||||||
|
if (MiBandConst.MI_1A.equals(deviceHW)) {
|
||||||
|
return getFirmwareVersionMajor() == 5;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -50,6 +50,12 @@ public class MiBandFWInstallHandler implements InstallHandler {
|
|||||||
GenericItem fwItem = new GenericItem(mContext.getString(R.string.miband_installhandler_miband_firmware, helper.getHumanFirmwareVersion()));
|
GenericItem fwItem = new GenericItem(mContext.getString(R.string.miband_installhandler_miband_firmware, helper.getHumanFirmwareVersion()));
|
||||||
fwItem.setIcon(R.drawable.ic_device_miband);
|
fwItem.setIcon(R.drawable.ic_device_miband);
|
||||||
|
|
||||||
|
if (!helper.isFirmwareGenerallyCompatibleWith(device)) {
|
||||||
|
fwItem.setDetails(mContext.getString(R.string.miband_fwinstaller_incompatible_version));
|
||||||
|
installActivity.setInfoText(mContext.getString(R.string.fwinstaller_firmware_not_compatible_to_device));
|
||||||
|
installActivity.setInstallEnabled(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
StringBuilder builder = new StringBuilder(mContext.getString(R.string.fw_upgrade_notice, helper.getHumanFirmwareVersion()));
|
StringBuilder builder = new StringBuilder(mContext.getString(R.string.fw_upgrade_notice, helper.getHumanFirmwareVersion()));
|
||||||
|
|
||||||
if (helper.isFirmwareWhitelisted()) {
|
if (helper.isFirmwareWhitelisted()) {
|
||||||
|
@ -2,6 +2,7 @@ package nodomain.freeyourgadget.gadgetbridge.service.devices.miband;
|
|||||||
|
|
||||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.CheckSums;
|
import nodomain.freeyourgadget.gadgetbridge.util.CheckSums;
|
||||||
|
|
||||||
public class DeviceInfo extends AbstractInfo {
|
public class DeviceInfo extends AbstractInfo {
|
||||||
@ -75,8 +76,28 @@ public class DeviceInfo extends AbstractInfo {
|
|||||||
'}';
|
'}';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isMili1() {
|
||||||
|
return hwVersion == 2;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isMili1A() {
|
public boolean isMili1A() {
|
||||||
return feature == 5 && appearance == 0 || feature == 0 && hwVersion == 208;
|
return feature == 5 && appearance == 0 || feature == 0 && hwVersion == 208;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isMilli1S() {
|
||||||
|
return false; // FIXME: what to do here?
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getHwVersion() {
|
||||||
|
if (isMili1()) {
|
||||||
|
return MiBandConst.MI_1;
|
||||||
|
}
|
||||||
|
if (isMili1A()) {
|
||||||
|
return MiBandConst.MI_1A;
|
||||||
|
}
|
||||||
|
if (isMilli1S()) {
|
||||||
|
return MiBandConst.MI_1S;
|
||||||
|
}
|
||||||
|
return "?";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -687,16 +687,17 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport {
|
|||||||
if (status == BluetoothGatt.GATT_SUCCESS) {
|
if (status == BluetoothGatt.GATT_SUCCESS) {
|
||||||
mDeviceInfo = new DeviceInfo(value);
|
mDeviceInfo = new DeviceInfo(value);
|
||||||
LOG.warn("Device info: " + mDeviceInfo);
|
LOG.warn("Device info: " + mDeviceInfo);
|
||||||
|
versionCmd.hwVersion = mDeviceInfo.getHwVersion();
|
||||||
versionCmd.fwVersion = mDeviceInfo.getHumanFirmwareVersion();
|
versionCmd.fwVersion = mDeviceInfo.getHumanFirmwareVersion();
|
||||||
handleGBDeviceEvent(versionCmd);
|
handleGBDeviceEvent(versionCmd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleDeviceName(byte[] value, int status) {
|
private void handleDeviceName(byte[] value, int status) {
|
||||||
if (status == BluetoothGatt.GATT_SUCCESS) {
|
// if (status == BluetoothGatt.GATT_SUCCESS) {
|
||||||
versionCmd.hwVersion = new String(value);
|
// versionCmd.hwVersion = new String(value);
|
||||||
handleGBDeviceEvent(versionCmd);
|
// handleGBDeviceEvent(versionCmd);
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -15,7 +15,6 @@ import java.util.UUID;
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandFWHelper;
|
import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandFWHelper;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandService;
|
import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandService;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.AbstractBTLEOperation;
|
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
|
import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.SetDeviceBusyAction;
|
import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.SetDeviceBusyAction;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.SetProgressAction;
|
import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.SetProgressAction;
|
||||||
@ -38,9 +37,6 @@ public class UpdateFirmwareOperation extends AbstractMiBandOperation {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doPerform() throws IOException {
|
protected void doPerform() throws IOException {
|
||||||
if (getSupport().getDeviceInfo().isMili1A()) {
|
|
||||||
throw new IOException("Firmware update is not supported for the Mi Band 1A, yet.");
|
|
||||||
}
|
|
||||||
MiBandFWHelper mFwHelper = new MiBandFWHelper(uri, getContext());
|
MiBandFWHelper mFwHelper = new MiBandFWHelper(uri, getContext());
|
||||||
String mMac = getDevice().getAddress();
|
String mMac = getDevice().getAddress();
|
||||||
String[] mMacOctets = mMac.split(":");
|
String[] mMacOctets = mMac.split(":");
|
||||||
|
@ -210,4 +210,6 @@
|
|||||||
<string name="device_not_connected">Not connected.</string>
|
<string name="device_not_connected">Not connected.</string>
|
||||||
<string name="user_feedback_all_alarms_disabled">All alarms disabled</string>
|
<string name="user_feedback_all_alarms_disabled">All alarms disabled</string>
|
||||||
<string name="pref_title_keep_data_on_device">Keep activity data on device</string>
|
<string name="pref_title_keep_data_on_device">Keep activity data on device</string>
|
||||||
|
<string name="miband_fwinstaller_incompatible_version">Incompatible firmware</string>
|
||||||
|
<string name="fwinstaller_firmware_not_compatible_to_device">This firmware is not compatible with the device</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
Loading…
Reference in New Issue
Block a user