CMF Buds 2a: Add touch options

This commit is contained in:
José Rebelo
2026-05-21 09:51:14 +01:00
parent 51b305fb04
commit 0c11ba44f8
11 changed files with 315 additions and 22 deletions
@@ -24,6 +24,7 @@ import java.util.List;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpecificSettings;
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpecificSettingsCustomizer;
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpecificSettingsScreen;
import nodomain.freeyourgadget.gadgetbridge.devices.AbstractBLClassicDeviceCoordinator;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.model.BatteryConfig;
@@ -68,17 +69,24 @@ public abstract class AbstractEarCoordinator extends AbstractBLClassicDeviceCoor
@Override
public DeviceSpecificSettings getDeviceSpecificSettings(final GBDevice device) {
final DeviceSpecificSettings deviceSpecificSettings = new DeviceSpecificSettings();
deviceSpecificSettings.addRootScreen(R.xml.devicesettings_nothing_ear1);
final List<Integer> audio = deviceSpecificSettings.addRootScreen(DeviceSpecificSettingsScreen.AUDIO);
audio.add(R.xml.devicesettings_nothing_ear1);
if (!getEqualizerPresets().isEmpty()) {
deviceSpecificSettings.addRootScreen(R.xml.devicesettings_nothing_equalizer);
audio.add(R.xml.devicesettings_nothing_equalizer);
}
if (supportsUltraBass()) {
deviceSpecificSettings.addRootScreen(R.xml.devicesettings_nothing_ultra_bass);
audio.add(R.xml.devicesettings_nothing_ultra_bass);
}
if (supportsTouchOptions()) {
final List<Integer> touchOptions = deviceSpecificSettings.addRootScreen(DeviceSpecificSettingsScreen.TOUCH_OPTIONS);
touchOptions.add(R.xml.devicesettings_cmf_buds_touch_options);
}
if (supportsLowLatency()) {
deviceSpecificSettings.addRootScreen(R.xml.devicesettings_headphones_low_latency);
final List<Integer> connection = deviceSpecificSettings.addRootScreen(DeviceSpecificSettingsScreen.CONNECTION);
connection.add(R.xml.devicesettings_headphones_low_latency);
}
deviceSpecificSettings.addRootScreen(R.xml.devicesettings_headphones);
final List<Integer> callsAndNotif = deviceSpecificSettings.addRootScreen(DeviceSpecificSettingsScreen.CALLS_AND_NOTIFICATIONS);
callsAndNotif.add(R.xml.devicesettings_headphones);
return deviceSpecificSettings;
}
@@ -117,4 +125,8 @@ public abstract class AbstractEarCoordinator extends AbstractBLClassicDeviceCoor
public boolean supportsUltraBass() {
return false;
}
public boolean supportsTouchOptions() {
return false;
}
}
@@ -90,4 +90,9 @@ public class CmfBuds2aCoordinator extends AbstractEarCoordinator {
public boolean supportsUltraBass() {
return true;
}
@Override
public boolean supportsTouchOptions() {
return true;
}
}
@@ -30,6 +30,7 @@ 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.service.devices.nothing.NothingBudsPreferences;
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
public class EarSettingsCustomizer implements DeviceSpecificSettingsCustomizer {
@@ -116,6 +117,15 @@ public class EarSettingsCustomizer implements DeviceSpecificSettingsCustomizer {
listPreference.setEntryValues(entryValues.toArray(new CharSequence[0]));
}
}
handler.addPreferenceHandlerFor(NothingBudsPreferences.PREF_CMF_BUDS_TOUCH__LEFT__TAP_2);
handler.addPreferenceHandlerFor(NothingBudsPreferences.PREF_CMF_BUDS_TOUCH__LEFT__TAP_3);
handler.addPreferenceHandlerFor(NothingBudsPreferences.PREF_CMF_BUDS_TOUCH__LEFT__TAP_1_HOLD);
handler.addPreferenceHandlerFor(NothingBudsPreferences.PREF_CMF_BUDS_TOUCH__LEFT__TAP_2_HOLD);
handler.addPreferenceHandlerFor(NothingBudsPreferences.PREF_CMF_BUDS_TOUCH__RIGHT__TAP_2);
handler.addPreferenceHandlerFor(NothingBudsPreferences.PREF_CMF_BUDS_TOUCH__RIGHT__TAP_3);
handler.addPreferenceHandlerFor(NothingBudsPreferences.PREF_CMF_BUDS_TOUCH__RIGHT__TAP_1_HOLD);
handler.addPreferenceHandlerFor(NothingBudsPreferences.PREF_CMF_BUDS_TOUCH__RIGHT__TAP_2_HOLD);
}
@Override
@@ -27,6 +27,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.UUID;
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
@@ -159,6 +160,19 @@ public class Ear1Support extends AbstractHeadphoneBTBRDeviceSupport {
)
);
break;
case NothingBudsPreferences.PREF_CMF_BUDS_TOUCH__LEFT__TAP_2:
case NothingBudsPreferences.PREF_CMF_BUDS_TOUCH__LEFT__TAP_3:
case NothingBudsPreferences.PREF_CMF_BUDS_TOUCH__LEFT__TAP_1_HOLD:
case NothingBudsPreferences.PREF_CMF_BUDS_TOUCH__LEFT__TAP_2_HOLD:
case NothingBudsPreferences.PREF_CMF_BUDS_TOUCH__RIGHT__TAP_2:
case NothingBudsPreferences.PREF_CMF_BUDS_TOUCH__RIGHT__TAP_3:
case NothingBudsPreferences.PREF_CMF_BUDS_TOUCH__RIGHT__TAP_1_HOLD:
case NothingBudsPreferences.PREF_CMF_BUDS_TOUCH__RIGHT__TAP_2_HOLD:
sendCommand(
"set touch options " + config,
nothingProtocol.encodeTouchOptions(config, prefs)
);
break;
default:
LOG.debug("CONFIG: " + config);
break;
@@ -224,11 +238,13 @@ public class Ear1Support extends AbstractHeadphoneBTBRDeviceSupport {
private final int bitmask;
NothingAudioMode (int bitmask) {
NothingAudioMode(int bitmask) {
this.bitmask = bitmask;
}
public int getBitmask() { return bitmask; }
public int getBitmask() {
return bitmask;
}
public static NothingAudioMode fromBitmask(int bitmask) {
for (NothingAudioMode flag : values()) {
@@ -386,6 +402,7 @@ public class Ear1Support extends AbstractHeadphoneBTBRDeviceSupport {
evt.fwVersion = new String(payload);
return evt;
}
private GBDeviceEventUpdatePreferences handleAudioModeStatus(byte[] payload) {
final GBDeviceEventUpdatePreferences preferencesEvent = new GBDeviceEventUpdatePreferences();
@@ -500,6 +517,58 @@ public class Ear1Support extends AbstractHeadphoneBTBRDeviceSupport {
return encodeAudioModeStatusReq();
}
public byte[] encodeTouchOptions(final String key, SharedPreferences prefs) {
final String actionString = prefs.getString(key, NothingTapAction.OFF.name());
final NothingTapAction action = NothingTapAction.valueOf(actionString.toUpperCase(Locale.ROOT));
final byte side;
final NothingTapType tapType;
switch (key) {
case NothingBudsPreferences.PREF_CMF_BUDS_TOUCH__LEFT__TAP_2:
side = battery_earphone_left;
tapType = NothingTapType.TAP_2;
break;
case NothingBudsPreferences.PREF_CMF_BUDS_TOUCH__LEFT__TAP_3:
side = battery_earphone_left;
tapType = NothingTapType.TAP_3;
break;
case NothingBudsPreferences.PREF_CMF_BUDS_TOUCH__LEFT__TAP_1_HOLD:
side = battery_earphone_left;
tapType = NothingTapType.TAP_1_HOLD;
break;
case NothingBudsPreferences.PREF_CMF_BUDS_TOUCH__LEFT__TAP_2_HOLD:
side = battery_earphone_left;
tapType = NothingTapType.TAP_2_HOLD;
break;
case NothingBudsPreferences.PREF_CMF_BUDS_TOUCH__RIGHT__TAP_2:
side = battery_earphone_right;
tapType = NothingTapType.TAP_2;
break;
case NothingBudsPreferences.PREF_CMF_BUDS_TOUCH__RIGHT__TAP_3:
side = battery_earphone_right;
tapType = NothingTapType.TAP_3;
break;
case NothingBudsPreferences.PREF_CMF_BUDS_TOUCH__RIGHT__TAP_1_HOLD:
side = battery_earphone_right;
tapType = NothingTapType.TAP_1_HOLD;
break;
case NothingBudsPreferences.PREF_CMF_BUDS_TOUCH__RIGHT__TAP_2_HOLD:
side = battery_earphone_right;
tapType = NothingTapType.TAP_2_HOLD;
break;
default:
LOG.error("Unknown touch option preference key {}", key);
return null;
}
return new byte[]{
0x01,
side,
0x01,
(byte) tapType.getCode(),
(byte) action.getCode()
};
}
private List<GBDeviceEvent> handleBatteryInfo(byte[] payload) {
List<GBDeviceEvent> batEvts = new ArrayList<>();
@@ -568,9 +637,9 @@ public class Ear1Support extends AbstractHeadphoneBTBRDeviceSupport {
batteries.put(battery_earphone_right, new GBDeviceEventBatteryInfo());
batteries.put(battery_case, new GBDeviceEventBatteryInfo());
batteries.get(battery_case).batteryIndex=0;
batteries.get(battery_earphone_left).batteryIndex=1;
batteries.get(battery_earphone_right).batteryIndex=2;
batteries.get(battery_case).batteryIndex = 0;
batteries.get(battery_earphone_left).batteryIndex = 1;
batteries.get(battery_earphone_right).batteryIndex = 2;
this.incrementCounter = incrementCounter;
}
@@ -0,0 +1,12 @@
package nodomain.freeyourgadget.gadgetbridge.service.devices.nothing;
public class NothingBudsPreferences {
public static final String PREF_CMF_BUDS_TOUCH__LEFT__TAP_2 = "cmf_buds_touch__left__tap_2";
public static final String PREF_CMF_BUDS_TOUCH__LEFT__TAP_3 = "cmf_buds_touch__left__tap_3";
public static final String PREF_CMF_BUDS_TOUCH__LEFT__TAP_1_HOLD = "cmf_buds_touch__left__tap_1_hold";
public static final String PREF_CMF_BUDS_TOUCH__LEFT__TAP_2_HOLD = "cmf_buds_touch__left__tap_2_hold";
public static final String PREF_CMF_BUDS_TOUCH__RIGHT__TAP_2 = "cmf_buds_touch__right__tap_2";
public static final String PREF_CMF_BUDS_TOUCH__RIGHT__TAP_3 = "cmf_buds_touch__right__tap_3";
public static final String PREF_CMF_BUDS_TOUCH__RIGHT__TAP_1_HOLD = "cmf_buds_touch__right__tap_1_hold";
public static final String PREF_CMF_BUDS_TOUCH__RIGHT__TAP_2_HOLD = "cmf_buds_touch__right__tap_2_hold";
}
@@ -0,0 +1,37 @@
package nodomain.freeyourgadget.gadgetbridge.service.devices.nothing;
import androidx.annotation.Nullable;
public enum NothingTapAction {
OFF(0x01),
PREVIOUS_TRACK(0x08),
NEXT_TRACK(0x09),
VOICE_ASSISTANT(0x0b),
VOLUME_UP(0x12),
VOLUME_DOWN(0x13),
ANC_MODE__ANC_TRANSPARENCY_OFF(0x0a),
ANC_MODE__ANC_TRANSPARENCY(0x16),
ANC_MODE__ANC_OFF(0x14),
ANC_MODE__TRANSPARENCY_OFF(0x15),
;
private final int code;
NothingTapAction(final int code) {
this.code = code;
}
public int getCode() {
return code;
}
@Nullable
public static NothingTapAction fromCode(final int code) {
for (NothingTapAction type : values()) {
if (type.code == code) {
return type;
}
}
return null;
}
}
@@ -0,0 +1,31 @@
package nodomain.freeyourgadget.gadgetbridge.service.devices.nothing;
import androidx.annotation.Nullable;
public enum NothingTapType {
TAP_2(0x02),
TAP_3(0x03),
TAP_1_HOLD(0x07),
TAP_2_HOLD(0x09),
;
private final int code;
NothingTapType(final int code) {
this.code = code;
}
public int getCode() {
return code;
}
@Nullable
public static NothingTapType fromCode(final int code) {
for (NothingTapType type : values()) {
if (type.code == code) {
return type;
}
}
return null;
}
}
@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M160,520L160,440L280,440L280,520L160,520ZM420,520L420,440L760,440L760,520L420,520Z"/>
</vector>
+25
View File
@@ -4535,6 +4535,31 @@
<item>game_mode</item>
</string-array>
<string-array name="cmf_buds_touch_tap_names">
<item>@string/sony_button_mode_off</item>
<item>@string/pref_media_previous</item>
<item>@string/pref_media_next</item>
<item>@string/pref_media_volumeup</item>
<item>@string/pref_media_volumedown</item>
<item>@string/pref_title_touch_voice_assistant</item>
<item>@string/redmi_buds_5_pro_combo_all</item>
<item>@string/redmi_buds_5_pro_combo_anc_transparency</item>
<item>@string/redmi_buds_5_pro_combo_anc_off</item>
<item>@string/redmi_buds_5_pro_combo_transparency_off</item>
</string-array>
<string-array name="cmf_buds_touch_tap_values">
<item>off</item>
<item>previous_track</item>
<item>next_track</item>
<item>volume_up</item>
<item>volume_down</item>
<item>voice_assistant</item>
<item>anc_mode__anc_transparency_off</item>
<item>anc_mode__anc_transparency</item>
<item>anc_mode__anc_off</item>
<item>anc_mode__transparency_off</item>
</string-array>
<string-array name="soundcore_anc_mode_names">
<item>@string/prefs_active_noise_cancelling_transport</item>
<item>@string/prefs_active_noise_cancelling_indoor</item>
+2
View File
@@ -3602,6 +3602,8 @@
<string name="double_tap">Double Tap</string>
<string name="triple_tap">Triple Tap</string>
<string name="long_press">Long Press</string>
<string name="tap_and_hold">Tap and Hold</string>
<string name="double_tap_and_hold">Double Tap and Hold</string>
<string name="continue_pressing">Continue Pressing</string>
<string name="quick_attention">Quick Attention</string>
<string name="watchface_widget_type_custom">Custom widget</string>
@@ -0,0 +1,80 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<PreferenceCategory
android:key="oppo_touch_header_left"
android:title="@string/left_earbud"
app:iconSpaceReserved="false">
<ListPreference
android:defaultValue="nothing"
android:entries="@array/cmf_buds_touch_tap_names"
android:entryValues="@array/cmf_buds_touch_tap_values"
android:icon="@drawable/ic_filter_2"
android:key="cmf_buds_touch__left__tap_2"
app:useSimpleSummaryProvider="true"
android:title="@string/double_tap" />
<ListPreference
android:defaultValue="nothing"
android:entries="@array/cmf_buds_touch_tap_names"
android:entryValues="@array/cmf_buds_touch_tap_values"
android:icon="@drawable/ic_filter_3"
android:key="cmf_buds_touch__left__tap_3"
app:useSimpleSummaryProvider="true"
android:title="@string/triple_tap" />
<ListPreference
android:defaultValue="nothing"
android:entries="@array/cmf_buds_touch_tap_names"
android:entryValues="@array/cmf_buds_touch_tap_values"
android:icon="@drawable/ic_horizontal_rule"
android:key="cmf_buds_touch__left__tap_1_hold"
app:useSimpleSummaryProvider="true"
android:title="@string/tap_and_hold" />
<ListPreference
android:defaultValue="nothing"
android:entries="@array/cmf_buds_touch_tap_names"
android:entryValues="@array/cmf_buds_touch_tap_values"
android:icon="@drawable/ic_double_tap_hold"
android:key="cmf_buds_touch__left__tap_2_hold"
app:useSimpleSummaryProvider="true"
android:title="@string/double_tap_and_hold" />
</PreferenceCategory>
<PreferenceCategory
android:key="oppo_touch_header_right"
android:title="@string/right_earbud"
app:iconSpaceReserved="false">
<ListPreference
android:defaultValue="nothing"
android:entries="@array/cmf_buds_touch_tap_names"
android:entryValues="@array/cmf_buds_touch_tap_values"
android:icon="@drawable/ic_filter_2"
android:key="cmf_buds_touch__right__tap_2"
app:useSimpleSummaryProvider="true"
android:title="@string/double_tap" />
<ListPreference
android:defaultValue="nothing"
android:entries="@array/cmf_buds_touch_tap_names"
android:entryValues="@array/cmf_buds_touch_tap_values"
android:icon="@drawable/ic_filter_3"
android:key="cmf_buds_touch__right__tap_3"
app:useSimpleSummaryProvider="true"
android:title="@string/triple_tap" />
<ListPreference
android:defaultValue="nothing"
android:entries="@array/cmf_buds_touch_tap_names"
android:entryValues="@array/cmf_buds_touch_tap_values"
android:icon="@drawable/ic_horizontal_rule"
android:key="cmf_buds_touch__right__tap_1_hold"
app:useSimpleSummaryProvider="true"
android:title="@string/tap_and_hold" />
<ListPreference
android:defaultValue="nothing"
android:entries="@array/cmf_buds_touch_tap_names"
android:entryValues="@array/cmf_buds_touch_tap_values"
android:icon="@drawable/ic_double_tap_hold"
android:key="cmf_buds_touch__right__tap_2_hold"
app:useSimpleSummaryProvider="true"
android:title="@string/double_tap_and_hold" />
</PreferenceCategory>
</androidx.preference.PreferenceScreen>