From 702651c119f2e8b76b422fbc9779ef9c6b7b2d80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Rebelo?= Date: Sun, 23 Jul 2023 19:40:11 +0100 Subject: [PATCH] Sony WH-1000XM3/WF-SP800N: Add volume setting --- CHANGELOG.md | 1 + .../SonyHeadphonesCapabilities.java | 3 +- .../headphones/SonyHeadphonesCoordinator.java | 1 + .../coordinators/SonyWFSP800NCoordinator.java | 3 +- .../SonyWH1000XM3Coordinator.java | 3 +- .../headphones/SonyHeadphonesProtocol.java | 3 + .../headphones/SonyHeadphonesSupport.java | 8 +-- .../impl/AbstractSonyProtocolImpl.java | 4 ++ .../protocol/impl/v1/PayloadTypeV1.java | 5 ++ .../protocol/impl/v1/SonyProtocolImplV1.java | 62 ++++++++++++++++++- .../protocol/impl/v2/SonyProtocolImplV2.java | 12 ++++ .../main/res/xml/devicesettings_volume.xml | 9 +++ 12 files changed, 103 insertions(+), 11 deletions(-) create mode 100644 app/src/main/res/xml/devicesettings_volume.xml diff --git a/CHANGELOG.md b/CHANGELOG.md index 97f1438bb..e5caacc23 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ * Huami: Persist workout raw details even if gpx has no points * Mi Band 5: Fix activity fetch error toast when stress monitoring is enabled * LeFun: Fix heart rate popup when measurement is triggered from phone +* Sony WH-1000XM3/WF-SP800N: Add volume setting * Sony WH-1000XM5: Fix speak-to-chat enable/disable * Zepp OS: Add loyalty cards integration with Catima * Zepp OS: Fix reminder creation 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 a44e4dfc7..621a5f347 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 @@ -39,5 +39,6 @@ public enum SonyHeadphonesCapabilities { SoundPosition, SurroundMode, QuickAccess, - PauseWhenTakenOff + PauseWhenTakenOff, + Volume, } 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 9ba73492f..e1c24ce85 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 @@ -196,6 +196,7 @@ public abstract class SonyHeadphonesCoordinator extends AbstractBLClassicDeviceC put(SonyHeadphonesCapabilities.SoundPosition, R.xml.devicesettings_sony_headphones_sound_position); put(SonyHeadphonesCapabilities.SurroundMode, R.xml.devicesettings_sony_headphones_surround_mode); put(SonyHeadphonesCapabilities.AudioUpsampling, R.xml.devicesettings_sony_headphones_audio_upsampling); + put(SonyHeadphonesCapabilities.Volume, R.xml.devicesettings_volume); }}); addSettingsUnderHeader(settings, R.xml.devicesettings_header_system, new LinkedHashMap() {{ diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/sony/headphones/coordinators/SonyWFSP800NCoordinator.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/sony/headphones/coordinators/SonyWFSP800NCoordinator.java index 55afcfd82..c165fd1ac 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/sony/headphones/coordinators/SonyWFSP800NCoordinator.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/sony/headphones/coordinators/SonyWFSP800NCoordinator.java @@ -64,7 +64,8 @@ public class SonyWFSP800NCoordinator extends SonyHeadphonesCoordinator { SonyHeadphonesCapabilities.ButtonModesLeftRight, SonyHeadphonesCapabilities.PauseWhenTakenOff, SonyHeadphonesCapabilities.AutomaticPowerOffWhenTakenOff, - SonyHeadphonesCapabilities.VoiceNotifications + SonyHeadphonesCapabilities.VoiceNotifications, + SonyHeadphonesCapabilities.Volume ); } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/sony/headphones/coordinators/SonyWH1000XM3Coordinator.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/sony/headphones/coordinators/SonyWH1000XM3Coordinator.java index 479c282b2..4b7252c8b 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/sony/headphones/coordinators/SonyWH1000XM3Coordinator.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/sony/headphones/coordinators/SonyWH1000XM3Coordinator.java @@ -56,7 +56,8 @@ public class SonyWH1000XM3Coordinator extends SonyHeadphonesCoordinator { SonyHeadphonesCapabilities.AudioUpsampling, SonyHeadphonesCapabilities.TouchSensorSingle, SonyHeadphonesCapabilities.AutomaticPowerOffByTime, - SonyHeadphonesCapabilities.VoiceNotifications + SonyHeadphonesCapabilities.VoiceNotifications, + SonyHeadphonesCapabilities.Volume ); } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sony/headphones/SonyHeadphonesProtocol.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sony/headphones/SonyHeadphonesProtocol.java index 88d6eff2a..ae99063e2 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sony/headphones/SonyHeadphonesProtocol.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sony/headphones/SonyHeadphonesProtocol.java @@ -201,6 +201,9 @@ public class SonyHeadphonesProtocol extends GBDeviceProtocol { case DeviceSettingsPreferenceConst.PREF_SONY_AUDIO_UPSAMPLING: configRequest = protocolImpl.setAudioUpsampling(AudioUpsampling.fromPreferences(prefs)); break; + case DeviceSettingsPreferenceConst.PREF_VOLUME: + configRequest = protocolImpl.setVolume(prefs.getInt(config, 15)); + break; case DeviceSettingsPreferenceConst.PREF_SONY_TOUCH_SENSOR: configRequest = protocolImpl.setTouchSensor(TouchSensor.fromPreferences(prefs)); break; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sony/headphones/SonyHeadphonesSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sony/headphones/SonyHeadphonesSupport.java index dd8a883db..be7dd37ba 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sony/headphones/SonyHeadphonesSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sony/headphones/SonyHeadphonesSupport.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 José Rebelo +/* Copyright (C) 2023 José Rebelo This file is part of Gadgetbridge. @@ -16,16 +16,10 @@ along with this program. If not, see . */ package nodomain.freeyourgadget.gadgetbridge.service.devices.sony.headphones; -import android.net.Uri; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.ArrayList; -import java.util.UUID; - import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent; -import nodomain.freeyourgadget.gadgetbridge.model.Alarm; import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.headphones.deviceevents.SonyHeadphonesEnqueueRequestEvent; import nodomain.freeyourgadget.gadgetbridge.service.serial.AbstractSerialDeviceSupport; import nodomain.freeyourgadget.gadgetbridge.service.serial.GBDeviceIoThread; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sony/headphones/protocol/impl/AbstractSonyProtocolImpl.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sony/headphones/protocol/impl/AbstractSonyProtocolImpl.java index 7d67819a6..d2caa5212 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sony/headphones/protocol/impl/AbstractSonyProtocolImpl.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sony/headphones/protocol/impl/AbstractSonyProtocolImpl.java @@ -126,5 +126,9 @@ public abstract class AbstractSonyProtocolImpl { public abstract Request powerOff(); + public abstract Request getVolume(); + + public abstract Request setVolume(final int volume); + public abstract List handlePayload(final MessageType messageType, final byte[] payload); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sony/headphones/protocol/impl/v1/PayloadTypeV1.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sony/headphones/protocol/impl/v1/PayloadTypeV1.java index 11c5f92f4..571717762 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sony/headphones/protocol/impl/v1/PayloadTypeV1.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sony/headphones/protocol/impl/v1/PayloadTypeV1.java @@ -53,6 +53,11 @@ public enum PayloadTypeV1 { AMBIENT_SOUND_CONTROL_SET(MessageType.COMMAND_1, 0x68), AMBIENT_SOUND_CONTROL_NOTIFY(MessageType.COMMAND_1, 0x69), + VOLUME_GET(MessageType.COMMAND_1, 0xa6), + VOLUME_RET(MessageType.COMMAND_1, 0xa7), + VOLUME_SET(MessageType.COMMAND_1, 0xa8), + VOLUME_NOTIFY(MessageType.COMMAND_1, 0xa9), + NOISE_CANCELLING_OPTIMIZER_START(MessageType.COMMAND_1, 0x84), NOISE_CANCELLING_OPTIMIZER_STATUS(MessageType.COMMAND_1, 0x85), 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 81483177e..4139af7f3 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 @@ -519,6 +519,31 @@ public class SonyProtocolImplV1 extends AbstractSonyProtocolImpl { ); } + @Override + public Request getVolume() { + return new Request( + PayloadTypeV1.VOLUME_GET.getMessageType(), + new byte[]{ + PayloadTypeV1.VOLUME_GET.getCode(), + (byte) 0x01, + (byte) 0x20 + } + ); + } + + @Override + public Request setVolume(final int volume) { + return new Request( + PayloadTypeV1.VOLUME_SET.getMessageType(), + new byte[]{ + PayloadTypeV1.VOLUME_SET.getCode(), + (byte) 0x01, + (byte) 0x20, + (byte) volume + } + ); + } + @Override public List handlePayload(final MessageType messageType, final byte[] payload) { final PayloadTypeV1 payloadType = PayloadTypeV1.fromCode(messageType, payload[0]); @@ -543,6 +568,9 @@ public class SonyProtocolImplV1 extends AbstractSonyProtocolImpl { case AMBIENT_SOUND_CONTROL_RET: case AMBIENT_SOUND_CONTROL_NOTIFY: return handleAmbientSoundControl(payload); + case VOLUME_RET: + case VOLUME_NOTIFY: + return handleVolume(payload); case NOISE_CANCELLING_OPTIMIZER_STATUS: return handleNoiseCancellingOptimizerStatus(payload); case NOISE_CANCELLING_OPTIMIZER_STATE_RET: @@ -602,6 +630,7 @@ public class SonyProtocolImplV1 extends AbstractSonyProtocolImpl { put(SonyHeadphonesCapabilities.PauseWhenTakenOff, getPauseWhenTakenOff()); put(SonyHeadphonesCapabilities.AmbientSoundControlButtonMode, getAmbientSoundControlButtonMode()); put(SonyHeadphonesCapabilities.QuickAccess, getQuickAccess()); + put(SonyHeadphonesCapabilities.Volume, getVolume()); }}; for (Map.Entry capabilityEntry : capabilityRequestMap.entrySet()) { @@ -667,7 +696,7 @@ public class SonyProtocolImplV1 extends AbstractSonyProtocolImpl { final AmbientSoundControl ambientSoundControl = new AmbientSoundControl(mode, focusOnVoice, ambientSound); - LOG.warn("Ambient sound control: {}", ambientSoundControl); + LOG.debug("Ambient sound control: {}", ambientSoundControl); final GBDeviceEventUpdatePreferences eventUpdatePreferences = new GBDeviceEventUpdatePreferences() .withPreferences(ambientSoundControl.toPreferences()); @@ -675,6 +704,37 @@ public class SonyProtocolImplV1 extends AbstractSonyProtocolImpl { return Collections.singletonList(eventUpdatePreferences); } + public List handleVolume(final byte[] payload) { + if (payload.length != 4) { + LOG.warn("Unexpected payload length {}", payload.length); + return Collections.emptyList(); + } + + AmbientSoundControl.Mode mode = null; + + if (payload[1] != (byte) 0x01) { + LOG.warn("Unexpected byte at position 1 for volume: {}", payload[1]); + return Collections.emptyList(); + } + if (payload[2] != (byte) 0x20) { + LOG.warn("Unexpected byte at position 2 for volume: {}", payload[1]); + return Collections.emptyList(); + } + + final int volume = payload[3]; + if (volume < 0 || volume > 30) { + LOG.warn("Volume {} is out of range", String.format("%02x", payload[3])); + return Collections.emptyList(); + } + + LOG.debug("Volume: {}", volume); + + final GBDeviceEventUpdatePreferences eventUpdatePreferences = new GBDeviceEventUpdatePreferences() + .withPreference(DeviceSettingsPreferenceConst.PREF_VOLUME, volume); + + return Collections.singletonList(eventUpdatePreferences); + } + public List handleNoiseCancellingOptimizerStatus(final byte[] payload) { if (payload.length != 4) { LOG.warn("Unexpected payload length {}", payload.length); 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 53bdc24ec..1ab83ba75 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 @@ -375,6 +375,18 @@ public class SonyProtocolImplV2 extends SonyProtocolImplV1 { ); } + @Override + public Request getVolume() { + LOG.warn("Volume not implemented for V2"); + return null; + } + + @Override + public Request setVolume(final int volume) { + LOG.warn("Volume not implemented for V2"); + return null; + } + @Override public List handlePayload(final MessageType messageType, final byte[] payload) { final PayloadTypeV2 payloadType = PayloadTypeV2.fromCode(messageType, payload[0]); diff --git a/app/src/main/res/xml/devicesettings_volume.xml b/app/src/main/res/xml/devicesettings_volume.xml new file mode 100644 index 000000000..47b4a0cd3 --- /dev/null +++ b/app/src/main/res/xml/devicesettings_volume.xml @@ -0,0 +1,9 @@ + + + +