diff --git a/CHANGELOG.md b/CHANGELOG.md
index 326c83453..79ac7bdf5 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,8 @@
### Changelog
+### {next}
+* Support for Galaxy Buds 2019
+
### 0.61.0
* Initial support for Nothing Ear(1)
* Amazfit Bip U/Pro: Fix flashing firmware and watchfaces
diff --git a/app/src/main/assets/galaxy_buds.svg b/app/src/main/assets/galaxy_buds.svg
new file mode 100644
index 000000000..1c3dd358b
--- /dev/null
+++ b/app/src/main/assets/galaxy_buds.svg
@@ -0,0 +1,86 @@
+
+
+
+
diff --git a/app/src/main/assets/ic_device_galaxy_buds.svg b/app/src/main/assets/ic_device_galaxy_buds.svg
new file mode 100644
index 000000000..29adf6f78
--- /dev/null
+++ b/app/src/main/assets/ic_device_galaxy_buds.svg
@@ -0,0 +1,103 @@
+
+
+
+
diff --git a/app/src/main/assets/ic_device_galaxy_buds_disabled.svg b/app/src/main/assets/ic_device_galaxy_buds_disabled.svg
new file mode 100644
index 000000000..4254aedfe
--- /dev/null
+++ b/app/src/main/assets/ic_device_galaxy_buds_disabled.svg
@@ -0,0 +1,103 @@
+
+
+
+
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/devicesettings/DeviceSettingsPreferenceConst.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/devicesettings/DeviceSettingsPreferenceConst.java
index d13f86859..eb5a3fb13 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/devicesettings/DeviceSettingsPreferenceConst.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/devicesettings/DeviceSettingsPreferenceConst.java
@@ -98,6 +98,17 @@ public class DeviceSettingsPreferenceConst {
public static final String PREF_NOTHING_EAR1_INEAR = "pref_nothing_inear_detection";
public static final String PREF_NOTHING_EAR1_AUDIOMODE = "pref_nothing_audiomode";
+ public static final String PREF_GALAXY_BUDS_AMBIENT_MODE = "pref_galaxy_buds_ambient_mode";
+ public static final String PREF_GALAXY_BUDS_AMBIENT_VOICE_FOCUS = "pref_galaxy_buds_ambient_voice_focus";
+ public static final String PREF_GALAXY_BUDS_AMBIENT_VOLUME = "pref_galaxy_buds_ambient_volume";
+ public static final String PREF_GALAXY_BUDS_LOCK_TOUCH = "pref_galaxy_buds_lock_touch";
+ public static final String PREF_GALAXY_BUDS_GAME_MODE = "pref_galaxy_buds_game_mode";
+ public static final String PREF_GALAXY_BUDS_EQUALIZER = "pref_galaxy_buds_equalizer";
+ public static final String PREF_GALAXY_BUDS_EQUALIZER_DOLBY = "pref_galaxy_buds_equalizer_dolby";
+ public static final String PREF_GALAXY_BUDS_EQUALIZER_MODE = "pref_galaxy_buds_equalizer_mode";
+ public static final String PREF_GALAXY_BUDS_TOUCH_LEFT = "pref_galaxy_buds_touch_left";
+ public static final String PREF_GALAXY_BUDS_TOUCH_RIGHT = "pref_galaxy_buds_touch_right";
+
public static final String PREF_SOUNDS = "sounds";
public static final String PREF_AUTH_KEY = "authkey";
}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/devicesettings/DeviceSpecificSettingsFragment.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/devicesettings/DeviceSpecificSettingsFragment.java
index 71ee4bfbe..9a52525fa 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/devicesettings/DeviceSpecificSettingsFragment.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/devicesettings/DeviceSpecificSettingsFragment.java
@@ -72,6 +72,16 @@ import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.Dev
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_DO_NOT_DISTURB_NOAUTO_START;
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_FAKE_RING_DURATION;
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_FIND_PHONE_ENABLED;
+import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_GALAXY_BUDS_AMBIENT_MODE;
+import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_GALAXY_BUDS_AMBIENT_VOICE_FOCUS;
+import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_GALAXY_BUDS_AMBIENT_VOLUME;
+import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_GALAXY_BUDS_EQUALIZER;
+import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_GALAXY_BUDS_EQUALIZER_DOLBY;
+import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_GALAXY_BUDS_EQUALIZER_MODE;
+import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_GALAXY_BUDS_GAME_MODE;
+import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_GALAXY_BUDS_LOCK_TOUCH;
+import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_GALAXY_BUDS_TOUCH_LEFT;
+import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_GALAXY_BUDS_TOUCH_RIGHT;
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_HYBRID_HR_DANGEROUS_EXTERNAL_INTENTS;
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_HYBRID_HR_DRAW_WIDGET_CIRCLES;
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_HYBRID_HR_FORCE_WHITE_COLOR;
@@ -464,6 +474,17 @@ public class DeviceSpecificSettingsFragment extends PreferenceFragmentCompat {
addPreferenceHandlerFor(PREF_NOTHING_EAR1_INEAR);
addPreferenceHandlerFor(PREF_NOTHING_EAR1_AUDIOMODE);
+ addPreferenceHandlerFor(PREF_GALAXY_BUDS_AMBIENT_MODE);
+ addPreferenceHandlerFor(PREF_GALAXY_BUDS_AMBIENT_VOICE_FOCUS);
+ addPreferenceHandlerFor(PREF_GALAXY_BUDS_AMBIENT_VOLUME);
+ addPreferenceHandlerFor(PREF_GALAXY_BUDS_LOCK_TOUCH);
+ addPreferenceHandlerFor(PREF_GALAXY_BUDS_GAME_MODE);
+ addPreferenceHandlerFor(PREF_GALAXY_BUDS_EQUALIZER);
+ addPreferenceHandlerFor(PREF_GALAXY_BUDS_EQUALIZER_DOLBY);
+ addPreferenceHandlerFor(PREF_GALAXY_BUDS_EQUALIZER_MODE);
+ addPreferenceHandlerFor(PREF_GALAXY_BUDS_TOUCH_LEFT);
+ addPreferenceHandlerFor(PREF_GALAXY_BUDS_TOUCH_RIGHT);
+
String sleepTimeState = prefs.getString(PREF_SLEEP_TIME, PREF_DO_NOT_DISTURB_OFF);
boolean sleepTimeScheduled = sleepTimeState.equals(PREF_DO_NOT_DISTURB_SCHEDULED);
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/galaxy_buds/GalaxyBudsDeviceCoordinator.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/galaxy_buds/GalaxyBudsDeviceCoordinator.java
new file mode 100644
index 000000000..4188628b7
--- /dev/null
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/galaxy_buds/GalaxyBudsDeviceCoordinator.java
@@ -0,0 +1,142 @@
+package nodomain.freeyourgadget.gadgetbridge.devices.galaxy_buds;
+
+import android.app.Activity;
+import android.content.Context;
+import android.net.Uri;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import nodomain.freeyourgadget.gadgetbridge.GBException;
+import nodomain.freeyourgadget.gadgetbridge.R;
+import nodomain.freeyourgadget.gadgetbridge.devices.AbstractDeviceCoordinator;
+import nodomain.freeyourgadget.gadgetbridge.devices.InstallHandler;
+import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider;
+import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
+import nodomain.freeyourgadget.gadgetbridge.entities.Device;
+import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
+import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceCandidate;
+import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample;
+import nodomain.freeyourgadget.gadgetbridge.model.DeviceType;
+
+public class GalaxyBudsDeviceCoordinator extends AbstractDeviceCoordinator {
+
+ @NonNull
+ @Override
+ public DeviceType getSupportedType(GBDeviceCandidate candidate) {
+
+ String name = candidate.getName();
+
+ if (name != null && (
+ name.startsWith("Galaxy Buds")
+ )) {
+ return DeviceType.GALAXY_BUDS;
+ }
+ return DeviceType.UNKNOWN;
+ }
+
+ @Override
+ public DeviceType getDeviceType() {
+ return DeviceType.GALAXY_BUDS;
+ }
+
+ //@Override
+ //public int getBatteryCount() {
+ // return 2;
+ //}
+
+ @Nullable
+ @Override
+ public Class extends Activity> getPairingActivity() {
+ return null;
+ }
+
+ @Override
+ public boolean supportsActivityDataFetching() {
+ return false;
+ }
+
+ @Override
+ public boolean supportsActivityTracking() {
+ return false;
+ }
+
+ @Override
+ public SampleProvider extends ActivitySample> getSampleProvider(GBDevice
+ device, DaoSession session) {
+ return null;
+ }
+
+ @Override
+ public InstallHandler findInstallHandler(Uri uri, Context context) {
+ return null;
+ }
+
+ @Override
+ public boolean supportsScreenshots() {
+ return false;
+ }
+
+ @Override
+ public int getAlarmSlotCount() {
+ return 0;
+ }
+
+ @Override
+ public boolean supportsSmartWakeup(GBDevice device) {
+ return false;
+ }
+
+ @Override
+ public boolean supportsHeartRateMeasurement(GBDevice device) {
+ return false;
+ }
+
+ @Override
+ public String getManufacturer() {
+ return "Samsung";
+ }
+
+ @Override
+ public boolean supportsAppsManagement() {
+ return false;
+ }
+
+ @Override
+ public Class extends Activity> getAppsManagementActivity() {
+ return null;
+ }
+
+ @Override
+ public boolean supportsCalendarEvents() {
+ return false;
+ }
+
+ @Override
+ public boolean supportsRealtimeData() {
+ return false;
+ }
+
+ @Override
+ public boolean supportsWeather() {
+ return false;
+ }
+
+ @Override
+ public boolean supportsFindDevice() {
+ return true;
+ }
+
+ @Override
+ protected void deleteDevice(@NonNull GBDevice gbDevice, @NonNull Device
+ device, @NonNull DaoSession session) throws GBException {
+
+ }
+
+ @Override
+ public int[] getSupportedDeviceSpecificSettings(GBDevice device) {
+ return new int[]{
+ R.xml.devicesettings_galaxy_buds,
+ };
+ }
+}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/DeviceType.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/DeviceType.java
index 9aa428005..01d60fe27 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/DeviceType.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/DeviceType.java
@@ -101,6 +101,7 @@ public enum DeviceType {
UM25(350, R.drawable.ic_device_default, R.drawable.ic_device_default_disabled, R.string.devicetype_um25),
DOMYOS_T540(400, R.drawable.ic_device_lovetoy, R.drawable.ic_device_lovetoy_disabled, R.string.devicetype_domyos_t540),
NOTHING_EAR1(410, R.drawable.ic_device_nothingear, R.drawable.ic_device_nothingear_disabled, R.string.devicetype_nothingear1),
+ GALAXY_BUDS(420, R.drawable.ic_device_galaxy_buds, R.drawable.ic_device_galaxy_buds_disabled, R.string.devicetype_galaxybuds),
TEST(1000, R.drawable.ic_device_default, R.drawable.ic_device_default_disabled, R.string.devicetype_test);
private final int key;
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceSupportFactory.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceSupportFactory.java
index 39572d05e..ad8e5064e 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceSupportFactory.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceSupportFactory.java
@@ -38,6 +38,7 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.banglejs.BangleJSDev
import nodomain.freeyourgadget.gadgetbridge.service.devices.casio.CasioGB6900DeviceSupport;
import nodomain.freeyourgadget.gadgetbridge.service.devices.casio.CasioGBX100DeviceSupport;
import nodomain.freeyourgadget.gadgetbridge.service.devices.domyos.DomyosT540Support;
+import nodomain.freeyourgadget.gadgetbridge.service.devices.galaxy_buds.GalaxyBudsDeviceSupport;
import nodomain.freeyourgadget.gadgetbridge.service.devices.hplus.HPlusSupport;
import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.HuamiSupport;
import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.amazfitband5.AmazfitBand5Support;
@@ -362,6 +363,10 @@ public class DeviceSupportFactory {
case NOTHING_EAR1:
deviceSupport = new ServiceDeviceSupport(new Ear1Support(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
break;
+ case GALAXY_BUDS:
+ deviceSupport = new ServiceDeviceSupport(new GalaxyBudsDeviceSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
+ break;
+
}
if (deviceSupport != null) {
deviceSupport.setContext(gbDevice, mBtAdapter, mContext);
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/galaxy_buds/GalaxyBudsDeviceSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/galaxy_buds/GalaxyBudsDeviceSupport.java
new file mode 100644
index 000000000..4dd3e18c2
--- /dev/null
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/galaxy_buds/GalaxyBudsDeviceSupport.java
@@ -0,0 +1,90 @@
+package nodomain.freeyourgadget.gadgetbridge.service.devices.galaxy_buds;
+
+import android.net.Uri;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.UUID;
+
+import nodomain.freeyourgadget.gadgetbridge.model.Alarm;
+import nodomain.freeyourgadget.gadgetbridge.service.serial.AbstractSerialDeviceSupport;
+import nodomain.freeyourgadget.gadgetbridge.service.serial.GBDeviceIoThread;
+import nodomain.freeyourgadget.gadgetbridge.service.serial.GBDeviceProtocol;
+
+public class GalaxyBudsDeviceSupport extends AbstractSerialDeviceSupport {
+ private static final Logger LOG = LoggerFactory.getLogger(GalaxyBudsDeviceSupport.class);
+
+
+ @Override
+ public void onSendConfiguration(String config) {
+ super.onSendConfiguration(config);
+ }
+
+ @Override
+ public void onSetAlarms(ArrayList extends Alarm> alarms) {
+
+ }
+
+ @Override
+ public void onInstallApp(Uri uri) {
+
+ }
+
+ @Override
+ public void onAppConfiguration(UUID appUuid, String config, Integer id) {
+
+ }
+
+ @Override
+ public void onHeartRateTest() {
+
+ }
+
+ @Override
+ public void onSetConstantVibration(int integer) {
+
+ }
+
+ @Override
+ public void onSetHeartRateMeasurementInterval(int seconds) {
+
+ }
+
+ @Override
+ public void onReadConfiguration(String config) {
+
+ }
+
+ @Override
+ public void onTestNewFunction() {
+ super.onTestNewFunction();
+ }
+
+ @Override
+ public boolean connect() {
+ getDeviceIOThread().start();
+ return true;
+ }
+
+ @Override
+ public synchronized GalaxyBudsIOThread getDeviceIOThread() {
+ return (GalaxyBudsIOThread) super.getDeviceIOThread();
+ }
+
+ @Override
+ public boolean useAutoConnect() {
+ return false;
+ }
+
+ protected GBDeviceProtocol createDeviceProtocol() {
+ return new GalaxyBudsProtocol(getDevice());
+ }
+
+ @Override
+ protected GBDeviceIoThread createDeviceIOThread() {
+ return new GalaxyBudsIOThread(getDevice(), getContext(), (GalaxyBudsProtocol) getDeviceProtocol(),
+ GalaxyBudsDeviceSupport.this, getBluetoothAdapter());
+ }
+}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/galaxy_buds/GalaxyBudsIOThread.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/galaxy_buds/GalaxyBudsIOThread.java
new file mode 100644
index 000000000..53610d1e8
--- /dev/null
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/galaxy_buds/GalaxyBudsIOThread.java
@@ -0,0 +1,46 @@
+package nodomain.freeyourgadget.gadgetbridge.service.devices.galaxy_buds;
+
+import static nodomain.freeyourgadget.gadgetbridge.util.GB.hexdump;
+
+import android.bluetooth.BluetoothAdapter;
+import android.content.Context;
+import android.os.ParcelUuid;
+
+import androidx.annotation.NonNull;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Arrays;
+import java.util.UUID;
+
+import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
+import nodomain.freeyourgadget.gadgetbridge.service.btclassic.BtClassicIoThread;
+
+public class GalaxyBudsIOThread extends BtClassicIoThread {
+ private static final Logger LOG = LoggerFactory.getLogger(GalaxyBudsIOThread.class);
+
+ private final GalaxyBudsProtocol galaxyBudsProtocol;
+
+ @NonNull
+ protected UUID getUuidToConnect(@NonNull ParcelUuid[] uuids) {
+ return galaxyBudsProtocol.UUID_DEVICE_CTRL;
+ }
+
+ public GalaxyBudsIOThread(GBDevice device, Context context, GalaxyBudsProtocol deviceProtocol,
+ GalaxyBudsDeviceSupport galaxyBudsDeviceSupport, BluetoothAdapter bluetoothAdapter) {
+ super(device, context, deviceProtocol, galaxyBudsDeviceSupport, bluetoothAdapter);
+ galaxyBudsProtocol = deviceProtocol;
+ }
+
+ @Override
+ protected byte[] parseIncoming(InputStream inStream) throws IOException {
+ byte[] buffer = new byte[1048576]; //HUGE read
+ int bytes = inStream.read(buffer);
+ LOG.debug("read " + bytes + " bytes. " + hexdump(buffer, 0, bytes));
+ return Arrays.copyOf(buffer, bytes);
+ }
+
+}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/galaxy_buds/GalaxyBudsProtocol.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/galaxy_buds/GalaxyBudsProtocol.java
new file mode 100644
index 000000000..1deaaef9f
--- /dev/null
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/galaxy_buds/GalaxyBudsProtocol.java
@@ -0,0 +1,248 @@
+package nodomain.freeyourgadget.gadgetbridge.service.devices.galaxy_buds;
+
+import static nodomain.freeyourgadget.gadgetbridge.util.CheckSums.crc16_ccitt;
+import static nodomain.freeyourgadget.gadgetbridge.util.GB.hexdump;
+
+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 java.util.UUID;
+
+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.GBDeviceEventVersionInfo;
+import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
+import nodomain.freeyourgadget.gadgetbridge.model.BatteryState;
+import nodomain.freeyourgadget.gadgetbridge.service.serial.GBDeviceProtocol;
+
+public class GalaxyBudsProtocol extends GBDeviceProtocol {
+ private static final Logger LOG = LoggerFactory.getLogger(GalaxyBudsProtocol.class);
+
+ final UUID UUID_DEVICE_CTRL = UUID.fromString("00001102-0000-1000-8000-00805f9b34fd");
+ private static final byte SOM = (byte) 0xFE;
+ private static final byte EOM = (byte) 0xEE;
+ private boolean isFirstExchange = true;
+
+ //incoming
+ private static final byte battery_status = (byte) 0x60;
+ private static final byte battery_status2 = (byte) 0x61;
+
+ //outgoing
+ private static final byte find_device_start = (byte) 0xa0;
+ private static final byte find_device_stop = (byte) 0xa1;
+
+ private static final byte set_ambient_mode = (byte) 0x80; //0x0/0x1
+ private static final byte set_ambient_volume = (byte) 0x84; // 0x1-0x5
+ private static final byte set_ambient_voice_focus = (byte) 0x85; // 0x0/0x1
+
+ private static final byte set_lock_touch = (byte) 0x90; // 0x0/0x1
+ private static final byte set_game_mode = (byte) 0x87; // 0x0/0x2 no idea if this is doing anything
+ private static final byte set_equalizer = (byte) 0x86; // 0x0/0x1
+
+ private static final byte set_reset = (byte) 0x50;
+
+ private static final byte set_touchpad_options = (byte) 0x92;
+
+ private static final byte get_debug_build_info = (byte) 0x28;
+ private static final byte get_serial_number = (byte) 0x29;
+ private static final byte get_debug_get_all_data = (byte) 0x26;
+ private static final byte get_debug_get_version = (byte) 0x24;
+
+ @Override
+ public GBDeviceEvent[] decodeResponse(byte[] responseData) {
+ List devEvts = new ArrayList<>();
+ LOG.debug("received data: " + hexdump(responseData));
+ LOG.debug("received data length: " + responseData.length);
+
+ if (isFirstExchange) {
+ isFirstExchange = false;
+ devEvts.add(new GBDeviceEventVersionInfo()); //TODO: this is a weird hack to make the DBHelper happy. Replace with proper + detection
+ }
+
+ ByteBuffer incoming = ByteBuffer.wrap(responseData);
+ incoming.order(ByteOrder.LITTLE_ENDIAN);
+
+ byte sof = incoming.get();
+ if (sof != SOM) {
+ LOG.error("Error in message, wrong start of frame: " + hexdump(responseData));
+ return null;
+ }
+ byte type = incoming.get();
+ int length = (int) (incoming.get() & 0xff);
+ byte message_id = incoming.get();
+ byte[] payload;
+ try {
+ payload = Arrays.copyOfRange(responseData, incoming.position(), incoming.position() + length);
+ } catch (Exception e) {
+ LOG.error("Error getting payload data: " + length + " , " + e);
+ return null;
+ }
+
+ switch (message_id) {
+ case battery_status:
+ devEvts.addAll(handleBatteryInfo(Arrays.copyOfRange(payload, 1, 3)));
+ break;
+ case battery_status2:
+ devEvts.addAll(handleBatteryInfo(Arrays.copyOfRange(payload, 2, 4)));
+ break;
+ default:
+ LOG.debug("Unhandled: " + hexdump(responseData));
+
+ }
+ return devEvts.toArray(new GBDeviceEvent[devEvts.size()]);
+ }
+
+
+ byte[] encodeMessage(byte command) {
+ ByteBuffer msgBuf = ByteBuffer.allocate(7);
+ msgBuf.order(ByteOrder.LITTLE_ENDIAN);
+ msgBuf.put(SOM);
+ msgBuf.put((byte) 0x0); //0x0 for sending
+ msgBuf.put((byte) 0x3); //size
+ msgBuf.put((byte) command); //command id
+ msgBuf.putShort((short) crc16_ccitt(new byte[]{command}));
+ msgBuf.put(EOM);
+ LOG.debug("DEBUG: " + hexdump(msgBuf.array()));
+ return msgBuf.array();
+ }
+
+ byte[] encodeMessage(byte command, byte parameter) {
+ ByteBuffer msgBuf = ByteBuffer.allocate(8);
+ msgBuf.order(ByteOrder.LITTLE_ENDIAN);
+ msgBuf.put(SOM);
+ msgBuf.put((byte) 0x0); //0x0 for sending
+ msgBuf.put((byte) 0x4); //size
+ msgBuf.put((byte) command); //command id
+ msgBuf.put((byte) parameter);
+ msgBuf.putShort((short) crc16_ccitt(new byte[]{command, parameter}));
+ msgBuf.put(EOM);
+ LOG.debug("DEBUG: " + hexdump(msgBuf.array()));
+ return msgBuf.array();
+ }
+
+ byte[] encodeMessage(byte command, byte parameter, byte value) {
+ ByteBuffer msgBuf = ByteBuffer.allocate(9);
+ msgBuf.order(ByteOrder.LITTLE_ENDIAN);
+ msgBuf.put(SOM);
+ msgBuf.put((byte) 0x0); //0x0 for sending
+ msgBuf.put((byte) 0x5); //size
+ msgBuf.put((byte) command);
+ msgBuf.put((byte) parameter);
+ msgBuf.put((byte) value);
+ msgBuf.putShort((short) crc16_ccitt(new byte[]{command, parameter, value}));
+ msgBuf.put(EOM);
+ LOG.debug("DEBUG: " + hexdump(msgBuf.array()));
+ return msgBuf.array();
+ }
+
+ @Override
+ public byte[] encodeFindDevice(boolean start) {
+ byte command = (byte) (start ? find_device_start : find_device_stop);
+ return encodeMessage(command);
+ }
+
+ @Override
+ public byte[] encodeReset(int reset) {
+ if (reset == RESET_FLAGS_FACTORY_RESET) {
+ return encodeMessage(set_reset);
+ }
+ return null;
+ }
+
+ @Override
+ public byte[] encodeTestNewFunction() {
+ //return encodeMessage(get_debug_build_info);
+ return null;
+ }
+
+ @Override
+ public byte[] encodeSendConfiguration(String config) {
+
+ SharedPreferences prefs = GBApplication.getDeviceSpecificSharedPrefs(getDevice().getAddress());
+
+ switch (config) {
+ case DeviceSettingsPreferenceConst.PREF_GALAXY_BUDS_AMBIENT_MODE:
+ byte enable_ambient = (byte) (prefs.getBoolean(DeviceSettingsPreferenceConst.PREF_GALAXY_BUDS_AMBIENT_MODE, false) ? 0x01 : 0x00);
+ return encodeMessage(set_ambient_mode, enable_ambient);
+ case DeviceSettingsPreferenceConst.PREF_GALAXY_BUDS_AMBIENT_VOICE_FOCUS:
+ byte enable_voice = (byte) (prefs.getBoolean(DeviceSettingsPreferenceConst.PREF_GALAXY_BUDS_AMBIENT_VOICE_FOCUS, false) ? 0x01 : 0x00);
+ return encodeMessage(set_ambient_voice_focus, enable_voice);
+ case DeviceSettingsPreferenceConst.PREF_GALAXY_BUDS_AMBIENT_VOLUME:
+ String ambient_volume = prefs.getString(DeviceSettingsPreferenceConst.PREF_GALAXY_BUDS_AMBIENT_VOLUME, "1");
+ byte ambient_volume_byte = (byte) Integer.parseInt(ambient_volume);
+ return encodeMessage(set_ambient_volume, ambient_volume_byte);
+ case DeviceSettingsPreferenceConst.PREF_GALAXY_BUDS_LOCK_TOUCH:
+ byte set_lock = (byte) (prefs.getBoolean(DeviceSettingsPreferenceConst.PREF_GALAXY_BUDS_LOCK_TOUCH, false) ? 0x01 : 0x00);
+ return encodeMessage(set_lock_touch, set_lock);
+ case DeviceSettingsPreferenceConst.PREF_GALAXY_BUDS_GAME_MODE:
+ byte game_mode = (byte) (prefs.getBoolean(DeviceSettingsPreferenceConst.PREF_GALAXY_BUDS_GAME_MODE, false) ? 0x2 : 0x00);
+ return encodeMessage(set_game_mode, game_mode);
+ case DeviceSettingsPreferenceConst.PREF_GALAXY_BUDS_EQUALIZER:
+ case DeviceSettingsPreferenceConst.PREF_GALAXY_BUDS_EQUALIZER_DOLBY:
+ case DeviceSettingsPreferenceConst.PREF_GALAXY_BUDS_EQUALIZER_MODE:
+ byte equalizer = (byte) (prefs.getBoolean(DeviceSettingsPreferenceConst.PREF_GALAXY_BUDS_EQUALIZER, false) ? 0x1 : 0x00);
+ boolean equalizer_dolby = prefs.getBoolean(DeviceSettingsPreferenceConst.PREF_GALAXY_BUDS_EQUALIZER_DOLBY, false);
+ int dolby = 0;
+ if (equalizer_dolby) {
+ dolby = 5;
+ }
+ String equalizer_mode = prefs.getString(DeviceSettingsPreferenceConst.PREF_GALAXY_BUDS_EQUALIZER_MODE, "0");
+ byte mode = (byte) (Integer.parseInt(equalizer_mode) + dolby);
+ return encodeMessage(set_equalizer, equalizer, mode);
+
+ case DeviceSettingsPreferenceConst.PREF_GALAXY_BUDS_TOUCH_LEFT:
+ case DeviceSettingsPreferenceConst.PREF_GALAXY_BUDS_TOUCH_RIGHT:
+ String touch_left = prefs.getString(DeviceSettingsPreferenceConst.PREF_GALAXY_BUDS_TOUCH_LEFT, "1");
+ String touch_right = prefs.getString(DeviceSettingsPreferenceConst.PREF_GALAXY_BUDS_TOUCH_RIGHT, "1");
+ byte touchmode_left = (byte) Integer.parseInt(touch_left);
+ byte touchmode_right = (byte) Integer.parseInt(touch_right);
+ return encodeMessage(set_touchpad_options, touchmode_left, touchmode_right);
+
+ default:
+ LOG.debug("CONFIG: " + config);
+ }
+ return super.encodeSendConfiguration(config);
+ }
+
+
+ private List handleBatteryInfo(byte[] payload) {
+ List deviceEvents = new ArrayList<>();
+ LOG.debug("Battery payload: " + hexdump(payload));
+ LOG.debug("pl: " + payload.length);
+ LOG.debug("p0: " + payload[0]);
+ LOG.debug("p1: " + payload[1]);
+
+ int batteryLevel1 = payload[0];
+ int batteryLevel2 = payload[1];
+
+ GBDeviceEventBatteryInfo evBattery1 = new GBDeviceEventBatteryInfo();
+ //evBattery1.batteryIndex = 0;
+ evBattery1.level = GBDevice.BATTERY_UNKNOWN;
+ evBattery1.level = (batteryLevel1 > 0) ? (short) batteryLevel1 : GBDevice.BATTERY_UNKNOWN;
+ evBattery1.state = (batteryLevel1 > 0) ? BatteryState.BATTERY_NORMAL : BatteryState.UNKNOWN;
+ deviceEvents.add(evBattery1);
+
+ GBDeviceEventBatteryInfo evBattery2 = new GBDeviceEventBatteryInfo();
+ //evBattery2.batteryIndex = 1;
+ evBattery2.level = GBDevice.BATTERY_UNKNOWN;
+ evBattery2.level = (batteryLevel2 > 0) ? (short) batteryLevel2 : GBDevice.BATTERY_UNKNOWN;
+ evBattery2.state = (batteryLevel2 > 0) ? BatteryState.BATTERY_NORMAL : BatteryState.UNKNOWN;
+ //deviceEvents.add(evBattery2);
+
+ return deviceEvents;
+ }
+
+ protected GalaxyBudsProtocol(GBDevice device) {
+ super(device);
+
+ }
+}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/nothing/Ear1Support.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/nothing/Ear1Support.java
index a21d5420e..166cc9b01 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/nothing/Ear1Support.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/nothing/Ear1Support.java
@@ -84,6 +84,7 @@ public class Ear1Support extends AbstractSerialDeviceSupport {
@Override
protected GBDeviceIoThread createDeviceIOThread() {
- return new NothingIOThread(getDevice(), getContext(), (NothingProtocol) getDeviceProtocol(), Ear1Support.this, getBluetoothAdapter());
+ return new NothingIOThread(getDevice(), getContext(), (NothingProtocol) getDeviceProtocol(),
+ Ear1Support.this, getBluetoothAdapter());
}
}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/nothing/NothingIOThread.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/nothing/NothingIOThread.java
index 0c803be4e..415ac4972 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/nothing/NothingIOThread.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/nothing/NothingIOThread.java
@@ -29,7 +29,8 @@ public class NothingIOThread extends BtClassicIoThread {
return mNothingProtocol.UUID_DEVICE_CTRL;
}
- public NothingIOThread(GBDevice device, Context context, NothingProtocol deviceProtocol, Ear1Support ear1Support, BluetoothAdapter bluetoothAdapter) {
+ public NothingIOThread(GBDevice device, Context context, NothingProtocol deviceProtocol,
+ Ear1Support ear1Support, BluetoothAdapter bluetoothAdapter) {
super(device, context, deviceProtocol, ear1Support, bluetoothAdapter);
mNothingProtocol = deviceProtocol;
}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/CheckSums.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/CheckSums.java
index 28c91189c..9b25a994e 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/CheckSums.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/CheckSums.java
@@ -115,4 +115,39 @@ public class CheckSums {
}
return out.toByteArray();
}
+
+ // https://github.com/ThePBone/GalaxyBudsClient/blob/master/GalaxyBudsClient/Utils/CRC16.cs
+
+ private static int[] Crc16Tab =
+ {0, 4129, 8258, 12387, 16516, 20645, 24774, 28903, 33032, 37161, 41290,
+ 45419, 49548, 53677, 57806, 61935, 4657, 528, 12915, 8786, 21173, 17044, 29431, 25302,
+ 37689, 33560, 45947, 41818, 54205, 50076, 62463, 58334, 9314, 13379, 1056, 5121, 25830,
+ 29895, 17572, 21637, 42346, 46411, 34088, 38153, 58862, 62927, 50604, 54669, 13907,
+ 9842, 5649, 1584, 30423, 26358, 22165, 18100, 46939, 42874, 38681, 34616, 63455, 59390,
+ 55197, 51132, 18628, 22757, 26758, 30887, 2112, 6241, 10242, 14371, 51660, 55789,
+ 59790, 63919, 35144, 39273, 43274, 47403, 23285, 19156, 31415, 27286, 6769, 2640,
+ 14899, 10770, 56317, 52188, 64447, 60318, 39801, 35672, 47931, 43802, 27814, 31879,
+ 19684, 23749, 11298, 15363, 3168, 7233, 60846, 64911, 52716, 56781, 44330, 48395,
+ 36200, 40265, 32407, 28342, 24277, 20212, 15891, 11826, 7761, 3696, 65439, 61374,
+ 57309, 53244, 48923, 44858, 40793, 36728, 37256, 33193, 45514, 41451, 53516, 49453,
+ 61774, 57711, 4224, 161, 12482, 8419, 20484, 16421, 28742, 24679, 33721, 37784, 41979,
+ 46042, 49981, 54044, 58239, 62302, 689, 4752, 8947, 13010, 16949, 21012, 25207, 29270,
+ 46570, 42443, 38312, 34185, 62830, 58703, 54572, 50445, 13538, 9411, 5280, 1153, 29798,
+ 25671, 21540, 17413, 42971, 47098, 34713, 38840, 59231, 63358, 50973, 55100, 9939,
+ 14066, 1681, 5808, 26199, 30326, 17941, 22068, 55628, 51565, 63758, 59695, 39368,
+ 35305, 47498, 43435, 22596, 18533, 30726, 26663, 6336, 2273, 14466, 10403, 52093,
+ 56156, 60223, 64286, 35833, 39896, 43963, 48026, 19061, 23124, 27191, 31254, 2801,
+ 6864, 10931, 14994, 64814, 60687, 56684, 52557, 48554, 44427, 40424, 36297, 31782,
+ 27655, 23652, 19525, 15522, 11395, 7392, 3265, 61215, 65342, 53085, 57212, 44955,
+ 49082, 36825, 40952, 28183, 32310, 20053, 24180, 11923, 16050, 3793, 7920};
+
+ // // https://github.com/ThePBone/GalaxyBudsClient/blob/master/GalaxyBudsClient/Utils/CRC16.cs
+ public static int crc16_ccitt(byte[] data) {
+
+ int i2 = 0;
+ for (int i3 = 0; i3 < data.length; i3++)
+ i2 = Crc16Tab[((i2 >> 8) ^ data[i3]) & 255] ^ (i2 << 8);
+
+ return 65535 & i2;
+ }
}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/DeviceHelper.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/DeviceHelper.java
index 431df5ccf..4ea75b6c6 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/DeviceHelper.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/DeviceHelper.java
@@ -49,6 +49,7 @@ import nodomain.freeyourgadget.gadgetbridge.devices.banglejs.BangleJSCoordinator
import nodomain.freeyourgadget.gadgetbridge.devices.casio.gb6900.CasioGB6900DeviceCoordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.casio.gbx100.CasioGBX100DeviceCoordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.domyos.DomyosT540Cooridnator;
+import nodomain.freeyourgadget.gadgetbridge.devices.galaxy_buds.GalaxyBudsDeviceCoordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.hplus.EXRIZUK8Coordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.hplus.HPlusCoordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.hplus.MakibesF68Coordinator;
@@ -308,6 +309,7 @@ public class DeviceHelper {
result.add(new DomyosT540Cooridnator());
result.add(new FitProDeviceCoordinator());
result.add(new Ear1Coordinator());
+ result.add(new GalaxyBudsDeviceCoordinator());
return result;
}
diff --git a/app/src/main/res/drawable/ic_device_galaxy_buds.xml b/app/src/main/res/drawable/ic_device_galaxy_buds.xml
new file mode 100644
index 000000000..65e2585b8
--- /dev/null
+++ b/app/src/main/res/drawable/ic_device_galaxy_buds.xml
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_device_galaxy_buds_disabled.xml b/app/src/main/res/drawable/ic_device_galaxy_buds_disabled.xml
new file mode 100644
index 000000000..830d4657e
--- /dev/null
+++ b/app/src/main/res/drawable/ic_device_galaxy_buds_disabled.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_equalizer.xml b/app/src/main/res/drawable/ic_equalizer.xml
new file mode 100644
index 000000000..5ff52042d
--- /dev/null
+++ b/app/src/main/res/drawable/ic_equalizer.xml
@@ -0,0 +1,3 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_graphic_eq.xml b/app/src/main/res/drawable/ic_graphic_eq.xml
new file mode 100644
index 000000000..c650a0849
--- /dev/null
+++ b/app/src/main/res/drawable/ic_graphic_eq.xml
@@ -0,0 +1,3 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_hearing.xml b/app/src/main/res/drawable/ic_hearing.xml
new file mode 100644
index 000000000..7a0167232
--- /dev/null
+++ b/app/src/main/res/drawable/ic_hearing.xml
@@ -0,0 +1,3 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_music_note.xml b/app/src/main/res/drawable/ic_music_note.xml
new file mode 100644
index 000000000..0e1b03e47
--- /dev/null
+++ b/app/src/main/res/drawable/ic_music_note.xml
@@ -0,0 +1,3 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_touch.xml b/app/src/main/res/drawable/ic_touch.xml
new file mode 100644
index 000000000..e93d7f975
--- /dev/null
+++ b/app/src/main/res/drawable/ic_touch.xml
@@ -0,0 +1,3 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_videogame.xml b/app/src/main/res/drawable/ic_videogame.xml
new file mode 100644
index 000000000..c50c195af
--- /dev/null
+++ b/app/src/main/res/drawable/ic_videogame.xml
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_voice.xml b/app/src/main/res/drawable/ic_voice.xml
new file mode 100644
index 000000000..85151bcde
--- /dev/null
+++ b/app/src/main/res/drawable/ic_voice.xml
@@ -0,0 +1,3 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_volume_up.xml b/app/src/main/res/drawable/ic_volume_up.xml
new file mode 100644
index 000000000..88bd805db
--- /dev/null
+++ b/app/src/main/res/drawable/ic_volume_up.xml
@@ -0,0 +1,3 @@
+
+
+
diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml
index 2532882fe..7f9e02e9c 100644
--- a/app/src/main/res/values/arrays.xml
+++ b/app/src/main/res/values/arrays.xml
@@ -1601,6 +1601,13 @@
FORWARD
REWIND
BROADCAST
+ Voice Assistant
+ Quick Ambient Sound
+ Volume
+ Ambient Sound
+ Spotify
+ Other Left
+ Other Right
- @string/pref_button_action_disabled
@@ -1788,5 +1795,44 @@
- false
+
+ - 1
+ - 2
+ - 3
+ - 4
+ - 5
+
+
+
+ - @string/pref_title_equalizer_bass_boost
+ - @string/pref_title_equalizer_soft
+ - @string/pref_title_equalizer_dynamic
+ - @string/pref_title_equalizer_clear
+ - @string/pref_title_equalizer_trebble
+
+
+
+ - 0
+ - 1
+ - 2
+ - 3
+ - 4
+
+
+
+
+ - @string/pref_title_touch_quick_ambient
+
+ - @string/pref_title_touch_ambient
+
+
+
+
+
+ - 1
+
+ - 3
+
+
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index f71c26433..779dc62b4 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -1282,7 +1282,32 @@
Take measurements during sleep
Frequency of measurements
Nothing Ear (1)
+ Galaxy Buds
Play/pause the music depending if you wear the earbuds
In-Ear detection
Audio mode
+ Equalizer Preset
+ Bass boost
+ Soft
+ Dynamic
+ Clear
+ Treble boost
+ Dolby Mode
+ Equalizer
+ Enable or disable equalizer
+ Dolby preset for equalizer
+ Game mode
+ Only if your phone supports game mode
+ Touch Lock
+ Disable touch events
+ Experimental
+ Ambient volume
+ pref_galaxy_buds_ambient_volume
+ Voice Focus
+ Make voice stand out
+ Ambient Sound
+ Ambient Mode
+ Left
+ Right
+ Touch Options
diff --git a/app/src/main/res/xml/devicesettings_galaxy_buds.xml b/app/src/main/res/xml/devicesettings_galaxy_buds.xml
new file mode 100644
index 000000000..d42db9f1f
--- /dev/null
+++ b/app/src/main/res/xml/devicesettings_galaxy_buds.xml
@@ -0,0 +1,104 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+