From aa9027e76f1ce6c36b80d09c0ec7bbd9a1e74476 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Rebelo?= Date: Sun, 20 Apr 2025 11:56:23 +0100 Subject: [PATCH] Zepp OS: Decouple implementation from HuamiSupport --- .idea/dictionaries/t.xml | 3 + .../devices/huami/HuamiDevicePrefs.java | 51 +++ .../service/devices/huami/HuamiSupport.java | 226 +++------- .../amazfitband5/AmazfitBand5Support.java | 3 +- .../huami/amazfitbip/AmazfitBipSupport.java | 3 +- .../huami/amazfitbips/AmazfitBipSSupport.java | 3 +- .../huami/amazfitbipu/AmazfitBipUSupport.java | 5 +- .../amazfitgts2/AmazfitGTS2MiniSupport.java | 5 +- .../huami/amazfitneo/AmazfitNeoSupport.java | 10 +- .../huami/amazfitx/AmazfitXSupport.java | 3 +- .../devices/huami/miband5/MiBand5Support.java | 3 +- .../devices/huami/miband6/MiBand6Support.java | 3 +- .../huami/operations/init/InitOperation.java | 3 - .../huami/zeppos/AbstractZeppOsService.java | 24 +- .../zeppos/ZeppOsBtleTransactionBuilder.java | 67 +++ .../devices/huami/zeppos/ZeppOsSupport.java | 403 ++++++++++-------- .../zeppos/ZeppOsTransactionBuilder.java | 35 ++ .../operations/AbstractZeppOsOperation.java | 92 ++++ .../operations/ZeppOsAgpsUpdateOperation.java | 16 +- .../ZeppOsFirmwareUpdateOperation.java | 31 +- .../ZeppOsGpxRouteUploadOperation.java | 12 +- .../ZeppOsMusicUploadOperation.java | 12 +- .../zeppos/services/ZeppOsAgpsService.java | 6 + .../zeppos/services/ZeppOsAlarmsService.java | 44 +- .../zeppos/services/ZeppOsAppsService.java | 11 +- .../services/ZeppOsAssistantService.java | 45 +- .../services/ZeppOsAuthenticationService.java | 14 +- .../zeppos/services/ZeppOsBatteryService.java | 6 +- .../services/ZeppOsCalendarService.java | 6 +- .../services/ZeppOsCannedMessagesService.java | 10 +- .../zeppos/services/ZeppOsConfigService.java | 55 ++- .../services/ZeppOsConnectionService.java | 4 +- .../services/ZeppOsContactsService.java | 9 +- .../services/ZeppOsDisplayItemsService.java | 19 +- .../services/ZeppOsFileTransferService.java | 4 +- .../services/ZeppOsFindDeviceService.java | 4 +- .../services/ZeppOsFtpServerService.java | 11 +- .../services/ZeppOsHeartRateService.java | 22 +- .../zeppos/services/ZeppOsHttpService.java | 7 + .../zeppos/services/ZeppOsLogsService.java | 9 +- .../services/ZeppOsLoyaltyCardService.java | 6 +- .../zeppos/services/ZeppOsMapsService.java | 4 +- .../services/ZeppOsMorningUpdatesService.java | 31 +- .../zeppos/services/ZeppOsMusicService.java | 56 ++- .../services/ZeppOsNotificationService.java | 24 +- .../zeppos/services/ZeppOsPhoneService.java | 22 +- .../services/ZeppOsRemindersService.java | 18 +- .../services/ZeppOsServicesService.java | 5 +- .../services/ZeppOsShortcutCardsService.java | 18 +- .../services/ZeppOsUserInfoService.java | 11 +- .../ZeppOsVibrationPatternsService.java | 15 +- .../services/ZeppOsVoiceMemosService.java | 9 + .../services/ZeppOsWatchfaceService.java | 16 +- .../zeppos/services/ZeppOsWeatherService.java | 5 +- .../zeppos/services/ZeppOsWifiService.java | 8 +- .../filetransfer/FileTransferRequest.java | 2 +- .../filetransfer/ZeppOsFileTransferImpl.java | 10 +- .../filetransfer/ZeppOsFileTransferV3.java | 11 +- .../util/preferences/DevicePrefs.java | 6 +- 59 files changed, 944 insertions(+), 632 deletions(-) create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/HuamiDevicePrefs.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/ZeppOsBtleTransactionBuilder.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/ZeppOsTransactionBuilder.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/operations/AbstractZeppOsOperation.java diff --git a/.idea/dictionaries/t.xml b/.idea/dictionaries/t.xml index 8d1672b973..c4575e4555 100644 --- a/.idea/dictionaries/t.xml +++ b/.idea/dictionaries/t.xml @@ -5,6 +5,7 @@ adhikary afanasev affero + agps alaoui alexey alipay @@ -23,6 +24,7 @@ bloß boun breathwork + btbr böhler carsten chamorro @@ -110,6 +112,7 @@ morpheuz mosenkovs multisport + nack nephiel nodomain nordhøy diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/HuamiDevicePrefs.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/HuamiDevicePrefs.java new file mode 100644 index 0000000000..34307abd4f --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/HuamiDevicePrefs.java @@ -0,0 +1,51 @@ +/* Copyright (C) 2025 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 . */ +package nodomain.freeyourgadget.gadgetbridge.service.devices.huami; + +import android.content.SharedPreferences; + +import org.apache.commons.lang3.StringUtils; + +import java.util.Locale; + +import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; +import nodomain.freeyourgadget.gadgetbridge.util.preferences.DevicePrefs; + +public class HuamiDevicePrefs extends DevicePrefs { + public HuamiDevicePrefs(final SharedPreferences preferences, final GBDevice gbDevice) { + super(preferences, gbDevice); + } + + public byte getLanguageId() { + byte languageCode = 0x02; // english default + + String localeString = getString("language", "auto"); + if (StringUtils.isBlank(localeString) || localeString.equals("auto")) { + String language = Locale.getDefault().getLanguage(); + String country = Locale.getDefault().getCountry(); + + localeString = language + "_" + country.toUpperCase(); + } + + final Integer id = HuamiLanguageType.idLookup.get(localeString); + if (id != null) { + languageCode = id.byteValue(); + } + + return languageCode; + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/HuamiSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/HuamiSupport.java index d8235f8831..0cef97a59c 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/HuamiSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/HuamiSupport.java @@ -117,7 +117,6 @@ import nodomain.freeyourgadget.gadgetbridge.model.ActivityUser; import nodomain.freeyourgadget.gadgetbridge.model.Alarm; import nodomain.freeyourgadget.gadgetbridge.model.SleepState; import nodomain.freeyourgadget.gadgetbridge.model.WearingState; -import nodomain.freeyourgadget.gadgetbridge.service.SleepAsAndroidSender; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.services.ZeppOsCannedMessagesService; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.services.ZeppOsWorldClocksService; import nodomain.freeyourgadget.gadgetbridge.util.MediaManager; @@ -168,7 +167,6 @@ import nodomain.freeyourgadget.gadgetbridge.util.StringUtils; import nodomain.freeyourgadget.gadgetbridge.util.Version; import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_ACTIVATE_DISPLAY_ON_LIFT; -import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_ALLOW_HIGH_MTU; import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_BT_CONNECTED_ADVERTISEMENT; import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_DATEFORMAT; import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_DISPLAY_ON_LIFT_SENSITIVITY; @@ -288,7 +286,7 @@ public abstract class HuamiSupport extends AbstractBTLEDeviceSupport public void notify(Intent intent) { String s = intent.getAction(); if (DeviceInfoProfile.ACTION_DEVICE_INFO.equals(s)) { - handleDeviceInfo((nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.deviceinfo.DeviceInfo) intent.getParcelableExtra(DeviceInfoProfile.EXTRA_DEVICE_INFO)); + handleDeviceInfo(intent.getParcelableExtra(DeviceInfoProfile.EXTRA_DEVICE_INFO)); } } }; @@ -296,8 +294,8 @@ public abstract class HuamiSupport extends AbstractBTLEDeviceSupport protected BluetoothGattCharacteristic characteristicHRControlPoint; private BluetoothGattCharacteristic characteristicChunked; - protected BluetoothGattCharacteristic characteristicChunked2021Write; - protected BluetoothGattCharacteristic characteristicChunked2021Read; + private BluetoothGattCharacteristic characteristicChunked2021Write; + private BluetoothGattCharacteristic characteristicChunked2021Read; private boolean needsAuth; private volatile boolean telephoneRinging; @@ -312,17 +310,16 @@ public abstract class HuamiSupport extends AbstractBTLEDeviceSupport protected MediaManager mediaManager; private boolean heartRateNotifyEnabled; protected static final int MIN_MTU = 23; - protected int mMTU = MIN_MTU; + private int mMTU = MIN_MTU; // Keep track of the previous MTU before reconnection, so that we can request it after reconnection private int previousMtu = -1; protected int mActivitySampleSize = 4; - protected Huami2021ChunkedEncoder huami2021ChunkedEncoder; - protected Huami2021ChunkedDecoder huami2021ChunkedDecoder; + private Huami2021ChunkedEncoder huami2021ChunkedEncoder; + private Huami2021ChunkedDecoder huami2021ChunkedDecoder; private final HuamiFetcher fetcher = new HuamiFetcher(this); - protected SleepAsAndroidSender sleepAsAndroidSender; public HuamiSupport() { this(LOG); } @@ -349,7 +346,6 @@ public abstract class HuamiSupport extends AbstractBTLEDeviceSupport public void setContext(final GBDevice gbDevice, final BluetoothAdapter btAdapter, final Context context) { super.setContext(gbDevice, btAdapter, context); this.mediaManager = new MediaManager(context); - this.sleepAsAndroidSender = new SleepAsAndroidSender(gbDevice); } @Override @@ -454,8 +450,7 @@ public abstract class HuamiSupport extends AbstractBTLEDeviceSupport byte[] tail = new byte[] { 0, BLETypeConversions.mapTimeZone(calendar, BLETypeConversions.TZ_FLAG_INCLUDE_DST_IN_TZ) }; // 0 = adjust reason bitflags? or DST offset?? , timezone // byte[] tail = new byte[] { 0x2 }; // reason - byte[] all = BLETypeConversions.join(bytes, tail); - return all; + return BLETypeConversions.join(bytes, tail); } /** @@ -522,7 +517,7 @@ public abstract class HuamiSupport extends AbstractBTLEDeviceSupport return this; } - public HuamiSupport enableFurtherNotifications(TransactionBuilder builder, boolean enable) { + public void enableFurtherNotifications(TransactionBuilder builder, boolean enable) { builder.notify(getCharacteristic(HuamiService.UUID_CHARACTERISTIC_3_CONFIGURATION), enable); builder.notify(getCharacteristic(HuamiService.UUID_CHARACTERISTIC_6_BATTERY_INFO), enable); builder.notify(getCharacteristic(HuamiService.UUID_CHARACTERISTIC_AUDIO), enable); @@ -532,8 +527,6 @@ public abstract class HuamiSupport extends AbstractBTLEDeviceSupport if (characteristicChunked2021Read != null) { builder.notify(characteristicChunked2021Read, enable); } - - return this; } @Override @@ -541,19 +534,23 @@ public abstract class HuamiSupport extends AbstractBTLEDeviceSupport return true; } + @Override + public HuamiDevicePrefs getDevicePrefs() { + return new HuamiDevicePrefs(GBApplication.getDeviceSpecificSharedPrefs(gbDevice.getAddress()), gbDevice); + } + @Override public boolean connectFirstTime() { needsAuth = true; return connect(); } - private HuamiSupport sendDefaultNotification(TransactionBuilder builder, SimpleNotification simpleNotification, short repeat, BtLEAction extraAction) { + private void sendDefaultNotification(TransactionBuilder builder, SimpleNotification simpleNotification, short repeat, BtLEAction extraAction) { LOG.info("Sending notification to MiBand: (" + repeat + " times)"); NotificationStrategy strategy = getNotificationStrategy(); for (short i = 0; i < repeat; i++) { strategy.sendDefaultNotification(builder, simpleNotification, extraAction); } - return this; } public NotificationStrategy getNotificationStrategy() { @@ -575,27 +572,24 @@ public abstract class HuamiSupport extends AbstractBTLEDeviceSupport private static final byte[] startHeartMeasurementContinuous = new byte[]{0x15, MiBandService.COMMAND_SET__HR_CONTINUOUS, 1}; private static final byte[] stopHeartMeasurementContinuous = new byte[]{0x15, MiBandService.COMMAND_SET__HR_CONTINUOUS, 0}; - private HuamiSupport requestBatteryInfo(TransactionBuilder builder) { + private void requestBatteryInfo(TransactionBuilder builder) { LOG.debug("Requesting Battery Info!"); BluetoothGattCharacteristic characteristic = getCharacteristic(HuamiService.UUID_CHARACTERISTIC_6_BATTERY_INFO); builder.read(characteristic); - return this; } - public HuamiSupport requestDeviceInfo(TransactionBuilder builder) { + public void requestDeviceInfo(TransactionBuilder builder) { LOG.debug("Requesting Device Info!"); deviceInfoProfile.requestDeviceInfo(builder); - return this; } /** * Part of device initialization process. Do not call manually. * * @param transaction - * @return */ - protected HuamiSupport setFitnessGoal(TransactionBuilder transaction) { + protected void setFitnessGoal(TransactionBuilder transaction) { LOG.info("Attempting to set Fitness Goal..."); BluetoothGattCharacteristic characteristic = getCharacteristic(HuamiService.UUID_CHARACTERISTIC_8_USER_SETTINGS); if (characteristic != null) { @@ -609,19 +603,17 @@ public abstract class HuamiSupport extends AbstractBTLEDeviceSupport } else { LOG.info("Unable to set Fitness Goal"); } - return this; } /** * Part of device initialization process. Do not call manually. * * @param transaction - * @return */ - protected HuamiSupport setUserInfo(TransactionBuilder transaction) { + protected void setUserInfo(TransactionBuilder transaction) { BluetoothGattCharacteristic characteristic = getCharacteristic(HuamiService.UUID_CHARACTERISTIC_8_USER_SETTINGS); if (characteristic == null) { - return this; + return; } LOG.info("Attempting to set user info..."); @@ -637,7 +629,7 @@ public abstract class HuamiSupport extends AbstractBTLEDeviceSupport if (alias == null || weight == 0 || height == 0 || birth_year == 0) { LOG.warn("Unable to set user info, make sure it is set up"); - return this; + return; } byte sex = 2; // other @@ -671,16 +663,14 @@ public abstract class HuamiSupport extends AbstractBTLEDeviceSupport }; transaction.write(characteristic, bytes); - return this; } /** * Part of device initialization process. Do not call manually. * * @param builder - * @return */ - protected HuamiSupport setWearLocation(TransactionBuilder builder) { + protected void setWearLocation(TransactionBuilder builder) { LOG.info("Attempting to set wear location..."); BluetoothGattCharacteristic characteristic = getCharacteristic(HuamiService.UUID_CHARACTERISTIC_8_USER_SETTINGS); if (characteristic != null) { @@ -696,7 +686,6 @@ public abstract class HuamiSupport extends AbstractBTLEDeviceSupport } builder.notify(characteristic, false); // TODO: this should actually be in some kind of finally-block in the queue. It should also be sent asynchronously after the notifications have completely arrived and processed. } - return this; } @Override @@ -724,7 +713,7 @@ public abstract class HuamiSupport extends AbstractBTLEDeviceSupport } } - private HuamiSupport setPassword(final TransactionBuilder builder) { + private void setPassword(final TransactionBuilder builder) { final boolean passwordEnabled = HuamiCoordinator.getPasswordEnabled(gbDevice.getAddress()); final String password = HuamiCoordinator.getPassword(gbDevice.getAddress()); @@ -732,7 +721,7 @@ public abstract class HuamiSupport extends AbstractBTLEDeviceSupport if (password == null || password.isEmpty()) { LOG.warn("Invalid password: {}", password); - return this; + return; } final ByteArrayOutputStream baos = new ByteArrayOutputStream(); @@ -746,12 +735,10 @@ public abstract class HuamiSupport extends AbstractBTLEDeviceSupport baos.write(0x00); } catch (final IOException e) { LOG.error("Failed to build password command", e); - return this; + return; } writeToConfiguration(builder, baos.toByteArray()); - - return this; } /** @@ -759,7 +746,7 @@ public abstract class HuamiSupport extends AbstractBTLEDeviceSupport * * @param builder */ - protected HuamiSupport setHeartrateSleepSupport(TransactionBuilder builder) { + protected void setHeartrateSleepSupport(TransactionBuilder builder) { final boolean enableHrSleepSupport = MiBandCoordinator.getHeartrateSleepSupport(gbDevice.getAddress()); if (characteristicHRControlPoint != null) { builder.notify(characteristicHRControlPoint, true); @@ -772,17 +759,15 @@ public abstract class HuamiSupport extends AbstractBTLEDeviceSupport } builder.notify(characteristicHRControlPoint, false); // TODO: this should actually be in some kind of finally-block in the queue. It should also be sent asynchronously after the notifications have completely arrived and processed. } - return this; } - protected HuamiSupport setHeartrateActivityMonitoring(TransactionBuilder builder) { + protected void setHeartrateActivityMonitoring(TransactionBuilder builder) { final boolean enableHrActivityMonitoring = HuamiCoordinator.getHeartrateActivityMonitoring(gbDevice.getAddress()); final byte[] cmd = {ENDPOINT_DISPLAY, 0x22, 0x00, (byte) (enableHrActivityMonitoring ? 0x01 : 0x00)}; writeToConfiguration(builder, cmd); - return this; } - protected HuamiSupport setHeartrateAlert(TransactionBuilder builder) { + protected void setHeartrateAlert(TransactionBuilder builder) { final boolean enableHrAlert = HuamiCoordinator.getHeartrateAlert(gbDevice.getAddress()); final int hrAlertThreshold = HuamiCoordinator.getHeartrateAlertHighThreshold(gbDevice.getAddress()); @@ -796,25 +781,22 @@ public abstract class HuamiSupport extends AbstractBTLEDeviceSupport writeToConfiguration(builder, cmd); - return this; } - protected HuamiSupport setHeartrateStressMonitoring(TransactionBuilder builder) { + protected void setHeartrateStressMonitoring(TransactionBuilder builder) { final boolean enableHrStressMonitoring = HuamiCoordinator.getHeartrateStressMonitoring(gbDevice.getAddress()); LOG.info("Setting heart rate stress monitoring to {}", enableHrStressMonitoring); final byte[] cmd = new byte[] {(byte) 0xfe, 0x06, 0x00, (byte) (enableHrStressMonitoring ? 0x01 : 0x00)}; writeToConfiguration(builder, cmd); - return this; } - private HuamiSupport setHeartrateMeasurementInterval(TransactionBuilder builder, int minutes) { + private void setHeartrateMeasurementInterval(TransactionBuilder builder, int minutes) { if (characteristicHRControlPoint != null) { builder.notify(characteristicHRControlPoint, true); LOG.info("Setting heart rate measurement interval to " + minutes + " minutes"); builder.write(characteristicHRControlPoint, new byte[]{HuamiService.COMMAND_SET_PERIODIC_HR_MEASUREMENT_INTERVAL, (byte) minutes}); builder.notify(characteristicHRControlPoint, false); // TODO: this should actually be in some kind of finally-block in the queue. It should also be sent asynchronously after the notifications have completely arrived and processed. } - return this; } private void performDefaultNotification(String task, SimpleNotification simpleNotification, short repeat, BtLEAction extraAction) { @@ -1459,14 +1441,12 @@ public abstract class HuamiSupport extends AbstractBTLEDeviceSupport } } - public HuamiSupport sendReboot(TransactionBuilder builder) { + public void sendReboot(TransactionBuilder builder) { builder.write(getCharacteristic(HuamiService.UUID_CHARACTERISTIC_FIRMWARE), new byte[] { HuamiService.COMMAND_FIRMWARE_REBOOT}); - return this; } - public HuamiSupport sendFactoryReset(TransactionBuilder builder) { + public void sendFactoryReset(TransactionBuilder builder) { writeToConfiguration(builder, HuamiService.COMMAND_FACTORY_RESET); - return this; } @Override @@ -2369,7 +2349,6 @@ public abstract class HuamiSupport extends AbstractBTLEDeviceSupport MiBand2SampleProvider provider = new MiBand2SampleProvider(gbDevice, session); MiBandActivitySample sample = createActivitySample(device, user, ts, provider); sample.setHeartRate(getHeartrateBpm()); - sleepAsAndroidSender.onHrChanged(sample.getHeartRate(), 0); // sample.setSteps(getSteps()); sample.setRawIntensity(ActivitySample.NOT_MEASURED); @@ -2462,7 +2441,7 @@ public abstract class HuamiSupport extends AbstractBTLEDeviceSupport if (versionCmd.fwVersion == null) { versionCmd.fwVersion = info.getSoftwareRevision(); } - if (versionCmd.fwVersion != null && versionCmd.fwVersion.length() > 0 && versionCmd.fwVersion.charAt(0) == 'V') { + if (versionCmd.fwVersion != null && !versionCmd.fwVersion.isEmpty() && versionCmd.fwVersion.charAt(0) == 'V') { versionCmd.fwVersion = versionCmd.fwVersion.substring(1); } handleGBDeviceEvent(versionCmd); @@ -2475,28 +2454,27 @@ public abstract class HuamiSupport extends AbstractBTLEDeviceSupport } } - private HuamiSupport sendCalendarEvents(TransactionBuilder builder) { + private void sendCalendarEvents(TransactionBuilder builder) { if (characteristicChunked == null) { // all except Mi Band 2 sendCalendarEventsAsAlarms(builder); } else { sendCalendarEventsAsReminders(builder); } - - return this; } /** * Fetch the events from the android device calendars and set the alarms on the miband. + * * @param builder */ - private HuamiSupport sendCalendarEventsAsAlarms(TransactionBuilder builder) { + private void sendCalendarEventsAsAlarms(TransactionBuilder builder) { DeviceCoordinator coordinator = gbDevice.getDeviceCoordinator(); Prefs prefs = new Prefs(GBApplication.getDeviceSpecificSharedPrefs(gbDevice.getAddress())); int maxAlarms = coordinator.getAlarmSlotCount(gbDevice); int availableSlots = Math.min(prefs.getInt(PREF_RESERVER_ALARMS_CALENDAR, 0), maxAlarms); if (availableSlots <= 0) { - return this; + return; } CalendarManager upcomingEvents = new CalendarManager(getContext(), getDevice().getAddress()); @@ -2519,13 +2497,12 @@ public abstract class HuamiSupport extends AbstractBTLEDeviceSupport iteration++; } - return this; } - private HuamiSupport sendCalendarEventsAsReminders(TransactionBuilder builder) { + private void sendCalendarEventsAsReminders(TransactionBuilder builder) { boolean syncCalendar = GBApplication.getDeviceSpecificSharedPrefs(gbDevice.getAddress()).getBoolean(PREF_SYNC_CALENDAR, false); if (!syncCalendar) { - return this; + return; } final DeviceCoordinator coordinator = gbDevice.getDeviceCoordinator(); @@ -2586,8 +2563,6 @@ public abstract class HuamiSupport extends AbstractBTLEDeviceSupport buf.put(new byte[6 + 6 + 1 + 1]); // default value is 0 writeToChunked(builder, 2, buf.array()); } - - return this; } @Override @@ -2763,7 +2738,7 @@ public abstract class HuamiSupport extends AbstractBTLEDeviceSupport } } - private HuamiSupport setVibrationPattern(final TransactionBuilder builder, final String preferenceKey) { + private void setVibrationPattern(final TransactionBuilder builder, final String preferenceKey) { // The preference key has one of the 3 prefixes final String notificationTypeName = preferenceKey.replace(PREF_HUAMI_VIBRATION_COUNT_PREFIX, "") .replace(PREF_HUAMI_VIBRATION_PROFILE_PREFIX, "") @@ -2779,8 +2754,6 @@ public abstract class HuamiSupport extends AbstractBTLEDeviceSupport ); setVibrationPattern(builder, notificationType, isTry, vibrationProfile); - - return this; } /** @@ -3079,7 +3052,7 @@ public abstract class HuamiSupport extends AbstractBTLEDeviceSupport } } - protected HuamiSupport setDateDisplay(TransactionBuilder builder) { + protected void setDateDisplay(TransactionBuilder builder) { DateTimeDisplay dateTimeDisplay = HuamiCoordinator.getDateDisplay(getContext(), gbDevice.getAddress()); LOG.info("Setting date display to " + dateTimeDisplay); switch (dateTimeDisplay) { @@ -3090,13 +3063,12 @@ public abstract class HuamiSupport extends AbstractBTLEDeviceSupport writeToConfiguration(builder,HuamiService.DATEFORMAT_DATE_TIME); break; } - return this; } - protected HuamiSupport setDateFormat(TransactionBuilder builder) { + protected void setDateFormat(TransactionBuilder builder) { String dateFormat = GBApplication.getDeviceSpecificSharedPrefs(gbDevice.getAddress()).getString("dateformat", "MM/dd/yyyy"); if (dateFormat == null) { - return this; + return; } switch (dateFormat) { case "MM/dd/yyyy": @@ -3110,10 +3082,9 @@ public abstract class HuamiSupport extends AbstractBTLEDeviceSupport LOG.warn("unsupported date format " + dateFormat); } - return this; } - private HuamiSupport setTimeFormat(TransactionBuilder builder) { + private void setTimeFormat(TransactionBuilder builder) { String timeFormat = GBApplication.getDevicePrefs(gbDevice).getTimeFormat(); LOG.info("Setting time format to " + timeFormat); @@ -3122,7 +3093,6 @@ public abstract class HuamiSupport extends AbstractBTLEDeviceSupport } else { writeToConfiguration(builder,HuamiService.DATEFORMAT_TIME_12_HOURS); } - return this; } protected HuamiSupport setGoalNotification(TransactionBuilder builder) { @@ -3136,7 +3106,7 @@ public abstract class HuamiSupport extends AbstractBTLEDeviceSupport return this; } - protected HuamiSupport setActivateDisplayOnLiftWrist(TransactionBuilder builder) { + protected void setActivateDisplayOnLiftWrist(TransactionBuilder builder) { ActivateDisplayOnLift displayOnLift = HuamiCoordinator.getActivateDisplayOnLiftWrist(getContext(), gbDevice.getAddress()); LOG.info("Setting activate display on lift wrist to " + displayOnLift); @@ -3167,10 +3137,9 @@ public abstract class HuamiSupport extends AbstractBTLEDeviceSupport default: LOG.warn("Unknown display on lift mode {}", displayOnLift); } - return this; } - protected HuamiSupport setActivateDisplayOnLiftWristSensitivity(TransactionBuilder builder) { + protected void setActivateDisplayOnLiftWristSensitivity(TransactionBuilder builder) { final ActivateDisplayOnLiftSensitivity sensitivity = HuamiCoordinator.getDisplayOnLiftSensitivity(gbDevice.getAddress()); LOG.info("Setting activate display on lift wrist sensitivity to " + sensitivity); @@ -3183,8 +3152,6 @@ public abstract class HuamiSupport extends AbstractBTLEDeviceSupport writeToConfiguration(builder, HuamiService.COMMAND_DISPLAY_ON_LIFT_WRIST_SPEED_NORMAL); break; } - - return this; } protected HuamiSupport setDisplayItems(TransactionBuilder builder) { @@ -3217,7 +3184,7 @@ public abstract class HuamiSupport extends AbstractBTLEDeviceSupport return this; } - protected HuamiSupport setDisplayItemsOld(TransactionBuilder builder, boolean isShortcuts, int defaultSettings, Map keyPosMap) { + protected void setDisplayItemsOld(TransactionBuilder builder, boolean isShortcuts, int defaultSettings, Map keyPosMap) { SharedPreferences prefs = GBApplication.getDeviceSpecificSharedPrefs(gbDevice.getAddress()); String pages; List enabledList; @@ -3285,7 +3252,6 @@ public abstract class HuamiSupport extends AbstractBTLEDeviceSupport } writeToConfiguration(builder, command); - return this; } protected HuamiSupport setDisplayItemsNew(TransactionBuilder builder, boolean isShortcuts, boolean forceWatchface, int defaultSettings) { @@ -3346,11 +3312,10 @@ public abstract class HuamiSupport extends AbstractBTLEDeviceSupport return this; } - protected HuamiSupport setShortcuts(TransactionBuilder builder) { - return this; + protected void setShortcuts(TransactionBuilder builder) { } - protected HuamiSupport setWorkoutActivityTypes(final TransactionBuilder builder) { + protected void setWorkoutActivityTypes(final TransactionBuilder builder) { final SharedPreferences prefs = GBApplication.getDeviceSpecificSharedPrefs(gbDevice.getAddress()); final List defaultActivityTypes = Arrays.asList(HuamiWorkoutScreenActivityType.Freestyle.name().toLowerCase(Locale.ROOT)); @@ -3392,16 +3357,14 @@ public abstract class HuamiSupport extends AbstractBTLEDeviceSupport writeToChunked(builder, 9, command.array()); - return this; } - protected HuamiSupport setBeepSounds(TransactionBuilder builder) { + protected void setBeepSounds(TransactionBuilder builder) { SharedPreferences prefs = GBApplication.getDeviceSpecificSharedPrefs(gbDevice.getAddress()); Set sounds = prefs.getStringSet(PREF_SOUNDS, new HashSet<>(Arrays.asList(getContext().getResources().getStringArray(R.array.pref_amazfitneo_sounds_default)))); LOG.info("Setting sounds to " + (sounds == null ? "none" : sounds)); - if (sounds != null) { final String[] soundOrder = new String[]{"button", "calls", "alarm", "notifications", "inactivity_warning", "sms", "email", "goal"}; byte[] command = new byte[]{0x3c, 0, 0, 0, 1, 0, 0, 2, 0, 0, 3, 0, 0, 4, 0, 0, 5, 0, 0, 6, 0, 0, 7, 0, 0}; @@ -3414,11 +3377,9 @@ public abstract class HuamiSupport extends AbstractBTLEDeviceSupport } writeToChunked(builder, 2, command); } - - return this; } - protected HuamiSupport setRotateWristToSwitchInfo(TransactionBuilder builder) { + protected void setRotateWristToSwitchInfo(TransactionBuilder builder) { boolean enable = HuamiCoordinator.getRotateWristToSwitchInfo(gbDevice.getAddress()); LOG.info("Setting rotate wrist to cycle info to " + enable); if (enable) { @@ -3426,15 +3387,13 @@ public abstract class HuamiSupport extends AbstractBTLEDeviceSupport } else { writeToConfiguration(builder, HuamiService.COMMAND_DISABLE_ROTATE_WRIST_TO_SWITCH_INFO); } - return this; } - protected HuamiSupport setDisplayCaller(TransactionBuilder builder) { + protected void setDisplayCaller(TransactionBuilder builder) { writeToConfiguration(builder, HuamiService.COMMAND_ENABLE_DISPLAY_CALLER); - return this; } - protected HuamiSupport setDoNotDisturb(TransactionBuilder builder) { + protected void setDoNotDisturb(TransactionBuilder builder) { DoNotDisturb doNotDisturb = HuamiCoordinator.getDoNotDisturb(gbDevice.getAddress()); boolean doNotDisturbLiftWrist = HuamiCoordinator.getDoNotDisturbLiftWrist(gbDevice.getAddress()); LOG.info("Setting do not disturb to {}, wake on lift wrist {}", doNotDisturb, doNotDisturbLiftWrist); @@ -3472,11 +3431,9 @@ public abstract class HuamiSupport extends AbstractBTLEDeviceSupport writeToConfiguration(builder, data); } - - return this; } - protected HuamiSupport setNightMode(TransactionBuilder builder) { + protected void setNightMode(TransactionBuilder builder) { String nightMode = MiBand3Coordinator.getNightMode(gbDevice.getAddress()); LOG.info("Setting night mode to " + nightMode); @@ -3508,11 +3465,9 @@ public abstract class HuamiSupport extends AbstractBTLEDeviceSupport LOG.error("Invalid night mode: " + nightMode); break; } - - return this; } - protected HuamiSupport setInactivityWarnings(TransactionBuilder builder) { + protected void setInactivityWarnings(TransactionBuilder builder) { boolean enable = HuamiCoordinator.getInactivityWarnings(gbDevice.getAddress()); LOG.info("Setting inactivity warnings to " + enable); @@ -3562,13 +3517,11 @@ public abstract class HuamiSupport extends AbstractBTLEDeviceSupport } else { writeToConfiguration(builder, HuamiService.COMMAND_DISABLE_INACTIVITY_WARNINGS); } - - return this; } - protected HuamiSupport setHourlyChime(TransactionBuilder builder) { + protected void setHourlyChime(TransactionBuilder builder) { if (!supportsHourlyChime()) - return this; + return; boolean enable = HuamiCoordinator.getHourlyChime(gbDevice.getAddress()); LOG.info("Setting hourly chime to " + enable); @@ -3593,15 +3546,13 @@ public abstract class HuamiSupport extends AbstractBTLEDeviceSupport } else { writeToConfiguration(builder, HuamiService.COMMAND_DISABLE_HOURLY_CHIME); } - - return this; } public boolean supportsHourlyChime() { return false; } - protected HuamiSupport setDisconnectNotification(TransactionBuilder builder) { + private void setDisconnectNotification(TransactionBuilder builder) { DisconnectNotificationSetting disconnectNotificationSetting = HuamiCoordinator.getDisconnectNotificationSetting(getContext(), gbDevice.getAddress()); LOG.info("Setting disconnect notification to " + disconnectNotificationSetting); @@ -3629,10 +3580,9 @@ public abstract class HuamiSupport extends AbstractBTLEDeviceSupport writeToConfiguration(builder, cmd); } - return this; } - private HuamiSupport setDistanceUnit(TransactionBuilder builder) { + private void setDistanceUnit(TransactionBuilder builder) { MiBandConst.DistanceUnit unit = HuamiCoordinator.getDistanceUnit(); LOG.info("Setting distance unit to " + unit); if (unit == MiBandConst.DistanceUnit.METRIC) { @@ -3640,10 +3590,9 @@ public abstract class HuamiSupport extends AbstractBTLEDeviceSupport } else { writeToConfiguration(builder, HuamiService.COMMAND_DISTANCE_UNIT_IMPERIAL); } - return this; } - protected HuamiSupport setBandScreenUnlock(TransactionBuilder builder) { + protected void setBandScreenUnlock(TransactionBuilder builder) { boolean enable = MiBand3Coordinator.getBandScreenUnlock(gbDevice.getAddress()); LOG.info("Setting band screen unlock to " + enable); @@ -3652,11 +3601,9 @@ public abstract class HuamiSupport extends AbstractBTLEDeviceSupport } else { writeToConfiguration(builder, MiBand3Service.COMMAND_DISABLE_BAND_SCREEN_UNLOCK); } - - return this; } - protected HuamiSupport setLanguage(TransactionBuilder builder) { + protected void setLanguage(TransactionBuilder builder) { String localeString = GBApplication.getDeviceSpecificSharedPrefs(gbDevice.getAddress()).getString("language", "auto"); if (localeString == null || localeString.equals("auto")) { String language = Locale.getDefault().getLanguage(); @@ -3704,39 +3651,18 @@ public abstract class HuamiSupport extends AbstractBTLEDeviceSupport } }); } - return this; } /* Some newer devices seem to support setting the language by id again instead of a locale string Amazfit Bip U and GTS 2 mini tested so far */ - protected HuamiSupport setLanguageByIdNew(TransactionBuilder builder) { - final byte[] command = new byte[]{0x06, 0x3b, 0x00, getLanguageId(), 0x03}; + protected void setLanguageByIdNew(TransactionBuilder builder) { + final byte[] command = new byte[]{0x06, 0x3b, 0x00, getDevicePrefs().getLanguageId(), 0x03}; writeToConfiguration(builder, command); - return this; } - protected byte getLanguageId() { - byte language_code = 0x02; // english default - - String localeString = GBApplication.getDeviceSpecificSharedPrefs(gbDevice.getAddress()).getString("language", "auto"); - if (localeString == null || localeString.equals("auto")) { - String language = Locale.getDefault().getLanguage(); - String country = Locale.getDefault().getCountry(); - - localeString = language + "_" + country.toUpperCase(); - } - - Integer id = HuamiLanguageType.idLookup.get(localeString); - if (id != null) { - language_code = id.byteValue(); - } - - return language_code; - } - - protected HuamiSupport setExposeHRThirdParty(TransactionBuilder builder) { + protected void setExposeHRThirdParty(TransactionBuilder builder) { boolean enable = HuamiCoordinator.getExposeHRThirdParty(gbDevice.getAddress()); LOG.info("Setting exposure of HR to third party apps to: " + enable); @@ -3745,11 +3671,9 @@ public abstract class HuamiSupport extends AbstractBTLEDeviceSupport } else { writeToConfiguration(builder, HuamiService.COMMAND_DISABLE_HR_CONNECTION); } - - return this; } - protected HuamiSupport setBtConnectedAdvertising(TransactionBuilder builder) { + protected void setBtConnectedAdvertising(TransactionBuilder builder) { boolean enable = HuamiCoordinator.getBtConnectedAdvertising(gbDevice.getAddress()); LOG.info("Setting connected advertisement to: " + enable); @@ -3758,8 +3682,6 @@ public abstract class HuamiSupport extends AbstractBTLEDeviceSupport } else { writeToConfiguration(builder, HuamiService.COMMAND_DISABLE_BT_CONNECTED_ADVERTISEMENT); } - - return this; } protected void writeToChunked(TransactionBuilder builder, int type, byte[] data) { @@ -3835,18 +3757,16 @@ public abstract class HuamiSupport extends AbstractBTLEDeviceSupport } } - protected HuamiSupport requestGPSVersion(TransactionBuilder builder) { + protected void requestGPSVersion(TransactionBuilder builder) { LOG.info("Requesting GPS version"); writeToConfiguration(builder, HuamiService.COMMAND_REQUEST_GPS_VERSION); - return this; } - protected HuamiSupport requestAlarms(TransactionBuilder builder) { + protected void requestAlarms(TransactionBuilder builder) { LOG.info("Requesting alarms"); //FIXME: on older devices only the first one works, and on newer only the last is sufficient writeToConfiguration(builder, HuamiService.COMMAND_REQUEST_ALARMS); writeToConfiguration(builder, HuamiService.COMMAND_REQUEST_ALARMS_WITH_TIMES); - return this; } @Override @@ -3949,7 +3869,7 @@ public abstract class HuamiSupport extends AbstractBTLEDeviceSupport } protected void setMtu(final int mtu) { - if (mtu > MIN_MTU && !allowHighMtu()) { + if (mtu > MIN_MTU && !getDevicePrefs().allowHighMtu()) { LOG.warn("High MTU is not allowed, ignoring"); return; } @@ -3965,22 +3885,10 @@ public abstract class HuamiSupport extends AbstractBTLEDeviceSupport } } - protected boolean allowHighMtu() { - return getDevicePrefs().getBoolean(PREF_ALLOW_HIGH_MTU, true); - } - public int getActivitySampleSize() { return mActivitySampleSize; } - public TimeUnit getFetchOperationsTimeUnit() { - // This is configurable because using seconds was causing issues on Amazfit GTR 3 - // However, using minutes can cause issues while fetching workouts shorter than 1 minute - final Prefs devicePrefs = getDevicePrefs(); - final boolean truncate = devicePrefs.getBoolean("huami_truncate_fetch_operation_timestamps", true); - return truncate ? TimeUnit.MINUTES : TimeUnit.SECONDS; - } - public boolean force2021Protocol() { return GBApplication.getDeviceSpecificSharedPrefs(gbDevice.getAddress()).getBoolean("force_new_protocol", false); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/amazfitband5/AmazfitBand5Support.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/amazfitband5/AmazfitBand5Support.java index cf7315f189..e234c66fbe 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/amazfitband5/AmazfitBand5Support.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/amazfitband5/AmazfitBand5Support.java @@ -35,9 +35,8 @@ public class AmazfitBand5Support extends MiBand5Support { } @Override - protected AmazfitBand5Support setShortcuts(TransactionBuilder builder) { + protected void setShortcuts(TransactionBuilder builder) { setDisplayItemsNew(builder, true, true, R.array.pref_amazfitband5_shortcuts_default); - return this; } @Override diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/amazfitbip/AmazfitBipSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/amazfitbip/AmazfitBipSupport.java index d714f1dddf..cbc5fc3283 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/amazfitbip/AmazfitBipSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/amazfitbip/AmazfitBipSupport.java @@ -65,13 +65,12 @@ public class AmazfitBipSupport extends HuamiSupport { } @Override - protected AmazfitBipSupport setShortcuts(TransactionBuilder builder) { + protected void setShortcuts(TransactionBuilder builder) { Map keyPosMap = new LinkedHashMap<>(); keyPosMap.put("alipay", 1); keyPosMap.put("weather", 2); setDisplayItemsOld(builder, true, R.array.pref_bip_shortcuts_default, keyPosMap); - return this; } @Override diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/amazfitbips/AmazfitBipSSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/amazfitbips/AmazfitBipSSupport.java index d23dbb0a86..f3da56f5be 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/amazfitbips/AmazfitBipSSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/amazfitbips/AmazfitBipSSupport.java @@ -99,9 +99,8 @@ public class AmazfitBipSSupport extends AmazfitBipSupport { } @Override - protected AmazfitBipSSupport setShortcuts(TransactionBuilder builder) { + protected void setShortcuts(TransactionBuilder builder) { setDisplayItemsNew(builder, true, true, R.array.pref_bips_display_items_default); - return this; } private boolean isDTH(Version version) { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/amazfitbipu/AmazfitBipUSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/amazfitbipu/AmazfitBipUSupport.java index 08d34994a9..6f255cc3a8 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/amazfitbipu/AmazfitBipUSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/amazfitbipu/AmazfitBipUSupport.java @@ -24,7 +24,6 @@ import java.io.IOException; import nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiFWHelper; import nodomain.freeyourgadget.gadgetbridge.devices.huami.amazfitbipu.AmazfitBipUFWHelper; import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder; -import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.HuamiSupport; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.amazfitbips.AmazfitBipSSupport; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.operations.update.UpdateFirmwareOperation; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.operations.update.UpdateFirmwareOperation2020; @@ -32,8 +31,8 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.operations.upd public class AmazfitBipUSupport extends AmazfitBipSSupport { @Override - protected HuamiSupport setLanguage(TransactionBuilder builder) { - return setLanguageByIdNew(builder); + protected void setLanguage(TransactionBuilder builder) { + setLanguageByIdNew(builder); } @Override diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/amazfitgts2/AmazfitGTS2MiniSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/amazfitgts2/AmazfitGTS2MiniSupport.java index 41ce7b51e0..9376c138cb 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/amazfitgts2/AmazfitGTS2MiniSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/amazfitgts2/AmazfitGTS2MiniSupport.java @@ -28,15 +28,14 @@ import nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiFWHelper; import nodomain.freeyourgadget.gadgetbridge.devices.huami.amazfitgts2.AmazfitGTS2MiniFWHelper; import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec; import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder; -import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.HuamiSupport; public class AmazfitGTS2MiniSupport extends AmazfitGTS2Support { private static final Logger LOG = LoggerFactory.getLogger(AmazfitGTS2MiniSupport.class); @Override - protected HuamiSupport setLanguage(TransactionBuilder builder) { - return setLanguageByIdNew(builder); + protected void setLanguage(TransactionBuilder builder) { + setLanguageByIdNew(builder); } @Override diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/amazfitneo/AmazfitNeoSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/amazfitneo/AmazfitNeoSupport.java index b75e4bb5ab..1373012a00 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/amazfitneo/AmazfitNeoSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/amazfitneo/AmazfitNeoSupport.java @@ -61,10 +61,9 @@ public class AmazfitNeoSupport extends MiBand5Support { } @Override - protected AmazfitNeoSupport setFitnessGoal(TransactionBuilder builder) { + protected void setFitnessGoal(TransactionBuilder builder) { LOG.info("Attempting to set Fitness Goal..."); setNeoFitnessGoal(builder); - return this; } @Override @@ -87,19 +86,18 @@ public class AmazfitNeoSupport extends MiBand5Support { } @Override - protected AmazfitNeoSupport requestAlarms(TransactionBuilder builder) { - return this; //Neo always returns response array with '03' in it which marks alarms unused on connect + protected void requestAlarms(TransactionBuilder builder) { + //Neo always returns response array with '03' in it which marks alarms unused on connect } @Override public boolean supportsHourlyChime() { return true; } @Override - protected AmazfitNeoSupport setHeartrateSleepSupport(TransactionBuilder builder) { + protected void setHeartrateSleepSupport(TransactionBuilder builder) { final boolean enableHrSleepSupport = MiBandCoordinator.getHeartrateSleepSupport(gbDevice.getAddress()); LOG.info("Setting Amazfit Neo heartrate sleep support to " + enableHrSleepSupport); writeToConfiguration(builder, new byte[] {0x06, 0x3c, 0x00, (byte) (enableHrSleepSupport ? 1 : 0 )}); - return this; } @Override diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/amazfitx/AmazfitXSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/amazfitx/AmazfitXSupport.java index 6697162b89..a0c79f7540 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/amazfitx/AmazfitXSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/amazfitx/AmazfitXSupport.java @@ -40,9 +40,8 @@ public class AmazfitXSupport extends MiBand5Support { } @Override - protected AmazfitXSupport setShortcuts(TransactionBuilder builder) { + protected void setShortcuts(TransactionBuilder builder) { setDisplayItemsNew(builder, true, true, R.array.pref_amazfitband5_shortcuts_default); - return this; } @Override diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/miband5/MiBand5Support.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/miband5/MiBand5Support.java index 4108acec3f..6af183d4fe 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/miband5/MiBand5Support.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/miband5/MiBand5Support.java @@ -42,9 +42,8 @@ public class MiBand5Support extends MiBand4Support { } @Override - protected MiBand5Support setShortcuts(TransactionBuilder builder) { + protected void setShortcuts(TransactionBuilder builder) { setDisplayItemsNew(builder, true, true, R.array.pref_miband5_shortcuts_default); - return this; } @Override diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/miband6/MiBand6Support.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/miband6/MiBand6Support.java index 0d1c80885a..342ca8d345 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/miband6/MiBand6Support.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/miband6/MiBand6Support.java @@ -56,9 +56,8 @@ public class MiBand6Support extends MiBand5Support { } @Override - protected MiBand6Support setShortcuts(TransactionBuilder builder) { + protected void setShortcuts(TransactionBuilder builder) { setDisplayItemsNew(builder, true, true, R.array.pref_miband6_shortcuts_default); - return this; } @Override diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/operations/init/InitOperation.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/operations/init/InitOperation.java index 08e13eb0c0..bc94ba5c1d 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/operations/init/InitOperation.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/operations/init/InitOperation.java @@ -100,9 +100,6 @@ public class InitOperation extends AbstractBTLEOperation { byte[] srcBytes = authKey.trim().getBytes(); if (authKey.length() == 34 && authKey.startsWith("0x")) { srcBytes = GB.hexStringToByteArray(authKey.substring(2)); - } else if (authKey.length() == 32 && huamiSupport instanceof ZeppOsSupport) { - // All Zepp OS devices require a hex key - srcBytes = GB.hexStringToByteArray(authKey); } System.arraycopy(srcBytes, 0, authKeyBytes, 0, Math.min(srcBytes.length, 16)); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/AbstractZeppOsService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/AbstractZeppOsService.java index 1b9bc398f3..610c8ae699 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/AbstractZeppOsService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/AbstractZeppOsService.java @@ -23,11 +23,13 @@ import androidx.annotation.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.function.Consumer; + import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent; import nodomain.freeyourgadget.gadgetbridge.devices.DeviceCoordinator; import nodomain.freeyourgadget.gadgetbridge.devices.huami.zeppos.ZeppOsCoordinator; -import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder; +import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.HuamiDevicePrefs; import nodomain.freeyourgadget.gadgetbridge.util.Prefs; public abstract class AbstractZeppOsService { @@ -67,7 +69,7 @@ public abstract class AbstractZeppOsService { return false; } - public void initialize(final TransactionBuilder builder) { + public void initialize(final ZeppOsTransactionBuilder builder) { // Do nothing by default // TODO implement a "quick initialize" that runs for the same firmware + Gb versions, since // we will already know the capabilities @@ -86,8 +88,8 @@ public abstract class AbstractZeppOsService { return (ZeppOsCoordinator) coordinator; } - protected Prefs getDevicePrefs() { - return new Prefs(GBApplication.getDeviceSpecificSharedPrefs(getSupport().getDevice().getAddress())); + protected HuamiDevicePrefs getDevicePrefs() { + return getSupport().getDevicePrefs(); } protected void write(final String taskName, final byte b) { @@ -98,11 +100,11 @@ public abstract class AbstractZeppOsService { this.mSupport.writeToChunked2021(taskName, getEndpoint(), data, isEncrypted()); } - protected void write(final TransactionBuilder builder, final byte b) { + protected void write(final ZeppOsTransactionBuilder builder, final byte b) { this.write(builder, new byte[]{b}); } - protected void write(final TransactionBuilder builder, final byte[] data) { + protected void write(final ZeppOsTransactionBuilder builder, final byte[] data) { this.mSupport.writeToChunked2021(builder, getEndpoint(), data, isEncrypted()); } @@ -114,6 +116,16 @@ public abstract class AbstractZeppOsService { return getSupport().getContext(); } + protected ZeppOsTransactionBuilder createTransactionBuilder(final String taskName) { + return mSupport.createZeppOsTransactionBuilder(taskName); + } + + protected void withTransactionBuilder(final String taskName, final Consumer consumer) { + final ZeppOsTransactionBuilder builder = createTransactionBuilder(taskName); + consumer.accept(builder); + builder.queue(mSupport); + } + @Nullable protected static Boolean booleanFromByte(final byte b) { switch (b) { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/ZeppOsBtleTransactionBuilder.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/ZeppOsBtleTransactionBuilder.java new file mode 100644 index 0000000000..989051f21f --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/ZeppOsBtleTransactionBuilder.java @@ -0,0 +1,67 @@ +/* Copyright (C) 2025 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 . */ +package nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos; + +import android.content.Context; + +import java.util.UUID; + +import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; +import nodomain.freeyourgadget.gadgetbridge.service.btle.AbstractBTLEDeviceSupport; +import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder; +import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.SetDeviceStateAction; +import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.SetProgressAction; + +public class ZeppOsBtleTransactionBuilder implements ZeppOsTransactionBuilder { + private final AbstractBTLEDeviceSupport mSupport; + private final TransactionBuilder mBuilder; + + public ZeppOsBtleTransactionBuilder(final AbstractBTLEDeviceSupport mSupport, final String taskName) { + this.mSupport = mSupport; + this.mBuilder = new TransactionBuilder(taskName); + } + + public ZeppOsBtleTransactionBuilder(final AbstractBTLEDeviceSupport mSupport, final TransactionBuilder builder) { + this.mSupport = mSupport; + this.mBuilder = builder; + } + + @Override + public void setProgress(final String text, final boolean ongoing, final int percentage, final Context context) { + mBuilder.add(new SetProgressAction(text, ongoing, percentage, context)); + } + + @Override + public void setDeviceState(final GBDevice device, final GBDevice.State deviceState, final Context context) { + mBuilder.add(new SetDeviceStateAction(device, deviceState, context)); + } + + @Override + public void notify(final UUID characteristic, final boolean enable) { + mBuilder.notify(mSupport.getCharacteristic(characteristic), enable); + } + + @Override + public void write(final UUID characteristic, final byte[] arr) { + mBuilder.write(mSupport.getCharacteristic(characteristic), arr); + } + + @Override + public void queue(final ZeppOsSupport support) { + mBuilder.queue(support.getQueue()); + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/ZeppOsSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/ZeppOsSupport.java index 3abebe1f43..3e4426b500 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/ZeppOsSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/ZeppOsSupport.java @@ -21,8 +21,6 @@ import static nodomain.freeyourgadget.gadgetbridge.service.btle.BLETypeConversio import static nodomain.freeyourgadget.gadgetbridge.service.btle.BLETypeConversions.fromUint8; import static nodomain.freeyourgadget.gadgetbridge.service.btle.BLETypeConversions.mapTimeZone; import static nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.services.ZeppOsConfigService.ConfigArg.HEART_RATE_ALL_DAY_MONITORING; -import static nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.services.ZeppOsConfigService.ConfigArg.LANGUAGE; -import static nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.services.ZeppOsConfigService.ConfigArg.LANGUAGE_FOLLOW_PHONE; import static nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.services.ZeppOsConfigService.ConfigArg.SLEEP_HIGH_ACCURACY_MONITORING; import android.bluetooth.BluetoothAdapter; @@ -63,19 +61,18 @@ import java.util.concurrent.TimeUnit; import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.R; -import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventAppInfo; import nodomain.freeyourgadget.gadgetbridge.capabilities.loyaltycards.LoyaltyCard; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventDisplayMessage; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventScreenshot; -import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventUpdatePreferences; +import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventVersionInfo; import nodomain.freeyourgadget.gadgetbridge.devices.huami.zeppos.ZeppOsMapsInstallHandler; import nodomain.freeyourgadget.gadgetbridge.devices.huami.zeppos.ZeppOsMusicInstallHandler; +import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandService; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.model.RecordedDataTypes; import nodomain.freeyourgadget.gadgetbridge.model.WorldClock; import nodomain.freeyourgadget.gadgetbridge.service.SleepAsAndroidSender; -import nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiFWHelper; import nodomain.freeyourgadget.gadgetbridge.devices.huami.zeppos.ZeppOsCoordinator; import nodomain.freeyourgadget.gadgetbridge.devices.huami.Huami2021Service; import nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiService; @@ -95,14 +92,20 @@ import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec; import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec; import nodomain.freeyourgadget.gadgetbridge.model.Reminder; import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec; +import nodomain.freeyourgadget.gadgetbridge.service.btle.AbstractBTLEDeviceSupport; import nodomain.freeyourgadget.gadgetbridge.service.btle.BLETypeConversions; import nodomain.freeyourgadget.gadgetbridge.service.btle.GattCharacteristic; +import nodomain.freeyourgadget.gadgetbridge.service.btle.GattService; import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder; import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.SetDeviceStateAction; +import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.IntentListener; +import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.deviceinfo.DeviceInfo; +import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.deviceinfo.DeviceInfoProfile; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.Huami2021ChunkedDecoder; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.Huami2021ChunkedEncoder; -import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.HuamiSupport; -import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.operations.update.UpdateFirmwareOperation; +import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.Huami2021Handler; +import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.HuamiDevicePrefs; +import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.HuamiFetcher; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.operations.ZeppOsFirmwareUpdateOperation; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.operations.ZeppOsAgpsUpdateOperation; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.operations.ZeppOsGpxRouteUploadOperation; @@ -150,13 +153,47 @@ import nodomain.freeyourgadget.gadgetbridge.util.GB; import nodomain.freeyourgadget.gadgetbridge.util.Prefs; import nodomain.freeyourgadget.gadgetbridge.util.RealtimeSamplesAggregator; -public class ZeppOsSupport extends HuamiSupport implements ZeppOsFileTransferService.DownloadCallback { +public class ZeppOsSupport extends AbstractBTLEDeviceSupport + implements Huami2021Handler, HuamiFetcher.HuamiFetchSupport, ZeppOsFileTransferService.DownloadCallback { private static final Logger LOG = LoggerFactory.getLogger(ZeppOsSupport.class); // Keep track of whether the rawSensor is enabled private boolean rawSensor = false; private ScheduledExecutorService rawSensorScheduler; - private RealtimeSamplesAggregator realtimeSamplesAggregator; + + private final DeviceInfoProfile deviceInfoProfile; + private final IntentListener mListener = intent -> { + String s = intent.getAction(); + if (DeviceInfoProfile.ACTION_DEVICE_INFO.equals(s)) { + final DeviceInfo info = intent.getParcelableExtra(DeviceInfoProfile.EXTRA_DEVICE_INFO); + LOG.debug("Device info: {}", info); + if (info == null) { + return; + } + final GBDeviceEventVersionInfo versionCmd = new GBDeviceEventVersionInfo(); + versionCmd.hwVersion = info.getHardwareRevision(); + versionCmd.fwVersion = info.getFirmwareRevision(); + if (versionCmd.fwVersion == null) { + versionCmd.fwVersion = info.getSoftwareRevision(); + } + if (versionCmd.fwVersion != null && !versionCmd.fwVersion.isEmpty() && versionCmd.fwVersion.charAt(0) == 'V') { + versionCmd.fwVersion = versionCmd.fwVersion.substring(1); + } + handleGBDeviceEvent(versionCmd); + } + }; + + protected static final int MIN_MTU = 23; + private int mMTU = MIN_MTU; + // Keep track of the previous MTU before reconnection, so that we can request it after reconnection + private int previousMtu = -1; + + private Huami2021ChunkedEncoder huami2021ChunkedEncoder; + private Huami2021ChunkedDecoder huami2021ChunkedDecoder; + + private final HuamiFetcher fetcher = new HuamiFetcher(this); + + private SleepAsAndroidSender sleepAsAndroidSender; // Services private final ZeppOsServicesService servicesService = new ZeppOsServicesService(this); @@ -241,40 +278,36 @@ public class ZeppOsSupport extends HuamiSupport implements ZeppOsFileTransferSer }}; public ZeppOsSupport() { - this(LOG); - } + super(LOG); - public ZeppOsSupport(final Logger logger) { - super(logger); + addSupportedService(GattService.UUID_SERVICE_HEART_RATE); + addSupportedService(GattService.UUID_SERVICE_DEVICE_INFORMATION); + + addSupportedService(MiBandService.UUID_SERVICE_MIBAND_SERVICE); + addSupportedService(HuamiService.UUID_SERVICE_FIRMWARE_SERVICE); + + deviceInfoProfile = new DeviceInfoProfile<>(this); + deviceInfoProfile.addListener(mListener); + addSupportedProfile(deviceInfoProfile); } @Override public void setContext(final GBDevice gbDevice, final BluetoothAdapter btAdapter, final Context context) { super.setContext(gbDevice, btAdapter, context); heartRateService.setSleepAsAndroidSender(sleepAsAndroidSender); - realtimeSamplesAggregator = new RealtimeSamplesAggregator(getContext(), getDevice()); + final RealtimeSamplesAggregator realtimeSamplesAggregator = new RealtimeSamplesAggregator(getContext(), getDevice()); heartRateService.setRealtimeSamplesAggregator(realtimeSamplesAggregator); stepsService.setRealtimeSamplesAggregator(realtimeSamplesAggregator); } @Override - protected byte getAuthFlags() { - return 0x00; + public HuamiDevicePrefs getDevicePrefs() { + return new HuamiDevicePrefs(GBApplication.getDeviceSpecificSharedPrefs(gbDevice.getAddress()), gbDevice); } @Override - public byte getCryptFlags() { - return (byte) 0x80; - } - - /** - * Do not reset the gatt callback implicitly, as that would interrupt operations. - * See #2912 for more - * information. - */ - @Override - public boolean getImplicitCallbackModify() { - return false; + public boolean useAutoConnect() { + return true; } @Override @@ -295,12 +328,12 @@ public class ZeppOsSupport extends HuamiSupport implements ZeppOsFileTransferSer setMtu(MIN_MTU); } - characteristicChunked2021Read = getCharacteristic(HuamiService.UUID_CHARACTERISTIC_CHUNKEDTRANSFER_2021_READ); + final BluetoothGattCharacteristic characteristicChunked2021Read = getCharacteristic(HuamiService.UUID_CHARACTERISTIC_CHUNKEDTRANSFER_2021_READ); if (characteristicChunked2021Read != null && huami2021ChunkedDecoder == null) { - huami2021ChunkedDecoder = new Huami2021ChunkedDecoder(this, force2021Protocol()); + huami2021ChunkedDecoder = new Huami2021ChunkedDecoder(this, true); } - characteristicChunked2021Write = getCharacteristic(HuamiService.UUID_CHARACTERISTIC_CHUNKEDTRANSFER_2021_WRITE); + final BluetoothGattCharacteristic characteristicChunked2021Write = getCharacteristic(HuamiService.UUID_CHARACTERISTIC_CHUNKEDTRANSFER_2021_WRITE); if (characteristicChunked2021Write != null && huami2021ChunkedEncoder == null) { huami2021ChunkedEncoder = new Huami2021ChunkedEncoder(getMTU()); } @@ -312,8 +345,9 @@ public class ZeppOsSupport extends HuamiSupport implements ZeppOsFileTransferSer } builder.notify(characteristicChunked2021Read, true); + builder.add(new SetDeviceStateAction(getDevice(), GBDevice.State.AUTHENTICATING, getContext())); - authenticationService.startAuthentication(builder); + authenticationService.startAuthentication(new ZeppOsBtleTransactionBuilder(this, builder)); return builder; } @@ -344,8 +378,7 @@ public class ZeppOsSupport extends HuamiSupport implements ZeppOsFileTransferSer findDeviceService.onFindDevice(start); } - @Override - protected void sendFindDeviceCommand(boolean start) { + private void sendFindDeviceCommand(boolean start) { findDeviceService.sendFindDeviceCommand(start); } @@ -355,7 +388,7 @@ public class ZeppOsSupport extends HuamiSupport implements ZeppOsFileTransferSer voiceMemosService.requestList(); } - super.onFetchRecordedData(dataTypes); + fetcher.onFetchRecordedData(dataTypes); } @Override @@ -380,11 +413,11 @@ public class ZeppOsSupport extends HuamiSupport implements ZeppOsFileTransferSer minuteInterval = Math.max(0, minuteInterval); } - final TransactionBuilder builder = createTransactionBuilder(String.format(Locale.ROOT, "set heart rate interval to: %d min", minuteInterval)); + final ZeppOsTransactionBuilder builder = createZeppOsTransactionBuilder(String.format(Locale.ROOT, "set heart rate interval to: %d min", minuteInterval)); configService.newSetter() .setByte(HEART_RATE_ALL_DAY_MONITORING, (byte) minuteInterval) .write(builder); - builder.queue(getQueue()); + builder.queue(this); } @Override @@ -408,8 +441,8 @@ public class ZeppOsSupport extends HuamiSupport implements ZeppOsFileTransferSer } @Override - protected void queueAlarm(final Alarm alarm, final TransactionBuilder builder) { - alarmsService.sendAlarm(alarm, builder); + public void onSetAlarms(final ArrayList alarms) { + alarmsService.onSetAlarms(alarms); } @Override @@ -424,14 +457,9 @@ public class ZeppOsSupport extends HuamiSupport implements ZeppOsFileTransferSer @Override public void onSetReminders(final ArrayList reminders) { - final TransactionBuilder builder; - try { - builder = performInitialized("onSetReminders"); - remindersService.sendReminders(builder, reminders); - builder.queue(getQueue()); - } catch (final IOException e) { - LOG.error("Unable to send reminders to device", e); - } + final ZeppOsTransactionBuilder builder = createZeppOsTransactionBuilder("onSetReminders"); + remindersService.sendReminders(builder, reminders); + builder.queue(this); } @Override @@ -471,8 +499,13 @@ public class ZeppOsSupport extends HuamiSupport implements ZeppOsFileTransferSer } @Override - protected void sendMusicStateToDevice(final MusicSpec musicSpec, final MusicStateSpec musicStateSpec) { - musicService.sendMusicState(musicSpec, musicStateSpec); + public void onSetMusicState(final MusicStateSpec stateSpec) { + musicService.onSetMusicState(stateSpec); + } + + @Override + public void onSetMusicInfo(final MusicSpec musicSpec) { + musicService.onSetMusicInfo(musicSpec); } @Override @@ -480,19 +513,6 @@ public class ZeppOsSupport extends HuamiSupport implements ZeppOsFileTransferSer stepsService.onEnableRealtimeSteps(enable); } - @Override - public UpdateFirmwareOperation createUpdateFirmwareOperation(final Uri uri) { - throw new UnsupportedOperationException("this method should not be used"); - } - - /** - * FIXME: Visibility hack for easier refactoring. - */ - @Override - public void setMtu(final int mtu) { - super.setMtu(mtu); - } - @Override public void onInstallApp(final Uri uri) { final ZeppOsAgpsInstallHandler agpsHandler = new ZeppOsAgpsInstallHandler(uri, getContext()); @@ -652,14 +672,15 @@ public class ZeppOsSupport extends HuamiSupport implements ZeppOsFileTransferSer } @Override - protected ZeppOsSupport setHeartrateSleepSupport(final TransactionBuilder builder) { + public void onEnableHeartRateSleepSupport(boolean enable) { + final ZeppOsTransactionBuilder builder = createZeppOsTransactionBuilder("enable heart rate sleep support: " + enable); final boolean enableHrSleepSupport = MiBandCoordinator.getHeartrateSleepSupport(gbDevice.getAddress()); configService.newSetter() .setBoolean(SLEEP_HIGH_ACCURACY_MONITORING, enableHrSleepSupport) .write(builder); - return this; + builder.queue(this); } @Override @@ -676,33 +697,23 @@ public class ZeppOsSupport extends HuamiSupport implements ZeppOsFileTransferSer @Override public void onSetTime() { - if (!GBApplication.getPrefs().syncTime()) { - return; + if (GBApplication.getPrefs().syncTime()) { + final ZeppOsTransactionBuilder builder = createZeppOsTransactionBuilder("set date and time"); + setCurrentTime(builder); + builder.queue(this); } - try { - final TransactionBuilder builder = performInitialized("set date and time"); - setCurrentTime(builder); - builder.queue(getQueue()); - CalendarReceiver.forceSync(getDevice()); - } catch (IOException ex) { - LOG.error("Unable to set time on Huami device", ex); - } + CalendarReceiver.forceSync(getDevice()); } - @Override - public void setCurrentTime(TransactionBuilder builder) { - if (!GBApplication.getPrefs().syncTime()) { - return; - } - + private void setCurrentTime(ZeppOsTransactionBuilder builder) { // It seems that the format sent to the Current Time characteristic changed in newer devices // to kind-of match the GATT spec, but it doesn't quite respect it? // - 11 bytes get sent instead of 10 (extra byte at the end for the offset in quarter-hours?) // - Day of week starts at 0 // Otherwise, the command gets rejected with an "Out of Range" error and init fails. - final Calendar timestamp = createCalendar(); + final Calendar timestamp = BLETypeConversions.createCalendar(); final byte[] year = fromUint16(timestamp.get(Calendar.YEAR)); final byte[] cmd = { @@ -719,20 +730,7 @@ public class ZeppOsSupport extends HuamiSupport implements ZeppOsFileTransferSer mapTimeZone(timestamp, BLETypeConversions.TZ_FLAG_INCLUDE_DST_IN_TZ), // TODO: Confirm this }; - builder.write(getCharacteristic(GattCharacteristic.UUID_CHARACTERISTIC_CURRENT_TIME), cmd); - } - - @Override - public HuamiSupport enableNotifications(final TransactionBuilder builder, final boolean enable) { - builder.notify(getCharacteristic(HuamiService.UUID_CHARACTERISTIC_CHUNKEDTRANSFER_2021_READ), enable); - return this; - } - - @Override - public ZeppOsSupport enableFurtherNotifications(final TransactionBuilder builder, - final boolean enable) { - // Nothing to do here, they are already enabled from enableNotifications - return this; + builder.write(GattCharacteristic.UUID_CHARACTERISTIC_CURRENT_TIME, cmd); } @Override @@ -779,7 +777,7 @@ public class ZeppOsSupport extends HuamiSupport implements ZeppOsFileTransferSer case SleepAsAndroidAction.SET_SUSPENDED: boolean suspended = extras.getBoolean("SUSPENDED", false); setRawSensor(!suspended); - enableRealtimeSamplesTimer(!suspended); + //FIXME is this really needed? enableRealtimeSamplesTimer(!suspended); sleepAsAndroidSender.pauseTracking(suspended); break; // Received when the app changes the batch size for the movement data @@ -866,86 +864,39 @@ public class ZeppOsSupport extends HuamiSupport implements ZeppOsFileTransferSer setRawSensor(enable); if (enable) { rawSensorScheduler = startRawSensors(); - } - else { + } else { stopRawSensors(); } } - @Override - protected ZeppOsSupport setLanguage(final TransactionBuilder builder) { - final String localeString = GBApplication.getDeviceSpecificSharedPrefs(gbDevice.getAddress()) - .getString("language", "auto"); - - LOG.info("Setting device language to {}", localeString); - - configService.newSetter() - .setByte(LANGUAGE, getLanguageId()) - .setBoolean(LANGUAGE_FOLLOW_PHONE, localeString.equals("auto")) - .write(builder); - - return this; - } - - @Override - protected void writeToChunked(final TransactionBuilder builder, - final int type, - final byte[] data) { - LOG.warn("writeToChunked is not supported"); - } - - @Override - protected void writeToChunkedOld(final TransactionBuilder builder, final int type, final byte[] data) { - LOG.warn("writeToChunkedOld is not supported"); - } - - @Override - public void writeToConfiguration(final TransactionBuilder builder, final byte[] data) { - LOG.warn("writeToConfiguration is not supported"); - } - - @Override - protected ZeppOsSupport requestGPSVersion(final TransactionBuilder builder) { - LOG.warn("Request GPS version not implemented"); - return this; - } - - public void requestDisplayItems(final TransactionBuilder builder) { + public void requestDisplayItems(final ZeppOsTransactionBuilder builder) { displayItemsService.requestItems(builder, ZeppOsDisplayItemsService.DISPLAY_ITEMS_MENU); } - public void requestApps(final TransactionBuilder builder) { + public void requestApps(final ZeppOsTransactionBuilder builder) { appsService.requestApps(builder); } - public void requestWatchfaces(final TransactionBuilder builder) { + public void requestWatchfaces(final ZeppOsTransactionBuilder builder) { watchfaceService.requestWatchfaces(builder); watchfaceService.requestCurrentWatchface(builder); } - @Override - public void phase2Initialize(final TransactionBuilder builder) { - LOG.info("2021 phase2Initialize..."); - if (allowHighMtu()) { - builder.requestMtu(247); + public void onAuthenticationSuccess() { + LOG.info("ZeppOS phase 2 initialize..."); + + final TransactionBuilder bleBuilder = new TransactionBuilder("phase 2 initialize"); + final var builder = new ZeppOsBtleTransactionBuilder(this, bleBuilder); + builder.setDeviceState(getDevice(), GBDevice.State.INITIALIZING, getContext()); + + if (getDevicePrefs().allowHighMtu()) { + bleBuilder.requestMtu(247); } if (GBApplication.getPrefs().syncTime()) { setCurrentTime(builder); } - requestDeviceInfo(builder); - - final GBDeviceEventUpdatePreferences evt = new GBDeviceEventUpdatePreferences() - .withPreference(DeviceSettingsPreferenceConst.WIFI_HOTSPOT_STATUS, null) - .withPreference(DeviceSettingsPreferenceConst.FTP_SERVER_ADDRESS, null) - .withPreference(DeviceSettingsPreferenceConst.FTP_SERVER_USERNAME, null) - .withPreference(DeviceSettingsPreferenceConst.FTP_SERVER_STATUS, null); - evaluateGBDeviceEvent(evt); - } - - @Override - public void phase3Initialize(final TransactionBuilder builder) { - LOG.info("2021 phase3Initialize..."); + deviceInfoProfile.requestDeviceInfo(bleBuilder); // Make sure that performInitialized is not called accidentally in here // (eg. by creating a new TransactionBuilder). @@ -956,12 +907,8 @@ public class ZeppOsSupport extends HuamiSupport implements ZeppOsFileTransferSer // initializeServices below mSupportedServices.clear(); servicesService.requestServices(builder); - } - @Override - @Deprecated - public HuamiFWHelper createFWHelper(final Uri uri, final Context context) throws IOException { - throw new UnsupportedOperationException("This function should not be used for Zepp OS devices"); + builder.queue(this); } public void addSupportedService(final short endpoint, final boolean encrypted) { @@ -972,7 +919,7 @@ public class ZeppOsSupport extends HuamiSupport implements ZeppOsFileTransferSer LOG.info("2021 initializeServices..."); try { - final TransactionBuilder builder = createTransactionBuilder("initialize services"); + final ZeppOsTransactionBuilder builder = createZeppOsTransactionBuilder("initialize services"); // At this point we got the service list from phase 3, so we know which // services are supported, and whether they are encrypted or not @@ -986,12 +933,29 @@ public class ZeppOsSupport extends HuamiSupport implements ZeppOsFileTransferSer } } - builder.queue(getQueue()); + builder.setDeviceState(getDevice(), GBDevice.State.INITIALIZED, getContext()); + + builder.queue(this); } catch (Exception e) { LOG.error("failed initializing device", e); } } + @Override + public void setActivityNotifications(final boolean control, final boolean data) { + final ZeppOsTransactionBuilder builder = createZeppOsTransactionBuilder("set activity notifications: " + control + " " + data); + builder.notify(HuamiService.UUID_CHARACTERISTIC_5_ACTIVITY_CONTROL, control); + builder.notify(HuamiService.UUID_CHARACTERISTIC_5_ACTIVITY_DATA, data); + builder.queue(this); + } + + @Override + public void writeActivityControl(final String name, final byte[] value) { + final ZeppOsTransactionBuilder builder = createZeppOsTransactionBuilder(name); + builder.write(HuamiService.UUID_CHARACTERISTIC_5_ACTIVITY_CONTROL, value); + builder.queue(this); + } + @Nullable public AbstractZeppOsService getService(final short endpoint) { return mServiceMap.get(endpoint); @@ -1002,18 +966,12 @@ public class ZeppOsSupport extends HuamiSupport implements ZeppOsFileTransferSer return 8; } - @Override - public boolean force2021Protocol() { - return true; - } - @Override public ZeppOsCoordinator getCoordinator() { return (ZeppOsCoordinator) gbDevice.getDeviceCoordinator(); } - @Override - protected void setRawSensor(final boolean enable) { + private void setRawSensor(final boolean enable) { LOG.info("Set raw sensor to {}", enable); rawSensor = enable; @@ -1033,8 +991,7 @@ public class ZeppOsSupport extends HuamiSupport implements ZeppOsFileTransferSer } } - @Override - protected void handleRawSensorData(final byte[] value) { + private void handleRawSensorData(final byte[] value) { // The g values seem to vary between -4100 and 4100, so we scale them final float scaleFactor = 4100f; final float gravity = -9.81f; @@ -1086,8 +1043,22 @@ public class ZeppOsSupport extends HuamiSupport implements ZeppOsFileTransferSer @Override public boolean onCharacteristicChanged(final BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic) { + if (super.onCharacteristicChanged(gatt, characteristic)) { + // handled upstream + return true; + } + final UUID characteristicUUID = characteristic.getUuid(); - if (HuamiService.UUID_CHARACTERISTIC_ZEPP_OS_FILE_TRANSFER_V3_SEND.equals(characteristicUUID)) { + if (HuamiService.UUID_CHARACTERISTIC_CHUNKEDTRANSFER_2021_READ.equals(characteristicUUID)) { + handleChunked(characteristic.getValue()); + return true; + } else if (HuamiService.UUID_CHARACTERISTIC_5_ACTIVITY_DATA.equals(characteristicUUID)) { + fetcher.onActivityData(characteristic.getValue()); + return true; + } else if (HuamiService.UUID_CHARACTERISTIC_5_ACTIVITY_CONTROL.equals(characteristicUUID)) { + fetcher.onActivityControl(characteristic.getValue()); + return true; + } else if (HuamiService.UUID_CHARACTERISTIC_ZEPP_OS_FILE_TRANSFER_V3_SEND.equals(characteristicUUID)) { fileTransferService.onCharacteristicChanged(characteristic); return true; } else if (HuamiService.UUID_CHARACTERISTIC_ZEPP_OS_FILE_TRANSFER_V3_RECEIVE.equals(characteristicUUID)) { @@ -1096,9 +1067,68 @@ public class ZeppOsSupport extends HuamiSupport implements ZeppOsFileTransferSer } else if (GattCharacteristic.UUID_CHARACTERISTIC_HEART_RATE_MEASUREMENT.equals(characteristicUUID)) { heartRateService.handleHeartRate(characteristic.getValue()); return true; + } else if (HuamiService.UUID_CHARACTERISTIC_RAW_SENSOR_DATA.equals(characteristicUUID)) { + handleRawSensorData(characteristic.getValue()); + return true; + } else { + LOG.warn("Unhandled characteristic changed: {}", characteristicUUID); + logMessageContent(characteristic.getValue()); } - return super.onCharacteristicChanged(gatt, characteristic); + return false; + } + + public int getMTU() { + return mMTU; + } + + public void setMtu(final int mtu) { + if (mtu > MIN_MTU && !getDevicePrefs().allowHighMtu()) { + LOG.warn("High MTU is not allowed, ignoring"); + return; + } + + if (mtu < MIN_MTU) { + LOG.error("Device announced unreasonable low MTU of {}, ignoring", mtu); + return; + } + + this.mMTU = mtu; + if (huami2021ChunkedEncoder != null) { + huami2021ChunkedEncoder.setMTU(mtu); + } + } + + private void handleChunked(final byte[] value) { + switch (value[0]) { + case 0x03: + if (huami2021ChunkedDecoder != null) { + final boolean needsAck = huami2021ChunkedDecoder.decode(value); + if (needsAck) { + sendChunkedAck(); + } + } else { + LOG.warn("Got chunked payload, but decoder is null"); + } + return; + case 0x04: + final byte handle = value[2]; + final byte count = value[4]; + LOG.info("Got chunked ack, handle={}, count={}", handle, count); + // TODO: We should probably update the handle and count on the encoder + return; + default: + LOG.warn("Unhandled chunked payload of type {}", value[0]); + } + } + + public void sendChunkedAck() { + final byte handle = huami2021ChunkedDecoder.getLastHandle(); + final byte count = huami2021ChunkedDecoder.getLastCount(); + + final ZeppOsTransactionBuilder builder = createZeppOsTransactionBuilder("send chunked ack"); + builder.write(HuamiService.UUID_CHARACTERISTIC_CHUNKEDTRANSFER_2021_READ, new byte[] {0x04, 0x00, handle, 0x01, count}); + builder.queue(this); } @Override @@ -1163,4 +1193,27 @@ public class ZeppOsSupport extends HuamiSupport implements ZeppOsFileTransferSer private byte bool(final boolean b) { return (byte) (b ? 1 : 0); } + + public void writeToChunked2021(final ZeppOsTransactionBuilder builder, final short type, final byte data, final boolean encrypt) { + writeToChunked2021(builder, type, new byte[]{data}, encrypt); + } + + public void writeToChunked2021(final ZeppOsTransactionBuilder builder, final short type, final byte[] data, final boolean encrypt) { + huami2021ChunkedEncoder.write(chunk -> builder.write(HuamiService.UUID_CHARACTERISTIC_CHUNKEDTRANSFER_2021_WRITE, chunk), type, data, true, encrypt); + } + + public void writeToChunked2021(final String taskName, final short type, final byte data, final boolean encrypt) { + writeToChunked2021(taskName, type, new byte[]{data}, encrypt); + } + + public void writeToChunked2021(final String taskName, final short type, final byte[] data, final boolean encrypt) { + final ZeppOsTransactionBuilder builder = createZeppOsTransactionBuilder(taskName); + writeToChunked2021(builder, type, data, encrypt); + builder.queue(this); + } + + public ZeppOsTransactionBuilder createZeppOsTransactionBuilder(final String taskName) { + // FIXME this needs to be moved upstream + return new ZeppOsBtleTransactionBuilder(this, taskName); + } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/ZeppOsTransactionBuilder.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/ZeppOsTransactionBuilder.java new file mode 100644 index 0000000000..2a9909929e --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/ZeppOsTransactionBuilder.java @@ -0,0 +1,35 @@ +/* Copyright (C) 2025 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 . */ +package nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos; + +import android.content.Context; + +import java.util.UUID; + +import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; + +public interface ZeppOsTransactionBuilder { + void setProgress(final String text, final boolean ongoing, final int percentage, final Context context); + + void setDeviceState(final GBDevice device, final GBDevice.State deviceState, final Context context); + + void notify(final UUID characteristic, final boolean enable); + + void write(final UUID characteristic, final byte[] arr); + + void queue(final ZeppOsSupport support); +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/operations/AbstractZeppOsOperation.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/operations/AbstractZeppOsOperation.java new file mode 100644 index 0000000000..3fb7f9d888 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/operations/AbstractZeppOsOperation.java @@ -0,0 +1,92 @@ +/* Copyright (C) 2025 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 . */ +package nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.operations; + +import android.content.Context; + +import java.io.IOException; + +import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; +import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.ZeppOsSupport; +import nodomain.freeyourgadget.gadgetbridge.service.devices.miband.operations.OperationStatus; + +/** + * This is a simplified version of the AbstractBTLEOperation, in order to allow for simpler + * Zepp OS btrfcomm support without a major refactor. It should not be used for new operations. + */ +@Deprecated +public abstract class AbstractZeppOsOperation { + private final T mSupport; + protected OperationStatus operationStatus = OperationStatus.INITIAL; + private String name; + + protected AbstractZeppOsOperation(T support) { + mSupport = support; + } + + public final void perform() throws IOException { + operationStatus = OperationStatus.RUNNING; + doPerform(); + } + + protected abstract void doPerform() throws IOException; + + protected void operationFinished() throws IOException { + } + + protected Context getContext() { + return mSupport.getContext(); + } + + protected GBDevice getDevice() { + return mSupport.getDevice(); + } + + protected void setName(String name) { + this.name = name; + } + + public String getName() { + if (name != null) { + return name; + } + String busyTask = getDevice().getBusyTask(); + if (busyTask != null) { + return busyTask; + } + return getClass().getSimpleName(); + } + + protected void unsetBusy() { + if (getDevice().isBusy()) { + getDevice().unsetBusyTask(); + getDevice().sendDeviceUpdateIntent(getContext()); + } + } + + public boolean isOperationRunning() { + return operationStatus == OperationStatus.RUNNING; + } + + public boolean isOperationFinished() { + return operationStatus == OperationStatus.FINISHED; + } + + public T getSupport() { + return mSupport; + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/operations/ZeppOsAgpsUpdateOperation.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/operations/ZeppOsAgpsUpdateOperation.java index bf1b37f9df..b202cc2855 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/operations/ZeppOsAgpsUpdateOperation.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/operations/ZeppOsAgpsUpdateOperation.java @@ -22,10 +22,8 @@ import org.slf4j.LoggerFactory; import java.io.IOException; import nodomain.freeyourgadget.gadgetbridge.R; -import nodomain.freeyourgadget.gadgetbridge.service.btle.AbstractBTLEOperation; -import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder; -import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.SetProgressAction; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.ZeppOsSupport; +import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.ZeppOsTransactionBuilder; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.services.ZeppOsAgpsService; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.services.ZeppOsConfigService; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.services.ZeppOsFileTransferService; @@ -40,7 +38,7 @@ import nodomain.freeyourgadget.gadgetbridge.util.GB; * 4. After successful ack from 3, update is finished. Trigger an AGPS config request from {@link ZeppOsConfigService} * to reload the AGPS update and expiration timestamps. */ -public class ZeppOsAgpsUpdateOperation extends AbstractBTLEOperation +public class ZeppOsAgpsUpdateOperation extends AbstractZeppOsOperation implements ZeppOsFileTransferService.UploadCallback, ZeppOsAgpsService.Callback { private static final Logger LOG = LoggerFactory.getLogger(ZeppOsAgpsUpdateOperation.class); @@ -120,9 +118,9 @@ public class ZeppOsAgpsUpdateOperation extends AbstractBTLEOperation +public class ZeppOsGpxRouteUploadOperation extends AbstractZeppOsOperation implements ZeppOsFileTransferService.UploadCallback { private static final Logger LOG = LoggerFactory.getLogger(ZeppOsGpxRouteUploadOperation.class); @@ -91,9 +89,9 @@ public class ZeppOsGpxRouteUploadOperation extends AbstractBTLEOperation +public class ZeppOsMusicUploadOperation extends AbstractZeppOsOperation implements ZeppOsFileTransferService.UploadCallback { private static final Logger LOG = LoggerFactory.getLogger(ZeppOsMusicUploadOperation.class); @@ -99,9 +97,9 @@ public class ZeppOsMusicUploadOperation extends AbstractBTLEOperation alarms) { + final int maxAlarms = getCoordinator().getAlarmSlotCount(getSupport().getDevice()); + + final ZeppOsTransactionBuilder builder = createTransactionBuilder("set alarms"); + boolean anyAlarmEnabled = false; + for (final Alarm alarm : alarms) { + if (alarm.getPosition() >= maxAlarms) { + if (alarm.getEnabled()) { + GB.toast(getContext(), "Only " + maxAlarms + " alarms are currently supported.", Toast.LENGTH_LONG, GB.WARN); + } + break; + } + + anyAlarmEnabled |= alarm.getEnabled(); + sendAlarm(alarm, builder); + } + builder.queue(getSupport()); + if (anyAlarmEnabled) { + GB.toast(getContext(), getContext().getString(R.string.user_feedback_miband_set_alarms_ok), Toast.LENGTH_SHORT, GB.INFO); + } else { + GB.toast(getContext(), getContext().getString(R.string.user_feedback_all_alarms_disabled), Toast.LENGTH_SHORT, GB.INFO); + } + } + + public void sendAlarm(final Alarm alarm, final ZeppOsTransactionBuilder builder) { final DeviceCoordinator coordinator = getSupport().getDevice().getDeviceCoordinator(); final Calendar calendar = AlarmUtils.toCalendar(alarm); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsAppsService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsAppsService.java index 96ee65a7f9..bf18cc1705 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsAppsService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsAppsService.java @@ -28,9 +28,9 @@ import java.util.List; import java.util.UUID; import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceApp; -import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.ZeppOsSupport; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.AbstractZeppOsService; +import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.ZeppOsTransactionBuilder; public class ZeppOsAppsService extends AbstractZeppOsService { private static final Logger LOG = LoggerFactory.getLogger(ZeppOsAppsService.class); @@ -78,7 +78,7 @@ public class ZeppOsAppsService extends AbstractZeppOsService { } } - public void initialize(final TransactionBuilder builder) { + public void initialize(final ZeppOsTransactionBuilder builder) { requestApps(builder); } @@ -92,7 +92,7 @@ public class ZeppOsAppsService extends AbstractZeppOsService { private void handleAppsPayload(final byte[] payload) { if (payload[1] != CMD_INCOMING) { - LOG.warn("Unexpected non-incoming payload ({})", String.format("0x%02x", payload[1])); + LOG.warn("Unexpected non-incoming apps payload ({})", String.format("0x%02x", payload[1])); return; } @@ -115,9 +115,10 @@ public class ZeppOsAppsService extends AbstractZeppOsService { } } + /** @noinspection SwitchStatementWithTooFewBranches*/ private void handleScreenshotPayload(final byte[] payload) { if (payload[1] != CMD_INCOMING) { - LOG.warn("Unexpected non-incoming payload ({})", String.format("0x%02x", payload[1])); + LOG.warn("Unexpected non-incoming screenshot payload ({})", String.format("0x%02x", payload[1])); return; } @@ -164,7 +165,7 @@ public class ZeppOsAppsService extends AbstractZeppOsService { // TODO broadcast something to update app manager } - public void requestApps(final TransactionBuilder builder) { + public void requestApps(final ZeppOsTransactionBuilder builder) { LOG.info("Request apps"); final ByteBuffer buf = ByteBuffer.allocate(16).order(ByteOrder.LITTLE_ENDIAN); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsAssistantService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsAssistantService.java index 81390174f2..8ae20221d4 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsAssistantService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsAssistantService.java @@ -48,9 +48,9 @@ import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventUpdatePref import nodomain.freeyourgadget.gadgetbridge.devices.huami.zeppos.ZeppOsCoordinator; import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec; import nodomain.freeyourgadget.gadgetbridge.service.btle.BLETypeConversions; -import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.ZeppOsSupport; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.AbstractZeppOsService; +import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.ZeppOsTransactionBuilder; import nodomain.freeyourgadget.gadgetbridge.util.DateTimeUtils; import nodomain.freeyourgadget.gadgetbridge.util.GB; import nodomain.freeyourgadget.gadgetbridge.util.Prefs; @@ -140,6 +140,25 @@ public class ZeppOsAssistantService extends AbstractZeppOsService { } } + @Override + public void dispose() { + handler.removeCallbacksAndMessages(null); + opusDecoder = null; + if (audioTrack != null) { + audioTrack.release(); + audioTrack = null; + } + if (rawVoiceOutputStream != null) { + try { + rawVoiceOutputStream.close(); + } catch (final IOException e) { + LOG.error("Failed to close raw voice output stream", e); + } + rawVoiceOutputStream = null; + } + voiceBuffer.clear(); + } + @Override public boolean onSendConfiguration(final String config, final Prefs prefs) { switch (config) { @@ -170,13 +189,29 @@ public class ZeppOsAssistantService extends AbstractZeppOsService { } @Override - public void initialize(final TransactionBuilder builder) { + public void initialize(final ZeppOsTransactionBuilder builder) { + handler.removeCallbacksAndMessages(null); + opusDecoder = null; + if (audioTrack != null) { + audioTrack.release(); + audioTrack = null; + } + if (rawVoiceOutputStream != null) { + try { + rawVoiceOutputStream.close(); + } catch (final IOException e) { + LOG.error("Failed to close raw voice output stream", e); + } + rawVoiceOutputStream = null; + } + voiceBuffer.clear(); + if (ZeppOsCoordinator.experimentalFeatures(getSupport().getDevice())) { requestCapabilities(builder); } } - public void requestCapabilities(final TransactionBuilder builder) { + public void requestCapabilities(final ZeppOsTransactionBuilder builder) { write(builder, CMD_CAPABILITIES_REQUEST); } @@ -285,13 +320,13 @@ public class ZeppOsAssistantService extends AbstractZeppOsService { public void sendVoiceReply(final List voiceFrames) { try { - final TransactionBuilder builder = getSupport().performInitialized("send voice reply"); + final ZeppOsTransactionBuilder builder = createTransactionBuilder("send voice reply"); for (final byte[] voiceFrame : voiceFrames) { // TODO encode } - builder.queue(getSupport().getQueue()); + builder.queue(getSupport()); } catch (final Exception e) { LOG.error("Failed to send voice reply", e); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsAuthenticationService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsAuthenticationService.java index f52a10c211..f90a6544cb 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsAuthenticationService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsAuthenticationService.java @@ -29,10 +29,9 @@ import nodomain.freeyourgadget.gadgetbridge.R; import nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiService; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.service.btle.BLETypeConversions; -import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder; -import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.SetDeviceStateAction; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.AbstractZeppOsService; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.ZeppOsSupport; +import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.ZeppOsTransactionBuilder; import nodomain.freeyourgadget.gadgetbridge.util.CryptoUtils; import nodomain.freeyourgadget.gadgetbridge.util.ECDH_B163; import nodomain.freeyourgadget.gadgetbridge.util.GB; @@ -122,14 +121,7 @@ public class ZeppOsAuthenticationService extends AbstractZeppOsService { LOG.debug("Auth Success"); try { - // Authenticated, now initialize phase 2 - final TransactionBuilder builder = getSupport().createTransactionBuilder("Authenticated, now initialize phase 2"); - builder.add(new SetDeviceStateAction(getSupport().getDevice(), GBDevice.State.INITIALIZING, getContext())); - builder.setCallback(null); // remove init operation as the callback - getSupport().phase2Initialize(builder); - getSupport().phase3Initialize(builder); - getSupport().setInitialized(builder); - getSupport().performImmediately(builder); + getSupport().onAuthenticationSuccess(); } catch (Exception e) { LOG.error("failed initializing device", e); } @@ -139,7 +131,7 @@ public class ZeppOsAuthenticationService extends AbstractZeppOsService { LOG.warn("Got unknown auth byte {}", String.format("0x%02x", payload[0])); } - public void startAuthentication(final TransactionBuilder builder) { + public void startAuthentication(final ZeppOsTransactionBuilder builder) { new Random().nextBytes(privateEC); final byte[] pub = ECDH_B163.ecdh_generate_public(privateEC); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsBatteryService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsBatteryService.java index 395c4ef7b6..c1f81fa0a2 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsBatteryService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsBatteryService.java @@ -21,10 +21,10 @@ import static org.apache.commons.lang3.ArrayUtils.subarray; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.HuamiBatteryInfo; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.AbstractZeppOsService; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.ZeppOsSupport; +import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.ZeppOsTransactionBuilder; public class ZeppOsBatteryService extends AbstractZeppOsService { private static final Logger LOG = LoggerFactory.getLogger(ZeppOsBatteryService.class); @@ -59,11 +59,11 @@ public class ZeppOsBatteryService extends AbstractZeppOsService { } @Override - public void initialize(final TransactionBuilder builder) { + public void initialize(final ZeppOsTransactionBuilder builder) { requestBatteryInfo(builder); } - public void requestBatteryInfo(final TransactionBuilder builder) { + public void requestBatteryInfo(final ZeppOsTransactionBuilder builder) { LOG.debug("Requesting Battery Info"); write(builder, CMD_BATTERY_REQUEST); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsCalendarService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsCalendarService.java index 84d104a187..3f0e44754b 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsCalendarService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsCalendarService.java @@ -26,9 +26,9 @@ import java.nio.charset.StandardCharsets; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventUpdatePreferences; import nodomain.freeyourgadget.gadgetbridge.model.CalendarEventSpec; import nodomain.freeyourgadget.gadgetbridge.service.btle.BLETypeConversions; -import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.ZeppOsSupport; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.AbstractZeppOsService; +import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.ZeppOsTransactionBuilder; import nodomain.freeyourgadget.gadgetbridge.util.StringUtils; public class ZeppOsCalendarService extends AbstractZeppOsService { @@ -59,11 +59,11 @@ public class ZeppOsCalendarService extends AbstractZeppOsService { } @Override - public void initialize(final TransactionBuilder builder) { + public void initialize(final ZeppOsTransactionBuilder builder) { requestCapabilities(builder); } - public void requestCapabilities(final TransactionBuilder builder) { + public void requestCapabilities(final ZeppOsTransactionBuilder builder) { write(builder, CMD_CAPABILITIES_REQUEST); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsCannedMessagesService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsCannedMessagesService.java index e425cc260f..f6f3dff103 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsCannedMessagesService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsCannedMessagesService.java @@ -35,9 +35,9 @@ import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventNotificati import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventUpdatePreferences; import nodomain.freeyourgadget.gadgetbridge.model.CannedMessagesSpec; import nodomain.freeyourgadget.gadgetbridge.service.btle.BLETypeConversions; -import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.ZeppOsSupport; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.AbstractZeppOsService; +import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.ZeppOsTransactionBuilder; import nodomain.freeyourgadget.gadgetbridge.util.StringUtils; public class ZeppOsCannedMessagesService extends AbstractZeppOsService { @@ -99,7 +99,7 @@ public class ZeppOsCannedMessagesService extends AbstractZeppOsService { } @Override - public void initialize(final TransactionBuilder builder) { + public void initialize(final ZeppOsTransactionBuilder builder) { requestCannedMessages(builder); } @@ -109,7 +109,7 @@ public class ZeppOsCannedMessagesService extends AbstractZeppOsService { return; } - final TransactionBuilder builder = new TransactionBuilder("set canned messages"); + final ZeppOsTransactionBuilder builder = createTransactionBuilder("set canned messages"); for (int i = 0; i < 16; i++) { LOG.debug("Deleting canned message {}", i); @@ -135,10 +135,10 @@ public class ZeppOsCannedMessagesService extends AbstractZeppOsService { buf.put(cannedMessage.getBytes(StandardCharsets.UTF_8)); write(builder, buf.array()); } - builder.queue(getSupport().getQueue()); + builder.queue(getSupport()); } - public void requestCannedMessages(final TransactionBuilder builder) { + public void requestCannedMessages(final ZeppOsTransactionBuilder builder) { LOG.info("Requesting canned messages"); write(builder, new byte[]{CMD_REQUEST}); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsConfigService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsConfigService.java index f10c70a82a..09c770e0ce 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsConfigService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsConfigService.java @@ -24,6 +24,8 @@ import static nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiConst.PREF import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.PREF_NIGHT_MODE; import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.PREF_NIGHT_MODE_END; import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.PREF_NIGHT_MODE_START; +import static nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.services.ZeppOsConfigService.ConfigArg.LANGUAGE; +import static nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.services.ZeppOsConfigService.ConfigArg.LANGUAGE_FOLLOW_PHONE; import android.text.TextUtils; import android.widget.Toast; @@ -75,11 +77,11 @@ import nodomain.freeyourgadget.gadgetbridge.devices.miband.DoNotDisturb; import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst; import nodomain.freeyourgadget.gadgetbridge.model.ActivityUser; import nodomain.freeyourgadget.gadgetbridge.service.btle.BLETypeConversions; -import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.ZeppOsMenuType; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.ZeppOsSupport; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.HuamiLanguageType; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.AbstractZeppOsService; +import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.ZeppOsTransactionBuilder; import nodomain.freeyourgadget.gadgetbridge.util.GB; import nodomain.freeyourgadget.gadgetbridge.util.MapUtils; import nodomain.freeyourgadget.gadgetbridge.util.Prefs; @@ -133,7 +135,7 @@ public class ZeppOsConfigService extends AbstractZeppOsService { } @Override - public void initialize(final TransactionBuilder builder) { + public void initialize(final ZeppOsTransactionBuilder builder) { write(builder, CMD_CAPABILITIES_REQUEST); requestAllConfigs(builder); } @@ -149,24 +151,22 @@ public class ZeppOsConfigService extends AbstractZeppOsService { case ActivityUser.PREF_USER_GOAL_WEIGHT_KG: case ActivityUser.PREF_USER_GOAL_STANDING_TIME_HOURS: case ActivityUser.PREF_USER_GOAL_FAT_BURN_TIME_MINUTES: { - final TransactionBuilder builder = new TransactionBuilder("set fitness goal"); - setFitnessGoal(builder); - builder.queue(getSupport().getQueue()); + withTransactionBuilder("set fitness goal", this::setFitnessGoal); return true; } // Measurement system is global case SettingsActivity.PREF_MEASUREMENT_SYSTEM: { - final TransactionBuilder builder = new TransactionBuilder("set measurement system"); - setMeasurementSystem(builder); - builder.queue(getSupport().getQueue()); + withTransactionBuilder("set measurement system", this::setMeasurementSystem); return true; } // Password needs sanity checks case PasswordCapabilityImpl.PREF_PASSWORD: case PasswordCapabilityImpl.PREF_PASSWORD_ENABLED: { - final TransactionBuilder builder = new TransactionBuilder("set " + prefKey); - setPassword(builder); - builder.queue(getSupport().getQueue()); + withTransactionBuilder("set " + prefKey, this::setPassword); + return true; + } + case PREF_LANGUAGE: { + withTransactionBuilder("set language", this::setLanguage); return true; } } @@ -179,9 +179,7 @@ public class ZeppOsConfigService extends AbstractZeppOsService { if (setConfig(prefs, prefKey, configSetter)) { try { // If the ConfigSetter was able to set the config, just write it and return - final TransactionBuilder builder = new TransactionBuilder("send config " + prefKey); - configSetter.write(builder); - builder.queue(getSupport().getQueue()); + withTransactionBuilder("send config " + prefKey, configSetter::write); } catch (final Exception e) { GB.toast("Error setting configuration", Toast.LENGTH_LONG, GB.ERROR, e); } @@ -192,7 +190,18 @@ public class ZeppOsConfigService extends AbstractZeppOsService { return false; } - private void setPassword(final TransactionBuilder builder) { + private void setLanguage(final ZeppOsTransactionBuilder builder) { + final String localeString = getDevicePrefs().getString("language", "auto"); + + LOG.info("Setting device language to {}", localeString); + + newSetter() + .setByte(LANGUAGE, getDevicePrefs().getLanguageId()) + .setBoolean(LANGUAGE_FOLLOW_PHONE, localeString.equals("auto")) + .write(builder); + } + + private void setPassword(final ZeppOsTransactionBuilder builder) { final boolean passwordEnabled = HuamiCoordinator.getPasswordEnabled(getSupport().getDevice().getAddress()); final String password = HuamiCoordinator.getPassword(getSupport().getDevice().getAddress()); @@ -209,7 +218,7 @@ public class ZeppOsConfigService extends AbstractZeppOsService { .write(builder); } - protected void setFitnessGoal(final TransactionBuilder builder) { + protected void setFitnessGoal(final ZeppOsTransactionBuilder builder) { final int goalSteps = GBApplication.getPrefs().getInt(ActivityUser.PREF_USER_STEPS_GOAL, ActivityUser.defaultUserStepsGoal); final int goalCalories = GBApplication.getPrefs().getInt(ActivityUser.PREF_USER_CALORIES_BURNT, ActivityUser.defaultUserCaloriesBurntGoal); final int goalSleep = GBApplication.getPrefs().getInt(ActivityUser.PREF_USER_SLEEP_DURATION, ActivityUser.defaultUserSleepDurationGoal); @@ -228,7 +237,7 @@ public class ZeppOsConfigService extends AbstractZeppOsService { .write(builder); } - private void setMeasurementSystem(final TransactionBuilder builder) { + private void setMeasurementSystem(final ZeppOsTransactionBuilder builder) { final String measurementSystem = GBApplication.getPrefs().getString(SettingsActivity.PREF_MEASUREMENT_SYSTEM, "metric"); LOG.info("Setting measurement system to {}", measurementSystem); @@ -312,11 +321,11 @@ public class ZeppOsConfigService extends AbstractZeppOsService { getSupport().evaluateGBDeviceEvent(eventUpdatePreferences); if (getSupport().getDevice().isInitialized()) { - if (prefs.containsKey(PREF_LANGUAGE) && prefs.get(PREF_LANGUAGE).equals(PREF_LANGUAGE_AUTO)) { + if (prefs.containsKey(PREF_LANGUAGE) && PREF_LANGUAGE_AUTO.equals(prefs.get(PREF_LANGUAGE))) { // Band is reporting automatic language, we need to send the actual language getSupport().onSendConfiguration(PREF_LANGUAGE); } - if (prefs.containsKey(PREF_TIMEFORMAT) && prefs.get(PREF_TIMEFORMAT).equals(PREF_TIMEFORMAT_AUTO)) { + if (prefs.containsKey(PREF_TIMEFORMAT) && PREF_TIMEFORMAT_AUTO.equals(prefs.get(PREF_TIMEFORMAT))) { // Band is reporting automatic time format, we need to send the actual time format getSupport().onSendConfiguration(PREF_TIMEFORMAT); } @@ -329,17 +338,17 @@ public class ZeppOsConfigService extends AbstractZeppOsService { } } - public void requestAllConfigs(final TransactionBuilder builder) { + public void requestAllConfigs(final ZeppOsTransactionBuilder builder) { for (final ConfigGroup configGroup : ConfigGroup.values()) { requestConfig(builder, configGroup); } } - public void requestConfig(final TransactionBuilder builder, final ConfigGroup config) { + public void requestConfig(final ZeppOsTransactionBuilder builder, final ConfigGroup config) { requestConfig(builder, config, true, ZeppOsConfigService.ConfigArg.getAllArgsForConfigGroup(config)); } - public void requestConfig(final TransactionBuilder builder, + public void requestConfig(final ZeppOsTransactionBuilder builder, final ConfigGroup config, final boolean includeConstraints, final List args) { @@ -906,7 +915,7 @@ public class ZeppOsConfigService extends AbstractZeppOsService { return baos.toByteArray(); } - public void write(final TransactionBuilder builder) { + public void write(final ZeppOsTransactionBuilder builder) { // Write one command per config group for (final ConfigGroup configGroup : arguments.keySet()) { ZeppOsConfigService.this.write(builder, encode(configGroup)); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsConnectionService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsConnectionService.java index 4a60c2f328..4ae60b1554 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsConnectionService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsConnectionService.java @@ -20,9 +20,9 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import nodomain.freeyourgadget.gadgetbridge.service.btle.BLETypeConversions; -import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.AbstractZeppOsService; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.ZeppOsSupport; +import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.ZeppOsTransactionBuilder; public class ZeppOsConnectionService extends AbstractZeppOsService { private static final Logger LOG = LoggerFactory.getLogger(ZeppOsConnectionService.class); @@ -61,7 +61,7 @@ public class ZeppOsConnectionService extends AbstractZeppOsService { LOG.warn("Unexpected connection payload byte {}", String.format("0x%02x", payload[0])); } - public void requestMTU(final TransactionBuilder builder) { + public void requestMTU(final ZeppOsTransactionBuilder builder) { write(builder, CMD_MTU_REQUEST); } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsContactsService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsContactsService.java index da40d1289f..b8311edbed 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsContactsService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsContactsService.java @@ -26,9 +26,9 @@ import java.util.List; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventUpdatePreferences; import nodomain.freeyourgadget.gadgetbridge.model.Contact; import nodomain.freeyourgadget.gadgetbridge.service.btle.BLETypeConversions; -import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.ZeppOsSupport; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.AbstractZeppOsService; +import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.ZeppOsTransactionBuilder; import nodomain.freeyourgadget.gadgetbridge.util.StringUtils; public class ZeppOsContactsService extends AbstractZeppOsService { @@ -41,7 +41,6 @@ public class ZeppOsContactsService extends AbstractZeppOsService { public static final byte CMD_SET_LIST = 0x07; public static final byte CMD_SET_LIST_ACK = 0x08; - private int version = 0; private int maxContacts = 0; public static final String PREF_CONTACTS_SLOT_COUNT = "zepp_os_contacts_slot_count"; @@ -59,7 +58,7 @@ public class ZeppOsContactsService extends AbstractZeppOsService { public void handlePayload(final byte[] payload) { switch (payload[0]) { case CMD_CAPABILITIES_RESPONSE: - version = payload[1]; + final int version = payload[1]; if (version != 1) { LOG.warn("Unsupported contacts service version {}", version); return; @@ -77,11 +76,11 @@ public class ZeppOsContactsService extends AbstractZeppOsService { } @Override - public void initialize(final TransactionBuilder builder) { + public void initialize(final ZeppOsTransactionBuilder builder) { requestCapabilities(builder); } - public void requestCapabilities(final TransactionBuilder builder) { + public void requestCapabilities(final ZeppOsTransactionBuilder builder) { write(builder, CMD_CAPABILITIES_REQUEST); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsDisplayItemsService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsDisplayItemsService.java index aff09ab83e..374bcd1047 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsDisplayItemsService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsDisplayItemsService.java @@ -40,10 +40,10 @@ import java.util.regex.Pattern; import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsUtils; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventUpdatePreferences; import nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiConst; -import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.ZeppOsMenuType; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.ZeppOsSupport; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.AbstractZeppOsService; +import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.ZeppOsTransactionBuilder; import nodomain.freeyourgadget.gadgetbridge.util.MapUtils; import nodomain.freeyourgadget.gadgetbridge.util.Prefs; import nodomain.freeyourgadget.gadgetbridge.util.StringUtils; @@ -123,7 +123,7 @@ public class ZeppOsDisplayItemsService extends AbstractZeppOsService { } @Override - public void initialize(final TransactionBuilder builder) { + public void initialize(final ZeppOsTransactionBuilder builder) { requestItems(builder, DISPLAY_ITEMS_MENU); requestItems(builder, DISPLAY_ITEMS_SHORTCUTS); if (getCoordinator().supportsControlCenter()) { @@ -131,7 +131,7 @@ public class ZeppOsDisplayItemsService extends AbstractZeppOsService { } } - public void requestItems(final TransactionBuilder builder, final byte type) { + public void requestItems(final ZeppOsTransactionBuilder builder, final byte type) { LOG.info("Requesting display items type={}", type); write(builder, new byte[]{CMD_REQUEST, type}); @@ -266,16 +266,13 @@ public class ZeppOsDisplayItemsService extends AbstractZeppOsService { final List allSettings, List enabledList, final FlagsMap flags) { - try { - final TransactionBuilder builder = new TransactionBuilder("set display items type " + menuType); - setDisplayItems(builder, menuType, allSettings, enabledList, flags); - builder.queue(getSupport().getQueue()); - } catch (final Exception e) { - LOG.error("Failed to set display items", e); - } + withTransactionBuilder( + "set display items type " + menuType, + builder -> setDisplayItems(builder, menuType, allSettings, enabledList, flags) + ); } - private void setDisplayItems(final TransactionBuilder builder, + private void setDisplayItems(final ZeppOsTransactionBuilder builder, final byte menuType, final List allSettings, List enabledList, diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsFileTransferService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsFileTransferService.java index 026ae7bcc5..05680a99cc 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsFileTransferService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsFileTransferService.java @@ -21,9 +21,9 @@ import android.bluetooth.BluetoothGattCharacteristic; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.ZeppOsSupport; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.AbstractZeppOsService; +import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.ZeppOsTransactionBuilder; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.services.filetransfer.ZeppOsFileTransferImpl; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.services.filetransfer.ZeppOsFileTransferV2; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.services.filetransfer.ZeppOsFileTransferV3; @@ -77,7 +77,7 @@ public class ZeppOsFileTransferService extends AbstractZeppOsService { } @Override - public void initialize(final TransactionBuilder builder) { + public void initialize(final ZeppOsTransactionBuilder builder) { write(builder, new byte[]{ZeppOsFileTransferImpl.CMD_CAPABILITIES_REQUEST}); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsFindDeviceService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsFindDeviceService.java index ed3f77ec03..3cf269744e 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsFindDeviceService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsFindDeviceService.java @@ -22,10 +22,10 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventFindPhone; -import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.HuamiUtils; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.AbstractZeppOsService; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.ZeppOsSupport; +import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.ZeppOsTransactionBuilder; import nodomain.freeyourgadget.gadgetbridge.util.Prefs; public class ZeppOsFindDeviceService extends AbstractZeppOsService { @@ -128,7 +128,7 @@ public class ZeppOsFindDeviceService extends AbstractZeppOsService { } @Override - public void initialize(final TransactionBuilder builder) { + public void initialize(final ZeppOsTransactionBuilder builder) { write(builder, CMD_CAPABILITIES_REQUEST); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsFtpServerService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsFtpServerService.java index 30331611f0..357a695274 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsFtpServerService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsFtpServerService.java @@ -26,9 +26,9 @@ import java.nio.charset.StandardCharsets; import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventUpdatePreferences; -import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.ZeppOsSupport; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.AbstractZeppOsService; +import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.ZeppOsTransactionBuilder; import nodomain.freeyourgadget.gadgetbridge.util.GB; import nodomain.freeyourgadget.gadgetbridge.util.Prefs; import nodomain.freeyourgadget.gadgetbridge.util.StringUtils; @@ -133,7 +133,14 @@ public class ZeppOsFtpServerService extends AbstractZeppOsService { } @Override - public void initialize(final TransactionBuilder builder) { + public void initialize(final ZeppOsTransactionBuilder builder) { + mCallback = null; + + final GBDeviceEventUpdatePreferences evt = new GBDeviceEventUpdatePreferences() + .withPreference(DeviceSettingsPreferenceConst.FTP_SERVER_ADDRESS, null) + .withPreference(DeviceSettingsPreferenceConst.FTP_SERVER_USERNAME, null) + .withPreference(DeviceSettingsPreferenceConst.FTP_SERVER_STATUS, null); + evaluateGBDeviceEvent(evt); } public void setCallback(final Callback callback) { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsHeartRateService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsHeartRateService.java index e39708e7b3..87c0004532 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsHeartRateService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsHeartRateService.java @@ -16,7 +16,6 @@ along with this program. If not, see . */ package nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.services; -import android.bluetooth.BluetoothGattCharacteristic; import android.os.Handler; import org.slf4j.Logger; @@ -26,9 +25,9 @@ import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventSleepState import nodomain.freeyourgadget.gadgetbridge.model.SleepState; import nodomain.freeyourgadget.gadgetbridge.service.SleepAsAndroidSender; import nodomain.freeyourgadget.gadgetbridge.service.btle.GattCharacteristic; -import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.AbstractZeppOsService; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.ZeppOsSupport; +import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.ZeppOsTransactionBuilder; import nodomain.freeyourgadget.gadgetbridge.util.RealtimeSamplesAggregator; public class ZeppOsHeartRateService extends AbstractZeppOsService { @@ -111,10 +110,10 @@ public class ZeppOsHeartRateService extends AbstractZeppOsService { realtimeStarted = true; realtimeOneShot = true; - final TransactionBuilder builder = new TransactionBuilder("HeartRateTest"); - builder.notify(getSupport().getCharacteristic(GattCharacteristic.UUID_CHARACTERISTIC_HEART_RATE_MEASUREMENT), true); + final ZeppOsTransactionBuilder builder = createTransactionBuilder("HeartRateTest"); + builder.notify(GattCharacteristic.UUID_CHARACTERISTIC_HEART_RATE_MEASUREMENT, true); write(builder, new byte[]{CMD_REALTIME_SET, REALTIME_MODE_START}); - builder.queue(getSupport().getQueue()); + builder.queue(getSupport()); realtimeHandler.removeCallbacksAndMessages(null); scheduleContinue(); @@ -133,13 +132,10 @@ public class ZeppOsHeartRateService extends AbstractZeppOsService { realtimeStarted = enable; realtimeOneShot = false; - final TransactionBuilder builder = new TransactionBuilder("set realtime heart rate measurement = " + enable); - final BluetoothGattCharacteristic hrCharacteristic = getSupport().getCharacteristic(GattCharacteristic.UUID_CHARACTERISTIC_HEART_RATE_MEASUREMENT); - if (hrCharacteristic != null) { - builder.notify(getSupport().getCharacteristic(GattCharacteristic.UUID_CHARACTERISTIC_HEART_RATE_MEASUREMENT), enable); - } + final ZeppOsTransactionBuilder builder = createTransactionBuilder("set realtime heart rate measurement = " + enable); + builder.notify(GattCharacteristic.UUID_CHARACTERISTIC_HEART_RATE_MEASUREMENT, enable); write(builder, new byte[]{CMD_REALTIME_SET, hrCmd}); - builder.queue(getSupport().getQueue()); + builder.queue(getSupport()); realtimeHandler.removeCallbacksAndMessages(null); if (enable) { @@ -178,8 +174,6 @@ public class ZeppOsHeartRateService extends AbstractZeppOsService { } private void sendContinue() { - final TransactionBuilder builder = new TransactionBuilder("hr continue"); - write(builder, new byte[]{CMD_REALTIME_SET, REALTIME_MODE_CONTINUE}); - builder.queue(getSupport().getQueue()); + write("hr continue", new byte[]{CMD_REALTIME_SET, REALTIME_MODE_CONTINUE}); } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsHttpService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsHttpService.java index 587a226c7e..11ae6c8af2 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsHttpService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsHttpService.java @@ -35,6 +35,7 @@ import java.util.Map; import java.util.Objects; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.ZeppOsSupport; +import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.ZeppOsTransactionBuilder; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.ZeppOsWeather; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.AbstractZeppOsService; import nodomain.freeyourgadget.gadgetbridge.util.FileUtils; @@ -120,6 +121,12 @@ public class ZeppOsHttpService extends AbstractZeppOsService { } } + @Override + public void initialize(final ZeppOsTransactionBuilder builder) { + urlToLocalFile.clear(); + urlDownloadCallbacks.clear(); + } + public void registerForDownload(final String url, final Uri uri, @Nullable final Callback callback) { this.urlToLocalFile.put(url, uri); this.urlDownloadCallbacks.put(url, callback); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsLogsService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsLogsService.java index ae286becdd..db3363877a 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsLogsService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsLogsService.java @@ -32,9 +32,9 @@ import java.util.Set; import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventUpdatePreferences; -import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.ZeppOsSupport; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.AbstractZeppOsService; +import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.ZeppOsTransactionBuilder; import nodomain.freeyourgadget.gadgetbridge.util.GB; import nodomain.freeyourgadget.gadgetbridge.util.Prefs; import nodomain.freeyourgadget.gadgetbridge.util.StringUtils; @@ -119,11 +119,8 @@ public class ZeppOsLogsService extends AbstractZeppOsService { } @Override - public void initialize(final TransactionBuilder builder) { - requestCapabilities(builder); - } - - public void requestCapabilities(final TransactionBuilder builder) { + public void initialize(final ZeppOsTransactionBuilder builder) { + sessions.clear(); write(builder, CMD_CAPABILITIES_REQUEST); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsLoyaltyCardService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsLoyaltyCardService.java index 519b97f5c4..a493c64484 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsLoyaltyCardService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsLoyaltyCardService.java @@ -30,9 +30,9 @@ import java.util.Objects; import nodomain.freeyourgadget.gadgetbridge.capabilities.loyaltycards.BarcodeFormat; import nodomain.freeyourgadget.gadgetbridge.capabilities.loyaltycards.LoyaltyCard; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventUpdatePreferences; -import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.ZeppOsSupport; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.AbstractZeppOsService; +import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.ZeppOsTransactionBuilder; import nodomain.freeyourgadget.gadgetbridge.util.MapUtils; import nodomain.freeyourgadget.gadgetbridge.util.Prefs; @@ -116,7 +116,7 @@ public class ZeppOsLoyaltyCardService extends AbstractZeppOsService { } @Override - public void initialize(final TransactionBuilder builder) { + public void initialize(final ZeppOsTransactionBuilder builder) { requestCapabilities(builder); } @@ -128,7 +128,7 @@ public class ZeppOsLoyaltyCardService extends AbstractZeppOsService { return supportedFormats; } - public void requestCapabilities(final TransactionBuilder builder) { + public void requestCapabilities(final ZeppOsTransactionBuilder builder) { write(builder, CMD_CAPABILITIES_REQUEST); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsMapsService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsMapsService.java index ac6c8f8769..c2d19ed760 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsMapsService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsMapsService.java @@ -34,9 +34,9 @@ import java.util.Locale; import nodomain.freeyourgadget.gadgetbridge.R; import nodomain.freeyourgadget.gadgetbridge.service.btle.BLETypeConversions; -import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.AbstractZeppOsService; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.ZeppOsSupport; +import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.ZeppOsTransactionBuilder; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.operations.ZeppOsMapsFile; import nodomain.freeyourgadget.gadgetbridge.util.GB; @@ -63,7 +63,7 @@ public class ZeppOsMapsService extends AbstractZeppOsService { } @Override - public void initialize(final TransactionBuilder builder) { + public void initialize(final ZeppOsTransactionBuilder builder) { write(builder, CMD_CAPABILITIES_REQUEST); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsMorningUpdatesService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsMorningUpdatesService.java index 4f41223798..9ba3b451ef 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsMorningUpdatesService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsMorningUpdatesService.java @@ -26,15 +26,16 @@ import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.regex.Matcher; import java.util.regex.Pattern; import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst; import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsUtils; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventUpdatePreferences; -import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.ZeppOsSupport; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.AbstractZeppOsService; +import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.ZeppOsTransactionBuilder; import nodomain.freeyourgadget.gadgetbridge.util.MapUtils; import nodomain.freeyourgadget.gadgetbridge.util.Prefs; import nodomain.freeyourgadget.gadgetbridge.util.StringUtils; @@ -54,15 +55,15 @@ public class ZeppOsMorningUpdatesService extends AbstractZeppOsService { private static final byte CMD_CATEGORIES_SET_ACK = 0x0a; private static final Map MORNING_UPDATES_MAP = new HashMap() {{ - put((byte) 0x02, "weather"); - put((byte) 0x03, "battery"); - put((byte) 0x04, "sleep"); - put((byte) 0x06, "event"); - put((byte) 0x07, "pai"); - put((byte) 0x08, "yesterdays_activity"); - put((byte) 0x09, "zepp_coach"); - put((byte) 0x0a, "cycle_tracking"); - put((byte) 0x0b, "readiness"); + put((byte) 0x02, "weather"); + put((byte) 0x03, "battery"); + put((byte) 0x04, "sleep"); + put((byte) 0x06, "event"); + put((byte) 0x07, "pai"); + put((byte) 0x08, "yesterdays_activity"); + put((byte) 0x09, "zepp_coach"); + put((byte) 0x0a, "cycle_tracking"); + put((byte) 0x0b, "readiness"); }}; public ZeppOsMorningUpdatesService(ZeppOsSupport support) { @@ -128,12 +129,12 @@ public class ZeppOsMorningUpdatesService extends AbstractZeppOsService { } @Override - public void initialize(final TransactionBuilder builder) { + public void initialize(final ZeppOsTransactionBuilder builder) { getEnabled(builder); getCategories(builder); } - public void getEnabled(final TransactionBuilder builder) { + public void getEnabled(final ZeppOsTransactionBuilder builder) { write(builder, CMD_ENABLED_GET); } @@ -141,7 +142,7 @@ public class ZeppOsMorningUpdatesService extends AbstractZeppOsService { write("set morning updates enabled", new byte[] {CMD_ENABLED_SET, bool(enabled)}); } - public void getCategories(final TransactionBuilder builder) { + public void getCategories(final ZeppOsTransactionBuilder builder) { write(builder, CMD_CATEGORIES_REQUEST); } @@ -165,12 +166,12 @@ public class ZeppOsMorningUpdatesService extends AbstractZeppOsService { for (final String category : categoriesSorted) { final byte id; if (idMap.containsKey(category)) { - id = idMap.get(category); + id = Objects.requireNonNull(idMap.get(category)); } else { // name doesn't match a known value, attempt to parse it as hex final Matcher matcher = Pattern.compile("^0[xX]([0-9a-fA-F]{1,2})$").matcher(category); if (matcher.find()) { - id = (byte) Integer.parseInt(matcher.group(1), 16); + id = (byte) Integer.parseInt(Objects.requireNonNull(matcher.group(1)), 16); } else { LOG.warn("Unknown category {}, and failed to parse as hex, not setting", category); return; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsMusicService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsMusicService.java index ae87beae27..38dd6cb955 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsMusicService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsMusicService.java @@ -16,6 +16,9 @@ along with this program. If not, see . */ package nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.services; +import android.os.Handler; +import android.os.Looper; + import org.apache.commons.lang3.ArrayUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -26,6 +29,8 @@ import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.ZeppOsSupport; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.HuamiSupport; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.AbstractZeppOsService; +import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.ZeppOsTransactionBuilder; +import nodomain.freeyourgadget.gadgetbridge.util.MediaManager; public class ZeppOsMusicService extends AbstractZeppOsService { private static final Logger LOG = LoggerFactory.getLogger(ZeppOsMusicService.class); @@ -44,6 +49,10 @@ public class ZeppOsMusicService extends AbstractZeppOsService { private static final byte BUTTON_VOLUME_UP = 0x05; private static final byte BUTTON_VOLUME_DOWN = 0x06; + private final Handler handler = new Handler(); + private MediaManager mediaManager; + protected boolean isMusicAppStarted = false; + public ZeppOsMusicService(final ZeppOsSupport support) { super(support, false); } @@ -103,16 +112,42 @@ public class ZeppOsMusicService extends AbstractZeppOsService { } } + @Override + public void initialize(final ZeppOsTransactionBuilder builder) { + if (mediaManager == null) { + mediaManager = new MediaManager(getContext()); + } + } + + @Override + public void dispose() { + handler.removeCallbacksAndMessages(null); + } + + public void onSetMusicState(final MusicStateSpec stateSpec) { + if (mediaManager.onSetMusicState(stateSpec) && isMusicAppStarted) { + sendMusicState(null, mediaManager.getBufferMusicStateSpec()); + } + } + + public void onSetMusicInfo(final MusicSpec musicSpec) { + if (mediaManager.onSetMusicInfo(musicSpec) && isMusicAppStarted) { + sendMusicState(mediaManager.getBufferMusicSpec(), mediaManager.getBufferMusicStateSpec()); + } + } + private void onMusicAppOpen() { - getSupport().onMusicAppOpen(); + isMusicAppStarted = true; + sendMusicStateDelayed(); } private void onMusicAppClosed() { - getSupport().onMusicAppClosed(); + LOG.info("Music app terminated"); + isMusicAppStarted = false; } - public void sendMusicState(final MusicSpec musicSpec, - final MusicStateSpec musicStateSpec) { + private void sendMusicState(final MusicSpec musicSpec, + final MusicStateSpec musicStateSpec) { LOG.info("Sending music: {}, {}", musicSpec, musicStateSpec); // TODO: Encode not playing state (flag 0x20, single 0x01 byte before volume) @@ -124,6 +159,19 @@ public class ZeppOsMusicService extends AbstractZeppOsService { write("send music state", cmd); } + /** + * Send the music state after a small delay. If we send it right as the app notifies us that it opened, + * it won't be recognized. + */ + private void sendMusicStateDelayed() { + final Looper mainLooper = Looper.getMainLooper(); + new Handler(mainLooper).postDelayed(() -> { + mediaManager.refresh(); + sendMusicState(mediaManager.getBufferMusicSpec(), mediaManager.getBufferMusicStateSpec()); + sendVolume(mediaManager.getPhoneVolume()); + }, 100); + } + public void sendVolume(final float volume) { LOG.info("Sending volume: {}", volume); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsNotificationService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsNotificationService.java index ae9c09e11f..8d9aa50983 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsNotificationService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsNotificationService.java @@ -42,10 +42,10 @@ import nodomain.freeyourgadget.gadgetbridge.model.CallSpec; import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec; import nodomain.freeyourgadget.gadgetbridge.model.NotificationType; import nodomain.freeyourgadget.gadgetbridge.service.btle.BLETypeConversions; -import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.ZeppOsBitmapFormat; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.ZeppOsSupport; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.AbstractZeppOsService; +import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.ZeppOsTransactionBuilder; import nodomain.freeyourgadget.gadgetbridge.util.BitmapUtil; import nodomain.freeyourgadget.gadgetbridge.util.LimitedQueue; import nodomain.freeyourgadget.gadgetbridge.util.NotificationUtils; @@ -103,11 +103,7 @@ public class ZeppOsNotificationService extends AbstractZeppOsService { } @Override - public void initialize(final TransactionBuilder builder) { - requestCapabilities(builder); - } - - public void requestCapabilities(final TransactionBuilder builder) { + public void initialize(final ZeppOsTransactionBuilder builder) { write(builder, NOTIFICATION_CMD_CAPABILITIES_REQUEST); } @@ -255,8 +251,6 @@ public class ZeppOsNotificationService extends AbstractZeppOsService { final ByteArrayOutputStream baos = new ByteArrayOutputStream(); try { - final TransactionBuilder builder = new TransactionBuilder("send notification"); - baos.write(NOTIFICATION_CMD_SEND); // ID @@ -285,12 +279,12 @@ public class ZeppOsNotificationService extends AbstractZeppOsService { // TODO put this behind a setting? baos.write(callSpec.number != null ? 0x01 : 0x00); // reply from watch - - write(builder, baos.toByteArray()); - builder.queue(getSupport().getQueue()); } catch (final Exception e) { LOG.error("Failed to send call", e); + return; } + + write("send notification", baos.toByteArray()); } public void sendNotification(final NotificationSpec notificationSpec) { @@ -306,8 +300,6 @@ public class ZeppOsNotificationService extends AbstractZeppOsService { // TODO Check real limit for notificationMaxLength / respect across all fields try { - final TransactionBuilder builder = new TransactionBuilder("send notification"); - baos.write(NOTIFICATION_CMD_SEND); baos.write(BLETypeConversions.fromUint32(notificationSpec.getId())); if (notificationSpec.type == NotificationType.GENERIC_SMS) { @@ -380,12 +372,12 @@ public class ZeppOsNotificationService extends AbstractZeppOsService { } baos.write(0); } - - write(builder, baos.toByteArray()); - builder.queue(getSupport().getQueue()); } catch (final Exception e) { LOG.error("Failed to send notification", e); + return; } + + write("send notification", baos.toByteArray()); } public void deleteNotification(final int id) { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsPhoneService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsPhoneService.java index 29109df246..5e4689c48d 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsPhoneService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsPhoneService.java @@ -16,9 +16,13 @@ along with this program. If not, see . */ package nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.services; +import android.Manifest; import android.bluetooth.BluetoothAdapter; +import android.content.pm.PackageManager; import androidx.annotation.Nullable; +import androidx.annotation.RequiresPermission; +import androidx.core.app.ActivityCompat; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -29,9 +33,9 @@ import java.nio.charset.StandardCharsets; import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventUpdatePreferences; -import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.ZeppOsSupport; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.AbstractZeppOsService; +import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.ZeppOsTransactionBuilder; import nodomain.freeyourgadget.gadgetbridge.util.Prefs; public class ZeppOsPhoneService extends AbstractZeppOsService { @@ -130,7 +134,7 @@ public class ZeppOsPhoneService extends AbstractZeppOsService { } @Override - public void initialize(final TransactionBuilder builder) { + public void initialize(final ZeppOsTransactionBuilder builder) { if (getCoordinator().supportsBluetoothPhoneCalls(getSupport().getDevice())) { requestCapabilities(builder); requestEnabled(builder); @@ -141,14 +145,15 @@ public class ZeppOsPhoneService extends AbstractZeppOsService { return version == 1; } - public void requestCapabilities(final TransactionBuilder builder) { + public void requestCapabilities(final ZeppOsTransactionBuilder builder) { write(builder, CMD_CAPABILITIES_REQUEST); } + @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT) public void getPairedStatus() { final String bluetoothName = getBluetoothName(); if (bluetoothName == null) { - LOG.error("bluetoothName is null"); + LOG.error("bluetoothName for paired status check is null"); return; } @@ -165,9 +170,13 @@ public class ZeppOsPhoneService extends AbstractZeppOsService { } public void startPairing() { + if (ActivityCompat.checkSelfPermission(getContext(), Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) { + LOG.error("Bluetooth permission not granted"); + return; + } final String bluetoothName = getBluetoothName(); if (bluetoothName == null) { - LOG.error("bluetoothName is null"); + LOG.error("bluetoothName for pairing is null"); return; } @@ -183,7 +192,7 @@ public class ZeppOsPhoneService extends AbstractZeppOsService { write("start phone pairing", buf.array()); } - public void requestEnabled(final TransactionBuilder builder) { + public void requestEnabled(final ZeppOsTransactionBuilder builder) { write(builder, CMD_ENABLED_REQUEST); } @@ -198,6 +207,7 @@ public class ZeppOsPhoneService extends AbstractZeppOsService { write("set phone enabled", cmd); } + @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT) @Nullable public String getBluetoothName() { final BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsRemindersService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsRemindersService.java index 20d7636daa..a1785862c2 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsRemindersService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsRemindersService.java @@ -37,9 +37,9 @@ import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventUpdatePref import nodomain.freeyourgadget.gadgetbridge.devices.DeviceCoordinator; import nodomain.freeyourgadget.gadgetbridge.model.Reminder; import nodomain.freeyourgadget.gadgetbridge.service.btle.BLETypeConversions; -import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.ZeppOsSupport; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.AbstractZeppOsService; +import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.ZeppOsTransactionBuilder; import nodomain.freeyourgadget.gadgetbridge.util.Prefs; import nodomain.freeyourgadget.gadgetbridge.util.StringUtils; @@ -107,9 +107,7 @@ public class ZeppOsRemindersService extends AbstractZeppOsService { case CMD_RESPONSE: LOG.info("Got reminders from band"); decodeAndUpdateReminders(payload); - final TransactionBuilder builder = getSupport().createTransactionBuilder("send reminders"); - sendReminders(builder); - builder.queue(getSupport().getQueue()); + withTransactionBuilder("send reminders", this::sendReminders); return; default: LOG.warn("Unexpected reminders payload byte {}", String.format("0x%02x", payload[0])); @@ -117,25 +115,25 @@ public class ZeppOsRemindersService extends AbstractZeppOsService { } @Override - public void initialize(final TransactionBuilder builder) { + public void initialize(final ZeppOsTransactionBuilder builder) { requestCapabilities(builder); requestReminders(builder); } - private void requestCapabilities(final TransactionBuilder builder) { + private void requestCapabilities(final ZeppOsTransactionBuilder builder) { write(builder, CMD_CAPABILITIES_REQUEST); } - private void requestReminders(final TransactionBuilder builder) { + private void requestReminders(final ZeppOsTransactionBuilder builder) { write(builder, CMD_REQUEST); } - public void sendReminders(final TransactionBuilder builder) { + public void sendReminders(final ZeppOsTransactionBuilder builder) { final List reminders = DBHelper.getReminders(getSupport().getDevice()); sendReminders(builder, reminders); } - public void sendReminders(final TransactionBuilder builder, final List reminders) { + public void sendReminders(final ZeppOsTransactionBuilder builder, final List reminders) { LOG.info("On Set Reminders: {}", reminders.size()); final int reminderSlotCount = getCoordinator().getReminderSlotCount(getSupport().getDevice()); @@ -209,7 +207,7 @@ public class ZeppOsRemindersService extends AbstractZeppOsService { } } - private void sendReminderToDevice(final TransactionBuilder builder, int position, final boolean update, final ZeppOsReminder reminder) { + private void sendReminderToDevice(final ZeppOsTransactionBuilder builder, int position, final boolean update, final ZeppOsReminder reminder) { final DeviceCoordinator coordinator = getCoordinator(); final int reminderSlotCount = coordinator.getReminderSlotCount(getSupport().getDevice()); if (position + 1 > reminderSlotCount) { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsServicesService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsServicesService.java index 4e0b19dcf9..3fa08a3b86 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsServicesService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsServicesService.java @@ -22,9 +22,9 @@ import org.slf4j.LoggerFactory; import java.nio.ByteBuffer; import java.nio.ByteOrder; -import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.ZeppOsSupport; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.AbstractZeppOsService; +import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.ZeppOsTransactionBuilder; public class ZeppOsServicesService extends AbstractZeppOsService { private static final Logger LOG = LoggerFactory.getLogger(ZeppOsServicesService.class); @@ -43,6 +43,7 @@ public class ZeppOsServicesService extends AbstractZeppOsService { return ENDPOINT; } + /** @noinspection SwitchStatementWithTooFewBranches*/ @Override public void handlePayload(final byte[] payload) { switch (payload[0]) { @@ -54,7 +55,7 @@ public class ZeppOsServicesService extends AbstractZeppOsService { } } - public void requestServices(final TransactionBuilder builder) { + public void requestServices(final ZeppOsTransactionBuilder builder) { write(builder, CMD_GET_LIST); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsShortcutCardsService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsShortcutCardsService.java index 8ff7d058f9..4bc8f344c4 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsShortcutCardsService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsShortcutCardsService.java @@ -32,15 +32,16 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Locale; +import java.util.Objects; import java.util.regex.Matcher; import java.util.regex.Pattern; import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst; import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsUtils; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventUpdatePreferences; -import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.ZeppOsSupport; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.AbstractZeppOsService; +import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.ZeppOsTransactionBuilder; import nodomain.freeyourgadget.gadgetbridge.util.Prefs; import nodomain.freeyourgadget.gadgetbridge.util.StringUtils; @@ -158,6 +159,7 @@ public class ZeppOsShortcutCardsService extends AbstractZeppOsService { } } + /** @noinspection SwitchStatementWithTooFewBranches*/ @Override public boolean onSendConfiguration(final String config, final Prefs prefs) { switch (config) { @@ -172,16 +174,8 @@ public class ZeppOsShortcutCardsService extends AbstractZeppOsService { } @Override - public void initialize(final TransactionBuilder builder) { - requestCapabilities(builder); - requestShortcutCards(builder); - } - - public void requestCapabilities(final TransactionBuilder builder) { + public void initialize(final ZeppOsTransactionBuilder builder) { write(builder, CMD_CAPABILITIES_REQUEST); - } - - public void requestShortcutCards(final TransactionBuilder builder) { write(builder, CMD_LIST_GET); } @@ -254,9 +248,9 @@ public class ZeppOsShortcutCardsService extends AbstractZeppOsService { } try { - baos.write(appNum.getBytes(StandardCharsets.UTF_8)); + baos.write(Objects.requireNonNull(appNum).getBytes(StandardCharsets.UTF_8)); baos.write(0); - baos.write(cardNum.getBytes(StandardCharsets.UTF_8)); + baos.write(Objects.requireNonNull(cardNum).getBytes(StandardCharsets.UTF_8)); baos.write(0); baos.write(1); // enabled baos.write(0); // ? diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsUserInfoService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsUserInfoService.java index e2069729f4..1add6539e9 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsUserInfoService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsUserInfoService.java @@ -34,9 +34,9 @@ import java.time.LocalDate; import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.model.ActivityUser; import nodomain.freeyourgadget.gadgetbridge.service.btle.BLETypeConversions; -import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.AbstractZeppOsService; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.ZeppOsSupport; +import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.ZeppOsTransactionBuilder; import nodomain.freeyourgadget.gadgetbridge.util.Prefs; public class ZeppOsUserInfoService extends AbstractZeppOsService { @@ -69,10 +69,11 @@ public class ZeppOsUserInfoService extends AbstractZeppOsService { } @Override - public void initialize(final TransactionBuilder builder) { + public void initialize(final ZeppOsTransactionBuilder builder) { setUserInfo(builder); } + /** @noinspection EnhancedSwitchMigration*/ @Override public boolean onSendConfiguration(final String config, final Prefs prefs) { switch (config) { @@ -82,16 +83,14 @@ public class ZeppOsUserInfoService extends AbstractZeppOsService { case PREF_USER_HEIGHT_CM: case PREF_USER_GENDER: case PREF_DEVICE_REGION: - final TransactionBuilder builder = getSupport().createTransactionBuilder("set user info"); - setUserInfo(builder); - builder.queue(getSupport().getQueue()); + withTransactionBuilder("set user info", this::setUserInfo); return true; } return false; } - public void setUserInfo(final TransactionBuilder builder) { + public void setUserInfo(final ZeppOsTransactionBuilder builder) { LOG.info("Attempting to set user info..."); final Prefs prefs = GBApplication.getPrefs(); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsVibrationPatternsService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsVibrationPatternsService.java index bedcb0724f..4abde7f9b3 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsVibrationPatternsService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsVibrationPatternsService.java @@ -31,11 +31,11 @@ import java.util.Locale; import nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiConst; import nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiCoordinator; import nodomain.freeyourgadget.gadgetbridge.devices.miband.VibrationProfile; -import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.HuamiUtils; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.HuamiVibrationPatternNotificationType; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.AbstractZeppOsService; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.ZeppOsSupport; +import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.ZeppOsTransactionBuilder; import nodomain.freeyourgadget.gadgetbridge.util.Prefs; public class ZeppOsVibrationPatternsService extends AbstractZeppOsService { @@ -68,7 +68,7 @@ public class ZeppOsVibrationPatternsService extends AbstractZeppOsService { } @Override - public void initialize(final TransactionBuilder builder) { + public void initialize(final ZeppOsTransactionBuilder builder) { for (final HuamiVibrationPatternNotificationType type : getCoordinator().getVibrationPatternNotificationTypes(getSupport().getDevice())) { // FIXME: Can we read these from the band? final String typeKey = type.name().toLowerCase(Locale.ROOT); @@ -81,9 +81,10 @@ public class ZeppOsVibrationPatternsService extends AbstractZeppOsService { if (config.startsWith(HuamiConst.PREF_HUAMI_VIBRATION_PROFILE_PREFIX) || config.startsWith(HuamiConst.PREF_HUAMI_VIBRATION_COUNT_PREFIX) || config.startsWith(HuamiConst.PREF_HUAMI_VIBRATION_TRY_PREFIX)) { - final TransactionBuilder builder = new TransactionBuilder("send " + config); - setVibrationPattern(builder, config); - builder.queue(getSupport().getQueue()); + withTransactionBuilder( + "send " + config, + builder -> setVibrationPattern(builder, config) + ); return true; } @@ -91,7 +92,7 @@ public class ZeppOsVibrationPatternsService extends AbstractZeppOsService { } - protected void setVibrationPattern(final TransactionBuilder builder, final String preferenceKey) { + protected void setVibrationPattern(final ZeppOsTransactionBuilder builder, final String preferenceKey) { // The preference key has one of the 3 prefixes final String notificationTypeName = preferenceKey.replace(PREF_HUAMI_VIBRATION_COUNT_PREFIX, "") .replace(PREF_HUAMI_VIBRATION_PROFILE_PREFIX, "") @@ -109,7 +110,7 @@ public class ZeppOsVibrationPatternsService extends AbstractZeppOsService { setVibrationPattern(builder, notificationType, isTry, vibrationProfile); } - private void setVibrationPattern(final TransactionBuilder builder, + private void setVibrationPattern(final ZeppOsTransactionBuilder builder, final HuamiVibrationPatternNotificationType notificationType, final boolean test, final VibrationProfile profile) { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsVoiceMemosService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsVoiceMemosService.java index 2a582b996c..bea24395bd 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsVoiceMemosService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsVoiceMemosService.java @@ -44,6 +44,7 @@ import nodomain.freeyourgadget.gadgetbridge.database.repository.AudioRecordingsR import nodomain.freeyourgadget.gadgetbridge.entities.AudioRecording; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.AbstractZeppOsService; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.ZeppOsSupport; +import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.ZeppOsTransactionBuilder; import nodomain.freeyourgadget.gadgetbridge.util.DateTimeUtils; import nodomain.freeyourgadget.gadgetbridge.util.FileUtils; import nodomain.freeyourgadget.gadgetbridge.util.StringUtils; @@ -132,6 +133,14 @@ public class ZeppOsVoiceMemosService extends AbstractZeppOsService { LOG.warn("Unexpected voice memos byte {}", String.format("0x%02x", payload[0])); } + @Override + public void initialize(final ZeppOsTransactionBuilder builder) { + downloadingRecordings.clear(); + downloadQueue.clear(); + downloading = false; + handler.removeCallbacksAndMessages(null); + } + public void requestList() { write("get voice memos list", CMD_LIST_REQUEST); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsWatchfaceService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsWatchfaceService.java index d52f542cab..6c4aab2219 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsWatchfaceService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsWatchfaceService.java @@ -39,9 +39,9 @@ import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSett import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventUpdatePreferences; import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceApp; import nodomain.freeyourgadget.gadgetbridge.service.btle.BLETypeConversions; -import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.ZeppOsSupport; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.AbstractZeppOsService; +import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.ZeppOsTransactionBuilder; import nodomain.freeyourgadget.gadgetbridge.util.Prefs; public class ZeppOsWatchfaceService extends AbstractZeppOsService { @@ -171,7 +171,7 @@ public class ZeppOsWatchfaceService extends AbstractZeppOsService { } @Override - public void initialize(final TransactionBuilder builder) { + public void initialize(final ZeppOsTransactionBuilder builder) { requestWatchfaces(builder); requestCurrentWatchface(builder); } @@ -180,21 +180,15 @@ public class ZeppOsWatchfaceService extends AbstractZeppOsService { return watchfaces; } - public void requestWatchfaces(final TransactionBuilder builder) { + public void requestWatchfaces(final ZeppOsTransactionBuilder builder) { write(builder, CMD_LIST_GET); } public void requestCurrentWatchface() { - try { - final TransactionBuilder builder = new TransactionBuilder("request current watchface"); - requestCurrentWatchface(builder); - builder.queue(getSupport().getQueue()); - } catch (final Exception e) { - LOG.error("Failed to request current watchface", e); - } + withTransactionBuilder("request current watchface", this::requestCurrentWatchface); } - public void requestCurrentWatchface(final TransactionBuilder builder) { + public void requestCurrentWatchface(final ZeppOsTransactionBuilder builder) { write(builder, CMD_CURRENT_GET); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsWeatherService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsWeatherService.java index 2bd1b340e6..dbd9efc7c0 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsWeatherService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsWeatherService.java @@ -24,7 +24,6 @@ import java.nio.charset.StandardCharsets; import java.util.ArrayList; import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec; -import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.AbstractZeppOsService; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.ZeppOsSupport; @@ -79,9 +78,7 @@ public class ZeppOsWeatherService extends AbstractZeppOsService { baos.write(locationName.getBytes(StandardCharsets.UTF_8)); baos.write((byte) 0x00); // ? - final TransactionBuilder builder = new TransactionBuilder("set weather location"); - write(builder, baos.toByteArray()); - builder.queue(getSupport().getQueue()); + write("set weather location", baos.toByteArray()); } catch (final Exception e) { LOG.error("Failed to set weather location", e); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsWifiService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsWifiService.java index b2b2b060f6..2558db29a3 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsWifiService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/ZeppOsWifiService.java @@ -28,9 +28,9 @@ import java.util.Locale; import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventUpdatePreferences; -import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.ZeppOsSupport; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.AbstractZeppOsService; +import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.ZeppOsTransactionBuilder; import nodomain.freeyourgadget.gadgetbridge.util.GB; import nodomain.freeyourgadget.gadgetbridge.util.Prefs; import nodomain.freeyourgadget.gadgetbridge.util.StringUtils; @@ -127,8 +127,12 @@ public class ZeppOsWifiService extends AbstractZeppOsService { } @Override - public void initialize(final TransactionBuilder builder) { + public void initialize(final ZeppOsTransactionBuilder builder) { + mCallback = null; + final GBDeviceEventUpdatePreferences evt = new GBDeviceEventUpdatePreferences() + .withPreference(DeviceSettingsPreferenceConst.WIFI_HOTSPOT_STATUS, null); + evaluateGBDeviceEvent(evt); } public void setCallback(final Callback callback) { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/filetransfer/FileTransferRequest.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/filetransfer/FileTransferRequest.java index f8c4664feb..79a0ec0662 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/filetransfer/FileTransferRequest.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/filetransfer/FileTransferRequest.java @@ -21,7 +21,7 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.service /** * Wrapper class to keep track of ongoing file send requests and their progress. */ -class FileTransferRequest { +public class FileTransferRequest { private final String url; private final String filename; private final int rawLength; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/filetransfer/ZeppOsFileTransferImpl.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/filetransfer/ZeppOsFileTransferImpl.java index 00ce77fcbe..46823eacd8 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/filetransfer/ZeppOsFileTransferImpl.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/filetransfer/ZeppOsFileTransferImpl.java @@ -19,8 +19,8 @@ import java.util.zip.Inflater; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventUpdatePreferences; import nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiService; -import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.ZeppOsSupport; +import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.ZeppOsTransactionBuilder; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.services.ZeppOsFileTransferService; import nodomain.freeyourgadget.gadgetbridge.util.CheckSums; import nodomain.freeyourgadget.gadgetbridge.util.StringUtils; @@ -117,10 +117,10 @@ public abstract class ZeppOsFileTransferImpl { // TODO: 3 unknown bytes for v3 - final TransactionBuilder builder = mSupport.createTransactionBuilder("enable file transfer v3 notifications"); - builder.notify(mSupport.getCharacteristic(HuamiService.UUID_CHARACTERISTIC_ZEPP_OS_FILE_TRANSFER_V3_SEND), true); - builder.notify(mSupport.getCharacteristic(HuamiService.UUID_CHARACTERISTIC_ZEPP_OS_FILE_TRANSFER_V3_RECEIVE), true); - builder.queue(mSupport.getQueue()); + final ZeppOsTransactionBuilder builder = mSupport.createZeppOsTransactionBuilder("enable file transfer v3 notifications"); + builder.notify(HuamiService.UUID_CHARACTERISTIC_ZEPP_OS_FILE_TRANSFER_V3_SEND, true); + builder.notify(HuamiService.UUID_CHARACTERISTIC_ZEPP_OS_FILE_TRANSFER_V3_RECEIVE, true); + builder.queue(mSupport); } mSupport.evaluateGBDeviceEvent(new GBDeviceEventUpdatePreferences(PREF_SUPPORTED_SERVICES, new HashSet<>(supportedServices))); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/filetransfer/ZeppOsFileTransferV3.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/filetransfer/ZeppOsFileTransferV3.java index 25b0c583ab..792cf38ebb 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/filetransfer/ZeppOsFileTransferV3.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/zeppos/services/filetransfer/ZeppOsFileTransferV3.java @@ -33,6 +33,7 @@ import nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiService; import nodomain.freeyourgadget.gadgetbridge.service.btle.BLETypeConversions; import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.ZeppOsSupport; +import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.ZeppOsTransactionBuilder; import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.services.ZeppOsFileTransferService; import nodomain.freeyourgadget.gadgetbridge.util.CheckSums; @@ -65,6 +66,7 @@ public class ZeppOsFileTransferV3 extends ZeppOsFileTransferImpl { super(fileTransferService, support); } + /** @noinspection SwitchStatementWithTooFewBranches*/ @Override public void handlePayload(final byte[] payload) { switch (payload[0]) { @@ -256,15 +258,12 @@ public class ZeppOsFileTransferV3 extends ZeppOsFileTransferImpl { final byte[] payload = buf.array(); - final TransactionBuilder builder = mSupport.createTransactionBuilder("send chunk v3"); + final ZeppOsTransactionBuilder builder = mSupport.createZeppOsTransactionBuilder("send chunk v3"); for (int i = 0; i < payload.length; i += partSize) { final byte[] part = ArrayUtils.subarray(payload, i, i + partSize); - builder.write( - mSupport.getCharacteristic(HuamiService.UUID_CHARACTERISTIC_ZEPP_OS_FILE_TRANSFER_V3_SEND), - part - ); + builder.write(HuamiService.UUID_CHARACTERISTIC_ZEPP_OS_FILE_TRANSFER_V3_SEND, part); } - builder.queue(mSupport.getQueue()); + builder.queue(mSupport); request.setProgress(request.getProgress() + chunk.length); request.setIndex(request.getIndex() + 1); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/preferences/DevicePrefs.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/preferences/DevicePrefs.java index d9cc1b8fdd..ac97f6bc8c 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/preferences/DevicePrefs.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/preferences/DevicePrefs.java @@ -32,7 +32,7 @@ import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst; public class DevicePrefs extends Prefs { - private GBDevice gbDevice; + private final GBDevice gbDevice; public DevicePrefs(final SharedPreferences preferences, GBDevice gbDevice) { super(preferences); @@ -115,4 +115,8 @@ public class DevicePrefs extends Prefs { return getInt(DeviceSettingsPreferenceConst.PREF_RESERVE_REMINDERS_CALENDAR, 9); } + public boolean allowHighMtu() { + return getBoolean(PREF_ALLOW_HIGH_MTU, true); + } + }