Xiaomi-protobuf: Fix activity sync stuck on duplicated or invalid files

Ref: #4305
This commit is contained in:
José Rebelo 2024-12-03 21:04:25 +00:00
parent 44d50e6246
commit 9748f389dd
3 changed files with 114 additions and 62 deletions

View File

@ -17,6 +17,8 @@
package nodomain.freeyourgadget.gadgetbridge.service.devices.xiaomi.activity;
import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -48,19 +50,48 @@ public class XiaomiActivityFileFetcher {
private ByteArrayOutputStream mBuffer = new ByteArrayOutputStream();
private boolean isFetching = false;
private final Handler timeoutHandler = new Handler(Looper.getMainLooper());
public XiaomiActivityFileFetcher(final XiaomiHealthService healthService) {
this.mHealthService = healthService;
}
public void dispose() {
clearTimeout();
}
private void clearTimeout() {
this.timeoutHandler.removeCallbacksAndMessages(null);
}
private void setTimeout() {
// #4305 - Set the timeout in case the watch does not send the file
this.timeoutHandler.postDelayed(() -> {
LOG.warn("Timed out waiting for activity file with {} bytes in the buffer", mBuffer.size());
triggerNextFetch();
}, 5000L);
}
public void addChunk(final byte[] chunk) {
clearTimeout();
final int total = BLETypeConversions.toUint16(chunk, 0);
final int num = BLETypeConversions.toUint16(chunk, 2);
if (num == 1) {
// reset buffer
mBuffer = new ByteArrayOutputStream();
}
LOG.debug("Got activity chunk {}/{}", num, total);
mBuffer.write(chunk, 4, chunk.length - 4);
if (num == total) {
if (num != total) {
setTimeout();
return;
}
final byte[] data = mBuffer.toByteArray();
mBuffer = new ByteArrayOutputStream();
@ -122,10 +153,17 @@ public class XiaomiActivityFileFetcher {
triggerNextFetch();
}
}
public void fetch(final List<XiaomiActivityFileId> fileIds) {
mFetchQueue.addAll(fileIds);
// #4305 - ensure unique files
for (final XiaomiActivityFileId fileId : fileIds) {
if (!mFetchQueue.contains(fileId)) {
mFetchQueue.add(fileId);
} else {
LOG.warn("Ignoring duplicated file {}", fileId);
}
}
if (!isFetching) {
// Currently not fetching anything, fetch the next
isFetching = true;
@ -139,6 +177,9 @@ public class XiaomiActivityFileFetcher {
}
private void triggerNextFetch() {
clearTimeout();
mBuffer = new ByteArrayOutputStream();
final XiaomiActivityFileId fileId = mFetchQueue.poll();
if (fileId == null) {
@ -153,6 +194,8 @@ public class XiaomiActivityFileFetcher {
LOG.debug("Triggering next fetch for: {}", fileId);
setTimeout();
mHealthService.requestRecordedData(fileId);
}

View File

@ -42,6 +42,10 @@ public abstract class AbstractXiaomiService {
}
public void dispose() {
}
/**
* Handle a preference change.
* @param config the preference key

View File

@ -203,6 +203,11 @@ public class XiaomiHealthService extends AbstractXiaomiService {
getSupport().sendCommand("get vitality score config", COMMAND_TYPE, CMD_CONFIG_VITALITY_SCORE_GET);
}
@Override
public void dispose() {
activityFetcher.dispose();
}
@Override
public boolean onSendConfiguration(final String config, final Prefs prefs) {
switch (config) {