mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge.git
synced 2026-07-31 07:44:24 +02:00
1MORE SonoFlow: Initial support (#4637)
Co-authored-by: pacjo <kamil.kroliczek2004@gmail.com> Co-committed-by: pacjo <kamil.kroliczek2004@gmail.com>
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<SwitchPreferenceCompat
|
||||
android:defaultValue="false"
|
||||
android:icon="@drawable/ic_devices_other"
|
||||
android:key="dual_device_support"
|
||||
android:layout="@layout/preference_checkbox"
|
||||
android:title="@string/dual_device_mode_title"
|
||||
android:summary="@string/dual_device_mode_summary" />
|
||||
</androidx.preference.PreferenceScreen>
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<SwitchPreferenceCompat
|
||||
android:defaultValue="false"
|
||||
android:icon="@drawable/ic_music_note"
|
||||
android:key="pref_soundcore_ldac_mode"
|
||||
android:layout="@layout/preference_checkbox"
|
||||
android:title="@string/soundcore_ldac_mode_title"
|
||||
android:summary="@string/soundcore_ldac_mode_summary" />
|
||||
</androidx.preference.PreferenceScreen>
|
||||
+3
@@ -107,6 +107,7 @@ public class DeviceSettingsPreferenceConst {
|
||||
public static final String PREF_DEVICE_INTENTS = "device_intents";
|
||||
|
||||
public static final String PREF_ACTIVE_NOISE_CANCELLING_TOGGLE = "active_noise_cancelling_toggle";
|
||||
public static final String PREF_NOISE_CONTROL_SELECTOR = "noise_control_selector";
|
||||
public static final String PREF_WEAR_SENSOR_TOGGLE = "wear_sensor_toggle";
|
||||
public static final String PREF_BANDW_PSERIES_VPT_ENABLED = "bandw_pseries_vpt_enabled";
|
||||
public static final String PREF_BANDW_PSERIES_VPT_LEVEL = "bandw_pseries_vpt_level";
|
||||
@@ -520,6 +521,8 @@ public class DeviceSettingsPreferenceConst {
|
||||
|
||||
public static final String PREF_QC35_NOISE_CANCELLING_LEVEL = "qc35_noise_cancelling_level";
|
||||
|
||||
public static final String PREF_DUAL_DEVICE_SUPPORT = "dual_device_support";
|
||||
|
||||
public static final String PREFS_ACTIVITY_IN_DEVICE_CARD = "prefs_activity_in_device_card";
|
||||
public static final String PREFS_ACTIVITY_IN_DEVICE_CARD_STEPS = "prefs_activity_in_device_card_steps";
|
||||
public static final String PREFS_ACTIVITY_IN_DEVICE_CARD_SLEEP = "prefs_activity_in_device_card_sleep";
|
||||
|
||||
+4
@@ -614,6 +614,7 @@ public class DeviceSpecificSettingsFragment extends AbstractPreferenceFragment i
|
||||
addPreferenceHandlerFor(PREF_SLEEP_MODE_SMART_ENABLE);
|
||||
|
||||
addPreferenceHandlerFor(PREF_ACTIVE_NOISE_CANCELLING_TOGGLE);
|
||||
addPreferenceHandlerFor(PREF_NOISE_CONTROL_SELECTOR);
|
||||
addPreferenceHandlerFor(PREF_WEAR_SENSOR_TOGGLE);
|
||||
addPreferenceHandlerFor(PREF_BANDW_PSERIES_GUI_VPT_LEVEL);
|
||||
|
||||
@@ -816,6 +817,9 @@ public class DeviceSpecificSettingsFragment extends AbstractPreferenceFragment i
|
||||
addPreferenceHandlerFor(PREF_FEMOMETER_MEASUREMENT_MODE);
|
||||
|
||||
addPreferenceHandlerFor(PREF_QC35_NOISE_CANCELLING_LEVEL);
|
||||
|
||||
addPreferenceHandlerFor(PREF_DUAL_DEVICE_SUPPORT);
|
||||
|
||||
addPreferenceHandlerFor(PREF_USER_FITNESS_GOAL);
|
||||
addPreferenceHandlerFor(PREF_USER_FITNESS_GOAL_NOTIFICATION);
|
||||
addPreferenceHandlerFor(PREF_USER_FITNESS_GOAL_SECONDARY);
|
||||
|
||||
+96
@@ -0,0 +1,96 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.devices.onemoresonoflow;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBException;
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpecificSettings;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpecificSettingsScreen;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.AbstractDeviceCoordinator;
|
||||
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.onemore_sonoflow.OneMoreSonoFlowSupport;
|
||||
|
||||
public class OneMoreSonoFlowCoordinator extends AbstractDeviceCoordinator {
|
||||
|
||||
@Override
|
||||
protected void deleteDevice(@NonNull GBDevice gbDevice, @NonNull Device device, @NonNull DaoSession session) throws GBException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Pattern getSupportedDeviceName() {
|
||||
return Pattern.compile("1MORE SonoFlow");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getManufacturer() {
|
||||
return "1MORE";
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Class<? extends DeviceSupport> getDeviceSupportClass() {
|
||||
return OneMoreSonoFlowSupport.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDeviceNameResource() {
|
||||
return R.string.devicetype_onemore_sonoflow;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BatteryConfig[] getBatteryConfig(final GBDevice device) {
|
||||
return new BatteryConfig[] {
|
||||
new BatteryConfig(
|
||||
0,
|
||||
GBDevice.BATTERY_ICON_DEFAULT,
|
||||
GBDevice.BATTERY_LABEL_DEFAULT,
|
||||
20,
|
||||
100
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public DeviceSpecificSettings getDeviceSpecificSettings(final GBDevice device) {
|
||||
final DeviceSpecificSettings settings = new DeviceSpecificSettings();
|
||||
|
||||
settings.addRootScreen(DeviceSpecificSettingsScreen.SOUND);
|
||||
settings.addSubScreen(
|
||||
DeviceSpecificSettingsScreen.SOUND,
|
||||
R.xml.devicesettings_onemore_noise_control_selector
|
||||
);
|
||||
settings.addSubScreen(
|
||||
DeviceSpecificSettingsScreen.SOUND,
|
||||
R.xml.devicesettings_ldac_toggle
|
||||
);
|
||||
settings.addRootScreen(
|
||||
DeviceSpecificSettingsScreen.CONNECTION,
|
||||
R.xml.devicesettings_dual_device_toggle
|
||||
);
|
||||
|
||||
settings.addRootScreen(DeviceSpecificSettingsScreen.CALLS_AND_NOTIFICATIONS);
|
||||
settings.addSubScreen(
|
||||
DeviceSpecificSettingsScreen.CALLS_AND_NOTIFICATIONS,
|
||||
R.xml.devicesettings_headphones
|
||||
);
|
||||
|
||||
return settings;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDefaultIconResource() {
|
||||
return R.drawable.ic_device_headphones;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDisabledIconResource() {
|
||||
return R.drawable.ic_device_headphones_disabled;
|
||||
}
|
||||
}
|
||||
@@ -29,6 +29,7 @@ package nodomain.freeyourgadget.gadgetbridge.model;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.DeviceCoordinator;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.UnknownDeviceCoordinator;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.onemoresonoflow.OneMoreSonoFlowCoordinator;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.asteroidos.AsteroidOSDeviceCoordinator;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.bandwpseries.BandWPSeriesDeviceCoordinator;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.banglejs.BangleJSCoordinator;
|
||||
@@ -563,6 +564,7 @@ public enum DeviceType {
|
||||
SOUNDCORE_Q30(SoundcoreQ30Coordinator.class),
|
||||
MOONDROP_SPACE_TRAVEL(MoondropSpaceTravelCoordinator.class),
|
||||
BOSE_QC35(QC35Coordinator.class),
|
||||
ONEMORE_SONOFLOW(OneMoreSonoFlowCoordinator.class),
|
||||
HONORBAND3(HonorBand3Coordinator.class),
|
||||
HONORBAND4(HonorBand4Coordinator.class),
|
||||
HONORBAND5(HonorBand5Coordinator.class),
|
||||
|
||||
+129
@@ -0,0 +1,129 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.onemore_sonoflow;
|
||||
|
||||
public class OneMorePacket {
|
||||
|
||||
// sent from phone
|
||||
public static final byte[] REQUEST_PREAMBLE = { 0x11, 0x01, 0x00 };
|
||||
|
||||
// sent from headphones
|
||||
public static final byte[] RESPONSE_PREAMBLE = { 0x01, 0x01, 0x00 };
|
||||
|
||||
// battery and firmware version (maybe more?)
|
||||
public static final byte GET_DEVICE_INFO_COMMAND = 0x4e;
|
||||
|
||||
public static final byte GET_NOISE_CONTROL_COMMAND = 0x5f;
|
||||
public static final byte SET_NOISE_CONTROL_COMMAND = 0x5e;
|
||||
|
||||
public static final byte GET_LDAC_COMMAND = 0x6c;
|
||||
public static final byte SET_LDAC_COMMAND = 0x6b;
|
||||
|
||||
public static final byte GET_DUAL_DEVICE_COMMAND = 0x77;
|
||||
public static final byte SET_DUAL_DEVICE_COMMAND = 0x76;
|
||||
|
||||
// TODO:
|
||||
// - figure out flags
|
||||
// - figure out checksums
|
||||
|
||||
public static byte[] createGetDeviceInfoPacket() {
|
||||
byte[] flags = { 0x00, 0x00, 0x00 };
|
||||
byte[] checksum = { 0x1c, 0x42 };
|
||||
|
||||
return concat(REQUEST_PREAMBLE, GET_DEVICE_INFO_COMMAND, flags, checksum);
|
||||
}
|
||||
|
||||
public static byte[] createGetNoiseControlModePacket() {
|
||||
byte[] flags = { 0x00, 0x00, 0x00 };
|
||||
byte[] checksum = { 0x0c, 0x43 };
|
||||
|
||||
return concat(REQUEST_PREAMBLE, GET_NOISE_CONTROL_COMMAND, flags, checksum);
|
||||
}
|
||||
|
||||
public static byte[] createSetNoiseControlModePacket(String mode) {
|
||||
byte[] flags = { 0x00, 0x01, 0x00 };
|
||||
byte[] checksum = { 0x13, 0x5c };
|
||||
|
||||
byte modeByte;
|
||||
switch (mode) {
|
||||
case "0":
|
||||
// Off
|
||||
modeByte = 0x00;
|
||||
break;
|
||||
case "1":
|
||||
// ANC
|
||||
modeByte = 0x01;
|
||||
break;
|
||||
case "2":
|
||||
// Pass-through
|
||||
modeByte = 0x03;
|
||||
break;
|
||||
default:
|
||||
throw new IllegalStateException("mode not one of the allowed values: [\"0\", \"1\", \"2\"]");
|
||||
}
|
||||
|
||||
return concat(REQUEST_PREAMBLE, SET_NOISE_CONTROL_COMMAND, flags, checksum, modeByte);
|
||||
}
|
||||
|
||||
public static byte[] createGetLdacModePacket() {
|
||||
byte[] flags = { 0x00, 0x00, 0x00 };
|
||||
byte[] checksum = { 0x0d, 0x71 };
|
||||
|
||||
return concat(REQUEST_PREAMBLE, GET_LDAC_COMMAND, flags, checksum);
|
||||
}
|
||||
|
||||
public static byte[] createSetLdacModePacket(boolean enabled) {
|
||||
byte[] flags = { 0x00, 0x01, 0x00 };
|
||||
byte[] checksum = { 0x2d, 0x57 };
|
||||
|
||||
byte modeByte = (byte) (enabled ? 0x02 : 0x00);
|
||||
|
||||
return concat(REQUEST_PREAMBLE, SET_LDAC_COMMAND, flags, checksum, modeByte);
|
||||
}
|
||||
|
||||
public static byte[] createGetDualDeviceModePacket() {
|
||||
byte[] flags = { 0x00, 0x00, 0x00 };
|
||||
byte[] checksum = { 0x0c, 0x6b };
|
||||
|
||||
return concat(REQUEST_PREAMBLE, GET_DUAL_DEVICE_COMMAND, flags, checksum);
|
||||
}
|
||||
|
||||
public static byte[] createSetDualDeviceModePacket(boolean enabled) {
|
||||
byte[] flags = { 0x00, 0x01, 0x00 };
|
||||
byte[] checksum = { 0x0d, 0x6a };
|
||||
|
||||
byte modeByte = (byte) (enabled ? 0x01 : 0x00);
|
||||
|
||||
return concat(REQUEST_PREAMBLE, SET_DUAL_DEVICE_COMMAND, flags, checksum, modeByte);
|
||||
}
|
||||
|
||||
private static byte[] concat(Object... args) {
|
||||
if (args == null || args.length == 0) {
|
||||
return new byte[0];
|
||||
}
|
||||
|
||||
int totalLength = 0;
|
||||
for (Object arg : args) {
|
||||
if (arg instanceof byte[]) {
|
||||
totalLength += ((byte[]) arg).length;
|
||||
} else if (arg instanceof Byte) {
|
||||
totalLength++;
|
||||
} else {
|
||||
throw new IllegalArgumentException("Invalid argument type: " + arg.getClass().getName() + ". Expected byte[] or Byte.");
|
||||
}
|
||||
}
|
||||
|
||||
byte[] result = new byte[totalLength];
|
||||
int offset = 0;
|
||||
|
||||
for (Object arg : args) {
|
||||
if (arg instanceof byte[]) {
|
||||
byte[] byteArray = (byte[]) arg;
|
||||
System.arraycopy(byteArray, 0, result, offset, byteArray.length);
|
||||
offset += byteArray.length;
|
||||
} else if (arg instanceof Byte) {
|
||||
result[offset++] = (Byte) arg;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.onemore_sonoflow;
|
||||
|
||||
import static nodomain.freeyourgadget.gadgetbridge.util.GB.hexdump;
|
||||
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.content.Context;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Arrays;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btclassic.BtClassicIoThread;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.serial.AbstractSerialDeviceSupport;
|
||||
|
||||
public class OneMoreSonoFlowIOThread extends BtClassicIoThread {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(OneMoreSonoFlowIOThread.class);
|
||||
|
||||
public OneMoreSonoFlowIOThread(
|
||||
GBDevice gbDevice,
|
||||
Context context,
|
||||
OneMoreSonoFlowProtocol deviceProtocol,
|
||||
AbstractSerialDeviceSupport deviceSupport,
|
||||
BluetoothAdapter btAdapter
|
||||
) {
|
||||
super(gbDevice, context, deviceProtocol, deviceSupport, btAdapter);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initialize() {
|
||||
super.initialize();
|
||||
|
||||
// get some device information
|
||||
// TODO: we might not receive some responses, it might be worth requesting them again if that's a significant issue
|
||||
// https://codeberg.org/Freeyourgadget/Gadgetbridge/pulls/4637#issuecomment-3035556
|
||||
write(OneMorePacket.createGetDeviceInfoPacket());
|
||||
write(OneMorePacket.createGetNoiseControlModePacket());
|
||||
write(OneMorePacket.createGetLdacModePacket());
|
||||
write(OneMorePacket.createGetDualDeviceModePacket());
|
||||
|
||||
setUpdateState(GBDevice.State.INITIALIZED);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected byte[] parseIncoming(InputStream stream) throws IOException {
|
||||
byte[] buffer = new byte[1048576]; // big value
|
||||
int bytes = stream.read(buffer);
|
||||
LOG.debug("read {} bytes. {}", bytes, hexdump(buffer, 0, bytes));
|
||||
|
||||
return Arrays.copyOf(buffer, bytes);
|
||||
}
|
||||
}
|
||||
+163
@@ -0,0 +1,163 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.onemore_sonoflow;
|
||||
|
||||
import static nodomain.freeyourgadget.gadgetbridge.util.ArrayUtils.startsWith;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.SharedPreferences;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst;
|
||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent;
|
||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventBatteryInfo;
|
||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventUpdatePreferences;
|
||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventVersionInfo;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.serial.GBDeviceProtocol;
|
||||
|
||||
public class OneMoreSonoFlowProtocol extends GBDeviceProtocol {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(OneMoreSonoFlowProtocol.class);
|
||||
|
||||
protected OneMoreSonoFlowProtocol(GBDevice device) {
|
||||
super(device);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] encodeSendConfiguration(String config) {
|
||||
SharedPreferences prefs = GBApplication.getDeviceSpecificSharedPrefs(getDevice().getAddress());
|
||||
|
||||
switch (config) {
|
||||
case DeviceSettingsPreferenceConst.PREF_NOISE_CONTROL_SELECTOR:
|
||||
return OneMorePacket.createSetNoiseControlModePacket(prefs.getString(config, "0"));
|
||||
|
||||
case DeviceSettingsPreferenceConst.PREF_SOUNDCORE_LDAC_MODE:
|
||||
return OneMorePacket.createSetLdacModePacket(prefs.getBoolean(config, false));
|
||||
|
||||
case DeviceSettingsPreferenceConst.PREF_DUAL_DEVICE_SUPPORT:
|
||||
return OneMorePacket.createSetDualDeviceModePacket(prefs.getBoolean(config, false));
|
||||
}
|
||||
|
||||
return super.encodeSendConfiguration(config);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GBDeviceEvent[] decodeResponse(byte[] responseData) {
|
||||
LOG.debug("decodeResponse: got: {}", Arrays.toString(responseData));
|
||||
|
||||
List<GBDeviceEvent> events = new ArrayList<>();
|
||||
ByteBuffer buffer = ByteBuffer.wrap(responseData);
|
||||
buffer.order(ByteOrder.BIG_ENDIAN);
|
||||
|
||||
while (buffer.position() < buffer.limit()) {
|
||||
if (!startsWith(buffer.array(), OneMorePacket.RESPONSE_PREAMBLE)) {
|
||||
LOG.warn("Unknown preamble, skipping byte");
|
||||
|
||||
// skip a byte and try again
|
||||
buffer.position(buffer.position() + 1);
|
||||
continue;
|
||||
}
|
||||
|
||||
LOG.debug("Preamble found, processing packet");
|
||||
|
||||
// skip too short packets (shortest recorded packet has 10 bytes)
|
||||
if (buffer.remaining() < 10) {
|
||||
LOG.warn("Incomplete packet (less than 10 bytes remaining), ignoring");
|
||||
break;
|
||||
}
|
||||
|
||||
byte command = buffer.get(buffer.position() + 3);
|
||||
if (buffer.remaining() >= 6 && command == OneMorePacket.GET_NOISE_CONTROL_COMMAND) {
|
||||
LOG.debug("Handling noise control packet");
|
||||
|
||||
events.add(decodeNoiseControlMode(buffer.get(9)));
|
||||
buffer.position(buffer.position() + 10);
|
||||
} else if (buffer.remaining() >= 6 && command == OneMorePacket.GET_LDAC_COMMAND) {
|
||||
LOG.debug("Handling LDAC packet");
|
||||
|
||||
events.add(decodeLdacMode(buffer.get(9)));
|
||||
buffer.position(buffer.position() + 10);
|
||||
} else if (buffer.remaining() >= 6 && command == OneMorePacket.GET_DUAL_DEVICE_COMMAND) {
|
||||
LOG.debug("Handling dual device packet");
|
||||
|
||||
events.add(decodeDualDeviceMode(buffer.get(9)));
|
||||
buffer.position(buffer.position() + 10);
|
||||
} else if (buffer.remaining() >= 10 && command == OneMorePacket.GET_DEVICE_INFO_COMMAND) {
|
||||
LOG.debug("Handling battery info packet");
|
||||
|
||||
events.add(decodeBatteryInfo(buffer.get(13)));
|
||||
events.add(decodeFirmwareInformation(buffer.get(10), buffer.get(11), buffer.get(12)));
|
||||
|
||||
buffer.position(buffer.position() + 19);
|
||||
} else {
|
||||
LOG.debug("Unknown packet command: 0x{} with buffer: {}, starting at: {}, ignoring packet", Integer.toHexString(command), Arrays.toString(buffer.array()), buffer.position());
|
||||
|
||||
// skip a byte and try again
|
||||
buffer.position(buffer.position() + 1);
|
||||
}
|
||||
}
|
||||
|
||||
return events.toArray(new GBDeviceEvent[0]);
|
||||
}
|
||||
|
||||
private GBDeviceEventUpdatePreferences decodeNoiseControlMode(byte value) {
|
||||
GBDeviceEventUpdatePreferences event = new GBDeviceEventUpdatePreferences();
|
||||
String mode = "0";
|
||||
|
||||
switch (value) {
|
||||
case 0x00:
|
||||
mode = "0";
|
||||
break;
|
||||
case 0x01:
|
||||
mode = "1";
|
||||
break;
|
||||
case 0x03:
|
||||
mode = "2";
|
||||
break;
|
||||
}
|
||||
|
||||
event.withPreference(DeviceSettingsPreferenceConst.PREF_NOISE_CONTROL_SELECTOR, mode);
|
||||
|
||||
return event;
|
||||
}
|
||||
|
||||
private GBDeviceEventUpdatePreferences decodeLdacMode(byte value) {
|
||||
GBDeviceEventUpdatePreferences event = new GBDeviceEventUpdatePreferences();
|
||||
boolean enabled = value == 0x02;
|
||||
|
||||
event.withPreference(DeviceSettingsPreferenceConst.PREF_SOUNDCORE_LDAC_MODE, enabled);
|
||||
|
||||
return event;
|
||||
}
|
||||
|
||||
private GBDeviceEventUpdatePreferences decodeDualDeviceMode(byte value) {
|
||||
GBDeviceEventUpdatePreferences event = new GBDeviceEventUpdatePreferences();
|
||||
boolean enabled = value == 0x01;
|
||||
|
||||
event.withPreference(DeviceSettingsPreferenceConst.PREF_DUAL_DEVICE_SUPPORT, enabled);
|
||||
|
||||
return event;
|
||||
}
|
||||
|
||||
@SuppressLint("DefaultLocale")
|
||||
private GBDeviceEventVersionInfo decodeFirmwareInformation(byte major, byte minor, byte patch) {
|
||||
GBDeviceEventVersionInfo event = new GBDeviceEventVersionInfo();
|
||||
event.fwVersion = String.format("%d.%d.%d", major, minor, patch);;
|
||||
|
||||
return event;
|
||||
}
|
||||
|
||||
private GBDeviceEventBatteryInfo decodeBatteryInfo(byte value) {
|
||||
GBDeviceEventBatteryInfo event = new GBDeviceEventBatteryInfo();
|
||||
event.level = value;
|
||||
|
||||
return event;
|
||||
}
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.onemore_sonoflow;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.AbstractHeadphoneDeviceSupport;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.serial.GBDeviceIoThread;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.serial.GBDeviceProtocol;
|
||||
|
||||
public class OneMoreSonoFlowSupport extends AbstractHeadphoneDeviceSupport {
|
||||
@Override
|
||||
protected GBDeviceProtocol createDeviceProtocol() {
|
||||
return new OneMoreSonoFlowProtocol(getDevice());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected GBDeviceIoThread createDeviceIOThread() {
|
||||
return new OneMoreSonoFlowIOThread(
|
||||
getDevice(),
|
||||
getContext(),
|
||||
(OneMoreSonoFlowProtocol) getDeviceProtocol(),
|
||||
OneMoreSonoFlowSupport.this,
|
||||
getBluetoothAdapter()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean useAutoConnect() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -3397,6 +3397,18 @@
|
||||
<item>3</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="onemore_noise_control_modes">
|
||||
<item>@string/off</item>
|
||||
<item>@string/prefs_active_noise_cancelling</item>
|
||||
<item>@string/prefs_active_noise_cancelling_transparency</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="onemore_noise_control_values">
|
||||
<item>0</item>
|
||||
<item>1</item>
|
||||
<item>2</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="redmi_buds_3_pro_equalizer_presets_names">
|
||||
<item>@string/redmi_buds_5_pro_equalizer_preset_standard</item>
|
||||
<item>@string/redmi_buds_5_pro_equalizer_preset_treble</item>
|
||||
|
||||
@@ -2979,6 +2979,7 @@
|
||||
<string name="qhybrid_summary_on_device_confirmation">On-device pairing confirmations can get annoying. Disabling them might lose you functionality.</string>
|
||||
<string name="devicetype_vesc">VESC</string>
|
||||
<string name="devicetype_bose_qc35">Bose QC35</string>
|
||||
<string name="devicetype_onemore_sonoflow">1MORE SonoFlow</string>
|
||||
<string name="devicetype_sony_wena3">Sony Wena 3</string>
|
||||
<string name="withings_steel_hr">Withings Steel HR</string>
|
||||
<string name="pref_button_action_disabled">Disabled</string>
|
||||
@@ -3242,6 +3243,9 @@
|
||||
<string name="purple">Purple</string>
|
||||
<string name="white">White</string>
|
||||
|
||||
<string name="dual_device_mode_title">Dual device mode</string>
|
||||
<string name="dual_device_mode_summary">Allow connecting headphones to two devices simultaneously</string>
|
||||
|
||||
<string name="prefs_wena3_title_screen">Display Settings</string>
|
||||
<string name="prefs_wena3_title_activity">Activity Settings</string>
|
||||
<string name="prefs_wena3_item_background_sync">Background Activity Data Sync</string>
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<ListPreference
|
||||
android:defaultValue="0"
|
||||
android:entries="@array/onemore_noise_control_modes"
|
||||
android:entryValues="@array/onemore_noise_control_values"
|
||||
android:icon="@drawable/ic_surround"
|
||||
android:key="noise_control_selector"
|
||||
android:summary="%s"
|
||||
android:title="@string/prefs_noise_control" />
|
||||
</androidx.preference.PreferenceScreen>
|
||||
Reference in New Issue
Block a user