Loyalty Cards: Move unsupported barcodes to coordinator

This commit is contained in:
José Rebelo
2026-01-03 14:07:46 +00:00
parent 22c541d8f2
commit dabc3ae4c9
7 changed files with 59 additions and 12 deletions
@@ -86,8 +86,14 @@ public class CatimaManager {
}
}
final Set<BarcodeFormat> supportedBarcodeFormats = gbDevice.getDeviceCoordinator().getSupportedBarcodeFormats(gbDevice);
final ArrayList<LoyaltyCard> cardsToSync = new ArrayList<>();
for (final LoyaltyCard card : cards) {
if (!supportedBarcodeFormats.contains(card.getBarcodeFormat())) {
LOG.debug("Ignoring card {} - unsupported barcode format {}", card.getId(), card.getBarcodeFormat());
continue;
}
if (syncGroupsOnly && !cardsInGroupsToSync.contains(card.getId())) {
continue;
}
@@ -61,6 +61,7 @@ import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSett
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpecificSettings;
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpecificSettingsCustomizer;
import nodomain.freeyourgadget.gadgetbridge.capabilities.HeartRateCapability;
import nodomain.freeyourgadget.gadgetbridge.capabilities.loyaltycards.BarcodeFormat;
import nodomain.freeyourgadget.gadgetbridge.capabilities.password.PasswordCapabilityImpl;
import nodomain.freeyourgadget.gadgetbridge.capabilities.widgets.WidgetManager;
import nodomain.freeyourgadget.gadgetbridge.database.DBHandler;
@@ -1129,4 +1130,9 @@ public abstract class AbstractDeviceCoordinator implements DeviceCoordinator {
public HeartRateZonesSpec getHeartRateZonesSpec(@NonNull GBDevice device) {
return null;
}
@Override
public Set<BarcodeFormat> getSupportedBarcodeFormats(@NonNull final GBDevice device) {
return Collections.emptySet();
}
}
@@ -40,6 +40,7 @@ import nodomain.freeyourgadget.gadgetbridge.GBException;
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpecificSettings;
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpecificSettingsCustomizer;
import nodomain.freeyourgadget.gadgetbridge.capabilities.HeartRateCapability;
import nodomain.freeyourgadget.gadgetbridge.capabilities.loyaltycards.BarcodeFormat;
import nodomain.freeyourgadget.gadgetbridge.capabilities.password.PasswordCapabilityImpl;
import nodomain.freeyourgadget.gadgetbridge.capabilities.widgets.WidgetManager;
import nodomain.freeyourgadget.gadgetbridge.entities.CyclingSample;
@@ -931,4 +932,6 @@ public interface DeviceCoordinator {
DeviceKind getDeviceKind(@NonNull GBDevice device);
HeartRateZonesSpec getHeartRateZonesSpec(@NonNull GBDevice device);
Set<BarcodeFormat> getSupportedBarcodeFormats(@NonNull final GBDevice device);
}
@@ -43,6 +43,7 @@ import de.greenrobot.dao.Property;
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpecificSettingsCustomizer;
import nodomain.freeyourgadget.gadgetbridge.capabilities.loyaltycards.BarcodeFormat;
import nodomain.freeyourgadget.gadgetbridge.devices.AbstractBLEDeviceCoordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider;
import nodomain.freeyourgadget.gadgetbridge.devices.SleepAsAndroidFeature;
@@ -290,4 +291,17 @@ public class BangleJSCoordinator extends AbstractBLEDeviceCoordinator {
public DeviceKind getDeviceKind(@NonNull GBDevice device) {
return DeviceKind.WATCH;
}
@Override
public Set<BarcodeFormat> getSupportedBarcodeFormats(@NonNull final GBDevice device) {
return Set.of(
BarcodeFormat.CODE_39,
BarcodeFormat.CODABAR,
BarcodeFormat.EAN_8,
BarcodeFormat.EAN_13,
BarcodeFormat.UPC_A,
BarcodeFormat.UPC_E,
BarcodeFormat.QR_CODE
);
}
}
@@ -34,6 +34,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import nodomain.freeyourgadget.gadgetbridge.BuildConfig;
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
@@ -44,6 +45,7 @@ import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpec
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpecificSettingsCustomizer;
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpecificSettingsScreen;
import nodomain.freeyourgadget.gadgetbridge.capabilities.HeartRateCapability;
import nodomain.freeyourgadget.gadgetbridge.capabilities.loyaltycards.BarcodeFormat;
import nodomain.freeyourgadget.gadgetbridge.capabilities.password.PasswordCapabilityImpl;
import nodomain.freeyourgadget.gadgetbridge.devices.DeviceCoordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.InstallHandler;
@@ -701,4 +703,13 @@ public abstract class ZeppOsCoordinator extends HuamiCoordinator {
final byte[] authKeyBytes = authKey.trim().getBytes();
return authKeyBytes.length == 32 || (authKey.trim().startsWith("0x") && authKeyBytes.length == 34);
}
@Override
public Set<BarcodeFormat> getSupportedBarcodeFormats(@NonNull final GBDevice device) {
return getPrefs(device)
.getStringSet(ZeppOsLoyaltyCardService.PREF_FORMATS, Collections.emptySet())
.stream()
.map(BarcodeFormat::valueOf)
.collect(Collectors.toSet());
}
}
@@ -86,6 +86,7 @@ import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.SimpleTimeZone;
import de.greenrobot.dao.query.QueryBuilder;
@@ -1770,16 +1771,11 @@ public class BangleJSDeviceSupport extends AbstractBTLESingleDeviceSupport {
}
private List<LoyaltyCard> filterSupportedCards(final List<LoyaltyCard> cards) {
final Set<BarcodeFormat> supportedBarcodeFormats = getDevice().getDeviceCoordinator().getSupportedBarcodeFormats(getDevice());
final List<LoyaltyCard> ret = new ArrayList<>();
for (final LoyaltyCard card : cards) {
// we hardcode here what is supported
if (card.getBarcodeFormat() == BarcodeFormat.CODE_39 ||
card.getBarcodeFormat() == BarcodeFormat.CODABAR ||
card.getBarcodeFormat() == BarcodeFormat.EAN_8 ||
card.getBarcodeFormat() == BarcodeFormat.EAN_13 ||
card.getBarcodeFormat() == BarcodeFormat.UPC_A ||
card.getBarcodeFormat() == BarcodeFormat.UPC_E ||
card.getBarcodeFormat() == BarcodeFormat.QR_CODE) {
if (supportedBarcodeFormats.contains(card.getBarcodeFormat())) {
ret.add(card);
}
}
@@ -24,9 +24,11 @@ import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import nodomain.freeyourgadget.gadgetbridge.capabilities.loyaltycards.BarcodeFormat;
import nodomain.freeyourgadget.gadgetbridge.capabilities.loyaltycards.LoyaltyCard;
@@ -57,6 +59,7 @@ public class ZeppOsLoyaltyCardService extends AbstractZeppOsService {
private final List<Integer> supportedColors = new ArrayList<>();
public static final String PREF_VERSION = "zepp_os_loyalty_cards_version";
public static final String PREF_FORMATS = "zepp_os_loyalty_cards_formats";
public ZeppOsLoyaltyCardService(final ZeppOsSupport support) {
super(support, false);
@@ -71,14 +74,18 @@ public class ZeppOsLoyaltyCardService extends AbstractZeppOsService {
public void handlePayload(final byte[] payload) {
switch (payload[0]) {
case CMD_CAPABILITIES_RESPONSE:
final GBDeviceEventUpdatePreferences updatePreferences = new GBDeviceEventUpdatePreferences();
supportedFormats.clear();
supportedColors.clear();
final int version = payload[1];
getSupport().evaluateGBDeviceEvent(new GBDeviceEventUpdatePreferences(PREF_VERSION, version));
updatePreferences.withPreference(PREF_VERSION, version);
if (version != 1 || payload[2] != 1) {
LOG.warn("Unexpected loyalty cards service version {}, {}", version, payload[2]);
// Persist the preference, so it's marked as not supported
getSupport().evaluateGBDeviceEvent(updatePreferences);
return;
}
@@ -94,6 +101,7 @@ public class ZeppOsLoyaltyCardService extends AbstractZeppOsService {
}
supportedFormats.add(barcodeFormat);
}
updatePreferences.withPreference(PREF_FORMATS, supportedFormats.stream().map(Enum::name).collect(Collectors.toSet()));
final byte numSupportedColors = payload[pos++];
final Map<Byte, Integer> colorCodes = MapUtils.reverse(COLOR_CODES);
@@ -114,6 +122,8 @@ public class ZeppOsLoyaltyCardService extends AbstractZeppOsService {
supportedColors
);
getSupport().evaluateGBDeviceEvent(updatePreferences);
return;
case CMD_SET_ACK:
LOG.info("Loyalty cards set ACK, status = {}", payload[1]);
@@ -243,7 +253,7 @@ public class ZeppOsLoyaltyCardService extends AbstractZeppOsService {
return Objects.requireNonNull(COLOR_CODES.get(nearestColor));
}
private static final Map<BarcodeFormat, Byte> BARCODE_FORMAT_CODES = new HashMap<BarcodeFormat, Byte>() {{
private static final Map<BarcodeFormat, Byte> BARCODE_FORMAT_CODES = new HashMap<>() {{
put(BarcodeFormat.CODE_128, (byte) 0x00);
put(BarcodeFormat.CODE_39, (byte) 0x01);
put(BarcodeFormat.ITF, (byte) 0x02);
@@ -258,7 +268,7 @@ public class ZeppOsLoyaltyCardService extends AbstractZeppOsService {
/**
* Map or RGB color to color byte - the watches only support color presets.
*/
private static final Map<Integer, Byte> COLOR_CODES = new HashMap<Integer, Byte>() {{
private static final Map<Integer, Byte> COLOR_CODES = new HashMap<>() {{
put(0x66c6ea, (byte) 0x00); // Light blue
put(0x008fc5, (byte) 0x01); // Blue
put(0xc19ffd, (byte) 0x02); // Light purple
@@ -274,6 +284,7 @@ public class ZeppOsLoyaltyCardService extends AbstractZeppOsService {
}};
public static boolean isSupported(final Prefs devicePrefs) {
return devicePrefs.getInt(PREF_VERSION, 0) == 1;
return devicePrefs.getInt(PREF_VERSION, 0) == 1 &&
!devicePrefs.getStringSet(PREF_FORMATS, Collections.emptySet()).isEmpty();
}
}