Health Connect: Prevent sync of devices which are not configured

This commit is contained in:
José Rebelo
2026-01-06 00:23:50 +00:00
parent 65dd8731fa
commit b94a0b5b34
2 changed files with 44 additions and 29 deletions
@@ -32,6 +32,10 @@ import androidx.work.WorkManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Collections;
import java.util.Locale;
import java.util.Set;
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.util.GBPrefs;
@@ -73,36 +77,41 @@ public class NewDataReceiver extends BroadcastReceiver {
prefs.getBoolean(GBPrefs.HEALTH_CONNECT_SYNC_ON_EVENT, false)) {
// Extract device from the intent
GBDevice device = intent.getParcelableExtra(GBDevice.EXTRA_DEVICE);
String deviceAddress = device != null ? device.getAddress() : null;
if (deviceAddress != null && !deviceAddress.isEmpty()) {
// For device-specific syncs, use a device-specific work name and APPEND policy
// This ensures each device's HC sync is queued and executed sequentially
String workName = HEALTH_CONNECT_SYNC_WORKER_TAG + "_" + deviceAddress;
OneTimeWorkRequest syncRequest = new OneTimeWorkRequest.Builder(HealthConnectSyncWorker.class)
.addTag(HEALTH_CONNECT_SYNC_WORKER_TAG)
.setInputData(
new Data.Builder()
.putString(HealthConnectSyncWorker.INPUT_DEVICE_ADDRESS, deviceAddress)
.build()
)
.build();
LOG.debug("Scheduling HC sync for device: {} with work name: {}", deviceAddress, workName);
// Use APPEND so multiple syncs for the same device queue up
WorkManager.getInstance(context).enqueueUniqueWork(
workName,
ExistingWorkPolicy.APPEND,
syncRequest
);
} else {
final GBDevice device = intent.getParcelableExtra(GBDevice.EXTRA_DEVICE);
final String deviceAddress = device != null ? device.getAddress() : null;
if (deviceAddress == null || deviceAddress.isBlank()) {
// This shouldn't happen for ACTION_NEW_DATA, but handle gracefully
LOG.warn("ACTION_NEW_DATA received without device information, skipping HC sync");
return;
}
final Set<String> hcDevices = prefs.getStringSet(GBPrefs.HEALTH_CONNECT_DEVICE_SELECTION, Collections.emptySet());
if (!hcDevices.contains(deviceAddress.toUpperCase(Locale.ROOT))) {
LOG.debug("Ignoring new data for {} - not configured for HC sync", deviceAddress);
return;
}
// For device-specific syncs, use a device-specific work name and APPEND policy
// This ensures each device's HC sync is queued and executed sequentially
String workName = HEALTH_CONNECT_SYNC_WORKER_TAG + "_" + deviceAddress;
OneTimeWorkRequest syncRequest = new OneTimeWorkRequest.Builder(HealthConnectSyncWorker.class)
.addTag(HEALTH_CONNECT_SYNC_WORKER_TAG)
.setInputData(
new Data.Builder()
.putString(HealthConnectSyncWorker.INPUT_DEVICE_ADDRESS, deviceAddress)
.build()
)
.build();
LOG.debug("Scheduling HC sync for device: {} with work name: {}", deviceAddress, workName);
// Use APPEND so multiple syncs for the same device queue up
WorkManager.getInstance(context).enqueueUniqueWork(
workName,
ExistingWorkPolicy.APPEND,
syncRequest
);
}
}
}
@@ -141,13 +141,19 @@ class HealthConnectUtils {
try {
val prefs = GBApplication.getPrefs()
val grantedPermissions = prefs.preferences.getStringSet(PREF_KEY_LAST_GRANTED_HC_PERMISSIONS, emptySet()) ?: emptySet()
val hcDevices = prefs.getStringSet(GBPrefs.HEALTH_CONNECT_DEVICE_SELECTION, emptySet())
// If a specific device address is provided, sync only that device
// Otherwise, sync all selected devices from preferences
val selectedDevices = if (deviceAddress != null && deviceAddress.isNotEmpty()) {
setOf(deviceAddress)
if (hcDevices.contains(deviceAddress.uppercase())) {
setOf(deviceAddress)
} else {
LOG.error("Attempting to sync {}, which is not configured for HC - refusing", deviceAddress)
emptySet()
}
} else {
prefs.getStringSet("health_connect_devices_multiselect", HashSet(20))
prefs.getStringSet(GBPrefs.HEALTH_CONNECT_DEVICE_SELECTION, emptySet())
}
if (selectedDevices.isNullOrEmpty()) {