From 57c8c773054434c9571a5574b73bedf72434b0eb Mon Sep 17 00:00:00 2001 From: Zahnstocher Date: Tue, 17 Sep 2024 11:37:39 +0200 Subject: [PATCH] Add support for Sony WF-C500 --- .../SonyHeadphonesCapabilities.java | 1 + .../headphones/SonyHeadphonesCoordinator.java | 6 +- .../coordinators/SonyWFC500Coordinator.java | 68 +++++++++++++++++++ .../gadgetbridge/model/DeviceType.java | 2 + .../protocol/impl/v1/SonyProtocolImplV1.java | 24 +++++++ .../protocol/impl/v1/params/BatteryType.java | 1 + .../protocol/impl/v2/SonyProtocolImplV2.java | 4 ++ app/src/main/res/values/strings.xml | 1 + .../impl/v2/SonyProtocolImplV2Test.java | 1 + 9 files changed, 105 insertions(+), 3 deletions(-) create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/sony/headphones/coordinators/SonyWFC500Coordinator.java diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/sony/headphones/SonyHeadphonesCapabilities.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/sony/headphones/SonyHeadphonesCapabilities.java index 0c48a33c7..6735be53d 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/sony/headphones/SonyHeadphonesCapabilities.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/sony/headphones/SonyHeadphonesCapabilities.java @@ -19,6 +19,7 @@ package nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones; public enum SonyHeadphonesCapabilities { BatterySingle, BatteryDual, + BatteryDual_2, BatteryCase, PowerOffFromPhone, AmbientSoundControl, diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/sony/headphones/SonyHeadphonesCoordinator.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/sony/headphones/SonyHeadphonesCoordinator.java index 0333ba0b3..b4a6dec31 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/sony/headphones/SonyHeadphonesCoordinator.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/sony/headphones/SonyHeadphonesCoordinator.java @@ -70,7 +70,7 @@ public abstract class SonyHeadphonesCoordinator extends AbstractBLClassicDeviceC @Override public int getBatteryCount() { if (supports(SonyHeadphonesCapabilities.BatterySingle)) { - if (supports(SonyHeadphonesCapabilities.BatteryDual)) { + if (supports(SonyHeadphonesCapabilities.BatteryDual) || supports(SonyHeadphonesCapabilities.BatteryDual_2)) { throw new IllegalStateException("A device can't have both single and dual battery"); } else if (supports(SonyHeadphonesCapabilities.BatteryCase)) { throw new IllegalStateException("Devices with single battery + case are not supported by the protocol"); @@ -87,7 +87,7 @@ public abstract class SonyHeadphonesCoordinator extends AbstractBLClassicDeviceC batteryCount += 1; } - if (supports(SonyHeadphonesCapabilities.BatteryDual)) { + if (supports(SonyHeadphonesCapabilities.BatteryDual) || supports(SonyHeadphonesCapabilities.BatteryDual_2)) { batteryCount += 2; } @@ -106,7 +106,7 @@ public abstract class SonyHeadphonesCoordinator extends AbstractBLClassicDeviceC batteries.add(new BatteryConfig(batteries.size(), R.drawable.ic_tws_case, R.string.battery_case)); } - if (supports(SonyHeadphonesCapabilities.BatteryDual)) { + if (supports(SonyHeadphonesCapabilities.BatteryDual) || supports(SonyHeadphonesCapabilities.BatteryDual_2)) { batteries.add(new BatteryConfig(batteries.size(), R.drawable.ic_galaxy_buds_l, R.string.left_earbud)); batteries.add(new BatteryConfig(batteries.size(), R.drawable.ic_galaxy_buds_r, R.string.right_earbud)); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/sony/headphones/coordinators/SonyWFC500Coordinator.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/sony/headphones/coordinators/SonyWFC500Coordinator.java new file mode 100644 index 000000000..6467b1f04 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/sony/headphones/coordinators/SonyWFC500Coordinator.java @@ -0,0 +1,68 @@ +/* Copyright (C) 2024 Zahnstocher + + This file is part of Gadgetbridge. + + Gadgetbridge is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Gadgetbridge is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . */ +package nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.coordinators; + +import java.util.Arrays; +import java.util.List; +import java.util.regex.Pattern; + +import nodomain.freeyourgadget.gadgetbridge.R; +import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.SonyHeadphonesCapabilities; +import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.SonyHeadphonesCoordinator; +import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; +import nodomain.freeyourgadget.gadgetbridge.model.BatteryConfig; + +public class SonyWFC500Coordinator extends SonyHeadphonesCoordinator { + @Override + protected Pattern getSupportedDeviceName() { + return Pattern.compile(".*WF-C500.*"); + } + + @Override + public BatteryConfig[] getBatteryConfig(final GBDevice device) { + final BatteryConfig battery1 = new BatteryConfig(0, R.drawable.ic_galaxy_buds_l, R.string.left_earbud); + final BatteryConfig battery2 = new BatteryConfig(1, R.drawable.ic_galaxy_buds_r, R.string.right_earbud); + + return new BatteryConfig[]{battery1, battery2}; + } + + @Override + public List getCapabilities() { + return Arrays.asList( + SonyHeadphonesCapabilities.BatteryDual_2, + SonyHeadphonesCapabilities.EqualizerSimple, + SonyHeadphonesCapabilities.EqualizerWithCustomBands, + SonyHeadphonesCapabilities.AudioUpsampling, + SonyHeadphonesCapabilities.PowerOffFromPhone + ); + } + + @Override + public int getDeviceNameResource() { + return R.string.devicetype_sony_wf_c500; + } + + @Override + public int getDefaultIconResource() { + return R.drawable.ic_device_galaxy_buds; + } + + @Override + public int getDisabledIconResource() { + return R.drawable.ic_device_galaxy_buds_disabled; + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/DeviceType.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/DeviceType.java index 667ed17b2..c85c80595 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/DeviceType.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/DeviceType.java @@ -221,6 +221,7 @@ import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.coordinators import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.coordinators.SonyWF1000XM3Coordinator; import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.coordinators.SonyWF1000XM4Coordinator; import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.coordinators.SonyWF1000XM5Coordinator; +import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.coordinators.SonyWFC500Coordinator; import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.coordinators.SonyWFSP800NCoordinator; import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.coordinators.SonyWH1000XM2Coordinator; import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.coordinators.SonyWH1000XM3Coordinator; @@ -459,6 +460,7 @@ public enum DeviceType { SONY_LINKBUDS_S(SonyLinkBudsSCoordinator.class), SONY_WH_1000XM5(SonyWH1000XM5Coordinator.class), SONY_WF_1000XM5(SonyWF1000XM5Coordinator.class), + SONY_WF_C500(SonyWFC500Coordinator.class), SOUNDCORE_LIBERTY3_PRO(SoundcoreLiberty3ProCoordinator.class), SOUNDCORE_LIBERTY4_NC(SoundcoreLiberty4NCCoordinator.class), SOUNDCORE_MOTION300(SoundcoreMotion300Coordinator.class), diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sony/headphones/protocol/impl/v1/SonyProtocolImplV1.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sony/headphones/protocol/impl/v1/SonyProtocolImplV1.java index b37b0dbc5..9c7f5f061 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sony/headphones/protocol/impl/v1/SonyProtocolImplV1.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sony/headphones/protocol/impl/v1/SonyProtocolImplV1.java @@ -638,6 +638,7 @@ public class SonyProtocolImplV1 extends AbstractSonyProtocolImpl { final Map capabilityRequestMap = new LinkedHashMap() {{ put(SonyHeadphonesCapabilities.BatterySingle, getBattery(BatteryType.SINGLE)); put(SonyHeadphonesCapabilities.BatteryDual, getBattery(BatteryType.DUAL)); + put(SonyHeadphonesCapabilities.BatteryDual_2, getBattery(BatteryType.DUAL_2)); put(SonyHeadphonesCapabilities.BatteryCase, getBattery(BatteryType.CASE)); put(SonyHeadphonesCapabilities.AmbientSoundControl, getAmbientSoundControl()); put(SonyHeadphonesCapabilities.AncOptimizer, getNoiseCancellingOptimizerState()); @@ -960,6 +961,29 @@ public class SonyProtocolImplV1 extends AbstractSonyProtocolImpl { gbDeviceEventBatteryInfoRight.level = payload[4]; gbDeviceEventBatteryInfoRight.state = payload[5] == 1 ? BatteryState.BATTERY_CHARGING : BatteryState.BATTERY_NORMAL; + batteryEvents.add(gbDeviceEventBatteryInfoRight); + } + } else if (BatteryType.DUAL_2.equals(batteryType)) { + // Dual Battery (L / R) + LOG.debug("Battery Level: L: {}, R: {}", payload[2], payload[4]); + + if (payload[2] != 0) { + final GBDeviceEventBatteryInfo gbDeviceEventBatteryInfoLeft = new GBDeviceEventBatteryInfo(); + + gbDeviceEventBatteryInfoLeft.batteryIndex = 0; + gbDeviceEventBatteryInfoLeft.level = payload[2]; + gbDeviceEventBatteryInfoLeft.state = payload[3] == 1 ? BatteryState.BATTERY_CHARGING : BatteryState.BATTERY_NORMAL; + + batteryEvents.add(gbDeviceEventBatteryInfoLeft); + } + + if (payload[4] != 0) { + final GBDeviceEventBatteryInfo gbDeviceEventBatteryInfoRight = new GBDeviceEventBatteryInfo(); + + gbDeviceEventBatteryInfoRight.batteryIndex = 1; + gbDeviceEventBatteryInfoRight.level = payload[4]; + gbDeviceEventBatteryInfoRight.state = payload[5] == 1 ? BatteryState.BATTERY_CHARGING : BatteryState.BATTERY_NORMAL; + batteryEvents.add(gbDeviceEventBatteryInfoRight); } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sony/headphones/protocol/impl/v1/params/BatteryType.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sony/headphones/protocol/impl/v1/params/BatteryType.java index b79facde2..73737f793 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sony/headphones/protocol/impl/v1/params/BatteryType.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sony/headphones/protocol/impl/v1/params/BatteryType.java @@ -19,5 +19,6 @@ package nodomain.freeyourgadget.gadgetbridge.service.devices.sony.headphones.pro public enum BatteryType { SINGLE, DUAL, + DUAL_2, CASE, } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sony/headphones/protocol/impl/v2/SonyProtocolImplV2.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sony/headphones/protocol/impl/v2/SonyProtocolImplV2.java index d452bb582..dd5107268 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sony/headphones/protocol/impl/v2/SonyProtocolImplV2.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sony/headphones/protocol/impl/v2/SonyProtocolImplV2.java @@ -1027,6 +1027,8 @@ public class SonyProtocolImplV2 extends SonyProtocolImplV1 { switch (b) { case 0x00: return BatteryType.SINGLE; + case 0x01: + return BatteryType.DUAL_2; case 0x09: return BatteryType.DUAL; case 0x0a: @@ -1041,6 +1043,8 @@ public class SonyProtocolImplV2 extends SonyProtocolImplV1 { switch (batteryType) { case SINGLE: return 0x00; + case DUAL_2: + return 0x01; case DUAL: return 0x09; case CASE: diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index c3f6b564a..ba14ed254 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1795,6 +1795,7 @@ Sony WF-1000XM3 Sony WF-1000XM4 Sony WF-1000XM5 + Sony WF-C500 Sony WI-SP600N Sony LinkBuds Sony LinkBuds S diff --git a/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sony/headphones/protocol/impl/v2/SonyProtocolImplV2Test.java b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sony/headphones/protocol/impl/v2/SonyProtocolImplV2Test.java index aa1c61840..59f52be27 100644 --- a/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sony/headphones/protocol/impl/v2/SonyProtocolImplV2Test.java +++ b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sony/headphones/protocol/impl/v2/SonyProtocolImplV2Test.java @@ -104,6 +104,7 @@ public class SonyProtocolImplV2Test { final Map commands = new LinkedHashMap() {{ put(BatteryType.SINGLE, "22:00"); put(BatteryType.DUAL, "22:09"); + put(BatteryType.DUAL_2, "22:01"); put(BatteryType.CASE, "22:0a"); }};