1
0
mirror of https://codeberg.org/Freeyourgadget/Gadgetbridge synced 2024-08-24 00:00:47 +02:00

Sony Headphones: Implement Noise Cancelling Optimizer

This commit is contained in:
José Rebelo 2022-01-14 23:50:00 +00:00 committed by Gitea
parent e50fa36632
commit d0f80eb5b4
15 changed files with 319 additions and 118 deletions

View File

@ -121,6 +121,10 @@ public class DeviceSettingsPreferenceConst {
public static final String PREF_SONY_AMBIENT_SOUND_CONTROL = "pref_sony_ambient_sound_control";
public static final String PREF_SONY_FOCUS_VOICE = "pref_sony_focus_voice";
public static final String PREF_SONY_AMBIENT_SOUND_LEVEL = "pref_sony_ambient_sound_level";
public static final String PREF_SONY_NOISE_OPTIMIZER_START = "pref_sony_noise_optimizer_start";
public static final String PREF_SONY_NOISE_OPTIMIZER_CANCEL = "pref_sony_noise_optimizer_cancel";
public static final String PREF_SONY_NOISE_OPTIMIZER_STATUS = "pref_sony_noise_optimizer_status";
public static final String PREF_SONY_NOISE_OPTIMIZER_STATE_PRESSURE = "pref_sony_noise_optimizer_state_pressure";
public static final String PREF_SONY_SOUND_POSITION = "pref_sony_sound_position";
public static final String PREF_SONY_SURROUND_MODE = "pref_sony_surround_mode";
public static final String PREF_SONY_EQUALIZER = "pref_sony_equalizer";

View File

@ -195,6 +195,19 @@ public class DeviceSpecificSettingsFragment extends PreferenceFragmentCompat imp
getListView().post(runnable);
}
/*
* delayed execution so that the preferences are applied first
*/
@Override
public void notifyPreferenceChanged(final String preferenceKey) {
invokeLater(new Runnable() {
@Override
public void run() {
GBApplication.deviceService().onSendConfiguration(preferenceKey);
}
});
}
private void setChangeListener() {
final Prefs prefs = new Prefs(getPreferenceManager().getSharedPreferences());
String disconnectNotificationState = prefs.getString(PREF_DISCONNECT_NOTIFICATION, PREF_DO_NOT_DISTURB_OFF);
@ -206,12 +219,7 @@ public class DeviceSpecificSettingsFragment extends PreferenceFragmentCompat imp
disconnectNotificationStart.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newVal) {
invokeLater(new Runnable() {
@Override
public void run() {
GBApplication.deviceService().onSendConfiguration(PREF_DISCONNECT_NOTIFICATION_START);
}
});
notifyPreferenceChanged(PREF_DISCONNECT_NOTIFICATION_START);
return true;
}
});
@ -223,12 +231,7 @@ public class DeviceSpecificSettingsFragment extends PreferenceFragmentCompat imp
disconnectNotificationEnd.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newVal) {
invokeLater(new Runnable() {
@Override
public void run() {
GBApplication.deviceService().onSendConfiguration(PREF_DISCONNECT_NOTIFICATION_END);
}
});
notifyPreferenceChanged(PREF_DISCONNECT_NOTIFICATION_END);
return true;
}
});
@ -243,12 +246,7 @@ public class DeviceSpecificSettingsFragment extends PreferenceFragmentCompat imp
Objects.requireNonNull(disconnectNotificationStart).setEnabled(scheduled);
Objects.requireNonNull(disconnectNotificationEnd).setEnabled(scheduled);
invokeLater(new Runnable() {
@Override
public void run() {
GBApplication.deviceService().onSendConfiguration(PREF_DISCONNECT_NOTIFICATION);
}
});
notifyPreferenceChanged(PREF_DISCONNECT_NOTIFICATION);
return true;
}
});
@ -264,12 +262,7 @@ public class DeviceSpecificSettingsFragment extends PreferenceFragmentCompat imp
nightModeStart.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newVal) {
invokeLater(new Runnable() {
@Override
public void run() {
GBApplication.deviceService().onSendConfiguration(PREF_NIGHT_MODE_START);
}
});
notifyPreferenceChanged(PREF_NIGHT_MODE_START);
return true;
}
});
@ -281,12 +274,7 @@ public class DeviceSpecificSettingsFragment extends PreferenceFragmentCompat imp
nightModeEnd.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newVal) {
invokeLater(new Runnable() {
@Override
public void run() {
GBApplication.deviceService().onSendConfiguration(PREF_NIGHT_MODE_END);
}
});
notifyPreferenceChanged(PREF_NIGHT_MODE_END);
return true;
}
});
@ -303,12 +291,7 @@ public class DeviceSpecificSettingsFragment extends PreferenceFragmentCompat imp
Objects.requireNonNull(nightModeStart).setEnabled(scheduled);
Objects.requireNonNull(nightModeEnd).setEnabled(scheduled);
invokeLater(new Runnable() {
@Override
public void run() {
GBApplication.deviceService().onSendConfiguration(PREF_NIGHT_MODE);
}
});
notifyPreferenceChanged(PREF_NIGHT_MODE);
return true;
}
});
@ -324,12 +307,7 @@ public class DeviceSpecificSettingsFragment extends PreferenceFragmentCompat imp
doNotDisturbStart.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newVal) {
invokeLater(new Runnable() {
@Override
public void run() {
GBApplication.deviceService().onSendConfiguration(PREF_DO_NOT_DISTURB_START);
}
});
notifyPreferenceChanged(PREF_DO_NOT_DISTURB_START);
return true;
}
});
@ -341,12 +319,7 @@ public class DeviceSpecificSettingsFragment extends PreferenceFragmentCompat imp
doNotDisturbEnd.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newVal) {
invokeLater(new Runnable() {
@Override
public void run() {
GBApplication.deviceService().onSendConfiguration(PREF_DO_NOT_DISTURB_END);
}
});
notifyPreferenceChanged(PREF_DO_NOT_DISTURB_END);
return true;
}
});
@ -362,12 +335,7 @@ public class DeviceSpecificSettingsFragment extends PreferenceFragmentCompat imp
Objects.requireNonNull(doNotDisturbStart).setEnabled(scheduled);
Objects.requireNonNull(doNotDisturbEnd).setEnabled(scheduled);
invokeLater(new Runnable() {
@Override
public void run() {
GBApplication.deviceService().onSendConfiguration(PREF_DO_NOT_DISTURB);
}
});
notifyPreferenceChanged(PREF_DO_NOT_DISTURB);
return true;
}
});
@ -495,12 +463,7 @@ public class DeviceSpecificSettingsFragment extends PreferenceFragmentCompat imp
sleepTimeInfo.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newVal) {
invokeLater(new Runnable() {
@Override
public void run() {
GBApplication.deviceService().onSendConfiguration(PREF_SLEEP_TIME);
}
});
notifyPreferenceChanged(PREF_SLEEP_TIME);
return true;
}
});
@ -512,12 +475,7 @@ public class DeviceSpecificSettingsFragment extends PreferenceFragmentCompat imp
sleepTimeStart.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newVal) {
invokeLater(new Runnable() {
@Override
public void run() {
GBApplication.deviceService().onSendConfiguration(PREF_SLEEP_TIME_START);
}
});
notifyPreferenceChanged(PREF_SLEEP_TIME_START);
return true;
}
});
@ -529,12 +487,7 @@ public class DeviceSpecificSettingsFragment extends PreferenceFragmentCompat imp
sleepTimeEnd.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newVal) {
invokeLater(new Runnable() {
@Override
public void run() {
GBApplication.deviceService().onSendConfiguration(PREF_SLEEP_TIME_END);
}
});
notifyPreferenceChanged(PREF_SLEEP_TIME_END);
return true;
}
});
@ -551,12 +504,7 @@ public class DeviceSpecificSettingsFragment extends PreferenceFragmentCompat imp
if (sleepTimeInfo != null) {
//sleepTimeInfo.setEnabled(!PREF_DO_NOT_DISTURB_OFF.equals(newVal.toString()));
}
invokeLater(new Runnable() {
@Override
public void run() {
GBApplication.deviceService().onSendConfiguration(PREF_SLEEP_TIME);
}
});
notifyPreferenceChanged(PREF_SLEEP_TIME);
return true;
}
});
@ -570,12 +518,7 @@ public class DeviceSpecificSettingsFragment extends PreferenceFragmentCompat imp
rotateWristCycleInfo.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newVal) {
invokeLater(new Runnable() {
@Override
public void run() {
GBApplication.deviceService().onSendConfiguration(PREF_MI2_ROTATE_WRIST_TO_SWITCH_INFO);
}
});
notifyPreferenceChanged(PREF_MI2_ROTATE_WRIST_TO_SWITCH_INFO);
return true;
}
});
@ -587,12 +530,7 @@ public class DeviceSpecificSettingsFragment extends PreferenceFragmentCompat imp
displayOnLiftStart.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newVal) {
invokeLater(new Runnable() {
@Override
public void run() {
GBApplication.deviceService().onSendConfiguration(PREF_DISPLAY_ON_LIFT_START);
}
});
notifyPreferenceChanged(PREF_DISPLAY_ON_LIFT_START);
return true;
}
});
@ -604,12 +542,7 @@ public class DeviceSpecificSettingsFragment extends PreferenceFragmentCompat imp
displayOnLiftEnd.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newVal) {
invokeLater(new Runnable() {
@Override
public void run() {
GBApplication.deviceService().onSendConfiguration(PREF_DISPLAY_ON_LIFT_END);
}
});
notifyPreferenceChanged(PREF_DISPLAY_ON_LIFT_END);
return true;
}
});
@ -626,12 +559,7 @@ public class DeviceSpecificSettingsFragment extends PreferenceFragmentCompat imp
if (rotateWristCycleInfo != null) {
rotateWristCycleInfo.setEnabled(!PREF_DO_NOT_DISTURB_OFF.equals(newVal.toString()));
}
invokeLater(new Runnable() {
@Override
public void run() {
GBApplication.deviceService().onSendConfiguration(PREF_ACTIVATE_DISPLAY_ON_LIFT);
}
});
notifyPreferenceChanged(PREF_ACTIVATE_DISPLAY_ON_LIFT);
return true;
}
});
@ -802,12 +730,7 @@ public class DeviceSpecificSettingsFragment extends PreferenceFragmentCompat imp
if (pref != null) {
pref.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
public boolean onPreferenceChange(Preference preference, Object newVal) {
invokeLater(new Runnable() {
@Override
public void run() {
GBApplication.deviceService().onSendConfiguration(preferenceKey);
}
});
notifyPreferenceChanged(preferenceKey);
if (extraListener != null) {
return extraListener.onPreferenceChange(preference, newVal);

View File

@ -39,6 +39,13 @@ public interface DeviceSpecificSettingsHandler {
*/
void addPreferenceHandlerFor(final String preferenceKey);
/**
* Notify the device that a preference changed.
*
* @param preferenceKey the preference key.
*/
void notifyPreferenceChanged(final String preferenceKey);
/**
* Adds a preference handler for a preference key. On change, this handler calls the provided extra listener, and then sends the preference to the device.
*

View File

@ -28,12 +28,21 @@ import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.Dev
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_SONY_EQUALIZER_BASS;
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_SONY_EQUALIZER_MODE;
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_SONY_FOCUS_VOICE;
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_SONY_NOISE_OPTIMIZER_CANCEL;
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_SONY_NOISE_OPTIMIZER_START;
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_SONY_NOISE_OPTIMIZER_STATUS;
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_SONY_SOUND_POSITION;
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_SONY_SURROUND_MODE;
import android.app.AlertDialog;
import android.content.Context;
import android.os.Parcel;
import androidx.preference.EditTextPreference;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import androidx.preference.ListPreference;
import androidx.preference.Preference;
@ -41,13 +50,17 @@ import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpecificSettingsCustomizer;
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpecificSettingsHandler;
import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.prefs.AmbientSoundControl;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.model.DeviceType;
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.headphones.protocol.impl.v1.params.NoiseCancellingOptimizerStatus;
public class SonyHeadphonesSettingsCustomizer implements DeviceSpecificSettingsCustomizer {
private ProgressDialog ancOptimizerProgressDialog;
final GBDevice device;
public SonyHeadphonesSettingsCustomizer(final GBDevice device) {
@ -80,6 +93,24 @@ public class SonyHeadphonesSettingsCustomizer implements DeviceSpecificSettingsC
}
}
}
// Handle ANC Optimizer status
if (preference.getKey().equals(PREF_SONY_NOISE_OPTIMIZER_STATUS)) {
final EditTextPreference optimizerStatusPreference = (EditTextPreference) preference;
final NoiseCancellingOptimizerStatus optimizerStatus = NoiseCancellingOptimizerStatus.valueOf(optimizerStatusPreference.getText().toUpperCase(Locale.ROOT));
if (ancOptimizerProgressDialog != null) {
switch (optimizerStatus) {
case FINISHED:
case NOT_RUNNING:
ancOptimizerProgressDialog.dismiss();
ancOptimizerProgressDialog = null;
break;
default:
ancOptimizerProgressDialog.setMessage(optimizerStatus.i18n(preference.getContext()));
}
}
}
}
@Override
@ -104,6 +135,54 @@ public class SonyHeadphonesSettingsCustomizer implements DeviceSpecificSettingsC
ambientSoundControlPrefListener.onPreferenceChange(ambientSoundControl, ambientSoundControl.getValue());
handler.addPreferenceHandlerFor(PREF_SONY_AMBIENT_SOUND_CONTROL, ambientSoundControlPrefListener);
}
// ANC Optimizer
final Preference ancOptimizer = handler.findPreference("pref_sony_anc_optimizer");
if (ancOptimizer != null) {
ancOptimizer.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(final Preference preference) {
if (ancOptimizerProgressDialog != null) {
// Already optimizing
return true;
}
final Context context = preference.getContext();
new AlertDialog.Builder(context)
.setTitle(R.string.sony_anc_optimize_confirmation_title)
.setMessage(R.string.sony_anc_optimize_confirmation_description)
.setIcon(R.drawable.ic_hearing)
.setPositiveButton(R.string.start, new DialogInterface.OnClickListener() {
public void onClick(final DialogInterface dialog, final int whichButton) {
handler.notifyPreferenceChanged(PREF_SONY_NOISE_OPTIMIZER_START);
ancOptimizerProgressDialog = new ProgressDialog(context);
ancOptimizerProgressDialog.setCancelable(false);
ancOptimizerProgressDialog.setMessage(context.getString(R.string.sony_anc_optimizer_status_starting));
ancOptimizerProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
ancOptimizerProgressDialog.setProgress(0);
ancOptimizerProgressDialog.setButton(DialogInterface.BUTTON_NEGATIVE, context.getString(R.string.Cancel), new DialogInterface.OnClickListener() {
@Override
public void onClick(final DialogInterface dialog, final int which) {
dialog.dismiss();
ancOptimizerProgressDialog = null;
handler.notifyPreferenceChanged(PREF_SONY_NOISE_OPTIMIZER_CANCEL);
}
});
ancOptimizerProgressDialog.show();
}
})
.setNegativeButton(android.R.string.cancel, null)
.show();
return true;
}
});
}
}
public static final Creator<SonyHeadphonesSettingsCustomizer> CREATOR = new Creator<SonyHeadphonesSettingsCustomizer>() {

View File

@ -44,6 +44,7 @@ public class SonyWH1000XM3Coordinator extends SonyHeadphonesCoordinator {
public int[] getSupportedDeviceSpecificSettings(final GBDevice device) {
return new int[]{
R.xml.devicesettings_sony_headphones_ambient_sound_control_wind_noise_reduction,
R.xml.devicesettings_sony_headphones_anc_optimizer,
R.xml.devicesettings_header_other,
R.xml.devicesettings_sony_warning_wh1000xm3,
R.xml.devicesettings_sony_headphones_equalizer,

View File

@ -45,6 +45,7 @@ public class SonyWH1000XM4Coordinator extends SonyHeadphonesCoordinator {
return new int[]{
// TODO: Function of [CUSTOM] button
R.xml.devicesettings_sony_headphones_ambient_sound_control_wind_noise_reduction,
R.xml.devicesettings_sony_headphones_anc_optimizer,
R.xml.devicesettings_header_other,
R.xml.devicesettings_sony_headphones_equalizer,
R.xml.devicesettings_sony_headphones_audio_upsampling,

View File

@ -152,6 +152,12 @@ public class SonyHeadphonesProtocol extends GBDeviceProtocol {
case DeviceSettingsPreferenceConst.PREF_SONY_AMBIENT_SOUND_LEVEL:
configRequest = protocolImpl.setAmbientSoundControl(AmbientSoundControl.fromPreferences(prefs));
break;
case DeviceSettingsPreferenceConst.PREF_SONY_NOISE_OPTIMIZER_START:
configRequest = protocolImpl.startNoiseCancellingOptimizer(true);
break;
case DeviceSettingsPreferenceConst.PREF_SONY_NOISE_OPTIMIZER_CANCEL:
configRequest = protocolImpl.startNoiseCancellingOptimizer(false);
break;
case DeviceSettingsPreferenceConst.PREF_SONY_SOUND_POSITION:
configRequest = protocolImpl.setSoundPosition(SoundPosition.fromPreferences(prefs));
break;
@ -211,10 +217,6 @@ public class SonyHeadphonesProtocol extends GBDeviceProtocol {
public byte[] encodeTestNewFunction() {
//return Request.fromHex(MessageType.COMMAND_1, "c40100").encode(sequenceNumber);
if (protocolImpl != null) {
return protocolImpl.startNoiseCancellingOptimizer().encode(sequenceNumber);
}
return null;
}

View File

@ -50,6 +50,8 @@ public abstract class AbstractSonyProtocolImpl {
public abstract Request setAmbientSoundControl(final AmbientSoundControl config);
public abstract Request getNoiseCancellingOptimizerState();
public abstract Request getAudioCodec();
public abstract Request getBattery(final BatteryType batteryType);
@ -94,7 +96,7 @@ public abstract class AbstractSonyProtocolImpl {
public abstract Request setVoiceNotifications(final VoiceNotifications config);
public abstract Request startNoiseCancellingOptimizer();
public abstract Request startNoiseCancellingOptimizer(final boolean start);
public abstract Request powerOff();

View File

@ -53,7 +53,12 @@ public enum PayloadType {
AMBIENT_SOUND_CONTROL_SET(MessageType.COMMAND_1, 0x68),
AMBIENT_SOUND_CONTROL_NOTIFY(MessageType.COMMAND_1, 0x69),
NOISE_CANCELLING_OPTIMIZER_START_REQUEST(MessageType.COMMAND_1, 0x84),
NOISE_CANCELLING_OPTIMIZER_START(MessageType.COMMAND_1, 0x84),
NOISE_CANCELLING_OPTIMIZER_STATUS(MessageType.COMMAND_1, 0x85),
NOISE_CANCELLING_OPTIMIZER_STATE_GET(MessageType.COMMAND_1, 0x86),
NOISE_CANCELLING_OPTIMIZER_STATE_RET(MessageType.COMMAND_1, 0x87),
NOISE_CANCELLING_OPTIMIZER_STATE_NOTIFY(MessageType.COMMAND_1, 0x89),
TOUCH_SENSOR_GET(MessageType.COMMAND_1, 0xd6),
TOUCH_SENSOR_RET(MessageType.COMMAND_1, 0xd7),

View File

@ -16,6 +16,9 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. */
package nodomain.freeyourgadget.gadgetbridge.service.devices.sony.headphones.protocol.impl.v1;
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_SONY_NOISE_OPTIMIZER_STATE_PRESSURE;
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_SONY_NOISE_OPTIMIZER_STATUS;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -53,6 +56,7 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.headphones.prot
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.headphones.protocol.impl.AbstractSonyProtocolImpl;
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.headphones.protocol.impl.v1.params.AudioCodec;
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.headphones.protocol.impl.v1.params.BatteryType;
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.headphones.protocol.impl.v1.params.NoiseCancellingOptimizerStatus;
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.headphones.protocol.impl.v1.params.VirtualSoundParam;
import nodomain.freeyourgadget.gadgetbridge.util.GB;
@ -130,6 +134,17 @@ public class SonyProtocolImplV1 extends AbstractSonyProtocolImpl {
return new Request(PayloadType.AMBIENT_SOUND_CONTROL_SET.getMessageType(), buf.array());
}
@Override
public Request getNoiseCancellingOptimizerState() {
return new Request(
PayloadType.NOISE_CANCELLING_OPTIMIZER_STATE_GET.getMessageType(),
new byte[]{
PayloadType.NOISE_CANCELLING_OPTIMIZER_STATE_GET.getCode(),
(byte) 0x01
}
);
}
@Override
public Request getAudioCodec() {
return new Request(
@ -399,14 +414,14 @@ public class SonyProtocolImplV1 extends AbstractSonyProtocolImpl {
}
@Override
public Request startNoiseCancellingOptimizer() {
public Request startNoiseCancellingOptimizer(final boolean start) {
return new Request(
PayloadType.NOISE_CANCELLING_OPTIMIZER_START_REQUEST.getMessageType(),
PayloadType.NOISE_CANCELLING_OPTIMIZER_START.getMessageType(),
new byte[]{
PayloadType.NOISE_CANCELLING_OPTIMIZER_START_REQUEST.getCode(),
PayloadType.NOISE_CANCELLING_OPTIMIZER_START.getCode(),
(byte) 0x01,
(byte) 0x00,
(byte) 0x01
(byte) (start ? 0x01 : 0x00)
}
);
}
@ -447,6 +462,11 @@ public class SonyProtocolImplV1 extends AbstractSonyProtocolImpl {
case AMBIENT_SOUND_CONTROL_RET:
case AMBIENT_SOUND_CONTROL_NOTIFY:
return handleAmbientSoundControl(payload);
case NOISE_CANCELLING_OPTIMIZER_STATUS:
return handleNoiseCancellingOptimizerStatus(payload);
case NOISE_CANCELLING_OPTIMIZER_STATE_RET:
case NOISE_CANCELLING_OPTIMIZER_STATE_NOTIFY:
return handleNoiseCancellingOptimizerState(payload);
case TOUCH_SENSOR_RET:
case TOUCH_SENSOR_NOTIFY:
return handleTouchSensor(payload);
@ -486,6 +506,7 @@ public class SonyProtocolImplV1 extends AbstractSonyProtocolImpl {
capabilityRequests.add(getBattery(BatteryType.SINGLE));
capabilityRequests.add(getAudioCodec());
capabilityRequests.add(getAmbientSoundControl());
capabilityRequests.add(getNoiseCancellingOptimizerState());
capabilityRequests.add(getAudioUpsampling());
capabilityRequests.add(getVoiceNotifications());
capabilityRequests.add(getAutomaticPowerOff());
@ -499,6 +520,7 @@ public class SonyProtocolImplV1 extends AbstractSonyProtocolImpl {
capabilityRequests.add(getBattery(BatteryType.SINGLE));
capabilityRequests.add(getAudioCodec());
capabilityRequests.add(getAmbientSoundControl());
capabilityRequests.add(getNoiseCancellingOptimizerState());
capabilityRequests.add(getAudioUpsampling());
capabilityRequests.add(getVoiceNotifications());
capabilityRequests.add(getAutomaticPowerOff());
@ -592,6 +614,50 @@ public class SonyProtocolImplV1 extends AbstractSonyProtocolImpl {
return Collections.singletonList(eventUpdatePreferences);
}
public List<? extends GBDeviceEvent> handleNoiseCancellingOptimizerStatus(final byte[] payload) {
if (payload.length != 4) {
LOG.warn("Unexpected payload length {}", payload.length);
return Collections.emptyList();
}
final NoiseCancellingOptimizerStatus status = NoiseCancellingOptimizerStatus.fromCode(payload[3]);
if (status == null) {
LOG.warn("Unable to determine noise cancelling opptimizer status from {}", GB.hexdump(payload));
return Collections.emptyList();
}
LOG.info("Noise Cancelling Optimizer status: {}", status);
final GBDeviceEventUpdatePreferences event = new GBDeviceEventUpdatePreferences()
.withPreference(PREF_SONY_NOISE_OPTIMIZER_STATUS, status.name().toLowerCase(Locale.ROOT));
return Collections.singletonList(event);
}
public List<? extends GBDeviceEvent> handleNoiseCancellingOptimizerState(final byte[] payload) {
// 89 01 01 01 01 0A
if (payload.length != 6) {
LOG.warn("Unexpected payload length {}", payload.length);
return Collections.emptyList();
}
final float pressure = payload[5] / 10.0f;
if (pressure <= 0 || pressure > 1.0f) {
LOG.warn("Invalid Noise Cancelling Optimizer pressure: {} atm, ignoring", pressure);
return Collections.emptyList();
}
LOG.info("Noise Cancelling Optimizer pressure: {} atm", pressure);
final GBDeviceEventUpdatePreferences event = new GBDeviceEventUpdatePreferences()
.withPreference(PREF_SONY_NOISE_OPTIMIZER_STATE_PRESSURE, String.format(Locale.getDefault(), "%.2f atm", pressure));
return Collections.singletonList(event);
}
public List<? extends GBDeviceEvent> handleAudioUpsampling(final byte[] payload) {
if (payload.length != 4) {
LOG.warn("Unexpected payload length {}", payload.length);

View File

@ -0,0 +1,56 @@
/* Copyright (C) 2021 José Rebelo
This file is part of Gadgetbridge.
Gadgetbridge is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Gadgetbridge is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
package nodomain.freeyourgadget.gadgetbridge.service.devices.sony.headphones.protocol.impl.v1.params;
import android.content.Context;
import java.util.Locale;
public enum NoiseCancellingOptimizerStatus {
NOT_RUNNING(0x00),
WEARING_CONDITION(0x01),
ATMOSPHERIC_PRESSURE(0x02),
ANALYZING(0x10),
FINISHED(0x11),
;
private final byte code;
NoiseCancellingOptimizerStatus(final int code) {
this.code = (byte) code;
}
public byte getCode() {
return this.code;
}
public static NoiseCancellingOptimizerStatus fromCode(final byte code) {
for (final NoiseCancellingOptimizerStatus audioCodec : values()) {
if (audioCodec.code == code) {
return audioCodec;
}
}
return null;
}
public String i18n(final Context context) {
final String stringName = String.format("sony_anc_optimizer_status_%s", name().toLowerCase(Locale.ROOT));
final int stringId = context.getResources().getIdentifier(stringName, "string", context.getPackageName());
return context.getString(stringId);
}
}

View File

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#7E7E7E"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M19,9l1.25,-2.75L23,5l-2.75,-1.25L19,1l-1.25,2.75L15,5l2.75,1.25L19,9zM11.5,9.5L9,4 6.5,9.5 1,12l5.5,2.5L9,20l2.5,-5.5L17,12l-5.5,-2.5zM19,15l-1.25,2.75L15,19l2.75,1.25L19,23l1.25,-2.75L23,19l-2.75,-1.25L19,15z"/>
</vector>

View File

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#7E7E7E"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M20.38,8.57l-1.23,1.85a8,8 0,0 1,-0.22 7.58L5.07,18A8,8 0,0 1,15.58 6.85l1.85,-1.23A10,10 0,0 0,3.35 19a2,2 0,0 0,1.72 1h13.85a2,2 0,0 0,1.74 -1,10 10,0 0,0 -0.27,-10.44zM10.59,15.41a2,2 0,0 0,2.83 0l5.66,-8.49 -8.49,5.66a2,2 0,0 0,0 2.83z"/>
</vector>

View File

@ -355,6 +355,7 @@
<string name="connected">Connected</string>
<string name="unknown_state">Unknown state</string>
<string name="_unknown_">(unknown)</string>
<string name="unknown">Unknown</string>
<string name="test">Test</string>
<string name="test_notification">Test notification</string>
<string name="this_is_a_test_notification_from_gadgetbridge">This is a test notification from Gadgetbridge</string>
@ -771,6 +772,7 @@
<string name="Cancel">Cancel</string>
<string name="Delete">Delete</string>
<string name="ok">OK</string>
<string name="start">Start</string>
<string name="set">Set</string>
<string name="activity_data_management_directory_content_title">Export/Import directory content</string>
<string name="activity_DB_ShowContentButton">Show Export/Import directory content</string>
@ -1393,6 +1395,12 @@
<string name="sony_ambient_sound_ambient_sound">Ambient Sound</string>
<string name="sony_ambient_sound_focus_voice">Focus on Voice</string>
<string name="sony_ambient_sound_level">Ambient Sound Level</string>
<string name="pref_header_sony_anc_optimizer">Noise Cancelling Optimizer</string>
<string name="sony_anc_optimize_title">Optimize</string>
<string name="sony_anc_optimize_description">Click to start the noise cancelling optimizer.</string>
<string name="sony_anc_optimize_confirmation_title">Noise Cancelling Optimizer</string>
<string name="sony_anc_optimize_confirmation_description">Use the headphones as you normally would. If the wearing condition or atmospheric pressure change, run the optimizer again.</string>
<string name="pref_anc_optimizer_state_pressure">Atmospheric pressure</string>
<string name="sony_sound_position">Sound Position</string>
<string name="sony_sound_position_off">Off</string>
<string name="sony_sound_position_front">Front</string>
@ -1408,6 +1416,12 @@
<string name="sony_surround_mode_concert_hall">Concert Hall</string>
<string name="sony_warn_sbc_codec">Warning: The equalizer, audio position and surround settings only work for the SBC audio codec.</string>
<string name="sony_equalizer">Equalizer</string>
<string name="sony_anc_optimizer_status_starting">Starting…</string>
<string name="sony_anc_optimizer_status_not_running">Not Running</string>
<string name="sony_anc_optimizer_status_wearing_condition">Measuring wearing condition…</string>
<string name="sony_anc_optimizer_status_atmospheric_pressure">Measuring atmostpheric pressure…</string>
<string name="sony_anc_optimizer_status_analyzing">Analyzing…</string>
<string name="sony_anc_optimizer_status_finished">Finishing…</string>
<string name="sony_equalizer_preset_off">Off</string>
<string name="sony_equalizer_preset_bright">Bright</string>
<string name="sony_equalizer_preset_excited">Excited</string>

View File

@ -0,0 +1,31 @@
<?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="pref_key_header_sony_anc_optimizer"
android:title="@string/pref_header_sony_anc_optimizer">
<EditTextPreference
android:defaultValue="@string/unknown"
android:enabled="false"
android:icon="@drawable/ic_pressure"
android:key="pref_sony_noise_optimizer_state_pressure"
android:shouldDisableView="false"
android:title="@string/pref_anc_optimizer_state_pressure"
app:useSimpleSummaryProvider="true" />
<Preference
android:icon="@drawable/ic_auto_awesome"
android:key="pref_sony_anc_optimizer"
android:summary="@string/sony_anc_optimize_description"
android:title="@string/sony_anc_optimize_title" />
<EditTextPreference
android:defaultValue="NOT_RUNNING"
android:enabled="false"
android:key="pref_sony_noise_optimizer_status"
android:shouldDisableView="false"
android:title="pref_sony_noise_optimizer_status"
app:isPreferenceVisible="false" />
</PreferenceCategory>
</androidx.preference.PreferenceScreen>