From e4933a0b42abd94b805e3822cef37c813e577b48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Rebelo?= Date: Sat, 6 May 2023 14:41:28 +0100 Subject: [PATCH] Sony Headphones: Improve unit tests --- .../prefs/EqualizerCustomBands.java | 7 +- .../protocol/impl/v1/SonyProtocolImplV1.java | 2 +- .../protocol/impl/MockSonyCoordinator.java | 52 +++ .../protocol/impl/SonyTestUtils.java | 71 +++- .../impl/v1/SonyProtocolImplV1Test.java | 336 +++++++++++++++--- .../impl/v3/SonyProtocolImplV3Test.java | 29 +- 6 files changed, 426 insertions(+), 71 deletions(-) create mode 100644 app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sony/headphones/protocol/impl/MockSonyCoordinator.java diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/sony/headphones/prefs/EqualizerCustomBands.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/sony/headphones/prefs/EqualizerCustomBands.java index ee61e1464..443969ec8 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/sony/headphones/prefs/EqualizerCustomBands.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/sony/headphones/prefs/EqualizerCustomBands.java @@ -21,13 +21,14 @@ import android.content.SharedPreferences; import java.util.Arrays; import java.util.HashMap; import java.util.List; +import java.util.Locale; import java.util.Map; import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst; public class EqualizerCustomBands { - private List bands; - private int bass; + private final List bands; + private final int bass; public EqualizerCustomBands(final List bands, final int bass) { if (bands.size() != 5) { @@ -57,7 +58,7 @@ public class EqualizerCustomBands { } public String toString() { - return String.format("EqualizerCustomBands{clearBass=%d, bands=%s}", bass, bands); + return String.format(Locale.ROOT, "EqualizerCustomBands{clearBass=%d, bands=%s}", bass, bands); } public Map toPreferences() { 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 bfe9a3bb0..81483177e 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 @@ -1172,7 +1172,7 @@ public class SonyProtocolImplV1 extends AbstractSonyProtocolImpl { return Collections.singletonList(event); } - protected Boolean booleanFromByte(final byte b) { + protected static Boolean booleanFromByte(final byte b) { switch (b) { case 0x00: return false; diff --git a/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sony/headphones/protocol/impl/MockSonyCoordinator.java b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sony/headphones/protocol/impl/MockSonyCoordinator.java new file mode 100644 index 000000000..c535d1be4 --- /dev/null +++ b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sony/headphones/protocol/impl/MockSonyCoordinator.java @@ -0,0 +1,52 @@ +/* Copyright (C) 2023 José Rebelo + + 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.service.devices.sony.headphones.protocol.impl; + +import androidx.annotation.NonNull; + +import java.util.ArrayList; +import java.util.List; + +import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.SonyHeadphonesCapabilities; +import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.SonyHeadphonesCoordinator; +import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceCandidate; +import nodomain.freeyourgadget.gadgetbridge.model.DeviceType; + +public class MockSonyCoordinator extends SonyHeadphonesCoordinator { + private final DeviceType deviceType = DeviceType.SONY_WH_1000XM3; + + private final List capabilities = new ArrayList<>(); + + @NonNull + @Override + public DeviceType getSupportedType(final GBDeviceCandidate candidate) { + return deviceType; + } + + @Override + public DeviceType getDeviceType() { + return deviceType; + } + + public void addCapability(final SonyHeadphonesCapabilities capability) { + capabilities.add(capability); + } + + public List getCapabilities() { + return capabilities; + } +} diff --git a/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sony/headphones/protocol/impl/SonyTestUtils.java b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sony/headphones/protocol/impl/SonyTestUtils.java index 30c82f615..b274aa1f6 100644 --- a/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sony/headphones/protocol/impl/SonyTestUtils.java +++ b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sony/headphones/protocol/impl/SonyTestUtils.java @@ -18,10 +18,18 @@ package nodomain.freeyourgadget.gadgetbridge.service.devices.sony.headphones.pro import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.function.Function; +import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent; +import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventUpdatePreferences; +import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.prefs.QuickAccess; import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.headphones.protocol.Message; import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.headphones.protocol.MessageType; import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.headphones.protocol.Request; @@ -30,10 +38,16 @@ import nodomain.freeyourgadget.gadgetbridge.util.GB; public class SonyTestUtils { public static void assertRequest(final Request request, final String messageHex) { final Message message = Message.fromBytes(GB.hexStringToByteArray(messageHex.replace(":", ""))); + assertNotNull(message); assertRequest(request, message.getType(), message.getPayload()); } public static void assertRequest(final Request request, final int messageType, final String payloadHex) { + if (payloadHex == null) { + assertNull(request); + return; + } + assertRequest( request, MessageType.fromCode((byte) messageType), @@ -43,12 +57,65 @@ public class SonyTestUtils { public static void assertRequest(final Request request, final MessageType messageType, final byte[] payload) { assertEquals("Message types should be the same", messageType, request.messageType()); - assertArrayEquals("Payloads should be the same", payload, request.payload()); + assertEquals("Payloads should be the same", hexdump(payload), hexdump(request.payload())); + } + + public static void assertRequests(Function requestFunction, final int messageType, final Map expectedRequests) { + for (Map.Entry entry : expectedRequests.entrySet()) { + final Request request = requestFunction.apply(entry.getKey()); + assertRequest(request, messageType, entry.getValue()); + } + } + + public static void assertRequests(Function requestFunction, final Map expectedRequests) { + assertRequests(requestFunction, 0x0c, expectedRequests); + } + + public static void assertPrefs(final List events, final Map expectedPrefs) { + assertEquals("Expect 1 events", 1, events.size()); + final GBDeviceEventUpdatePreferences event = (GBDeviceEventUpdatePreferences) events.get(0); + assertEquals("Expect number of prefs", expectedPrefs.size(), event.preferences.size()); + + for (Map.Entry pref : expectedPrefs.entrySet()) { + assertEquals("Expect " + pref.getKey() + " value", pref.getValue(), event.preferences.get(pref.getKey())); + } + } + + public static void printRequests(Function requestFunction, final Map expectedRequests) { + for (Map.Entry entry : expectedRequests.entrySet()) { + final Request request = requestFunction.apply(entry.getKey()); + printRequest(request); + } } public static List handleMessage(final AbstractSonyProtocolImpl protocol, final String messageHex) { final Message message = Message.fromBytes(GB.hexStringToByteArray(messageHex.replace(":", ""))); - + assertNotNull("Failed to deserialize message from bytes", message); return protocol.handlePayload(message.getType(), message.getPayload()); } + + public static void printRequest(final Request request) { + System.out.printf(Locale.ROOT, "0x%02x - %s%n", request.messageType().getCode(), hexdump(request.payload())); + } + + public static String hexdump(byte[] buffer, int offset, int length) { + if (length == -1) { + length = buffer.length - offset; + } + + char[] hexChars = new char[length * 2 + length - 1]; + for (int i = 0; i < length; i++) { + int v = buffer[i + offset] & 0xFF; + hexChars[i * 3] = GB.HEX_CHARS[v >>> 4]; + hexChars[i * 3 + 1] = GB.HEX_CHARS[v & 0x0F]; + if (i + 1 < length) { + hexChars[i * 3 + 2] = ':'; + } + } + return new String(hexChars).toLowerCase(Locale.ROOT); + } + + public static String hexdump(byte[] buffer) { + return hexdump(buffer, 0, buffer.length); + } } diff --git a/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sony/headphones/protocol/impl/v1/SonyProtocolImplV1Test.java b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sony/headphones/protocol/impl/v1/SonyProtocolImplV1Test.java index 481877a4a..5c3ce9a53 100644 --- a/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sony/headphones/protocol/impl/v1/SonyProtocolImplV1Test.java +++ b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sony/headphones/protocol/impl/v1/SonyProtocolImplV1Test.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 José Rebelo +/* Copyright (C) 2023 José Rebelo This file is part of Gadgetbridge. @@ -16,163 +16,404 @@ along with this program. If not, see . */ package nodomain.freeyourgadget.gadgetbridge.service.devices.sony.headphones.protocol.impl.v1; -import static org.junit.Assert.*; - +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; import static nodomain.freeyourgadget.gadgetbridge.service.devices.sony.headphones.protocol.impl.SonyTestUtils.assertRequest; +import static nodomain.freeyourgadget.gadgetbridge.service.devices.sony.headphones.protocol.impl.SonyTestUtils.assertRequests; +import org.junit.Before; import org.junit.Test; +import java.util.Arrays; +import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent; +import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.SonyHeadphonesCapabilities; +import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.SonyHeadphonesCoordinator; +import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.prefs.AmbientSoundControl; +import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.prefs.AmbientSoundControlButtonMode; +import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.prefs.AudioUpsampling; +import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.prefs.AutomaticPowerOff; import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.prefs.ButtonModes; +import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.prefs.EqualizerCustomBands; +import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.prefs.EqualizerPreset; +import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.prefs.PauseWhenTakenOff; +import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.prefs.QuickAccess; +import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.prefs.SoundPosition; +import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.prefs.SpeakToChatConfig; +import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.prefs.SpeakToChatEnabled; +import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.prefs.SurroundMode; +import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.prefs.TouchSensor; +import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.prefs.VoiceNotifications; import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.headphones.protocol.MessageType; import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.headphones.protocol.Request; +import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.headphones.protocol.impl.MockSonyCoordinator; +import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.headphones.protocol.impl.v1.params.BatteryType; import nodomain.freeyourgadget.gadgetbridge.util.GB; public class SonyProtocolImplV1Test { - private final SonyProtocolImplV1 protocol = new SonyProtocolImplV1(null); + private final MockSonyCoordinator coordinator = new MockSonyCoordinator(); + private final SonyProtocolImplV1 protocol = new SonyProtocolImplV1(null) { + @Override + protected SonyHeadphonesCoordinator getCoordinator() { + return coordinator; + } + }; + + @Before + public void before() { + coordinator.getCapabilities().clear(); + } @Test public void getAmbientSoundControl() { - // TODO final Request request = protocol.getAmbientSoundControl(); assertRequest(request, 0x0c, "66:02"); } @Test public void setAmbientSoundControl() { - // TODO + final Map commands = new LinkedHashMap() {{ + put(new AmbientSoundControl(AmbientSoundControl.Mode.OFF, false, 0), "68:02:00:00:00:01:00:00"); + put(new AmbientSoundControl(AmbientSoundControl.Mode.OFF, false, 5), "68:02:00:00:00:01:00:05"); + put(new AmbientSoundControl(AmbientSoundControl.Mode.OFF, true, 5), "68:02:00:00:00:01:01:05"); + put(new AmbientSoundControl(AmbientSoundControl.Mode.OFF, true, 10), "68:02:00:00:00:01:01:0A"); + put(new AmbientSoundControl(AmbientSoundControl.Mode.AMBIENT_SOUND, false, 0), "68:02:11:00:00:01:00:00"); + put(new AmbientSoundControl(AmbientSoundControl.Mode.AMBIENT_SOUND, false, 10), "68:02:11:00:00:01:00:0A"); + put(new AmbientSoundControl(AmbientSoundControl.Mode.AMBIENT_SOUND, true, 10), "68:02:11:00:00:01:01:0A"); + put(new AmbientSoundControl(AmbientSoundControl.Mode.AMBIENT_SOUND, false, 15), "68:02:11:00:00:01:00:0F"); + put(new AmbientSoundControl(AmbientSoundControl.Mode.AMBIENT_SOUND, true, 15), "68:02:11:00:00:01:01:0F"); + put(new AmbientSoundControl(AmbientSoundControl.Mode.NOISE_CANCELLING, false, 0), "68:02:11:00:01:01:00:00"); + put(new AmbientSoundControl(AmbientSoundControl.Mode.NOISE_CANCELLING, true, 15), "68:02:11:00:01:01:01:00"); + put(new AmbientSoundControl(AmbientSoundControl.Mode.NOISE_CANCELLING, false, 15), "68:02:11:00:01:01:00:00"); + }}; + + for (Map.Entry entry : commands.entrySet()) { + final Request request = protocol.setAmbientSoundControl(entry.getKey()); + assertRequest(request, 0x0c, entry.getValue()); + } + + coordinator.addCapability(SonyHeadphonesCapabilities.WindNoiseReduction); + final Map commandsWindNoiseReduction = new LinkedHashMap() {{ + put(new AmbientSoundControl(AmbientSoundControl.Mode.OFF, false, 0), "68:02:00:02:00:01:00:00"); + put(new AmbientSoundControl(AmbientSoundControl.Mode.OFF, false, 5), "68:02:00:02:00:01:00:05"); + put(new AmbientSoundControl(AmbientSoundControl.Mode.OFF, true, 5), "68:02:00:02:00:01:01:05"); + put(new AmbientSoundControl(AmbientSoundControl.Mode.OFF, true, 10), "68:02:00:02:00:01:01:0A"); + put(new AmbientSoundControl(AmbientSoundControl.Mode.AMBIENT_SOUND, false, 0), "68:02:11:02:00:01:00:00"); + put(new AmbientSoundControl(AmbientSoundControl.Mode.AMBIENT_SOUND, false, 10), "68:02:11:02:00:01:00:0A"); + put(new AmbientSoundControl(AmbientSoundControl.Mode.AMBIENT_SOUND, true, 10), "68:02:11:02:00:01:01:0A"); + put(new AmbientSoundControl(AmbientSoundControl.Mode.AMBIENT_SOUND, false, 15), "68:02:11:02:00:01:00:0F"); + put(new AmbientSoundControl(AmbientSoundControl.Mode.AMBIENT_SOUND, true, 15), "68:02:11:02:00:01:01:0F"); + put(new AmbientSoundControl(AmbientSoundControl.Mode.NOISE_CANCELLING, false, 0), "68:02:11:02:02:01:00:00"); + put(new AmbientSoundControl(AmbientSoundControl.Mode.NOISE_CANCELLING, true, 15), "68:02:11:02:02:01:01:00"); + put(new AmbientSoundControl(AmbientSoundControl.Mode.NOISE_CANCELLING, false, 15), "68:02:11:02:02:01:00:00"); + put(new AmbientSoundControl(AmbientSoundControl.Mode.WIND_NOISE_REDUCTION, false, 5), "68:02:11:02:01:01:00:00"); + put(new AmbientSoundControl(AmbientSoundControl.Mode.WIND_NOISE_REDUCTION, false, 15), "68:02:11:02:01:01:00:00"); + put(new AmbientSoundControl(AmbientSoundControl.Mode.WIND_NOISE_REDUCTION, true, 15), "68:02:11:02:01:01:01:00"); + }}; + + for (Map.Entry entry : commandsWindNoiseReduction.entrySet()) { + final Request request = protocol.setAmbientSoundControl(entry.getKey()); + assertRequest(request, 0x0c, entry.getValue()); + } + } + + @Test + public void setSpeakToChatEnabled() { + assertRequests(protocol::setSpeakToChatEnabled, new LinkedHashMap() {{ + put(new SpeakToChatEnabled(false), "f8:05:01:00"); + put(new SpeakToChatEnabled(true), "f8:05:01:01"); + }}); + } + + @Test + public void getSpeakToChatEnabled() { + final Request request = protocol.getSpeakToChatEnabled(); + assertRequest(request, 0x0c, "f6:05"); + } + + @Test + public void setSpeakToChatConfig() { + assertRequests(protocol::setSpeakToChatConfig, new LinkedHashMap() {{ + put(new SpeakToChatConfig(false, SpeakToChatConfig.Sensitivity.AUTO, SpeakToChatConfig.Timeout.SHORT), "fc:05:00:00:00:00"); + put(new SpeakToChatConfig(false, SpeakToChatConfig.Sensitivity.AUTO, SpeakToChatConfig.Timeout.STANDARD), "fc:05:00:00:00:01"); + put(new SpeakToChatConfig(false, SpeakToChatConfig.Sensitivity.AUTO, SpeakToChatConfig.Timeout.LONG), "fc:05:00:00:00:02"); + put(new SpeakToChatConfig(false, SpeakToChatConfig.Sensitivity.AUTO, SpeakToChatConfig.Timeout.OFF), "fc:05:00:00:00:03"); + + put(new SpeakToChatConfig(false, SpeakToChatConfig.Sensitivity.HIGH, SpeakToChatConfig.Timeout.SHORT), "fc:05:00:01:00:00"); + put(new SpeakToChatConfig(false, SpeakToChatConfig.Sensitivity.HIGH, SpeakToChatConfig.Timeout.STANDARD), "fc:05:00:01:00:01"); + put(new SpeakToChatConfig(false, SpeakToChatConfig.Sensitivity.HIGH, SpeakToChatConfig.Timeout.LONG), "fc:05:00:01:00:02"); + put(new SpeakToChatConfig(false, SpeakToChatConfig.Sensitivity.HIGH, SpeakToChatConfig.Timeout.OFF), "fc:05:00:01:00:03"); + + put(new SpeakToChatConfig(false, SpeakToChatConfig.Sensitivity.LOW, SpeakToChatConfig.Timeout.SHORT), "fc:05:00:02:00:00"); + put(new SpeakToChatConfig(false, SpeakToChatConfig.Sensitivity.LOW, SpeakToChatConfig.Timeout.STANDARD), "fc:05:00:02:00:01"); + put(new SpeakToChatConfig(false, SpeakToChatConfig.Sensitivity.LOW, SpeakToChatConfig.Timeout.LONG), "fc:05:00:02:00:02"); + put(new SpeakToChatConfig(false, SpeakToChatConfig.Sensitivity.LOW, SpeakToChatConfig.Timeout.OFF), "fc:05:00:02:00:03"); + + put(new SpeakToChatConfig(true, SpeakToChatConfig.Sensitivity.AUTO, SpeakToChatConfig.Timeout.SHORT), "fc:05:00:00:01:00"); + put(new SpeakToChatConfig(true, SpeakToChatConfig.Sensitivity.AUTO, SpeakToChatConfig.Timeout.STANDARD), "fc:05:00:00:01:01"); + put(new SpeakToChatConfig(true, SpeakToChatConfig.Sensitivity.AUTO, SpeakToChatConfig.Timeout.LONG), "fc:05:00:00:01:02"); + put(new SpeakToChatConfig(true, SpeakToChatConfig.Sensitivity.AUTO, SpeakToChatConfig.Timeout.OFF), "fc:05:00:00:01:03"); + + put(new SpeakToChatConfig(true, SpeakToChatConfig.Sensitivity.HIGH, SpeakToChatConfig.Timeout.SHORT), "fc:05:00:01:01:00"); + put(new SpeakToChatConfig(true, SpeakToChatConfig.Sensitivity.HIGH, SpeakToChatConfig.Timeout.STANDARD), "fc:05:00:01:01:01"); + put(new SpeakToChatConfig(true, SpeakToChatConfig.Sensitivity.HIGH, SpeakToChatConfig.Timeout.LONG), "fc:05:00:01:01:02"); + put(new SpeakToChatConfig(true, SpeakToChatConfig.Sensitivity.HIGH, SpeakToChatConfig.Timeout.OFF), "fc:05:00:01:01:03"); + + put(new SpeakToChatConfig(true, SpeakToChatConfig.Sensitivity.LOW, SpeakToChatConfig.Timeout.SHORT), "fc:05:00:02:01:00"); + put(new SpeakToChatConfig(true, SpeakToChatConfig.Sensitivity.LOW, SpeakToChatConfig.Timeout.STANDARD), "fc:05:00:02:01:01"); + put(new SpeakToChatConfig(true, SpeakToChatConfig.Sensitivity.LOW, SpeakToChatConfig.Timeout.LONG), "fc:05:00:02:01:02"); + put(new SpeakToChatConfig(true, SpeakToChatConfig.Sensitivity.LOW, SpeakToChatConfig.Timeout.OFF), "fc:05:00:02:01:03"); + }}); + } + + @Test + public void getSpeakToChatConfig() { + final Request request = protocol.getSpeakToChatConfig(); + assertRequest(request, 0x0c, "fa:05"); } @Test public void getNoiseCancellingOptimizerState() { - // TODO + final Request request = protocol.getNoiseCancellingOptimizerState(); + assertRequest(request, 0x0c, "86:01"); } @Test public void getAudioCodec() { - // TODO + final Request request = protocol.getAudioCodec(); + assertRequest(request, 0x0c, "18:00"); } @Test public void getBattery() { - // TODO + final Map commands = new LinkedHashMap() {{ + put(BatteryType.SINGLE, "10:00"); + put(BatteryType.DUAL, "10:01"); + put(BatteryType.CASE, "10:02"); + }}; + + for (Map.Entry entry : commands.entrySet()) { + final Request request = protocol.getBattery(entry.getKey()); + assertRequest(request, 0x0c, entry.getValue()); + } } @Test public void getFirmwareVersion() { - // TODO + final Request request = protocol.getFirmwareVersion(); + assertRequest(request, 0x0c, "04:02"); } @Test public void getAudioUpsampling() { - // TODO + final Request request = protocol.getAudioUpsampling(); + assertRequest(request, 0x0c, "e6:02"); } @Test public void setAudioUpsampling() { - // TODO + assertRequests(protocol::setAudioUpsampling, new LinkedHashMap() {{ + put(new AudioUpsampling(false), "e8:02:00:00"); + put(new AudioUpsampling(true), "e8:02:00:01"); + }}); } @Test public void getAutomaticPowerOff() { - // TODO + final Request request = protocol.getAutomaticPowerOff(); + assertRequest(request, 0x0c, "f6:04"); } @Test public void setAutomaticPowerOff() { - // TODO + assertRequests(protocol::setAutomaticPowerOff, new LinkedHashMap() {{ + put(AutomaticPowerOff.OFF, "f8:04:01:11:00"); + put(AutomaticPowerOff.AFTER_5_MIN, "f8:04:01:00:00"); + put(AutomaticPowerOff.AFTER_30_MIN, "f8:04:01:01:01"); + put(AutomaticPowerOff.AFTER_1_HOUR, "f8:04:01:02:02"); + put(AutomaticPowerOff.AFTER_3_HOUR, "f8:04:01:03:03"); + put(AutomaticPowerOff.WHEN_TAKEN_OFF, "f8:04:01:10:00"); + }}); } @Test public void getButtonModes() { - // TODO + final Request request = protocol.getButtonModes(); + assertRequest(request, 0x0c, "f6:06"); } @Test public void setButtonModes() { - // TODO - final Request request = protocol.setButtonModes(new ButtonModes( - ButtonModes.Mode.AMBIENT_SOUND_CONTROL, - ButtonModes.Mode.PLAYBACK_CONTROL - )); - assertRequest(request, "3e0c0100000005f806020020323c"); + assertRequests(protocol::setButtonModes, new LinkedHashMap() {{ + put(new ButtonModes(ButtonModes.Mode.OFF, ButtonModes.Mode.OFF), "f8:06:02:ff:ff"); + put(new ButtonModes(ButtonModes.Mode.OFF, ButtonModes.Mode.AMBIENT_SOUND_CONTROL), "f8:06:02:ff:00"); + put(new ButtonModes(ButtonModes.Mode.OFF, ButtonModes.Mode.PLAYBACK_CONTROL), "f8:06:02:ff:20"); + put(new ButtonModes(ButtonModes.Mode.OFF, ButtonModes.Mode.VOLUME_CONTROL), "f8:06:02:ff:10"); + put(new ButtonModes(ButtonModes.Mode.OFF, ButtonModes.Mode.OFF), "f8:06:02:ff:ff"); + put(new ButtonModes(ButtonModes.Mode.AMBIENT_SOUND_CONTROL, ButtonModes.Mode.OFF), "f8:06:02:00:ff"); + put(new ButtonModes(ButtonModes.Mode.PLAYBACK_CONTROL, ButtonModes.Mode.OFF), "f8:06:02:20:ff"); + put(new ButtonModes(ButtonModes.Mode.VOLUME_CONTROL, ButtonModes.Mode.OFF), "f8:06:02:10:ff"); + }}); + } + + @Test + public void getQuickAccess() { + final Request request = protocol.getQuickAccess(); + assertNull(request); + } + + @Test + public void setQuickAccess() { + assertRequests(protocol::setQuickAccess, new LinkedHashMap() {{ + put(new QuickAccess(QuickAccess.Mode.OFF, QuickAccess.Mode.OFF), null); + put(new QuickAccess(QuickAccess.Mode.OFF, QuickAccess.Mode.SPOTIFY), null); + put(new QuickAccess(QuickAccess.Mode.SPOTIFY, QuickAccess.Mode.OFF), null); + put(new QuickAccess(QuickAccess.Mode.SPOTIFY, QuickAccess.Mode.SPOTIFY), null); + }}); + } + + @Test + public void getAmbientSoundControlButtonMode() { + final Request request = protocol.getAmbientSoundControlButtonMode(); + assertNull(request); + } + + @Test + public void setAmbientSoundControlButtonMode() { + assertRequests(protocol::setAmbientSoundControlButtonMode, new LinkedHashMap() {{ + put(AmbientSoundControlButtonMode.NC_AS_OFF, null); + put(AmbientSoundControlButtonMode.NC_AS, null); + put(AmbientSoundControlButtonMode.NC_OFF, null); + put(AmbientSoundControlButtonMode.AS_OFF, null); + }}); } @Test public void getPauseWhenTakenOff() { - // TODO + final Request request = protocol.getPauseWhenTakenOff(); + assertRequest(request, 0x0c, "f6:03"); } @Test public void setPauseWhenTakenOff() { - // TODO + assertRequests(protocol::setPauseWhenTakenOff, new LinkedHashMap() {{ + put(new PauseWhenTakenOff(false), "f8:03:00:00"); + put(new PauseWhenTakenOff(true), "f8:03:00:01"); + }}); } @Test public void getEqualizer() { - // TODO + final Request request = protocol.getEqualizer(); + assertRequest(request, 0x0c, "56:01"); } @Test public void setEqualizerPreset() { - + assertRequests(protocol::setEqualizerPreset, new LinkedHashMap() {{ + put(EqualizerPreset.OFF, "58:01:00:00"); + put(EqualizerPreset.BRIGHT, "58:01:10:00"); + put(EqualizerPreset.EXCITED, "58:01:11:00"); + put(EqualizerPreset.MELLOW, "58:01:12:00"); + put(EqualizerPreset.RELAXED, "58:01:13:00"); + put(EqualizerPreset.VOCAL, "58:01:14:00"); + put(EqualizerPreset.TREBLE_BOOST, "58:01:15:00"); + put(EqualizerPreset.BASS_BOOST, "58:01:16:00"); + put(EqualizerPreset.SPEECH, "58:01:17:00"); + put(EqualizerPreset.MANUAL, "58:01:a0:00"); + put(EqualizerPreset.CUSTOM_1, "58:01:a1:00"); + }}); } @Test public void setEqualizerCustomBands() { - // TODO + assertRequests(protocol::setEqualizerCustomBands, new LinkedHashMap() {{ + put(new EqualizerCustomBands(Arrays.asList(0, 0, 0, 0, 0), 0), "58:01:ff:06:0a:0a:0a:0a:0a:0a"); + put(new EqualizerCustomBands(Arrays.asList(5, 1, 0, 4, 0), 0), "58:01:ff:06:0a:0f:0b:0a:0e:0a"); + put(new EqualizerCustomBands(Arrays.asList(10, 0, 3, 0, 5), -2), "58:01:ff:06:08:14:0a:0d:0a:0f"); + put(new EqualizerCustomBands(Arrays.asList(-3, -7, 0, 2, 9), 0), "58:01:ff:06:0a:07:03:0a:0c:13"); + put(new EqualizerCustomBands(Arrays.asList(-3, -7, 0, 2, 9), 7), "58:01:ff:06:11:07:03:0a:0c:13"); + }}); } @Test public void getSoundPosition() { - // TODO + final Request request = protocol.getSoundPosition(); + assertRequest(request, 0x0c, "46:02"); } @Test public void setSoundPosition() { - // TODO + assertRequests(protocol::setSoundPosition, new LinkedHashMap() {{ + put(SoundPosition.OFF, "48:02:00"); + put(SoundPosition.FRONT, "48:02:03"); + put(SoundPosition.FRONT_LEFT, "48:02:01"); + put(SoundPosition.FRONT_RIGHT, "48:02:02"); + put(SoundPosition.REAR_LEFT, "48:02:11"); + put(SoundPosition.REAR_RIGHT, "48:02:12"); + }}); } @Test public void getSurroundMode() { - // TODO + final Request request = protocol.getSurroundMode(); + assertRequest(request, 0x0c, "46:01"); } @Test public void setSurroundMode() { - // TODO + assertRequests(protocol::setSurroundMode, new LinkedHashMap() {{ + put(SurroundMode.OFF, "48:01:00"); + put(SurroundMode.ARENA, "48:01:02"); + put(SurroundMode.CLUB, "48:01:04"); + put(SurroundMode.OUTDOOR_STAGE, "48:01:01"); + put(SurroundMode.CONCERT_HALL, "48:01:03"); + }}); } @Test public void getTouchSensor() { - // TODO + final Request request = protocol.getTouchSensor(); + assertRequest(request, 0x0c, "d6:d2"); } @Test public void setTouchSensor() { - // TODO + assertRequests(protocol::setTouchSensor, new LinkedHashMap() {{ + put(new TouchSensor(false), "d8:d2:01:00"); + put(new TouchSensor(true), "d8:d2:01:01"); + }}); } @Test public void getVoiceNotifications() { - // TODO + final Request request = protocol.getVoiceNotifications(); + assertRequest(request, 0x0e, "46:01:01"); } @Test public void setVoiceNotifications() { - // TODO + assertRequests(protocol::setVoiceNotifications, 0x0e, new LinkedHashMap() {{ + put(new VoiceNotifications(false), "48:01:01:00"); + put(new VoiceNotifications(true), "48:01:01:01"); + }}); } @Test public void startNoiseCancellingOptimizer() { - // TODO + assertRequests(protocol::startNoiseCancellingOptimizer, new LinkedHashMap() {{ + put(Boolean.TRUE, "84:01:00:01"); + put(Boolean.FALSE, "84:01:00:00"); + }}); } @Test public void powerOff() { - // TODO + final Request request = protocol.powerOff(); + assertRequest(request, 0x0c, "22:00:01"); } @Test @@ -215,6 +456,11 @@ public class SonyProtocolImplV1Test { // TODO } + @Test + public void handleSpeakToChatEnabled() { + // TODO + } + @Test public void handleButtonModes() { // TODO @@ -232,7 +478,6 @@ public class SonyProtocolImplV1Test { @Test public void handleAudioCodec() { - // TODO final List event = protocol.handlePayload( MessageType.fromCode((byte) 0x0c), GB.hexStringToByteArray("1b:00:01".replace(":", "")) @@ -281,20 +526,13 @@ public class SonyProtocolImplV1Test { // TODO } + @Test + public void handleSpeakToChatConfig() { + // TODO + } + @Test public void handleVoiceNotifications() { // TODO } - - @Test - public void booleanFromByte() { - assertEquals(Boolean.FALSE, protocol.booleanFromByte((byte) 0x00)); - assertEquals(Boolean.TRUE, protocol.booleanFromByte((byte) 0x01)); - assertNull(protocol.booleanFromByte((byte) 0x02)); - } - - @Test - public void supportsWindNoiseCancelling() { - // TODO - } } diff --git a/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sony/headphones/protocol/impl/v3/SonyProtocolImplV3Test.java b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sony/headphones/protocol/impl/v3/SonyProtocolImplV3Test.java index 41f4ec3db..4f3d7c71e 100644 --- a/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sony/headphones/protocol/impl/v3/SonyProtocolImplV3Test.java +++ b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sony/headphones/protocol/impl/v3/SonyProtocolImplV3Test.java @@ -18,6 +18,7 @@ package nodomain.freeyourgadget.gadgetbridge.service.devices.sony.headphones.pro import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import static nodomain.freeyourgadget.gadgetbridge.service.devices.sony.headphones.protocol.impl.SonyTestUtils.assertPrefs; import static nodomain.freeyourgadget.gadgetbridge.service.devices.sony.headphones.protocol.impl.SonyTestUtils.assertRequest; import static nodomain.freeyourgadget.gadgetbridge.service.devices.sony.headphones.protocol.impl.SonyTestUtils.handleMessage; @@ -87,25 +88,21 @@ public class SonyProtocolImplV3Test { @Test public void handleQuickAccess() { - final Map commands = new LinkedHashMap() {{ + final Map commands = new LinkedHashMap() {{ + // Ret + put("3e:0c:00:00:00:00:05:f7:0d:02:00:00:17:3c", new QuickAccess(QuickAccess.Mode.OFF, QuickAccess.Mode.OFF)); + put("3e:0c:01:00:00:00:05:f7:0d:02:00:01:19:3c", new QuickAccess(QuickAccess.Mode.OFF, QuickAccess.Mode.SPOTIFY)); + put("3e:0c:01:00:00:00:05:f7:0d:02:01:00:19:3c", new QuickAccess(QuickAccess.Mode.SPOTIFY, QuickAccess.Mode.OFF)); + // Notify - put(new QuickAccess(QuickAccess.Mode.OFF, QuickAccess.Mode.OFF), "3e:0c:00:00:00:00:05:f9:0d:02:00:00:19:3c"); - put(new QuickAccess(QuickAccess.Mode.OFF, QuickAccess.Mode.SPOTIFY), "3e:0c:01:00:00:00:05:f9:0d:02:00:01:1b:3c"); - put(new QuickAccess(QuickAccess.Mode.SPOTIFY, QuickAccess.Mode.OFF), "3e:0c:01:00:00:00:05:f9:0d:02:01:00:1b:3c"); + put("3e:0c:00:00:00:00:05:f9:0d:02:00:00:19:3c", new QuickAccess(QuickAccess.Mode.OFF, QuickAccess.Mode.OFF)); + put("3e:0c:01:00:00:00:05:f9:0d:02:00:01:1b:3c", new QuickAccess(QuickAccess.Mode.OFF, QuickAccess.Mode.SPOTIFY)); + put("3e:0c:01:00:00:00:05:f9:0d:02:01:00:1b:3c", new QuickAccess(QuickAccess.Mode.SPOTIFY, QuickAccess.Mode.OFF)); }}; - for (Map.Entry entry : commands.entrySet()) { - final List events = handleMessage(protocol, entry.getValue()); - assertEquals("Expect 1 events", 1, events.size()); - final GBDeviceEventUpdatePreferences event = (GBDeviceEventUpdatePreferences) events.get(0); - final Map expectedPrefs = entry.getKey().toPreferences(); - assertEquals("Expect 2 prefs", 2, expectedPrefs.size()); - final Object prefDoubleTap = expectedPrefs.get(DeviceSettingsPreferenceConst.PREF_SONY_QUICK_ACCESS_DOUBLE_TAP); - assertNotNull(prefDoubleTap); - assertEquals(prefDoubleTap, event.preferences.get(DeviceSettingsPreferenceConst.PREF_SONY_QUICK_ACCESS_DOUBLE_TAP)); - final Object prefTripleTap = expectedPrefs.get(DeviceSettingsPreferenceConst.PREF_SONY_QUICK_ACCESS_TRIPLE_TAP); - assertNotNull(prefTripleTap); - assertEquals(prefTripleTap, event.preferences.get(DeviceSettingsPreferenceConst.PREF_SONY_QUICK_ACCESS_TRIPLE_TAP)); + for (Map.Entry entry : commands.entrySet()) { + final List events = handleMessage(protocol, entry.getKey()); + assertPrefs(events, entry.getValue().toPreferences()); } }