mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge.git
synced 2026-07-31 07:44:24 +02:00
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:
+120
@@ -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),
|
||||||
|
|||||||
+27
@@ -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());
|
||||||
|
}
|
||||||
|
}
|
||||||
+64
@@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
+95
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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>
|
||||||
|
|||||||
@@ -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>
|
||||||
Reference in New Issue
Block a user