Add EarFun Free Pro 3 support

New device integration based on the EarFun Air Pro 4 implementation,
adapted to match the Free Pro 3 specifications:

- Qualcomm QCC3072, Bluetooth 5.3
- Codecs: SBC, AAC, aptX, aptX Adaptive (no LDAC, no LC3)
- 10-band equalizer
- Hybrid ANC (4 modes: ANC, wind noise, ambient, normal)
- 6-mic array with cVc 8.0
- Game mode (<55ms low latency)
- Multipoint (2 devices)
- 3 batteries (left, right, case)
- Touch gestures (single/double/triple/long press per earbud)

Differences from Air Pro 4:
- No LDAC codec, only aptX + aptX Adaptive
- No LE Audio / Advanced Audio Mode
- No in-ear detection setting

Detection: name "EarFun Free Pro 3", MAC prefix 70:5A:6F,
9 SDP UUIDs (includes 0000110c AVRCP Target, excludes Air Pro 4's
df21fe2c/180f/180a UUIDs).
This commit is contained in:
Antoine
2026-06-23 16:36:41 +02:00
committed by José Rebelo
parent edc714d87b
commit 15fc96385d
10 changed files with 541 additions and 0 deletions
@@ -0,0 +1,120 @@
/* Copyright (C) 2026 Obside
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 <https://www.gnu.org/licenses/>. */
package nodomain.freeyourgadget.gadgetbridge.devices.earfun;
import androidx.annotation.NonNull;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
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.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceCandidate;
import nodomain.freeyourgadget.gadgetbridge.model.BatteryConfig;
import nodomain.freeyourgadget.gadgetbridge.service.DeviceSupport;
import nodomain.freeyourgadget.gadgetbridge.service.devices.earfun.freepro3.EarFunFreePro3DeviceSupport;
import nodomain.freeyourgadget.gadgetbridge.service.devices.earfun.freepro3.EarFunFreePro3SettingsCustomizer;
public class EarFunFreePro3Coordinator extends AbstractEarFunCoordinator {
@Override
public int getDeviceNameResource() {
return R.string.devicetype_earfun_free_pro_3;
}
@Override
public boolean supports(GBDeviceCandidate candidate) {
if (candidate.getName().startsWith("EarFun Free Pro 3")) {
return true;
}
// fallback: check UUIDs and MAC prefix to detect even if device name was changed
// Free Pro 3 has 9 UUIDs: 5 standard audio + 4 vendor (EB04-EB07)
// Same MAC prefix (70:5A:6F) as Air Pro 4, so we must distinguish by UUID set
String[] uuids = {
"00001101-0000-1000-8000-00805f9b34fb",
"0000111e-0000-1000-8000-00805f9b34fb",
"0000110b-0000-1000-8000-00805f9b34fb",
"0000110c-0000-1000-8000-00805f9b34fb",
"0000110e-0000-1000-8000-00805f9b34fb",
"0000eb04-d102-11e1-9b23-00025b00a5a5",
"0000eb06-d102-11e1-9b23-00025b00a5a5",
"0000eb07-d102-11e1-9b23-00025b00a5a5",
"0000eb05-d102-11e1-9b23-00025b00a5a5"};
boolean allServicesSupported = Arrays.stream(uuids)
.map(UUID::fromString)
.map(candidate::supportsService).allMatch(b -> b);
// Must NOT have Air Pro 4 extras (df21fe2c, 180f battery, 180a device info)
boolean hasAirPro4Extras = candidate.supportsService(
UUID.fromString("df21fe2c-2515-4fdb-8886-f12c4d67927c"));
boolean macAddressMatches = candidate.getMacAddress().toUpperCase().startsWith("70:5A:6F");
return allServicesSupported && !hasAirPro4Extras && macAddressMatches;
}
@NonNull
@Override
public Class<? extends DeviceSupport> getDeviceSupportClass(final GBDevice device) {
return EarFunFreePro3DeviceSupport.class;
}
@Override
public int getBatteryCount(final GBDevice device) {
return 3;
}
@Override
public BatteryConfig[] getBatteryConfig(final GBDevice device) {
BatteryConfig battery1 = new BatteryConfig(2, R.drawable.ic_buds_pro_case, R.string.battery_case);
BatteryConfig battery2 = new BatteryConfig(0, R.drawable.ic_nothing_ear_l, R.string.left_earbud);
BatteryConfig battery3 = new BatteryConfig(1, R.drawable.ic_nothing_ear_r, R.string.right_earbud);
return new BatteryConfig[]{battery1, battery2, battery3};
}
@Override
public DeviceSpecificSettings getDeviceSpecificSettings(final GBDevice device) {
final DeviceSpecificSettings deviceSpecificSettings = new DeviceSpecificSettings();
// Category Audio Experience
deviceSpecificSettings.addRootScreen(R.xml.devicesettings_earfun_header_audio_experience);
deviceSpecificSettings.addRootScreen(R.xml.devicesettings_earfun_10_band_equalizer);
deviceSpecificSettings.addRootScreen(R.xml.devicesettings_earfun_free_pro_3_sound_control);
// Category Audio Quality & Connectivity
deviceSpecificSettings.addRootScreen(R.xml.devicesettings_earfun_header_connectivity);
deviceSpecificSettings.addRootScreen(R.xml.devicesettings_earfun_free_pro_3_audio_quality);
// Category System Settings
deviceSpecificSettings.addRootScreen(R.xml.devicesettings_earfun_header_system_settings);
deviceSpecificSettings.addRootScreen(R.xml.devicesettings_earfun_free_pro_3_gestures);
deviceSpecificSettings.addRootScreen(R.xml.devicesettings_earfun_find_device);
deviceSpecificSettings.addRootScreen(R.xml.devicesettings_earfun_device_name);
final List<Integer> callsAndNotif = deviceSpecificSettings.addRootScreen(DeviceSpecificSettingsScreen.CALLS_AND_NOTIFICATIONS);
callsAndNotif.add(R.xml.devicesettings_headphones);
return deviceSpecificSettings;
}
@Override
public DeviceSpecificSettingsCustomizer getDeviceSpecificSettingsCustomizer(final GBDevice device) {
return new EarFunFreePro3SettingsCustomizer(device);
}
}
@@ -54,6 +54,7 @@ import nodomain.freeyourgadget.gadgetbridge.devices.cycling_sensor.coordinator.C
import nodomain.freeyourgadget.gadgetbridge.devices.divoom.PixooCoordinator; import nodomain.freeyourgadget.gadgetbridge.devices.divoom.PixooCoordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.domyos.DomyosT540Coordinator; import nodomain.freeyourgadget.gadgetbridge.devices.domyos.DomyosT540Coordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.earfun.EarFunAirPro4Coordinator; import nodomain.freeyourgadget.gadgetbridge.devices.earfun.EarFunAirPro4Coordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.earfun.EarFunFreePro3Coordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.earfun.EarFunAirSCoordinator; import nodomain.freeyourgadget.gadgetbridge.devices.earfun.EarFunAirSCoordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.evenrealities.G1DeviceCoordinator; import nodomain.freeyourgadget.gadgetbridge.devices.evenrealities.G1DeviceCoordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.femometer.FemometerVinca2DeviceCoordinator; import nodomain.freeyourgadget.gadgetbridge.devices.femometer.FemometerVinca2DeviceCoordinator;
@@ -969,6 +970,7 @@ public enum DeviceType {
B_AND_W_P_SERIES(BandWPSeriesDeviceCoordinator.class), B_AND_W_P_SERIES(BandWPSeriesDeviceCoordinator.class),
EARFUN_AIR_S(EarFunAirSCoordinator.class), EARFUN_AIR_S(EarFunAirSCoordinator.class),
EARFUN_AIR_PRO_4(EarFunAirPro4Coordinator.class), EARFUN_AIR_PRO_4(EarFunAirPro4Coordinator.class),
EARFUN_FREE_PRO_3(EarFunFreePro3Coordinator.class),
SCANNABLE(ScannableDeviceCoordinator.class), SCANNABLE(ScannableDeviceCoordinator.class),
CYCLING_SENSOR(CyclingSensorCoordinator.class), CYCLING_SENSOR(CyclingSensorCoordinator.class),
BLE_GATT_CLIENT(BleGattClientCoordinator.class), BLE_GATT_CLIENT(BleGattClientCoordinator.class),
@@ -0,0 +1,27 @@
/* Copyright (C) 2026 Obside
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 <https://www.gnu.org/licenses/>. */
package nodomain.freeyourgadget.gadgetbridge.service.devices.earfun.freepro3;
import nodomain.freeyourgadget.gadgetbridge.service.devices.earfun.EarFunDeviceSupport;
public class EarFunFreePro3DeviceSupport extends EarFunDeviceSupport {
@Override
protected EarFunFreePro3Protocol createDeviceProtocol() {
return new EarFunFreePro3Protocol(getDevice());
}
}
@@ -0,0 +1,64 @@
/* Copyright (C) 2026 Obside
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 <https://www.gnu.org/licenses/>. */
package nodomain.freeyourgadget.gadgetbridge.service.devices.earfun.freepro3;
import static nodomain.freeyourgadget.gadgetbridge.service.devices.earfun.EarFunPacketEncoder.joinPackets;
import android.os.Bundle;
import androidx.annotation.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.model.DeviceType;
import nodomain.freeyourgadget.gadgetbridge.service.devices.earfun.EarFunPacketEncoder;
import nodomain.freeyourgadget.gadgetbridge.service.devices.earfun.EarFunProtocol;
import nodomain.freeyourgadget.gadgetbridge.service.devices.earfun.prefs.Equalizer;
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
public class EarFunFreePro3Protocol extends EarFunProtocol {
private static final Logger LOG = LoggerFactory.getLogger(EarFunFreePro3Protocol.class);
@Override
public byte[] encodeTestNewFunction(@Nullable Bundle options) {
return joinPackets(
// new EarFunPacket(EarFunPacket.Command.COMMAND_REBOOT).encode()
);
}
@Override
public byte[] encodeSendConfiguration(String config) {
if (Equalizer.containsKey(Equalizer.TenBandEqualizer, config)) {
Prefs prefs = getDevicePrefs();
return EarFunPacketEncoder.encodeSetEqualizerTenBands(prefs);
}
return super.encodeSendConfiguration(config);
}
@Override
public byte[] encodeSettingsReq() {
return EarFunPacketEncoder.encodeAirPro4SettingsReq();
}
protected EarFunFreePro3Protocol(GBDevice device) {
super(device);
DeviceType type = device.getType();
}
}
@@ -0,0 +1,95 @@
/* Copyright (C) 2026 Obside
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 <https://www.gnu.org/licenses/>. */
package nodomain.freeyourgadget.gadgetbridge.service.devices.earfun.freepro3;
import static nodomain.freeyourgadget.gadgetbridge.service.devices.earfun.prefs.EarFunSettingsPreferenceConst.PREF_EARFUN_AMBIENT_SOUND_CONTROL;
import static nodomain.freeyourgadget.gadgetbridge.service.devices.earfun.prefs.EarFunSettingsPreferenceConst.PREF_EARFUN_ANC_MODE;
import static nodomain.freeyourgadget.gadgetbridge.service.devices.earfun.prefs.EarFunSettingsPreferenceConst.PREF_EARFUN_EQUALIZER_PRESET;
import static nodomain.freeyourgadget.gadgetbridge.service.devices.earfun.prefs.EarFunSettingsPreferenceConst.PREF_EARFUN_TRANSPARENCY_MODE;
import static nodomain.freeyourgadget.gadgetbridge.service.devices.earfun.prefs.Equalizer.TenBandEqualizerPresets;
import androidx.preference.ListPreference;
import androidx.preference.Preference;
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpecificSettingsHandler;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.service.devices.earfun.EarFunSettingsCustomizer;
import nodomain.freeyourgadget.gadgetbridge.service.devices.earfun.prefs.Equalizer;
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
public class EarFunFreePro3SettingsCustomizer extends EarFunSettingsCustomizer {
@Override
public void onPreferenceChange(Preference preference, DeviceSpecificSettingsHandler handler) {
super.onPreferenceChange(preference, handler);
String key = preference.getKey();
if (key == null) {
return;
}
switch (key) {
case PREF_EARFUN_AMBIENT_SOUND_CONTROL:
onPreferenceChangeAmbientSoundControl(handler);
break;
case PREF_EARFUN_EQUALIZER_PRESET:
onPreferenceChangeEqualizerPreset(handler, Equalizer.TenBandEqualizer, TenBandEqualizerPresets);
break;
}
// if the band sliders match a preset, update the preset list
if (Equalizer.containsKey(Equalizer.TenBandEqualizer, key)) {
int equalizerPreset = getSelectedPresetFromEqualizerBands(handler,
Equalizer.TenBandEqualizer, TenBandEqualizerPresets);
ListPreference listPreferenceEqualizerPreset = handler.findPreference(PREF_EARFUN_EQUALIZER_PRESET);
if (listPreferenceEqualizerPreset != null) {
listPreferenceEqualizerPreset.setValue(Integer.toString(equalizerPreset));
}
}
}
@Override
public void customizeSettings(DeviceSpecificSettingsHandler handler, Prefs prefs, String rootKey) {
super.customizeSettings(handler, prefs, rootKey);
initializeEqualizerPresetListPreference(handler, TenBandEqualizerPresets);
}
private void onPreferenceChangeAmbientSoundControl(DeviceSpecificSettingsHandler handler) {
ListPreference listPreferenceAmbientSound = handler.findPreference(PREF_EARFUN_AMBIENT_SOUND_CONTROL);
ListPreference listPreferenceTransparencyMode = handler.findPreference(PREF_EARFUN_TRANSPARENCY_MODE);
ListPreference listPreferenceAncMode = handler.findPreference(PREF_EARFUN_ANC_MODE);
if (listPreferenceAmbientSound == null || listPreferenceTransparencyMode == null || listPreferenceAncMode == null) {
return;
}
switch (listPreferenceAmbientSound.getValue()) {
case "1": // noise cancelling
listPreferenceTransparencyMode.setVisible(false);
listPreferenceAncMode.setVisible(true);
break;
case "2": // transparency
listPreferenceTransparencyMode.setVisible(true);
listPreferenceAncMode.setVisible(false);
break;
default:
listPreferenceTransparencyMode.setVisible(false);
listPreferenceAncMode.setVisible(false);
}
}
public EarFunFreePro3SettingsCustomizer(final GBDevice device) {
super(device);
}
}
+44
View File
@@ -4171,6 +4171,18 @@
<item>8</item> <item>8</item>
</string-array> </string-array>
<string-array name="earfun_free_pro_3_audio_codec_names">
<item>@string/pref_title_stable_connection</item>
<item>aptX</item>
<item>aptX Adaptive</item>
</string-array>
<string-array name="earfun_free_pro_3_audio_codec_values">
<item>0</item>
<item>1</item>
<item>3</item>
</string-array>
<string-array name="earfun_advanced_audio_mode_names"> <string-array name="earfun_advanced_audio_mode_names">
<item>Google Fast Pair</item> <item>Google Fast Pair</item>
<item>LE Audio</item> <item>LE Audio</item>
@@ -4251,6 +4263,38 @@
<item>13</item> <item>13</item>
</string-array> </string-array>
<string-array name="earfun_free_pro_3_tap_action_names">
<item>@string/none</item>
<item>@string/pref_media_volumeup</item>
<item>@string/pref_media_volumedown</item>
<item>@string/pref_media_next</item>
<item>@string/pref_media_previous</item>
<item>@string/pref_media_playpause</item>
<item>@string/prefs_game_mode</item>
<item>@string/pref_title_touch_voice_assistant</item>
<item>@string/earfun_tap_action_noise_control_all_modes</item>
<item>@string/earfun_tap_action_noise_control_normal_wind</item>
<item>@string/earfun_tap_action_noise_control_normal_ambient</item>
<item>@string/earfun_tap_action_noise_control_wind_ambient</item>
<item>@string/earfun_tap_action_redial</item>
</string-array>
<string-array name="earfun_free_pro_3_tap_action_values">
<item>16</item>
<item>2</item>
<item>3</item>
<item>5</item>
<item>4</item>
<item>1</item>
<item>7</item>
<item>6</item>
<item>8</item>
<item>9</item>
<item>10</item>
<item>11</item>
<item>13</item>
</string-array>
<string-array name="sony_ambient_sound_control_wind_noise_reduction_names"> <string-array name="sony_ambient_sound_control_wind_noise_reduction_names">
<item>@string/sony_ambient_sound_off</item> <item>@string/sony_ambient_sound_off</item>
<item>@string/sony_ambient_sound_noise_cancelling</item> <item>@string/sony_ambient_sound_noise_cancelling</item>
+1
View File
@@ -2281,6 +2281,7 @@
<string name="devicetype_bandw_pseries" translatable="false">Bowers and Wilkins P series</string> <string name="devicetype_bandw_pseries" translatable="false">Bowers and Wilkins P series</string>
<string name="devicetype_earfun_air_s" translatable="false">EarFun Air S</string> <string name="devicetype_earfun_air_s" translatable="false">EarFun Air S</string>
<string name="devicetype_earfun_air_pro_4" translatable="false">EarFun Air Pro 4</string> <string name="devicetype_earfun_air_pro_4" translatable="false">EarFun Air Pro 4</string>
<string name="devicetype_earfun_free_pro_3" translatable="false">EarFun Free Pro 3</string>
<string name="devicetype_atc_ble_oepl" translatable="false">ATC_BLE_OEPL</string> <string name="devicetype_atc_ble_oepl" translatable="false">ATC_BLE_OEPL</string>
<string name="devicetype_igpsport_bsc200" translatable="false">iGPSPORT BSC200</string> <string name="devicetype_igpsport_bsc200" translatable="false">iGPSPORT BSC200</string>
<string name="devicetype_igpsport_bsc200s" translatable="false">iGPSPORT BSC200S</string> <string name="devicetype_igpsport_bsc200s" translatable="false">iGPSPORT BSC200S</string>
@@ -0,0 +1,34 @@
<?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">
<SwitchPreferenceCompat
android:defaultValue="false"
android:icon="@drawable/ic_videogame"
android:key="pref_earfun_game_mode"
android:layout="@layout/preference_checkbox"
android:summary="@string/earfun_low_latency_mode_hint"
android:title="@string/earfun_low_latency_mode" />
<SwitchPreferenceCompat
android:defaultValue="false"
android:icon="@drawable/ic_bluetooth_searching"
android:key="pref_earfun_connect_two_devices"
android:layout="@layout/preference_checkbox"
android:summary="@string/earfun_connect_two_devices_hint"
android:title="@string/earfun_connect_two_devices" />
<ListPreference
android:defaultValue="0"
android:entries="@array/earfun_free_pro_3_audio_codec_names"
android:entryValues="@array/earfun_free_pro_3_audio_codec_values"
android:icon="@drawable/ic_equalizer"
android:key="pref_earfun_audio_codec"
app:useSimpleSummaryProvider="true"
android:title="@string/audio_codec" />
<Preference
android:key="pref_earfun_audio_codec_hint"
android:selectable="false"
android:summary="@string/earfun_audio_codec_hint" />
</androidx.preference.PreferenceScreen>
@@ -0,0 +1,100 @@
<?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">
<PreferenceScreen
android:icon="@drawable/ic_touch"
android:key="pref_screen_earfun_touch_options"
android:persistent="false"
android:title="@string/prefs_galaxy_touch_options">
<SwitchPreferenceCompat
android:defaultValue="false"
android:icon="@drawable/ic_hearing"
android:key="pref_earfun_touch_mode"
android:layout="@layout/preference_checkbox"
android:title="@string/prefs_touch_lock_buds2" />
<PreferenceCategory android:title="@string/single_tap">
<ListPreference
android:defaultValue="16"
android:dependency="pref_earfun_touch_mode"
android:entries="@array/earfun_free_pro_3_tap_action_names"
android:entryValues="@array/earfun_free_pro_3_tap_action_values"
android:icon="@drawable/ic_filter_1"
android:key="pref_earfun_single_tap_left_action"
app:useSimpleSummaryProvider="true"
android:title="@string/prefs_left" />
<ListPreference
android:defaultValue="16"
android:dependency="pref_earfun_touch_mode"
android:entries="@array/earfun_free_pro_3_tap_action_names"
android:entryValues="@array/earfun_free_pro_3_tap_action_values"
android:key="pref_earfun_single_tap_right_action"
app:useSimpleSummaryProvider="true"
android:title="@string/prefs_right" />
</PreferenceCategory>
<PreferenceCategory android:title="@string/double_tap">
<ListPreference
android:defaultValue="16"
android:dependency="pref_earfun_touch_mode"
android:entries="@array/earfun_free_pro_3_tap_action_names"
android:entryValues="@array/earfun_free_pro_3_tap_action_values"
android:icon="@drawable/ic_filter_2"
android:key="pref_earfun_double_tap_left_action"
app:useSimpleSummaryProvider="true"
android:title="@string/prefs_left" />
<ListPreference
android:defaultValue="16"
android:dependency="pref_earfun_touch_mode"
android:entries="@array/earfun_free_pro_3_tap_action_names"
android:entryValues="@array/earfun_free_pro_3_tap_action_values"
android:key="pref_earfun_double_tap_right_action"
app:useSimpleSummaryProvider="true"
android:title="@string/prefs_right" />
</PreferenceCategory>
<PreferenceCategory android:title="@string/triple_tap">
<ListPreference
android:defaultValue="16"
android:dependency="pref_earfun_touch_mode"
android:entries="@array/earfun_free_pro_3_tap_action_names"
android:entryValues="@array/earfun_free_pro_3_tap_action_values"
android:icon="@drawable/ic_filter_3"
android:key="pref_earfun_tripple_tap_left_action"
app:useSimpleSummaryProvider="true"
android:title="@string/prefs_left" />
<ListPreference
android:defaultValue="16"
android:dependency="pref_earfun_touch_mode"
android:entries="@array/earfun_free_pro_3_tap_action_names"
android:entryValues="@array/earfun_free_pro_3_tap_action_values"
android:key="pref_earfun_tripple_tap_right_action"
app:useSimpleSummaryProvider="true"
android:title="@string/prefs_right" />
</PreferenceCategory>
<PreferenceCategory android:title="@string/long_press">
<ListPreference
android:defaultValue="16"
android:dependency="pref_earfun_touch_mode"
android:entries="@array/earfun_free_pro_3_tap_action_names"
android:entryValues="@array/earfun_free_pro_3_tap_action_values"
android:icon="@drawable/ic_touch"
android:key="pref_earfun_long_tap_left_action"
app:useSimpleSummaryProvider="true"
android:title="@string/prefs_left" />
<ListPreference
android:defaultValue="16"
android:dependency="pref_earfun_touch_mode"
android:entries="@array/earfun_free_pro_3_tap_action_names"
android:entryValues="@array/earfun_free_pro_3_tap_action_values"
android:key="pref_earfun_long_tap_right_action"
app:useSimpleSummaryProvider="true"
android:title="@string/prefs_right" />
</PreferenceCategory>
</PreferenceScreen>
</androidx.preference.PreferenceScreen>
@@ -0,0 +1,54 @@
<?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">
<ListPreference
android:defaultValue="0"
android:entries="@array/earfun_ambient_sound_control_names"
android:entryValues="@array/earfun_ambient_sound_control_values"
android:icon="@drawable/ic_hearing"
android:key="pref_earfun_ambient_sound_control"
app:useSimpleSummaryProvider="true"
android:title="@string/pref_header_sony_ambient_sound_control" />
<ListPreference
android:defaultValue="0"
android:entries="@array/earfun_transparency_mode_names"
android:entryValues="@array/earfun_transparency_mode_values"
android:icon="@drawable/ic_hearing"
android:key="pref_earfun_transparency_mode"
app:useSimpleSummaryProvider="true"
android:title="@string/earfun_transparency_mode" />
<ListPreference
android:defaultValue="0"
android:entries="@array/earfun_anc_mode_names"
android:entryValues="@array/earfun_anc_mode_values"
android:icon="@drawable/ic_hearing"
android:key="pref_earfun_anc_mode"
app:useSimpleSummaryProvider="true"
android:title="@string/earfun_anc_mode" />
<ListPreference
android:defaultValue="0"
android:entries="@array/earfun_microphone_mode_names"
android:entryValues="@array/earfun_microphone_mode_values"
android:icon="@drawable/ic_microphone"
android:key="pref_earfun_microphone_mode"
app:useSimpleSummaryProvider="true"
android:title="@string/earfun_microphone_mode" />
<Preference
android:key="pref_earfun_microphone_mode_hint"
android:selectable="false"
android:summary="@string/earfun_microphone_mode_hint" />
<SeekBarPreference
android:defaultValue="0"
android:icon="@drawable/ic_volume_up"
android:key="pref_earfun_voice_prompt_volume"
android:max="4"
android:title="@string/earfun_voice_prompt_volume"
app:min="0"
app:showSeekBarValue="true" />
</androidx.preference.PreferenceScreen>