mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge.git
synced 2025-01-10 17:11:56 +01:00
Compare commits
2 Commits
2a377ba5ab
...
145c2b8c6c
Author | SHA1 | Date | |
---|---|---|---|
|
145c2b8c6c | ||
|
944e0d92a7 |
@ -88,9 +88,10 @@ public abstract class ZeppOsCoordinator extends HuamiCoordinator {
|
||||
protected final Pattern getSupportedDeviceName() {
|
||||
// Most devices use the exact bluetooth name
|
||||
// Some devices have a " XXXX" suffix with the last 4 digits of mac address (eg. Mi Band 7)
|
||||
// *However*, some devices broadcast a 2nd bluetooth device with "-XXXX" suffix, which is only
|
||||
// used for calls and Gadgetbridge can't use for pairing.
|
||||
return Pattern.compile("^" + getDeviceBluetoothName() + "( [A-Z0-9]{4})?$");
|
||||
// *However*, some devices broadcast a 2nd bluetooth device with "-XXXX" suffix, which I believe
|
||||
// is only used for calls, and Gadgetbridge can't use for pairing, but I was not yet able to
|
||||
// fully confirm this, so we still recognize them.
|
||||
return Pattern.compile("^" + getDeviceBluetoothName() + "([- ][A-Z0-9]{4})?$");
|
||||
}
|
||||
|
||||
@NonNull
|
||||
|
@ -28,12 +28,15 @@ import org.json.JSONObject;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.zip.CRC32;
|
||||
@ -43,10 +46,13 @@ import java.util.zip.ZipFile;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceApp;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.HuamiFirmwareType;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.UIHHContainer;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.BitmapUtil;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.CheckSums;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.FileUtils;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.GBZipFile;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.UriHelper;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.ZipFileException;
|
||||
|
||||
public class ZeppOsFwHelper {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ZeppOsFwHelper.class);
|
||||
@ -136,6 +142,12 @@ public class ZeppOsFwHelper {
|
||||
return;
|
||||
}
|
||||
|
||||
final byte[] header = getHeader(file, 4);
|
||||
if (header == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (Arrays.equals(header, GBZipFile.ZIP_HEADER)) {
|
||||
try (ZipFile zipFile = new ZipFile(file, java.util.zip.ZipFile.OPEN_READ)) {
|
||||
processZipFile(zipFile);
|
||||
} catch (final ZipException e) {
|
||||
@ -143,8 +155,64 @@ public class ZeppOsFwHelper {
|
||||
} catch (final IOException e) {
|
||||
LOG.warn("Error while processing {}", uri, e);
|
||||
}
|
||||
} else if (Arrays.equals(header, UIHHContainer.UIHH_HEADER)) {
|
||||
// FIXME: This should be refactored to avoid pulling the entire file to memory
|
||||
// However, it's currently only used for agps updates, which are usually just ~140KB
|
||||
try (InputStream in = new BufferedInputStream(uriHelper.openInputStream())) {
|
||||
final byte[] fullFile = FileUtils.readAll(in, 32 * 1024 * 1024); // 32MB
|
||||
processAsUihh(fullFile);
|
||||
} catch (final IOException e) {
|
||||
LOG.error("Failed to read full uihh from file", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO process as UIHH
|
||||
private void processAsUihh(byte[] bytes) {
|
||||
final UIHHContainer uihh = UIHHContainer.fromRawBytes(bytes);
|
||||
if (uihh == null) {
|
||||
LOG.warn("Invalid UIHH file");
|
||||
return;
|
||||
}
|
||||
|
||||
final Set<UIHHContainer.FileType> agpsEpoTypes = new HashSet<>();
|
||||
UIHHContainer.FileEntry uihhFirmwareZipFile = null;
|
||||
boolean hasChangelog = false;
|
||||
for (final UIHHContainer.FileEntry file : uihh.getFiles()) {
|
||||
switch (file.getType()) {
|
||||
case FIRMWARE_ZIP:
|
||||
uihhFirmwareZipFile = file;
|
||||
continue;
|
||||
case FIRMWARE_CHANGELOG:
|
||||
hasChangelog = true;
|
||||
continue;
|
||||
case AGPS_EPO_GR_3:
|
||||
case AGPS_EPO_GAL_7:
|
||||
case AGPS_EPO_BDS_3:
|
||||
agpsEpoTypes.add(file.getType());
|
||||
continue;
|
||||
default:
|
||||
LOG.warn("Unexpected file for {}", file.getType());
|
||||
}
|
||||
}
|
||||
|
||||
if (uihhFirmwareZipFile != null && hasChangelog) {
|
||||
// UIHH firmware update
|
||||
final GBZipFile zipFile = new GBZipFile(uihhFirmwareZipFile.getContent());
|
||||
final byte[] firmwareBin;
|
||||
try {
|
||||
firmwareBin = zipFile.getFileFromZip("META/firmware.bin");
|
||||
} catch (final ZipFileException e) {
|
||||
LOG.error("Failed to read zip from UIHH", e);
|
||||
return;
|
||||
}
|
||||
|
||||
if (isCompatibleFirmwareBin(firmwareBin)) {
|
||||
firmwareType = HuamiFirmwareType.FIRMWARE_UIHH_2021_ZIP_WITH_CHANGELOG;
|
||||
}
|
||||
} else if (agpsEpoTypes.size() == 3) {
|
||||
// AGPS EPO update
|
||||
firmwareType = HuamiFirmwareType.AGPS_UIHH;
|
||||
}
|
||||
}
|
||||
|
||||
private void processZipFile(final ZipFile zipFile) {
|
||||
@ -432,6 +500,23 @@ public class ZeppOsFwHelper {
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static byte[] getHeader(final File file, final int bytes) {
|
||||
final byte[] header = new byte[bytes];
|
||||
|
||||
try (InputStream is = new FileInputStream(file)) {
|
||||
if (is.read(header) != header.length) {
|
||||
LOG.warn("Read unexpected number of header bytes");
|
||||
return null;
|
||||
}
|
||||
} catch (final IOException e) {
|
||||
LOG.error("Error while reading header bytes", e);
|
||||
return null;
|
||||
}
|
||||
|
||||
return header;
|
||||
}
|
||||
|
||||
public static boolean searchString(final byte[] fwBytes, final String str) {
|
||||
final byte[] strBytes = (str + "\0").getBytes(StandardCharsets.UTF_8);
|
||||
|
||||
|
@ -642,11 +642,13 @@ public final class ZeppOsSupport extends HuamiSupport implements ZeppOsFileTrans
|
||||
return;
|
||||
}
|
||||
|
||||
new ZeppOsFirmwareUpdateOperation(Uri.parse(uihhFile.toURI().toString()), this).perform();
|
||||
new ZeppOsFirmwareUpdateOperation(
|
||||
Uri.parse(uihhFile.toURI().toString()),
|
||||
this
|
||||
).perform();
|
||||
}
|
||||
|
||||
} catch (final Exception e) {
|
||||
GB.toast(getContext(), "AGPS file cannot be installed: " + e.getMessage(), Toast.LENGTH_LONG, GB.ERROR, e);
|
||||
GB.toast(getContext(), "AGPS install error: " + e.getMessage(), Toast.LENGTH_LONG, GB.ERROR, e);
|
||||
}
|
||||
|
||||
return;
|
||||
@ -661,14 +663,16 @@ public final class ZeppOsSupport extends HuamiSupport implements ZeppOsFileTrans
|
||||
fileTransferService
|
||||
).perform();
|
||||
} catch (final Exception e) {
|
||||
GB.toast(getContext(), "Gpx route file cannot be installed: " + e.getMessage(), Toast.LENGTH_LONG, GB.ERROR, e);
|
||||
GB.toast(getContext(), "Gpx install error: " + e.getMessage(), Toast.LENGTH_LONG, GB.ERROR, e);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
new ZeppOsFirmwareUpdateOperation(uri, this).perform();
|
||||
} catch (final IOException ex) {
|
||||
GB.toast(getContext(), "Firmware cannot be installed: " + ex.getMessage(), Toast.LENGTH_LONG, GB.ERROR, ex);
|
||||
GB.toast(getContext(), "Firmware install error: " + ex.getMessage(), Toast.LENGTH_LONG, GB.ERROR, ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user