diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/nothing/AbstractEarCoordinator.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/nothing/AbstractEarCoordinator.java new file mode 100644 index 000000000..8da21877c --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/nothing/AbstractEarCoordinator.java @@ -0,0 +1,101 @@ +/* Copyright (C) 2023 Daniele Gobbetti, 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.devices.nothing; + +import android.content.Context; +import android.net.Uri; + +import androidx.annotation.NonNull; + +import nodomain.freeyourgadget.gadgetbridge.GBException; +import nodomain.freeyourgadget.gadgetbridge.R; +import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpecificSettingsCustomizer; +import nodomain.freeyourgadget.gadgetbridge.devices.AbstractBLClassicDeviceCoordinator; +import nodomain.freeyourgadget.gadgetbridge.devices.InstallHandler; +import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession; +import nodomain.freeyourgadget.gadgetbridge.entities.Device; +import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; +import nodomain.freeyourgadget.gadgetbridge.model.BatteryConfig; +import nodomain.freeyourgadget.gadgetbridge.service.DeviceSupport; +import nodomain.freeyourgadget.gadgetbridge.service.devices.nothing.Ear1Support; + +public abstract class AbstractEarCoordinator extends AbstractBLClassicDeviceCoordinator { + @Override + public InstallHandler findInstallHandler(Uri uri, Context context) { + return null; + } + + @Override + public String getManufacturer() { + return "Nothing"; + } + + @Override + public boolean supportsFindDevice() { + return true; + } + + @Override + protected void deleteDevice(@NonNull GBDevice gbDevice, @NonNull Device device, @NonNull DaoSession session) throws GBException { + + } + + @Override + public int getBatteryCount() { + return 3; + } + + @Override + public BatteryConfig[] getBatteryConfig() { + BatteryConfig battery1 = new BatteryConfig(0, R.drawable.ic_tws_case, R.string.battery_case); + BatteryConfig battery2 = new BatteryConfig(1, R.drawable.ic_nothing_ear_l, R.string.left_earbud); + BatteryConfig battery3 = new BatteryConfig(2, R.drawable.ic_nothing_ear_r, R.string.right_earbud); + return new BatteryConfig[]{battery1, battery2, battery3}; + } + + @NonNull + @Override + public Class getDeviceSupportClass() { + return Ear1Support.class; + } + + @Override + public int[] getSupportedDeviceSpecificSettings(GBDevice device) { + return new int[]{ + R.xml.devicesettings_nothing_ear1 + }; + } + + @Override + public int getDefaultIconResource() { + return R.drawable.ic_device_nothingear; + } + + @Override + public int getDisabledIconResource() { + return R.drawable.ic_device_nothingear_disabled; + } + + @Override + public DeviceSpecificSettingsCustomizer getDeviceSpecificSettingsCustomizer(final GBDevice device) { + return new EarSettingsCustomizer(); + } + + public abstract boolean incrementCounter(); + + public abstract boolean supportsLightAncAndTransparency(); +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/nothing/Ear1Coordinator.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/nothing/Ear1Coordinator.java index 8fd1b844a..0c688a262 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/nothing/Ear1Coordinator.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/nothing/Ear1Coordinator.java @@ -1,87 +1,27 @@ package nodomain.freeyourgadget.gadgetbridge.devices.nothing; -import android.content.Context; -import android.net.Uri; - -import androidx.annotation.NonNull; - import java.util.regex.Pattern; -import nodomain.freeyourgadget.gadgetbridge.GBException; import nodomain.freeyourgadget.gadgetbridge.R; -import nodomain.freeyourgadget.gadgetbridge.devices.AbstractBLClassicDeviceCoordinator; -import nodomain.freeyourgadget.gadgetbridge.devices.InstallHandler; -import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession; -import nodomain.freeyourgadget.gadgetbridge.entities.Device; -import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; -import nodomain.freeyourgadget.gadgetbridge.model.BatteryConfig; -import nodomain.freeyourgadget.gadgetbridge.service.DeviceSupport; -import nodomain.freeyourgadget.gadgetbridge.service.devices.nothing.Ear1Support; -public class Ear1Coordinator extends AbstractBLClassicDeviceCoordinator { +public class Ear1Coordinator extends AbstractEarCoordinator { @Override protected Pattern getSupportedDeviceName() { return Pattern.compile("Nothing ear (1)", Pattern.LITERAL); } - @Override - public InstallHandler findInstallHandler(Uri uri, Context context) { - return null; - } - - @Override - public String getManufacturer() { - return "Nothing"; - } - - @Override - public boolean supportsFindDevice() { - return true; - } - - @Override - protected void deleteDevice(@NonNull GBDevice gbDevice, @NonNull Device device, @NonNull DaoSession session) throws GBException { - - } - - @Override - public int getBatteryCount() { - return 3; - } - - @Override - public BatteryConfig[] getBatteryConfig() { - BatteryConfig battery1 = new BatteryConfig(0, R.drawable.ic_tws_case, R.string.battery_case); - BatteryConfig battery2 = new BatteryConfig(1, R.drawable.ic_nothing_ear_l, R.string.left_earbud); - BatteryConfig battery3 = new BatteryConfig(2, R.drawable.ic_nothing_ear_r, R.string.right_earbud); - return new BatteryConfig[]{battery1, battery2, battery3}; - } - - @NonNull - @Override - public Class getDeviceSupportClass() { - return Ear1Support.class; - } - - @Override - public int[] getSupportedDeviceSpecificSettings(GBDevice device) { - return new int[] { - R.xml.devicesettings_nothing_ear1 - }; - } - @Override public int getDeviceNameResource() { return R.string.devicetype_nothingear1; } @Override - public int getDefaultIconResource() { - return R.drawable.ic_device_nothingear; + public boolean incrementCounter() { + return false; } @Override - public int getDisabledIconResource() { - return R.drawable.ic_device_nothingear_disabled; + public boolean supportsLightAncAndTransparency() { + return true; } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/nothing/Ear2Coordinator.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/nothing/Ear2Coordinator.java index 367f9ac42..33c074700 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/nothing/Ear2Coordinator.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/nothing/Ear2Coordinator.java @@ -16,88 +16,28 @@ along with this program. If not, see . */ package nodomain.freeyourgadget.gadgetbridge.devices.nothing; -import android.content.Context; -import android.net.Uri; - -import androidx.annotation.NonNull; - import java.util.regex.Pattern; -import nodomain.freeyourgadget.gadgetbridge.GBException; import nodomain.freeyourgadget.gadgetbridge.R; -import nodomain.freeyourgadget.gadgetbridge.devices.AbstractBLClassicDeviceCoordinator; -import nodomain.freeyourgadget.gadgetbridge.devices.InstallHandler; -import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession; -import nodomain.freeyourgadget.gadgetbridge.entities.Device; -import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; -import nodomain.freeyourgadget.gadgetbridge.model.BatteryConfig; -import nodomain.freeyourgadget.gadgetbridge.service.DeviceSupport; -import nodomain.freeyourgadget.gadgetbridge.service.devices.nothing.Ear1Support; -public class Ear2Coordinator extends AbstractBLClassicDeviceCoordinator { +public class Ear2Coordinator extends AbstractEarCoordinator { @Override protected Pattern getSupportedDeviceName() { return Pattern.compile("Ear (2)", Pattern.LITERAL); } - @Override - public InstallHandler findInstallHandler(Uri uri, Context context) { - return null; - } - - @Override - public String getManufacturer() { - return "Nothing"; - } - - @Override - public boolean supportsFindDevice() { - return true; - } - - @Override - protected void deleteDevice(@NonNull GBDevice gbDevice, @NonNull Device device, @NonNull DaoSession session) throws GBException { - - } - - @Override - public int getBatteryCount() { - return 3; - } - - @Override - public BatteryConfig[] getBatteryConfig() { - BatteryConfig battery1 = new BatteryConfig(0, R.drawable.ic_tws_case, R.string.battery_case); - BatteryConfig battery2 = new BatteryConfig(1, R.drawable.ic_nothing_ear_l, R.string.left_earbud); - BatteryConfig battery3 = new BatteryConfig(2, R.drawable.ic_nothing_ear_r, R.string.right_earbud); - return new BatteryConfig[]{battery1, battery2, battery3}; - } - - @NonNull - @Override - public Class getDeviceSupportClass() { - return Ear1Support.class; - } - - @Override - public int[] getSupportedDeviceSpecificSettings(GBDevice device) { - return new int[] { - R.xml.devicesettings_nothing_ear1 - }; - } - @Override public int getDeviceNameResource() { return R.string.devicetype_nothingear2; } @Override - public int getDefaultIconResource() { - return R.drawable.ic_device_nothingear; + public boolean incrementCounter() { + return false; } @Override - public int getDisabledIconResource() { - return R.drawable.ic_device_nothingear_disabled; + public boolean supportsLightAncAndTransparency() { + return true; } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/nothing/EarSettingsCustomizer.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/nothing/EarSettingsCustomizer.java new file mode 100644 index 000000000..5c0277953 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/nothing/EarSettingsCustomizer.java @@ -0,0 +1,92 @@ +/* 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.devices.nothing; + +import android.os.Parcel; + +import androidx.preference.ListPreference; +import androidx.preference.Preference; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Set; + +import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst; +import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpecificSettingsCustomizer; +import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpecificSettingsHandler; +import nodomain.freeyourgadget.gadgetbridge.util.Prefs; + +public class EarSettingsCustomizer implements DeviceSpecificSettingsCustomizer { + @Override + public void onPreferenceChange(final Preference preference, final DeviceSpecificSettingsHandler handler) { + } + + @Override + public void customizeSettings(final DeviceSpecificSettingsHandler handler, final Prefs prefs) { + final AbstractEarCoordinator earCoordinator = (AbstractEarCoordinator) handler.getDevice().getDeviceCoordinator(); + + if (!earCoordinator.supportsLightAncAndTransparency()) { + // If light anc and transparency is not supported, remove the values from the preference + final Preference audioModePref = handler.findPreference(DeviceSettingsPreferenceConst.PREF_NOTHING_EAR1_AUDIOMODE); + + if (audioModePref != null) { + final CharSequence[] originalEntries = ((ListPreference) audioModePref).getEntries(); + final CharSequence[] originalEntryValues = ((ListPreference) audioModePref).getEntryValues(); + + final List entries = new ArrayList<>(); + final List entryValues = new ArrayList<>(); + + for (int i = 0; i < originalEntries.length; i++) { + if ("anc".equals(originalEntryValues[i].toString()) || "off".equals(originalEntryValues[i].toString())) { + entries.add(originalEntries[i]); + entryValues.add(originalEntryValues[i]); + } + } + + ((ListPreference) audioModePref).setEntries(entries.toArray(new CharSequence[0])); + ((ListPreference) audioModePref).setEntryValues(entryValues.toArray(new CharSequence[0])); + } + } + } + + @Override + public Set getPreferenceKeysWithSummary() { + return Collections.emptySet(); + } + + public static final Creator CREATOR = new Creator() { + @Override + public EarSettingsCustomizer createFromParcel(final Parcel in) { + return new EarSettingsCustomizer(); + } + + @Override + public EarSettingsCustomizer[] newArray(final int size) { + return new EarSettingsCustomizer[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(final Parcel dest, final int flags) { + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/nothing/EarStickCoordinator.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/nothing/EarStickCoordinator.java new file mode 100644 index 000000000..11c718198 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/nothing/EarStickCoordinator.java @@ -0,0 +1,43 @@ +/* Copyright (C) 2023 Daniele Gobbetti, 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.devices.nothing; + +import java.util.regex.Pattern; + +import nodomain.freeyourgadget.gadgetbridge.R; + +public class EarStickCoordinator extends AbstractEarCoordinator { + @Override + protected Pattern getSupportedDeviceName() { + return Pattern.compile("Ear (stick)", Pattern.LITERAL); + } + + @Override + public int getDeviceNameResource() { + return R.string.devicetype_nothingearstick; + } + + @Override + public boolean incrementCounter() { + return true; + } + + @Override + public boolean supportsLightAncAndTransparency() { + return false; + } +} 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 b1a9777f5..7d8a03bb8 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/DeviceType.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/DeviceType.java @@ -115,6 +115,7 @@ import nodomain.freeyourgadget.gadgetbridge.devices.miscale2.MiScale2DeviceCoord import nodomain.freeyourgadget.gadgetbridge.devices.no1f1.No1F1Coordinator; import nodomain.freeyourgadget.gadgetbridge.devices.nothing.Ear1Coordinator; import nodomain.freeyourgadget.gadgetbridge.devices.nothing.Ear2Coordinator; +import nodomain.freeyourgadget.gadgetbridge.devices.nothing.EarStickCoordinator; import nodomain.freeyourgadget.gadgetbridge.devices.nut.NutCoordinator; import nodomain.freeyourgadget.gadgetbridge.devices.pebble.PebbleCoordinator; import nodomain.freeyourgadget.gadgetbridge.devices.pinetime.PineTimeJFCoordinator; @@ -279,6 +280,7 @@ public enum DeviceType { DOMYOS_T540(DomyosT540Coordinator.class), NOTHING_EAR1(Ear1Coordinator.class), NOTHING_EAR2(Ear2Coordinator.class), + NOTHING_EAR_STICK(EarStickCoordinator.class), GALAXY_BUDS_PRO(GalaxyBudsProDeviceCoordinator.class), GALAXY_BUDS_LIVE(GalaxyBudsLiveDeviceCoordinator.class), GALAXY_BUDS(GalaxyBudsDeviceCoordinator.class), diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/nothing/NothingProtocol.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/nothing/NothingProtocol.java index 9f773553c..e3de16717 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/nothing/NothingProtocol.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/nothing/NothingProtocol.java @@ -20,6 +20,7 @@ import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSett import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventBatteryInfo; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventVersionInfo; +import nodomain.freeyourgadget.gadgetbridge.devices.nothing.AbstractEarCoordinator; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.model.BatteryState; import nodomain.freeyourgadget.gadgetbridge.service.serial.GBDeviceProtocol; @@ -61,6 +62,8 @@ public class NothingProtocol extends GBDeviceProtocol { private static final short in_ear_detection = (short) 0xf004; private static final short audio_mode = (short) 0xf00f; + private final boolean incrementCounter; + private int messageCounter = 0x00; private HashMap batteries; private static final byte battery_earphone_left = 0x02; @@ -133,10 +136,16 @@ public class NothingProtocol extends GBDeviceProtocol { ByteBuffer msgBuf = ByteBuffer.allocate(8 + payload.length); msgBuf.order(ByteOrder.LITTLE_ENDIAN); msgBuf.put((byte) 0x55); //sof - msgBuf.putShort(control); + msgBuf.putShort((short) (incrementCounter ? (control | 0x40) : control)); msgBuf.putShort(command); msgBuf.putShort((short) payload.length); - msgBuf.put((byte) 0x00); //fsn TODO: is this always 0? + msgBuf.put((byte) messageCounter); //fsn + if (incrementCounter) { + messageCounter++; + if ((byte) messageCounter == (byte) 0xfd) { + messageCounter = 0x00; + } + } msgBuf.put(payload); if (isCrcNeeded(control)) { @@ -294,8 +303,13 @@ public class NothingProtocol extends GBDeviceProtocol { return (byte) ((control & MASK_DEVICE_TYPE) >> 8); } + private AbstractEarCoordinator getCoordinator() { + return (AbstractEarCoordinator) getDevice().getDeviceCoordinator(); + } + protected NothingProtocol(GBDevice device) { super(device); + batteries = new HashMap<>(3); batteries.put(battery_earphone_left, new GBDeviceEventBatteryInfo()); @@ -306,5 +320,6 @@ public class NothingProtocol extends GBDeviceProtocol { batteries.get(battery_earphone_left).batteryIndex=1; batteries.get(battery_earphone_right).batteryIndex=2; + incrementCounter = getCoordinator().incrementCounter(); } } diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index d09fb8b3f..c57150f86 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -2820,8 +2820,15 @@ 2 3 - - + + + @string/prefs_active_noise_cancelling + @string/prefs_active_noise_cancelling_light + @string/prefs_active_noise_cancelling_transparency + @string/off + + + anc anc-light transparency diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index aa487bdfe..c7e09d949 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1961,6 +1961,7 @@ Frequency of measurements Nothing Ear (1) Nothing Ear (2) + Nothing Ear (Stick) Galaxy Buds Galaxy Buds Live Galaxy Buds Pro @@ -2001,6 +2002,8 @@ Ambient Mode Ambient Sound Options Active Noise Cancelling + Light Active Noise Cancelling + Transparency Active Noise Cancelling Level High Low diff --git a/app/src/main/res/xml/devicesettings_nothing_ear1.xml b/app/src/main/res/xml/devicesettings_nothing_ear1.xml index 746624935..05dd62534 100644 --- a/app/src/main/res/xml/devicesettings_nothing_ear1.xml +++ b/app/src/main/res/xml/devicesettings_nothing_ear1.xml @@ -8,8 +8,8 @@ android:title="@string/nothing_prefs_inear_title" />