diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/casio/CasioConstants.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/casio/CasioConstants.java index ed49846d94..2db060ac53 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/casio/CasioConstants.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/casio/CasioConstants.java @@ -120,6 +120,18 @@ public final class CasioConstants { MODEL_CASIO_GBX100 } + public enum ConfigurationOption { + OPTION_GENDER, + OPTION_WEIGHT, + OPTION_HEIGHT, + OPTION_WRIST, + OPTION_BIRTHDAY, + OPTION_STEP_GOAL, + OPTION_DISTANCE_GOAL, + OPTION_ACTIVITY_GOAL, + OPTION_ALL + } + public static Map characteristicToByte = new HashMap() { { put("CASIO_WATCH_NAME", (byte) 0x23); @@ -135,6 +147,9 @@ public final class CasioConstants { put("CASIO_DST_SETTING", (byte) 0x1e); put("CASIO_SERVICE_DISCOVERY_MANAGER", (byte) 0x47); put("CASIO_CURRENT_TIME", (byte) 0x09); + put("CASIO_SETTING_FOR_USER_PROFILE", (byte) 0x45); + put("CASIO_SETTING_FOR_TARGET_VALUE", (byte) 0x43); + put("ALERT_LEVEL", (byte) 0x0a); } }; } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/casio/gbx100/CasioGBX100DeviceCoordinator.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/casio/gbx100/CasioGBX100DeviceCoordinator.java index dcaf5df921..dda42ba149 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/casio/gbx100/CasioGBX100DeviceCoordinator.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/casio/gbx100/CasioGBX100DeviceCoordinator.java @@ -117,7 +117,7 @@ public class CasioGBX100DeviceCoordinator extends AbstractDeviceCoordinator { @Override public int getAlarmSlotCount() { - return 0; // 4 regular and one snooze + return 4; } @Override @@ -149,4 +149,12 @@ public class CasioGBX100DeviceCoordinator extends AbstractDeviceCoordinator { 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_find_phone, + R.xml.devicesettings_wearlocation + }; + } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/casio/CasioGBX100DeviceSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/casio/CasioGBX100DeviceSupport.java index 00fbc4bb13..33006dbd17 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/casio/CasioGBX100DeviceSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/casio/CasioGBX100DeviceSupport.java @@ -17,12 +17,11 @@ along with this program. If not, see . */ package nodomain.freeyourgadget.gadgetbridge.service.devices.casio; -import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothGatt; import android.bluetooth.BluetoothGattCharacteristic; -import android.bluetooth.BluetoothGattDescriptor; -import android.bluetooth.BluetoothGattService; +import android.content.SharedPreferences; import android.net.Uri; +import android.os.Handler; import android.widget.Toast; import org.slf4j.Logger; @@ -37,10 +36,12 @@ import java.util.UUID; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; -import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventCallControl; +import nodomain.freeyourgadget.gadgetbridge.GBApplication; +import nodomain.freeyourgadget.gadgetbridge.R; +import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventFindPhone; -import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventMusicControl; import nodomain.freeyourgadget.gadgetbridge.devices.casio.CasioConstants; +import nodomain.freeyourgadget.gadgetbridge.devices.makibeshr3.MakibesHR3Constants; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.model.Alarm; import nodomain.freeyourgadget.gadgetbridge.model.CalendarEventSpec; @@ -51,24 +52,29 @@ import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec; import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec; import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec; import nodomain.freeyourgadget.gadgetbridge.service.btle.AbstractBTLEDeviceSupport; -import nodomain.freeyourgadget.gadgetbridge.service.btle.GattCharacteristic; -import nodomain.freeyourgadget.gadgetbridge.service.btle.GattService; -import nodomain.freeyourgadget.gadgetbridge.service.btle.ServerTransactionBuilder; import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder; -import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.SetDeviceStateAction; +import nodomain.freeyourgadget.gadgetbridge.service.devices.casio.operations.GetConfigurationOperation; import nodomain.freeyourgadget.gadgetbridge.service.devices.casio.operations.InitOperationGBX100; +import nodomain.freeyourgadget.gadgetbridge.service.devices.casio.operations.SetConfigurationOperation; import nodomain.freeyourgadget.gadgetbridge.util.GB; -import nodomain.freeyourgadget.gadgetbridge.util.StringUtils; -public class CasioGBX100DeviceSupport extends AbstractBTLEDeviceSupport { +import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_FIND_PHONE_ENABLED; +import static nodomain.freeyourgadget.gadgetbridge.model.ActivityUser.PREF_USER_ACTIVETIME_MINUTES; +import static nodomain.freeyourgadget.gadgetbridge.model.ActivityUser.PREF_USER_DISTANCE_METERS; +import static nodomain.freeyourgadget.gadgetbridge.model.ActivityUser.PREF_USER_GENDER; +import static nodomain.freeyourgadget.gadgetbridge.model.ActivityUser.PREF_USER_HEIGHT_CM; +import static nodomain.freeyourgadget.gadgetbridge.model.ActivityUser.PREF_USER_STEPS_GOAL; +import static nodomain.freeyourgadget.gadgetbridge.model.ActivityUser.PREF_USER_WEIGHT_KG; +import static nodomain.freeyourgadget.gadgetbridge.model.ActivityUser.PREF_USER_YEAR_OF_BIRTH; + +public class CasioGBX100DeviceSupport extends AbstractBTLEDeviceSupport implements SharedPreferences.OnSharedPreferenceChangeListener { private static final Logger LOG = LoggerFactory.getLogger(CasioGBX100DeviceSupport.class); - private final ArrayList mCasioCharacteristics = new ArrayList(); - private MusicSpec mBufferMusicSpec = null; - private MusicStateSpec mBufferMusicStateSpec = null; - private BluetoothGatt mBtGatt = null; private boolean mFirstConnect = false; + private boolean mGetConfigurationPending = false; private ArrayList mSyncedNotificationIDs = new ArrayList<>(); + private int mLastCallId = 0; + private final Handler mFindPhoneHandler = new Handler(); public CasioGBX100DeviceSupport() { super(LOG); @@ -82,15 +88,10 @@ public class CasioGBX100DeviceSupport extends AbstractBTLEDeviceSupport { return connect(); } - public void setInitialized(TransactionBuilder builder) { + public void setInitialized() { mFirstConnect = false; - builder.add(new SetDeviceStateAction(gbDevice, GBDevice.State.INITIALIZED, getContext())); - } - - @Override - public void onServicesDiscovered(BluetoothGatt gatt) { - mBtGatt = gatt; - super.onServicesDiscovered(gatt); + gbDevice.setState(GBDevice.State.INITIALIZED); + gbDevice.sendDeviceUpdateIntent(getContext()); } @Override @@ -105,6 +106,12 @@ public class CasioGBX100DeviceSupport extends AbstractBTLEDeviceSupport { getDevice().setFirmwareVersion("N/A"); getDevice().setFirmwareVersion2("N/A"); + SharedPreferences preferences = GBApplication.getDeviceSpecificSharedPrefs(this.getDevice().getAddress()); + preferences.registerOnSharedPreferenceChangeListener(this); + + SharedPreferences prefs = GBApplication.getPrefs().getPreferences(); + prefs.registerOnSharedPreferenceChangeListener(this); + return builder; } @@ -124,13 +131,22 @@ public class CasioGBX100DeviceSupport extends AbstractBTLEDeviceSupport { @Override public boolean onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { - boolean handled = false; - UUID characteristicUUID = characteristic.getUuid(); byte[] data = characteristic.getValue(); if (data.length == 0) return true; + if (characteristicUUID.equals(CasioConstants.CASIO_ALL_FEATURES_CHARACTERISTIC_UUID)) { + if(data[0] == CasioConstants.characteristicToByte.get("ALERT_LEVEL")) { + if(data[1] == 0x02) { + onReverseFindDevice(true); + } else { + onReverseFindDevice(false); + } + return true; + } + } + LOG.info("Unhandled characteristic change: " + characteristicUUID + " code: " + String.format("0x%1x ...", data[0])); return super.onCharacteristicChanged(gatt, characteristic); } @@ -140,6 +156,14 @@ public class CasioGBX100DeviceSupport extends AbstractBTLEDeviceSupport { return true; } + public void syncProfile() { + try { + new SetConfigurationOperation(this, CasioConstants.ConfigurationOption.OPTION_ALL).perform(); + } catch (IOException e) { + GB.toast(getContext(), "Sending Casio configuration failed", Toast.LENGTH_SHORT, GB.ERROR, e); + } + } + private void showNotification(byte icon, String sender, String title, String message, int id, boolean delete) { byte[] titleBytes = new byte[0]; if(title != null) @@ -256,6 +280,51 @@ public class CasioGBX100DeviceSupport extends AbstractBTLEDeviceSupport { } } + private void onReverseFindDevice(boolean start) { + if (start) { + SharedPreferences sharedPreferences = GBApplication.getDeviceSpecificSharedPrefs(getDevice().getAddress()); + + String findPhone = sharedPreferences.getString(PREF_FIND_PHONE_ENABLED, getContext().getString(R.string.p_off)); + + if(findPhone.equals(getContext().getString(R.string.p_off))) + return; + + GBDeviceEventFindPhone findPhoneEvent = new GBDeviceEventFindPhone(); + findPhoneEvent.event = GBDeviceEventFindPhone.Event.START; + evaluateGBDeviceEvent(findPhoneEvent); + + if(!findPhone.equals(getContext().getString(R.string.p_on))) { + String duration = sharedPreferences.getString(MakibesHR3Constants.PREF_FIND_PHONE_DURATION, "0"); + + try { + int iDuration; + + try { + iDuration = Integer.valueOf(duration); + } catch (Exception ex) { + LOG.warn(ex.getMessage()); + iDuration = 60; + } + if(iDuration > 0) { + this.mFindPhoneHandler.postDelayed(new Runnable() { + @Override + public void run() { + onReverseFindDevice(false); + } + }, iDuration * 1000); + } + } catch (Exception e) { + LOG.error("Unexpected exception in MiBand2Coordinator.getTime: " + e.getMessage()); + } + } + } else { + // Always send stop, ignore preferences. + GBDeviceEventFindPhone findPhoneEvent = new GBDeviceEventFindPhone(); + findPhoneEvent.event = GBDeviceEventFindPhone.Event.STOP; + evaluateGBDeviceEvent(findPhoneEvent); + } + } + public void writeCurrentTime(TransactionBuilder builder) { byte[] arr = new byte[11]; Calendar cal = Calendar.getInstance(); @@ -306,11 +375,14 @@ public class CasioGBX100DeviceSupport extends AbstractBTLEDeviceSupport { @Override public void onSetCallState(CallSpec callSpec) { - final AtomicInteger c = new AtomicInteger((int) (System.currentTimeMillis()/1000)); switch (callSpec.command) { case CallSpec.CALL_INCOMING: - showNotification(CasioConstants.CATEGORY_INCOMING_CALL, "Phone", callSpec.name, callSpec.number, c.incrementAndGet(), false); + final AtomicInteger c = new AtomicInteger((int) (System.currentTimeMillis()/1000)); + mLastCallId = c.incrementAndGet(); + showNotification(CasioConstants.CATEGORY_INCOMING_CALL, "Phone", callSpec.name, callSpec.number, mLastCallId, false); break; + case CallSpec.CALL_END: + showNotification(CasioConstants.CATEGORY_INCOMING_CALL, null, null, null, mLastCallId, true); default: LOG.info("not sending CallSpec since only CALL_INCOMING is handled"); break; @@ -423,12 +495,26 @@ public class CasioGBX100DeviceSupport extends AbstractBTLEDeviceSupport { @Override public void onSendConfiguration(String config) { + LOG.info("onSendConfiguration" + config); + } + public void onGetConfigurationFinished() { + mGetConfigurationPending = false; } @Override public void onReadConfiguration(String config) { - + LOG.info("onReadConfiguration" + config); + // This is called upon pairing to retrieve the current watch settings, if any + if(config == null) { + try { + mGetConfigurationPending = true; + new GetConfigurationOperation(this, true).perform(); + } catch (IOException e) { + mGetConfigurationPending = false; + GB.toast(getContext(), "Reading Casio configuration failed", Toast.LENGTH_SHORT, GB.ERROR, e); + } + } } @Override @@ -440,4 +526,44 @@ public class CasioGBX100DeviceSupport extends AbstractBTLEDeviceSupport { public void onSendWeather(WeatherSpec weatherSpec) { } + + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { + LOG.debug(key + " changed"); + + if (!this.isConnected()) { + LOG.debug("ignoring change, we're disconnected"); + return; + } + + if(mGetConfigurationPending) { + LOG.debug("Preferences are being fetched right now"); + return; + } + try { + if (key.equals(DeviceSettingsPreferenceConst.PREF_WEARLOCATION)) { + new SetConfigurationOperation(this, CasioConstants.ConfigurationOption.OPTION_WRIST).perform(); + } else if(key.equals(PREF_USER_STEPS_GOAL)) { + new SetConfigurationOperation(this, CasioConstants.ConfigurationOption.OPTION_STEP_GOAL).perform(); + } else if(key.equals(PREF_USER_ACTIVETIME_MINUTES)) { + new SetConfigurationOperation(this, CasioConstants.ConfigurationOption.OPTION_ACTIVITY_GOAL).perform(); + } else if(key.equals(PREF_USER_DISTANCE_METERS)) { + new SetConfigurationOperation(this, CasioConstants.ConfigurationOption.OPTION_DISTANCE_GOAL).perform(); + } else if(key.equals(PREF_USER_GENDER)) { + new SetConfigurationOperation(this, CasioConstants.ConfigurationOption.OPTION_GENDER).perform(); + } else if(key.equals(PREF_USER_HEIGHT_CM)) { + new SetConfigurationOperation(this, CasioConstants.ConfigurationOption.OPTION_HEIGHT).perform(); + } else if(key.equals(PREF_USER_WEIGHT_KG)) { + new SetConfigurationOperation(this, CasioConstants.ConfigurationOption.OPTION_WEIGHT).perform(); + } else if(key.equals(PREF_USER_YEAR_OF_BIRTH)) { + new SetConfigurationOperation(this, CasioConstants.ConfigurationOption.OPTION_BIRTHDAY).perform(); + } else if (key.equals(PREF_FIND_PHONE_ENABLED) || + key.equals(MakibesHR3Constants.PREF_FIND_PHONE_DURATION)) { + // No action, we check the shared preferences when the device tries to ring the phone. + } else { + return; + } + } catch (IOException e) { + LOG.info("Error sending configuration change to watch"); + } + } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/casio/operations/GetConfigurationOperation.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/casio/operations/GetConfigurationOperation.java new file mode 100644 index 0000000000..2ca3f873cf --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/casio/operations/GetConfigurationOperation.java @@ -0,0 +1,119 @@ +package nodomain.freeyourgadget.gadgetbridge.service.devices.casio.operations; + +import android.bluetooth.BluetoothGatt; +import android.bluetooth.BluetoothGattCharacteristic; +import android.content.SharedPreferences; + +import org.apache.commons.lang3.RandomStringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.util.UUID; +import java.util.prefs.Preferences; + +import nodomain.freeyourgadget.gadgetbridge.GBApplication; +import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpecificSettingsFragment; +import nodomain.freeyourgadget.gadgetbridge.devices.casio.CasioConstants; +import nodomain.freeyourgadget.gadgetbridge.service.btle.AbstractBTLEOperation; +import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder; +import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.PlainAction; +import nodomain.freeyourgadget.gadgetbridge.service.devices.casio.CasioGBX100DeviceSupport; +import nodomain.freeyourgadget.gadgetbridge.service.devices.miband.operations.OperationStatus; +import nodomain.freeyourgadget.gadgetbridge.util.BcdUtil; +import nodomain.freeyourgadget.gadgetbridge.util.Prefs; + +import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_WEARLOCATION; + +public class GetConfigurationOperation extends AbstractBTLEOperation { + private static final Logger LOG = LoggerFactory.getLogger(GetConfigurationOperation.class); + private final CasioGBX100DeviceSupport support; + private final boolean mFirstConnect; + + public GetConfigurationOperation(CasioGBX100DeviceSupport support, boolean firstconnect) { + super(support); + this.support = support; + this.mFirstConnect = firstconnect; + } + + @Override + protected void doPerform() throws IOException { + byte[] command = new byte[1]; + command[0] = CasioConstants.characteristicToByte.get("CASIO_SETTING_FOR_USER_PROFILE"); + TransactionBuilder builder = performInitialized("getConfiguration"); + builder.setGattCallback(this); + support.writeAllFeaturesRequest(builder, command); + builder.queue(getQueue()); + } + + @Override + protected void operationFinished() { + operationStatus = OperationStatus.FINISHED; + if (getDevice() != null) { + try { + TransactionBuilder builder = performInitialized("finishe operation"); + builder.wait(0); + builder.setGattCallback(null); // unset ourselves from being the queue's gatt callback + builder.queue(getQueue()); + } catch (IOException ex) { + LOG.info("Error resetting Gatt callback: " + ex.getMessage()); + } + } + support.onGetConfigurationFinished(); + } + + @Override + public boolean onCharacteristicChanged(BluetoothGatt gatt, + BluetoothGattCharacteristic characteristic) { + UUID characteristicUUID = characteristic.getUuid(); + byte[] data = characteristic.getValue(); + + if (data.length == 0) + return true; + + if (characteristicUUID.equals(CasioConstants.CASIO_ALL_FEATURES_CHARACTERISTIC_UUID)) { + if(data[0] == CasioConstants.characteristicToByte.get("CASIO_SETTING_FOR_USER_PROFILE")) { + boolean female = ((data[1] & 0x01) == 0x01) ; + boolean right = ((data[1] & 0x02) == 0x02); + byte[] compData = new byte[data.length]; + for(int i=0; i { + private static final Logger LOG = LoggerFactory.getLogger(GetConfigurationOperation.class); + private final CasioGBX100DeviceSupport support; + private final CasioConstants.ConfigurationOption option; + + public SetConfigurationOperation(CasioGBX100DeviceSupport support, CasioConstants.ConfigurationOption option) { + super(support); + this.support = support; + this.option = option; + } + + @Override + protected void doPerform() throws IOException { + byte[] command = new byte[1]; + command[0] = CasioConstants.characteristicToByte.get("CASIO_SETTING_FOR_USER_PROFILE"); + TransactionBuilder builder = performInitialized("getConfiguration"); + builder.setGattCallback(this); + support.writeAllFeaturesRequest(builder, command); + builder.queue(getQueue()); + } + + @Override + public boolean onCharacteristicChanged(BluetoothGatt gatt, + BluetoothGattCharacteristic characteristic) { + UUID characteristicUUID = characteristic.getUuid(); + byte[] data = characteristic.getValue(); + + if (data.length == 0) + return true; + + if (characteristicUUID.equals(CasioConstants.CASIO_ALL_FEATURES_CHARACTERISTIC_UUID)) { + byte[] oldData = new byte[data.length]; + System.arraycopy(data, 0, oldData, 0, data.length); + + if (data[0] == CasioConstants.characteristicToByte.get("CASIO_SETTING_FOR_USER_PROFILE")) { + + ActivityUser user = new ActivityUser(); + boolean all = (option == CasioConstants.ConfigurationOption.OPTION_ALL); + if (option == CasioConstants.ConfigurationOption.OPTION_GENDER || all) { + if (user.getGender() == GENDER_MALE) { + data[1] = (byte) (data[1] & ~0x01); + } else { + data[1] = (byte) (data[1] | 0x01); + } + } + + for(int i=2; i> 8) & 0xff); + } + + if(option == CasioConstants.ConfigurationOption.OPTION_DISTANCE_GOAL || all) { + // The watch requires a monthly goal, so we multiply that with 30 + // and divide it by 100 because the value is set in 100m units + int distance = user.getDistanceMeters() * 30; + distance = distance / 100; + data[6] = (byte)(distance & 0xff); + data[7] = (byte)((distance >> 8) & 0xff); + } + + if(option == CasioConstants.ConfigurationOption.OPTION_ACTIVITY_GOAL || all) { + // The watch requires a monthly goal, so we multiply that with 30 + int time = user.getActiveTimeMinutes() * 30; + data[9] = (byte)(time & 0xff); + data[10] = (byte)((time >> 8) & 0xff); + } + + if(Arrays.equals(oldData, data)) { + LOG.info("No configuration update required"); + operationFinished(); + } else { + // Operation will be finished in Gatt callback + try { + TransactionBuilder builder = performInitialized("setConfiguration"); + builder.setGattCallback(this); + support.writeAllFeatures(builder, data); + builder.queue(getQueue()); + } catch (IOException e) { + LOG.info("Error writing configuration to Casio watch"); + } + } + return true; + } + + } + LOG.info("Unhandled characteristic changed: " + characteristicUUID); + return super.onCharacteristicChanged(gatt, characteristic); + } + + @Override + protected void operationFinished() { + LOG.info("SetConfigurationOperation finished"); + + operationStatus = OperationStatus.FINISHED; + if (getDevice() != null) { + unsetBusy(); + try { + TransactionBuilder builder = performInitialized("finishe operation"); + builder.setGattCallback(null); // unset ourselves from being the queue's gatt callback + builder.wait(0); + builder.queue(getQueue()); + } catch (IOException ex) { + LOG.info("Error resetting Gatt callback: " + ex.getMessage()); + } + } + } + + private void requestTargetSettings() { + byte[] command = new byte[1]; + command[0] = CasioConstants.characteristicToByte.get("CASIO_SETTING_FOR_TARGET_VALUE"); + try { + TransactionBuilder builder = performInitialized("getConfiguration"); + builder.setGattCallback(this); + support.writeAllFeaturesRequest(builder, command); + builder.queue(getQueue()); + } catch(IOException e) { + LOG.info("Error requesting Casio configuration"); + } + } + + @Override + public boolean onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { + + UUID characteristicUUID = characteristic.getUuid(); + byte[] data = characteristic.getValue(); + + if (data.length == 0) + return true; + + if (characteristicUUID.equals(CasioConstants.CASIO_ALL_FEATURES_CHARACTERISTIC_UUID)) { + if(data[0] == CasioConstants.characteristicToByte.get("CASIO_SETTING_FOR_USER_PROFILE")) { + requestTargetSettings(); + return true; + } + if(data[0] == CasioConstants.characteristicToByte.get("CASIO_SETTING_FOR_TARGET_VALUE")) { + operationFinished(); + return true; + } + } + return super.onCharacteristicWrite(gatt, characteristic, status); + } +} \ No newline at end of file