diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/xiaomi/XiaomiCoordinator.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/xiaomi/XiaomiCoordinator.java index fdcb7109d..f7ae7caea 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/xiaomi/XiaomiCoordinator.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/xiaomi/XiaomiCoordinator.java @@ -343,6 +343,12 @@ public abstract class XiaomiCoordinator extends AbstractBLEDeviceCoordinator { settings.add(R.xml.devicesettings_header_other); settings.add(R.xml.devicesettings_camera_remote); + // + // Developer + // + settings.add(R.xml.devicesettings_header_developer); + settings.add(R.xml.devicesettings_keep_activity_data_on_device); + return ArrayUtils.toPrimitive(settings.toArray(new Integer[0])); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/xiaomi/XiaomiPreferences.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/xiaomi/XiaomiPreferences.java index e29017385..86c17af4f 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/xiaomi/XiaomiPreferences.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/xiaomi/XiaomiPreferences.java @@ -22,7 +22,10 @@ import java.util.GregorianCalendar; import java.util.Locale; import java.util.TimeZone; +import nodomain.freeyourgadget.gadgetbridge.GBApplication; +import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.proto.xiaomi.XiaomiProto; +import nodomain.freeyourgadget.gadgetbridge.util.Prefs; public final class XiaomiPreferences { private XiaomiPreferences() { @@ -61,4 +64,9 @@ public final class XiaomiPreferences { public static String getPrefPossibleValuesKey(final String key) { return String.format(Locale.ROOT, "%s_possible_values", key); } + + public static boolean keepActivityDataOnDevice(final GBDevice gbDevice) { + final Prefs prefs = new Prefs(GBApplication.getDeviceSpecificSharedPrefs(gbDevice.getAddress())); + return prefs.getBoolean("keep_activity_data_on_device", false); + } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/xiaomi/activity/XiaomiActivityFileFetcher.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/xiaomi/activity/XiaomiActivityFileFetcher.java index f996b4842..bbeefb2a0 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/xiaomi/activity/XiaomiActivityFileFetcher.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/xiaomi/activity/XiaomiActivityFileFetcher.java @@ -33,6 +33,7 @@ import java.util.Set; import nodomain.freeyourgadget.gadgetbridge.R; import nodomain.freeyourgadget.gadgetbridge.service.btle.BLETypeConversions; +import nodomain.freeyourgadget.gadgetbridge.service.devices.xiaomi.XiaomiPreferences; import nodomain.freeyourgadget.gadgetbridge.service.devices.xiaomi.XiaomiSupport; import nodomain.freeyourgadget.gadgetbridge.service.devices.xiaomi.services.XiaomiHealthService; import nodomain.freeyourgadget.gadgetbridge.util.CheckSums; @@ -43,9 +44,8 @@ public class XiaomiActivityFileFetcher { private final XiaomiHealthService mHealthService; - private final Queue> mFetchQueue = new LinkedList<>(); - private ByteArrayOutputStream mBuffer = null; - private Set pendingFiles = new HashSet<>(); + private final Queue mFetchQueue = new LinkedList<>(); + private ByteArrayOutputStream mBuffer = new ByteArrayOutputStream(); private boolean isFetching = false; public XiaomiActivityFileFetcher(final XiaomiHealthService healthService) { @@ -58,18 +58,11 @@ public class XiaomiActivityFileFetcher { LOG.debug("Got activity chunk {}/{}", num, total); - if (num == 1) { - if (mBuffer == null) { - mBuffer = new ByteArrayOutputStream(); - } - mBuffer.reset(); - mBuffer.write(chunk, 4, chunk.length - 4); - } + mBuffer.write(chunk, 4, chunk.length - 4); if (num == total) { final byte[] data = mBuffer.toByteArray(); - mBuffer.reset(); - mBuffer = null; + mBuffer = new ByteArrayOutputStream(); if (data.length < 13) { LOG.warn("Activity data length of {} is too short", data.length); @@ -78,8 +71,15 @@ public class XiaomiActivityFileFetcher { return; } - if (!validChecksum(data)) { - LOG.warn("Invalid activity data checksum"); + final int arrCrc32 = CheckSums.getCRC32(data, 0, data.length - 4); + final int expectedCrc32 = BLETypeConversions.toUint32(data, data.length - 4); + + if (arrCrc32 != expectedCrc32) { + LOG.warn( + "Invalid activity data checksum: got {}, expected {}", + String.format("%08X", arrCrc32), + String.format("%08X", expectedCrc32) + ); // FIXME this may mess up the order.. maybe we should just abort triggerNextFetch(); return; @@ -104,18 +104,21 @@ public class XiaomiActivityFileFetcher { } if (activityParser.parse(fileId, activityData)) { - LOG.debug("Acking recorded data {}", fileId); - //mHealthService.ackRecordedData(fileId); + if (!XiaomiPreferences.keepActivityDataOnDevice(mHealthService.getSupport().getDevice())) { + LOG.debug("Acking recorded data {}", fileId); + mHealthService.ackRecordedData(fileId); + } } - // FIXME only after receiving everything triggerNextFetch(); + triggerNextFetch(); } } - public void fetch(final List fileIds) { - mFetchQueue.add(fileIds); + public void fetch(final XiaomiActivityFileId fileId) { + mFetchQueue.add(fileId); if (!isFetching) { // Currently not fetching anything, fetch the next + isFetching = true; final XiaomiSupport support = mHealthService.getSupport(); final Context context = support.getContext(); GB.updateTransferNotification(context.getString(R.string.busy_task_fetch_activity_data),"", true, 0, context); @@ -125,21 +128,18 @@ public class XiaomiActivityFileFetcher { } private void triggerNextFetch() { - final List fileIds = mFetchQueue.poll(); + final XiaomiActivityFileId fileId = mFetchQueue.poll(); - if (fileIds == null || fileIds.isEmpty()) { + if (fileId == null) { + LOG.debug("Nothing more to fetch"); + isFetching = false; mHealthService.getSupport().getDevice().unsetBusyTask(); GB.updateTransferNotification(null, "", false, 100, mHealthService.getSupport().getContext()); return; } - mHealthService.requestRecordedData(fileIds); - } + LOG.debug("Triggering next fetch for: {}", fileId); - public boolean validChecksum(final byte[] arr) { - final int arrCrc32 = CheckSums.getCRC32(arr, 0, arr.length - 4); - final int expectedCrc32 = BLETypeConversions.toUint32(arr, arr.length - 4); - - return arrCrc32 == expectedCrc32; + mHealthService.requestRecordedData(fileId); } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/xiaomi/services/XiaomiHealthService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/xiaomi/services/XiaomiHealthService.java index ebc5b4fef..91cc82bea 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/xiaomi/services/XiaomiHealthService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/xiaomi/services/XiaomiHealthService.java @@ -410,7 +410,7 @@ public class XiaomiHealthService extends AbstractXiaomiService { } public void onFetchRecordedData(final int dataTypes) { - LOG.debug("Fetch recorded data: {}", dataTypes); + LOG.debug("Fetch recorded data: {}", String.format("0x%08X", dataTypes)); fetchRecordedDataToday(); } @@ -439,19 +439,14 @@ public class XiaomiHealthService extends AbstractXiaomiService { ); } - public void requestRecordedData(final List fileIds) { - final ByteBuffer buf = ByteBuffer.allocate(7 * fileIds.size()).order(ByteOrder.LITTLE_ENDIAN); - for (final XiaomiActivityFileId fileId : fileIds) { - buf.put(fileId.toBytes()); - } - + public void requestRecordedData(final XiaomiActivityFileId fileId) { getSupport().sendCommand( "request recorded data", XiaomiProto.Command.newBuilder() .setType(COMMAND_TYPE) .setSubtype(CMD_ACTIVITY_FETCH_REQUEST) .setHealth(XiaomiProto.Health.newBuilder().setActivityRequestFileIds( - ByteString.copyFrom(buf.array()) + ByteString.copyFrom(fileId.toBytes()) )) .build() ); @@ -476,26 +471,19 @@ public class XiaomiHealthService extends AbstractXiaomiService { return; } - LOG.debug("Got {} record IDs", recordIds.length / 7); + LOG.debug("Got {} activity file IDs", recordIds.length / 7); final ByteBuffer buf = ByteBuffer.wrap(recordIds).order(ByteOrder.LITTLE_ENDIAN); - final List fileIds = new ArrayList<>(); - while (buf.position() < buf.limit()) { final XiaomiActivityFileId fileId = XiaomiActivityFileId.from(buf); LOG.debug("Got activity to fetch: {}", fileId); - fileIds.add(fileId); - } - - if (!fileIds.isEmpty()) { - LOG.debug("Fetching {} files", fileIds.size()); - activityFetcher.fetch(fileIds); + activityFetcher.fetch(fileId); } if (subtype == CMD_ACTIVITY_FETCH_TODAY) { LOG.debug("Fetch recorded data from the past"); - // FIXME fix scheduling fetchRecordedDataPast(); + fetchRecordedDataPast(); } }