diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/casio/CasioGB6900DeviceSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/casio/CasioGB6900DeviceSupport.java index bb0bb8b14..19ac8a532 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/casio/CasioGB6900DeviceSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/casio/CasioGB6900DeviceSupport.java @@ -55,12 +55,13 @@ 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.devices.casio.operations.InitOperationGB6900; +import nodomain.freeyourgadget.gadgetbridge.service.devices.casio.operations.SetAlarmOperation; import nodomain.freeyourgadget.gadgetbridge.util.GB; import nodomain.freeyourgadget.gadgetbridge.util.StringUtils; import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_DISCONNECTNOTIF_NOSHED; -public class CasioGB6900DeviceSupport extends AbstractBTLEDeviceSupport { +public class CasioGB6900DeviceSupport extends CasioSupport { private static final Logger LOG = LoggerFactory.getLogger(CasioGB6900DeviceSupport.class); private final ArrayList mCasioCharacteristics = new ArrayList(); @@ -69,7 +70,6 @@ public class CasioGB6900DeviceSupport extends AbstractBTLEDeviceSupport { private MusicStateSpec mBufferMusicStateSpec = null; private BluetoothGatt mBtGatt = null; private CasioConstants.Model mModel = CasioConstants.Model.MODEL_CASIO_GENERIC; - private boolean mFirstConnect = false; private static final int mCasioSleepTime = 50; @@ -81,7 +81,6 @@ public class CasioGB6900DeviceSupport extends AbstractBTLEDeviceSupport { addSupportedService(CasioConstants.CASIO_IMMEDIATE_ALERT_SERVICE_UUID); addSupportedService(CasioConstants.CURRENT_TIME_SERVICE_UUID); addSupportedService(CasioConstants.WATCH_CTRL_SERVICE_UUID); - addSupportedService(CasioConstants.WATCH_FEATURES_SERVICE_UUID); addSupportedService(CasioConstants.CASIO_PHONE_ALERT_STATUS_SERVICE); addSupportedService(CasioConstants.MORE_ALERT_SERVICE_UUID); addSupportedService(CasioConstants.TX_POWER_SERVICE_UUID); @@ -140,8 +139,7 @@ public class CasioGB6900DeviceSupport extends AbstractBTLEDeviceSupport { LOG.info("Initializing"); if(mFirstConnect) { - gbDevice.setState(GBDevice.State.INITIALIZED); - gbDevice.sendDeviceUpdateIntent(getContext()); + setInitialized(); getDevice().setFirmwareVersion("N/A"); getDevice().setFirmwareVersion2("N/A"); return builder; @@ -238,23 +236,7 @@ public class CasioGB6900DeviceSupport extends AbstractBTLEDeviceSupport { } private void writeCasioCurrentTime(TransactionBuilder builder) { - byte[] arr = new byte[10]; - Calendar cal = Calendar.getInstance(); - - int year = cal.get(Calendar.YEAR); - arr[0] = (byte)((year >>> 0) & 0xff); - arr[1] = (byte)((year >>> 8) & 0xff); - arr[2] = (byte)(1 + cal.get(Calendar.MONTH)); - arr[3] = (byte)cal.get(Calendar.DAY_OF_MONTH); - arr[4] = (byte)cal.get(Calendar.HOUR_OF_DAY); - arr[5] = (byte)cal.get(Calendar.MINUTE); - arr[6] = (byte)(1 + cal.get(Calendar.SECOND)); - byte dayOfWk = (byte)(cal.get(Calendar.DAY_OF_WEEK) - 1); - if(dayOfWk == 0) - dayOfWk = 7; - arr[7] = dayOfWk; - arr[8] = (byte)(int) TimeUnit.MILLISECONDS.toSeconds(256 * cal.get(Calendar.MILLISECOND)); - arr[9] = 1; // or 0? + byte[] arr = prepareCurrentTime(); BluetoothGattCharacteristic charact = getCharacteristic(CasioConstants.CURRENT_TIME_CHARACTERISTIC_UUID); if(charact != null) { @@ -487,23 +469,18 @@ public class CasioGB6900DeviceSupport extends AbstractBTLEDeviceSupport { } } - @Override - public boolean useAutoConnect() { - return true; - } - @Override public void onNotification(NotificationSpec notificationSpec) { String notificationTitle = StringUtils.getFirstOf(notificationSpec.sender, notificationSpec.title); byte icon; - switch (notificationSpec.type) { - case GENERIC_SMS: + switch (notificationSpec.type.getGenericType()) { + case "generic_sms": icon = CasioConstants.SMS_NOTIFICATION_ID; break; - case GENERIC_CALENDAR: + case "generic_calendar": icon = CasioConstants.CALENDAR_NOTIFICATION_ID; break; - case GENERIC_EMAIL: + case "generic_email": icon = CasioConstants.MAIL_NOTIFICATION_ID; break; default: @@ -513,40 +490,15 @@ public class CasioGB6900DeviceSupport extends AbstractBTLEDeviceSupport { showNotification(icon, notificationTitle, notificationSpec.body); } - @Override - public void onDeleteNotification(int id) { - - } - @Override public void onSetAlarms(ArrayList alarms) { - int alarmOffset = 4; - byte[] data = new byte[20]; - if(!isConnected()) return; - for(int i=0; i mSyncedNotificationIDs = new ArrayList<>(); @@ -99,19 +99,6 @@ public class CasioGBX100DeviceSupport extends AbstractBTLEDeviceSupport implemen public CasioGBX100DeviceSupport() { super(LOG); - addSupportedService(CasioConstants.WATCH_FEATURES_SERVICE_UUID); - } - - @Override - public boolean connectFirstTime() { - mFirstConnect = true; - return connect(); - } - - public void setInitialized() { - mFirstConnect = false; - gbDevice.setState(GBDevice.State.INITIALIZED); - gbDevice.sendDeviceUpdateIntent(getContext()); } @Override @@ -251,11 +238,6 @@ public class CasioGBX100DeviceSupport extends AbstractBTLEDeviceSupport implemen return super.onCharacteristicChanged(gatt, characteristic); } - @Override - public boolean useAutoConnect() { - return true; - } - public void syncProfile() { try { new SetConfigurationOperation(this, CasioConstants.ConfigurationOption.OPTION_ALL).perform(); @@ -442,23 +424,8 @@ public class CasioGBX100DeviceSupport extends AbstractBTLEDeviceSupport implemen public void writeCurrentTime(TransactionBuilder builder) { byte[] arr = new byte[11]; - Calendar cal = Calendar.getInstance(); - - int year = cal.get(Calendar.YEAR); - arr[0] = CasioConstants.characteristicToByte.get("CASIO_CURRENT_TIME"); - arr[1] = (byte)(year & 0xff); - arr[2] = (byte)((year >>> 8) & 0xff); - arr[3] = (byte)(1 + cal.get(Calendar.MONTH)); - arr[4] = (byte)cal.get(Calendar.DAY_OF_MONTH); - arr[5] = (byte)cal.get(Calendar.HOUR_OF_DAY); - arr[6] = (byte)cal.get(Calendar.MINUTE); - arr[7] = (byte)(1 + cal.get(Calendar.SECOND)); - byte dayOfWk = (byte)(cal.get(Calendar.DAY_OF_WEEK) - 1); - if(dayOfWk == 0) - dayOfWk = 7; - arr[8] = dayOfWk; - arr[9] = (byte)(int) TimeUnit.MILLISECONDS.toSeconds(256 * cal.get(Calendar.MILLISECOND)); - arr[10] = 1; // or 0? + byte[] tmp = prepareCurrentTime(); + System.arraycopy(tmp, 0, arr, 1, 10); writeAllFeatures(builder, arr); } @@ -473,7 +440,6 @@ public class CasioGBX100DeviceSupport extends AbstractBTLEDeviceSupport implemen @Override public void onSetAlarms(ArrayList alarms) { - int alarmOffset = 4; byte[] data1 = new byte[5]; byte[] data2 = new byte[17]; @@ -492,9 +458,6 @@ public class CasioGBX100DeviceSupport extends AbstractBTLEDeviceSupport implemen } else { settings[0] = 0; } - if(alm.getRepetition(Alarm.ALARM_ONCE)) { - settings[i * alarmOffset] |= 0x20; - } settings[1] = 0x40; settings[2] = (byte)alm.getHour(); settings[3] = (byte)alm.getMinute(); @@ -557,55 +520,6 @@ public class CasioGBX100DeviceSupport extends AbstractBTLEDeviceSupport implemen } } - @Override - public void onSetCannedMessages(CannedMessagesSpec cannedMessagesSpec) { - - } - - @Override - public void onSetMusicState(MusicStateSpec stateSpec) { - - } - - @Override - public void onSetMusicInfo(MusicSpec musicSpec) { - - } - - @Override - public void onEnableRealtimeSteps(boolean enable) { - } - - @Override - public void onInstallApp(Uri uri) { - - } - - @Override - public void onAppInfoReq() { - - } - - @Override - public void onAppStart(UUID uuid, boolean start) { - - } - - @Override - public void onAppDelete(UUID uuid) { - - } - - @Override - public void onAppConfiguration(UUID appUuid, String config, Integer id) { - - } - - @Override - public void onAppReorder(UUID[] uuids) { - - } - @Override public void onFetchRecordedData(int dataTypes) { try { @@ -615,56 +529,6 @@ public class CasioGBX100DeviceSupport extends AbstractBTLEDeviceSupport implemen } } - @Override - public void onReset(int flags) { - - } - - @Override - public void onHeartRateTest() { - - } - - @Override - public void onEnableRealtimeHeartRateMeasurement(boolean enable) { - - } - - @Override - public void onFindDevice(boolean start) { - - } - - @Override - public void onSetConstantVibration(int integer) { - - } - - @Override - public void onScreenshotReq() { - - } - - @Override - public void onEnableHeartRateSleepSupport(boolean enable) { - - } - - @Override - public void onSetHeartRateMeasurementInterval(int seconds) { - - } - - @Override - public void onAddCalendarEvent(CalendarEventSpec calendarEventSpec) { - - } - - @Override - public void onDeleteCalendarEvent(byte type, long id) { - - } - @Override public void onSendConfiguration(String config) { LOG.info("onSendConfiguration" + config); @@ -704,11 +568,6 @@ public class CasioGBX100DeviceSupport extends AbstractBTLEDeviceSupport implemen } } - @Override - public void onSendWeather(WeatherSpec weatherSpec) { - - } - public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { LOG.debug(key + " changed"); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/casio/CasioSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/casio/CasioSupport.java new file mode 100644 index 000000000..a7c7875a4 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/casio/CasioSupport.java @@ -0,0 +1,227 @@ +package nodomain.freeyourgadget.gadgetbridge.service.devices.casio; + +import android.net.Uri; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.Calendar; +import java.util.UUID; +import java.util.concurrent.TimeUnit; + +import nodomain.freeyourgadget.gadgetbridge.devices.casio.CasioConstants; +import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; +import nodomain.freeyourgadget.gadgetbridge.model.Alarm; +import nodomain.freeyourgadget.gadgetbridge.model.CalendarEventSpec; +import nodomain.freeyourgadget.gadgetbridge.model.CallSpec; +import nodomain.freeyourgadget.gadgetbridge.model.CannedMessagesSpec; +import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec; +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.devices.huami.HuamiSupport; + +public class CasioSupport extends AbstractBTLEDeviceSupport { + + protected boolean mFirstConnect = false; + private static final Logger LOG = LoggerFactory.getLogger(HuamiSupport.class); + + public CasioSupport() { + this(LOG); + } + + public CasioSupport(Logger logger) { + super(logger); + addSupportedService(CasioConstants.WATCH_FEATURES_SERVICE_UUID); + } + + @Override + public boolean connectFirstTime() { + mFirstConnect = true; + return connect(); + } + + protected byte[] prepareCurrentTime() { + byte[] arr = new byte[10]; + Calendar cal = Calendar.getInstance(); + + int year = cal.get(Calendar.YEAR); + arr[0] = (byte)((year >>> 0) & 0xff); + arr[1] = (byte)((year >>> 8) & 0xff); + arr[2] = (byte)(1 + cal.get(Calendar.MONTH)); + arr[3] = (byte)cal.get(Calendar.DAY_OF_MONTH); + arr[4] = (byte)cal.get(Calendar.HOUR_OF_DAY); + arr[5] = (byte)cal.get(Calendar.MINUTE); + arr[6] = (byte)(1 + cal.get(Calendar.SECOND)); + byte dayOfWk = (byte)(cal.get(Calendar.DAY_OF_WEEK) - 1); + if(dayOfWk == 0) + dayOfWk = 7; + arr[7] = dayOfWk; + arr[8] = (byte)(int) TimeUnit.MILLISECONDS.toSeconds(256 * cal.get(Calendar.MILLISECOND)); + arr[9] = 1; // or 0? + return arr; + } + + public void setInitialized() { + mFirstConnect = false; + gbDevice.setState(GBDevice.State.INITIALIZED); + gbDevice.sendDeviceUpdateIntent(getContext()); + } + + @Override + public void onNotification(NotificationSpec notificationSpec) { + + } + + @Override + public void onDeleteNotification(int id) { + + } + + @Override + public void onSetTime() { + + } + + @Override + public void onSetAlarms(ArrayList alarms) { + + } + + @Override + public void onSetCallState(CallSpec callSpec) { + + } + + @Override + public void onSetCannedMessages(CannedMessagesSpec cannedMessagesSpec) { + + } + + @Override + public void onSetMusicState(MusicStateSpec stateSpec) { + + } + + @Override + public void onSetMusicInfo(MusicSpec musicSpec) { + + } + + @Override + public void onEnableRealtimeSteps(boolean enable) { + + } + + @Override + public void onInstallApp(Uri uri) { + + } + + @Override + public void onAppInfoReq() { + + } + + @Override + public void onAppStart(UUID uuid, boolean start) { + + } + + @Override + public void onAppDelete(UUID uuid) { + + } + + @Override + public void onAppConfiguration(UUID appUuid, String config, Integer id) { + + } + + @Override + public void onAppReorder(UUID[] uuids) { + + } + + @Override + public void onFetchRecordedData(int dataTypes) { + + } + + @Override + public void onReset(int flags) { + + } + + @Override + public void onHeartRateTest() { + + } + + @Override + public void onEnableRealtimeHeartRateMeasurement(boolean enable) { + + } + + @Override + public void onFindDevice(boolean start) { + + } + + @Override + public void onSetConstantVibration(int integer) { + + } + + @Override + public void onScreenshotReq() { + + } + + @Override + public void onEnableHeartRateSleepSupport(boolean enable) { + + } + + @Override + public void onSetHeartRateMeasurementInterval(int seconds) { + + } + + @Override + public void onAddCalendarEvent(CalendarEventSpec calendarEventSpec) { + + } + + @Override + public void onDeleteCalendarEvent(byte type, long id) { + + } + + @Override + public void onSendConfiguration(String config) { + + } + + @Override + public void onReadConfiguration(String config) { + + } + + @Override + public void onTestNewFunction() { + + } + + @Override + public void onSendWeather(WeatherSpec weatherSpec) { + + } + + @Override + public boolean useAutoConnect() { + return true; + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/casio/operations/SetAlarmOperation.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/casio/operations/SetAlarmOperation.java new file mode 100644 index 000000000..085e60f5c --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/casio/operations/SetAlarmOperation.java @@ -0,0 +1,135 @@ +/* Copyright (C) 2020-2021 Andreas Böhler + + 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 . */ +package nodomain.freeyourgadget.gadgetbridge.service.devices.casio.operations; + +import android.bluetooth.BluetoothGatt; +import android.bluetooth.BluetoothGattCharacteristic; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.UUID; + +import nodomain.freeyourgadget.gadgetbridge.devices.casio.CasioConstants; +import nodomain.freeyourgadget.gadgetbridge.model.Alarm; +import nodomain.freeyourgadget.gadgetbridge.service.btle.AbstractBTLEOperation; +import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder; +import nodomain.freeyourgadget.gadgetbridge.service.devices.casio.CasioGB6900DeviceSupport; +import nodomain.freeyourgadget.gadgetbridge.service.devices.miband.operations.OperationStatus; + +public class SetAlarmOperation extends AbstractBTLEOperation { + private static final Logger LOG = LoggerFactory.getLogger(GetConfigurationOperation.class); + private final ArrayList mAlarms; + + public SetAlarmOperation(CasioGB6900DeviceSupport support, ArrayList alarms) { + super(support); + this.mAlarms = alarms; + } + + @Override + protected void prePerform() throws IOException { + super.prePerform(); + getDevice().setBusyTask("SetAlarmOperation starting..."); // mark as busy quickly to avoid interruptions from the outside + } + + private void getSettingForAlarm() { + if (getDevice() != null) { + try { + TransactionBuilder builder = performInitialized("getSettingForAlarm"); + builder.setGattCallback(this); + builder.read(getCharacteristic(CasioConstants.CASIO_SETTING_FOR_ALM_CHARACTERISTIC_UUID)); + builder.queue(getQueue()); + } catch (IOException ex) { + LOG.info("Error retrieving alarm settings: " + ex.getMessage()); + } + } + } + + @Override + protected void doPerform() throws IOException { + getSettingForAlarm(); + } + + @Override + protected void operationFinished() { + operationStatus = OperationStatus.FINISHED; + unsetBusy(); + if (getDevice() != null) { + try { + TransactionBuilder builder = performInitialized("finished 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()); + } + } + } + + @Override + public boolean onCharacteristicRead(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_SETTING_FOR_ALM_CHARACTERISTIC_UUID)) { + StringBuilder str = new StringBuilder("onCharacteristicRead: Received alarm settings: "); + for(int i=0; i