diff --git a/CHANGELOG.md b/CHANGELOG.md index 9cdd536f5..fcfca102d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ ### Changelog +#### Version 0.36.3 +* Basic Makibes HR3 support + #### Version 0.36.2 * Amazfit Bip: Untested support for Lite variant * Force Lineage OS to ask for permission when Trust is used to fix non-working incoming calls diff --git a/app/build.gradle b/app/build.gradle index 49de3f12c..f3f530079 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -25,8 +25,8 @@ android { targetSdkVersion 27 // Note: always bump BOTH versionCode and versionName! - versionName "0.36.2" - versionCode 157 + versionName "0.36.3" + versionCode 158 vectorDrawables.useSupportLibrary = true } buildTypes { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/devicesettings/DeviceSettingsPreferenceConst.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/devicesettings/DeviceSettingsPreferenceConst.java new file mode 100644 index 000000000..a470e6cc2 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/devicesettings/DeviceSettingsPreferenceConst.java @@ -0,0 +1,5 @@ +package nodomain.freeyourgadget.gadgetbridge.activities.devicesettings; + +public class DeviceSettingsPreferenceConst { + public static final String PREF_TIMEFORMAT = "timeformat"; +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/makibeshr3/MakibesHR3Constants.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/makibeshr3/MakibesHR3Constants.java new file mode 100644 index 000000000..7805d8ac7 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/makibeshr3/MakibesHR3Constants.java @@ -0,0 +1,213 @@ +/* Copyright (C) 2016-2019 Andreas Shimokawa, Carsten Pfeiffer, João + Paulo Barraca + + 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.devices.makibeshr3; + +import java.util.UUID; + +public final class MakibesHR3Constants { + + + public static final UUID UUID_SERVICE = UUID.fromString("6e400001-b5a3-f393-e0a9-e50e24dcca9e"); + public static final UUID UUID_CHARACTERISTIC_CONTROL = UUID.fromString("6e400002-b5a3-f393-e0a9-e50e24dcca9e"); + + // time + // mode ab:00:04:ff:7c:80:** (00: 24h, 01: 12h) + + // confirm write? + // ab:00:09:ff:52:80:00:13:06:09:0f:0b + + // disconnect? + // ab:00:03:ff:ff:80 + + // Services and Characteristics + // 00001801-0000-1000-8000-00805f9b34fb + // 00002a05-0000-1000-8000-00805f9b34fb + // 00001800-0000-1000-8000-00805f9b34fb + // 00002a00-0000-1000-8000-00805f9b34fb + // 00002a01-0000-1000-8000-00805f9b34fb + // 00002a02-0000-1000-8000-00805f9b34fb + // 00002a04-0000-1000-8000-00805f9b34fb + // 00002aa6-0000-1000-8000-00805f9b34fb + // 6e400001-b5a3-f393-e0a9-e50e24dcca9e // Nordic UART Service + // 6e400002-b5a3-f393-e0a9-e50e24dcca9e // control + // 6e400003-b5a3-f393-e0a9-e50e24dcca9e + // 0000fee7-0000-1000-8000-00805f9b34fb + // 0000fec9-0000-1000-8000-00805f9b34fb + // 0000fea1-0000-1000-8000-00805f9b34fb + // 0000fea2-0000-1000-8000-00805f9b34fb + + // Command structure + // ab 00 [argument_count] ff [command] 80 [arguments] + // where [argument_count] is [arguments].length + 3 + + // refresh sends + // 51 + // 52 + // 93 (CMD_SET_DATE_TIME) + + public static final byte[] DATA_TEMPLATE = { + (byte) 0xab, + (byte) 0x00, + (byte) 0, // argument_count + (byte) 0xff, + (byte) 0, // command + (byte) 0x80 +// ,arguments + }; + + public static final int DATA_ARGUMENT_COUNT_INDEX = 2; + public static final int DATA_COMMAND_INDEX = 4; + public static final int DATA_ARGUMENTS_INDEX = 6; + + + // 00 + public static final byte CMD_FACTORY_RESET = (byte) 0x23; + + + // 00 + // year (+2000) + // month + // day + // 0b + // 00 + // year (+2000) + // month + // day + // 0b + // 19 + public static final byte CMD_UNKNOWN_51 = (byte) 0x51; + + // this is the last command sent on sync + // 00 + // year (+2000) + // month + // 14 this isn't the current day + // hour (current) + // minute (current) + public static final byte CMD_UNKNOWN_52 = (byte) 0x52; + + + public static final byte CMD_FIND_DEVICE = (byte) 0x71; + + + public static final byte ARG_SEND_NOTIFICATION_SOURCE_CALL = (byte) 0x01; + public static final byte ARG_SEND_NOTIFICATION_SOURCE_STOP_CALL = (byte) 0x02; + public static final byte ARG_SEND_NOTIFICATION_SOURCE_MESSAGE = (byte) 0x03; + public static final byte ARG_SEND_NOTIFICATION_SOURCE_QQ = (byte) 0x07; + public static final byte ARG_SEND_NOTIFICATION_SOURCE_WECHAT = (byte) 0x09; + public static final byte ARG_SEND_NOTIFICATION_SOURCE_WHATSAPP = (byte) 0x0a; + public static final byte ARG_SEND_NOTIFICATION_SOURCE_LINE = (byte) 0x0e; + public static final byte ARG_SEND_NOTIFICATION_SOURCE_TWITTER = (byte) 0x0f; + public static final byte ARG_SEND_NOTIFICATION_SOURCE_FACEBOOK = (byte) 0x10; + public static final byte ARG_SEND_NOTIFICATION_SOURCE_FACEBOOK2 = (byte) 0x11; + public static final byte ARG_SEND_NOTIFICATION_SOURCE_WEIBO = (byte) 0x13; + public static final byte ARG_SEND_NOTIFICATION_SOURCE_KAKOTALK = (byte) 0x14; + // ARG_SET_NOTIFICATION_SOURCE_* + // 02 + // ASCII + public static final byte CMD_SEND_NOTIFICATION = (byte) 0x72; + + + public static final byte ARG_SET_ALARM_REMINDER_REPEAT_WEEKDAY = (byte) 0x1F; + public static final byte ARG_SET_ALARM_REMINDER_REPEAT_CUSTOM = (byte) 0x40; + public static final byte ARG_SET_ALARM_REMINDER_REPEAT_EVERY_DAY = (byte) 0x7F; + public static final byte ARG_SET_ALARM_REMINDER_REPEAT_ONE_TIME = (byte) 0x80; + // reminder id starting at 0 + // enable (00/01) + // hour + // minute + // ARG_SET_ALARM_REMINDER_REPEAT_* + public static final byte CMD_SET_ALARM_REMINDER = (byte) 0x73; + + + public static final byte ARG_SET_PERSONAL_INFORMATION_UNIT_DISTANCE_MILES = (byte) 0x00; + public static final byte ARG_SET_PERSONAL_INFORMATION_UNIT_DISTANCE_KILOMETERS = (byte) 0x01; + public static final byte ARG_SET_PERSONAL_INFORMATION_UNIT_LENGTH_INCHES = (byte) 0x00; + public static final byte ARG_SET_PERSONAL_INFORMATION_UNIT_LENGTH_CENTIMETERS = (byte) 0x01; + // step length (in/cm) + // age (years) + // height (in/cm) + // weight (lb/kg) + // ARG_SET_PERSONAL_INFORMATION_UNIT_DISTANCE_* + // target step count (kilo) + // 5a + // 82 + // 3c + // 5a + // 28 + // b4 + // 5d + // 64 + public static final byte CMD_SET_PERSONAL_INFORMATION = (byte) 0x74; + + + // enable (00/01) + // start hour + // start minute + // end hour + // end minute + // 2d + public static final byte CMD_SET_SEDENTARY_REMINDER = (byte) 0x75; + + + // enable (00/01) + // start hour + // start minute + // end hour + // end minute + public static final byte CMD_SET_QUITE_HOURS = (byte) 0x76; + + + // enable (00/01) + public static final byte CMD_SET_HEADS_UP_SCREEN = (byte) 0x77; + + + // The watch enters photograph mode, but doesn't appear to send a trigger signal. + // enable (00/01) + public static final byte CMD_SET_PHOTOGRAPH_MODE = (byte) 0x79; + + + // enable (00/01) + public static final byte CMD_SET_LOST_REMINDER = (byte) 0x7a; + + + // 7b has 1 argument. Looks like enable/disable. + + // 7e has 14 arguments. + + public static final byte ARG_SET_TIMEMODE_24H = 0x00; + public static final byte ARG_SET_TIMEMODE_12H = 0x01; + // ARG_SET_TIMEMODE_* + public static final byte CMD_SET_TIMEMODE = (byte) 0x7c; + + + // 00 + // year hi + // year lo + // month + // day + // hour + // minute + // second + public static final byte CMD_SET_DATE_TIME = (byte) 0x93; + + + // If this is sent after {@link CMD_FACTORY_RESET}, it's a shutdown, not a reboot. + // Rebooting resets the watch face and wallpaper. + public static final byte CMD_REBOOT = (byte) 0xff; +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/makibeshr3/MakibesHR3Coordinator.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/makibeshr3/MakibesHR3Coordinator.java new file mode 100644 index 000000000..a81c789a9 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/makibeshr3/MakibesHR3Coordinator.java @@ -0,0 +1,181 @@ +/* Copyright (C) 2017-2019 Daniele Gobbetti, João Paulo Barraca, tiparega + + 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.devices.makibeshr3; + +import android.app.Activity; +import android.content.Context; +import android.content.SharedPreferences; +import android.net.Uri; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import nodomain.freeyourgadget.gadgetbridge.GBApplication; +import nodomain.freeyourgadget.gadgetbridge.GBException; +import nodomain.freeyourgadget.gadgetbridge.R; +import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst; +import nodomain.freeyourgadget.gadgetbridge.devices.AbstractDeviceCoordinator; +import nodomain.freeyourgadget.gadgetbridge.devices.InstallHandler; +import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider; +import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession; +import nodomain.freeyourgadget.gadgetbridge.entities.Device; +import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; +import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceCandidate; +import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample; +import nodomain.freeyourgadget.gadgetbridge.model.DeviceType; + +import static nodomain.freeyourgadget.gadgetbridge.GBApplication.getContext; + + +public class MakibesHR3Coordinator extends AbstractDeviceCoordinator { + + private static final Logger LOG = LoggerFactory.getLogger(MakibesHR3Coordinator.class); + + public static byte getTimeMode(String deviceAddress) { + SharedPreferences sharedPrefs = GBApplication.getDeviceSpecificSharedPrefs(deviceAddress); + + String tmode = sharedPrefs.getString(DeviceSettingsPreferenceConst.PREF_TIMEFORMAT, getContext().getString(R.string.p_timeformat_24h)); + + LOG.debug("tmode is " + tmode); + + if (getContext().getString(R.string.p_timeformat_24h).equals(tmode)) { + return MakibesHR3Constants.ARG_SET_TIMEMODE_24H; + } else { + return MakibesHR3Constants.ARG_SET_TIMEMODE_12H; + } + } + + @NonNull + @Override + public DeviceType getSupportedType(GBDeviceCandidate candidate) { + String name = candidate.getDevice().getName(); + + // TODO: + if ((name != null) && name.equals("Y808")) { + return DeviceType.MAKIBESHR3; + } + + return DeviceType.UNKNOWN; + } + + @Override + protected void deleteDevice(@NonNull GBDevice gbDevice, @NonNull Device device, @NonNull DaoSession session) throws GBException { + + } + + @Override + public int getBondingStyle(GBDevice deviceCandidate) { + return BONDING_STYLE_NONE; + } + + @Override + public boolean supportsCalendarEvents() { + return false; + } + + @Override + public boolean supportsRealtimeData() { + return false; + } + + @Override + public boolean supportsWeather() { + return false; + } + + @Override + public boolean supportsFindDevice() { + return true; + } + + @Override + public DeviceType getDeviceType() { + return DeviceType.MAKIBESHR3; + } + + @Nullable + @Override + public Class getPairingActivity() { + return null; + } + + @Override + public boolean supportsActivityDataFetching() { + return false; + } + + @Override + public boolean supportsActivityTracking() { + return false; + } + + @Override + public SampleProvider getSampleProvider(GBDevice device, DaoSession session) { + return null; + } + + @Override + public InstallHandler findInstallHandler(Uri uri, Context context) { + return null; + } + + @Override + public boolean supportsScreenshots() { + return false; + } + + @Override + public int getAlarmSlotCount() { + // TODO: + return 5; + } + + @Override + public boolean supportsSmartWakeup(GBDevice device) { + return false; + } + + @Override + public boolean supportsHeartRateMeasurement(GBDevice device) { + return true; + } + + @Override + public String getManufacturer() { + return "Makibes"; + } + + @Override + public boolean supportsAppsManagement() { + return false; + } + + @Override + public Class getAppsManagementActivity() { + return null; + } + + @Override + public int[] getSupportedDeviceSpecificSettings(GBDevice device) { + return new int[]{ + R.xml.devicesettings_timeformat + }; + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandConst.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandConst.java index ff410a9f9..a69ca4ead 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandConst.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandConst.java @@ -17,14 +17,10 @@ along with this program. If not, see . */ package nodomain.freeyourgadget.gadgetbridge.devices.miband; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import nodomain.freeyourgadget.gadgetbridge.util.Prefs; import nodomain.freeyourgadget.gadgetbridge.util.Version; public final class MiBandConst { - private static final Logger LOG = LoggerFactory.getLogger(MiBandConst.class); public static final String PREF_USER_ALIAS = "mi_user_alias"; public static final String PREF_MIBAND_WEARSIDE = "mi_wearside"; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/DeviceType.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/DeviceType.java index 9d28b072e..532ff57d6 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/DeviceType.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/DeviceType.java @@ -57,6 +57,7 @@ public enum DeviceType { CASIOGB6900(120, R.drawable.ic_device_default, R.drawable.ic_device_default_disabled, R.string.devicetype_casiogb6900), MISCALE2(131, R.drawable.ic_device_default, R.drawable.ic_device_default_disabled, R.string.devicetype_miscale2), BFH16(140, R.drawable.ic_device_default, R.drawable.ic_device_default_disabled, R.string.devicetype_bfh16), + MAKIBESHR3(150, R.drawable.ic_device_default, R.drawable.ic_device_hplus_disabled, R.string.devicetype_makibes_hr3), MIJIA_LYWSD02(200, R.drawable.ic_device_pebble, R.drawable.ic_device_pebble_disabled, R.string.devicetype_mijia_lywsd02), TEST(1000, R.drawable.ic_device_default, R.drawable.ic_device_default_disabled, R.string.devicetype_test); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceSupportFactory.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceSupportFactory.java index d9d5f2ebb..743122c22 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceSupportFactory.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceSupportFactory.java @@ -42,6 +42,7 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.id115.ID115Support; import nodomain.freeyourgadget.gadgetbridge.service.devices.jyou.BFH16DeviceSupport; import nodomain.freeyourgadget.gadgetbridge.service.devices.jyou.TeclastH30Support; import nodomain.freeyourgadget.gadgetbridge.service.devices.liveview.LiveviewSupport; +import nodomain.freeyourgadget.gadgetbridge.service.devices.makibeshr3.MakibesHR3DeviceSupport; import nodomain.freeyourgadget.gadgetbridge.service.devices.miband.MiBandSupport; import nodomain.freeyourgadget.gadgetbridge.service.devices.mijia_lywsd02.MijiaLywsd02Support; import nodomain.freeyourgadget.gadgetbridge.service.devices.miscale2.MiScale2DeviceSupport; @@ -199,6 +200,10 @@ public class DeviceSupportFactory { break; case MIJIA_LYWSD02: deviceSupport = new ServiceDeviceSupport(new MijiaLywsd02Support(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING)); + break; + case MAKIBESHR3: + deviceSupport = new ServiceDeviceSupport(new MakibesHR3DeviceSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING)); + break; } if (deviceSupport != null) { deviceSupport.setContext(gbDevice, mBtAdapter, mContext); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/amazfitbip/AmazfitBipFirmwareInfo.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/amazfitbip/AmazfitBipFirmwareInfo.java index 02bc939d2..2a49b1b6e 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/amazfitbip/AmazfitBipFirmwareInfo.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/amazfitbip/AmazfitBipFirmwareInfo.java @@ -112,6 +112,7 @@ public class AmazfitBipFirmwareInfo extends HuamiFirmwareInfo { // Latin Firmware crcToVersion.put(52828, "1.1.5.36 (Latin)"); + crcToVersion.put(60625, "1.1.6.30 (Latin)"); // resources crcToVersion.put(12586, "0.0.8.74"); @@ -138,6 +139,7 @@ public class AmazfitBipFirmwareInfo extends HuamiFirmwareInfo { crcToVersion.put(5341, "1.1.5.02-24"); crcToVersion.put(22662, "1.1.5.36"); crcToVersion.put(24045, "1.1.5.56"); + crcToVersion.put(37677, "1.1.6.30"); // gps crcToVersion.put(61520, "9367,8f79a91,0,0,"); @@ -149,7 +151,8 @@ public class AmazfitBipFirmwareInfo extends HuamiFirmwareInfo { // font crcToVersion.put(61054, "8"); - crcToVersion.put(62291, "9 (Latin)"); + crcToVersion.put(62291, "9 (old Latin)"); + crcToVersion.put(59577, "9 (Latin)"); } public AmazfitBipFirmwareInfo(byte[] bytes) { @@ -182,7 +185,7 @@ public class AmazfitBipFirmwareInfo extends HuamiFirmwareInfo { if (ArrayUtils.startsWith(bytes, NEWFT_HEADER)) { if (bytes[10] == 0x01) { return HuamiFirmwareType.FONT; - } else if (bytes[10] == 0x02) { + } else if (bytes[10] == 0x02 || bytes[10] == 0x0A) { return HuamiFirmwareType.FONT_LATIN; } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/makibeshr3/MakibesHR3DeviceSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/makibeshr3/MakibesHR3DeviceSupport.java new file mode 100644 index 000000000..6a782481e --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/makibeshr3/MakibesHR3DeviceSupport.java @@ -0,0 +1,522 @@ +package nodomain.freeyourgadget.gadgetbridge.service.devices.makibeshr3; + +import android.bluetooth.BluetoothGattCharacteristic; +import android.net.Uri; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.Calendar; +import java.util.UUID; + +import nodomain.freeyourgadget.gadgetbridge.devices.makibeshr3.MakibesHR3Constants; +import nodomain.freeyourgadget.gadgetbridge.devices.makibeshr3.MakibesHR3Coordinator; +import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; +import nodomain.freeyourgadget.gadgetbridge.model.Alarm; +import nodomain.freeyourgadget.gadgetbridge.model.CalendarEventSpec; +import nodomain.freeyourgadget.gadgetbridge.model.CallSpec; +import nodomain.freeyourgadget.gadgetbridge.model.CannedMessagesSpec; +import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec; +import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec; +import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec; +import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec; +import nodomain.freeyourgadget.gadgetbridge.service.btle.AbstractBTLEDeviceSupport; +import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder; +import nodomain.freeyourgadget.gadgetbridge.service.serial.GBDeviceProtocol; + +public class MakibesHR3DeviceSupport extends AbstractBTLEDeviceSupport { + + private static final Logger LOG = LoggerFactory.getLogger(MakibesHR3DeviceSupport.class); + + private BluetoothGattCharacteristic ctrlCharacteristic = null; + + public MakibesHR3DeviceSupport() { + super(LOG); + + addSupportedService(MakibesHR3Constants.UUID_SERVICE); + } + + @Override + public boolean useAutoConnect() { + return false; + } + + @Override + public void onNotification(NotificationSpec notificationSpec) { + TransactionBuilder transactionBuilder = this.createTransactionBuilder("onnotificaiton"); + + byte sender; + + switch (notificationSpec.type) { + case FACEBOOK: + case FACEBOOK_MESSENGER: + sender = MakibesHR3Constants.ARG_SEND_NOTIFICATION_SOURCE_FACEBOOK; + break; + case LINE: + sender = MakibesHR3Constants.ARG_SEND_NOTIFICATION_SOURCE_LINE; + break; + case TELEGRAM: + sender = MakibesHR3Constants.ARG_SEND_NOTIFICATION_SOURCE_MESSAGE; + break; + case TWITTER: + sender = MakibesHR3Constants.ARG_SEND_NOTIFICATION_SOURCE_TWITTER; + break; + case WECHAT: + sender = MakibesHR3Constants.ARG_SEND_NOTIFICATION_SOURCE_WECHAT; + break; + case WHATSAPP: + sender = MakibesHR3Constants.ARG_SEND_NOTIFICATION_SOURCE_WHATSAPP; + break; + case KAKAO_TALK: + sender = MakibesHR3Constants.ARG_SEND_NOTIFICATION_SOURCE_KAKOTALK; + break; + + default: + sender = MakibesHR3Constants.ARG_SEND_NOTIFICATION_SOURCE_MESSAGE; + break; + } + + this.sendNotification(transactionBuilder, + sender, notificationSpec.title + ": " + notificationSpec.body); + + try { + this.performConnected(transactionBuilder.getTransaction()); + } catch (Exception ex) { + LoggerFactory.getLogger(this.getClass()).error("notification failed"); + } + } + + @Override + public void onDeleteNotification(int id) { + + } + + @Override + public void onSetTime() { + TransactionBuilder transactionBuilder = this.createTransactionBuilder("settime"); + + this.setDateTime(transactionBuilder); + + try { + this.performConnected(transactionBuilder.getTransaction()); + } catch (Exception ex) { + LoggerFactory.getLogger(this.getClass()).error("factory reset failed"); + } + } + + @Override + public void onSetAlarms(ArrayList alarms) { + + TransactionBuilder transactionBuilder = this.createTransactionBuilder("setalarms"); + + for (int i = 0; i < alarms.size(); ++i) { + Alarm alarm = alarms.get(i); + + // Should we use @alarm.getPosition() rather than @i? + this.setAlarmReminder( + transactionBuilder, + i, + alarm.getEnabled(), + alarm.getHour(), + alarm.getMinute(), + MakibesHR3Constants.ARG_SET_ALARM_REMINDER_REPEAT_CUSTOM); + } + + try { + this.performConnected(transactionBuilder.getTransaction()); + } catch (Exception ex) { + LoggerFactory.getLogger(this.getClass()).error("setalarms failed"); + } + } + + @Override + public void onSetCallState(CallSpec callSpec) { + TransactionBuilder transactionBuilder = this.createTransactionBuilder("callstate"); + LOG.debug("callSpec " + callSpec.command); + if (callSpec.command == CallSpec.CALL_INCOMING) { + this.sendNotification(transactionBuilder, MakibesHR3Constants.ARG_SEND_NOTIFICATION_SOURCE_CALL, callSpec.name); + } else { + this.sendNotification(transactionBuilder, MakibesHR3Constants.ARG_SEND_NOTIFICATION_SOURCE_STOP_CALL, callSpec.name); + } + + try { + this.performConnected(transactionBuilder.getTransaction()); + } catch (Exception ex) { + LoggerFactory.getLogger(this.getClass()).error("call state failed"); + } + } + + @Override + public void onSetCannedMessages(CannedMessagesSpec cannedMessagesSpec) { + + } + + @Override + public void onSetMusicState(MusicStateSpec stateSpec) { + + } + + @Override + public void onSetMusicInfo(MusicSpec musicSpec) { + + } + + @Override + public void onEnableRealtimeSteps(boolean enable) { + + } + + @Override + public void onInstallApp(Uri uri) { + + } + + @Override + public void onAppInfoReq() { + + } + + @Override + public void onAppStart(UUID uuid, boolean start) { + + } + + @Override + public void onAppDelete(UUID uuid) { + + } + + @Override + public void onAppConfiguration(UUID appUuid, String config, Integer id) { + + } + + @Override + public void onAppReorder(UUID[] uuids) { + + } + + @Override + public void onFetchRecordedData(int dataTypes) { + + } + + @Override + public void onReset(int flags) { + + if ((flags & GBDeviceProtocol.RESET_FLAGS_FACTORY_RESET) != 0) { + TransactionBuilder transactionBuilder = this.createTransactionBuilder("reset"); + this.factoryReset(transactionBuilder); + + try { + this.performConnected(transactionBuilder.getTransaction()); + } catch (Exception ex) { + LoggerFactory.getLogger(this.getClass()).error("factory reset failed"); + } + } else if ((flags & GBDeviceProtocol.RESET_FLAGS_REBOOT) != 0) { + TransactionBuilder transactionBuilder = this.createTransactionBuilder("reboot"); + this.reboot(transactionBuilder); + + try { + this.performConnected(transactionBuilder.getTransaction()); + } catch (Exception ex) { + LoggerFactory.getLogger(this.getClass()).error("factory reset failed"); + } + } + } + + @Override + public void onHeartRateTest() { + + } + + @Override + public void onEnableRealtimeHeartRateMeasurement(boolean enable) { + + } + + @Override + public void onFindDevice(boolean start) { + if (!start) { + return; + } + + TransactionBuilder transactionBuilder = this.createTransactionBuilder("finddevice"); + + this.findDevice(transactionBuilder); + + try { + this.performConnected(transactionBuilder.getTransaction()); + } catch (Exception e) { + LOG.debug("ERROR"); + } + } + + @Override + public void onSetConstantVibration(int integer) { + + } + + @Override + public void onScreenshotReq() { + + } + + @Override + public void onEnableHeartRateSleepSupport(boolean enable) { + + } + + @Override + public void onSetHeartRateMeasurementInterval(int seconds) { + + } + + @Override + public void onAddCalendarEvent(CalendarEventSpec calendarEventSpec) { + + } + + @Override + public void onDeleteCalendarEvent(byte type, long id) { + + } + + @Override + public void onSendConfiguration(String config) { + + } + + @Override + public void onReadConfiguration(String config) { + + } + + @Override + public void onTestNewFunction() { + + } + + @Override + public void onSendWeather(WeatherSpec weatherSpec) { + + } + + private MakibesHR3DeviceSupport sendUserInfo(TransactionBuilder builder) { + // builder.write(ctrlCharacteristic, MakibesHR3Constants.CMD_SET_PREF_START); + // builder.write(ctrlCharacteristic, MakibesHR3Constants.CMD_SET_PREF_START1); + + syncPreferences(builder); + + // builder.write(ctrlCharacteristic, new byte[]{MakibesHR3Constants.CMD_SET_CONF_END}); + return this; + } + + private MakibesHR3DeviceSupport syncPreferences(TransactionBuilder transaction) { + + this.setTimeMode(transaction); + this.setDateTime(transaction); + // setDayOfWeek(transaction); + // setTimeMode(transaction); + + // setGender(transaction); + // setAge(transaction); + // setWeight(transaction); + // setHeight(transaction); + + // setGoal(transaction); + // setLanguage(transaction); + // setScreenTime(transaction); + // setUnit(transaction); + // setAllDayHeart(transaction); + + return this; + } + + @Override + protected TransactionBuilder initializeDevice(TransactionBuilder builder) { + gbDevice.setState(GBDevice.State.INITIALIZING); + gbDevice.sendDeviceUpdateIntent(getContext()); + + this.ctrlCharacteristic = getCharacteristic(MakibesHR3Constants.UUID_CHARACTERISTIC_CONTROL); + + builder.setGattCallback(this); + + // Allow modifications + builder.write(this.ctrlCharacteristic, new byte[]{0x01, 0x00}); + + // Initialize device + sendUserInfo(builder); //Sync preferences + + gbDevice.setState(GBDevice.State.INITIALIZED); + gbDevice.sendDeviceUpdateIntent(getContext()); + + getDevice().setFirmwareVersion("N/A"); + getDevice().setFirmwareVersion2("N/A"); + + return builder; + } + + /** + * @param command + * @param data + * @return + */ + private byte[] craftData(byte command, byte[] data) { + byte[] result = new byte[MakibesHR3Constants.DATA_TEMPLATE.length + data.length]; + + System.arraycopy(MakibesHR3Constants.DATA_TEMPLATE, 0, result, 0, MakibesHR3Constants.DATA_TEMPLATE.length); + + result[MakibesHR3Constants.DATA_ARGUMENT_COUNT_INDEX] = (byte) (data.length + 3); + result[MakibesHR3Constants.DATA_COMMAND_INDEX] = command; + + System.arraycopy(data, 0, result, 6, data.length); + + return result; + } + + + private byte[] craftData(byte command) { + return this.craftData(command, new byte[]{}); + } + + private void writeSafe(BluetoothGattCharacteristic characteristic, TransactionBuilder builder, byte[] data) { + final int maxMessageLength = 20; + + // For every split, we need 1 byte extra. + int extraBytes = (((data.length - maxMessageLength) / maxMessageLength) + 1); + + int totalDataLength = (data.length + extraBytes); + + int segmentCount = (((totalDataLength - 1) / maxMessageLength) + 1); + + byte[] indexedData = new byte[totalDataLength]; + + int it = 0; + int segmentIndex = 0; + for (int i = 0; i < data.length; ++i) { + if ((i != 0) && ((it % maxMessageLength) == 0)) { + indexedData[it++] = (byte) segmentIndex++; + } + + indexedData[it++] = data[i]; + } + + for (int i = 0; i < segmentCount; ++i) { + int segmentStart = (i * maxMessageLength); + int segmentLength; + + if (i == (segmentCount - 1)) { + segmentLength = (indexedData.length - segmentStart); + } else { + segmentLength = maxMessageLength; + } + + byte[] segment = new byte[segmentLength]; + + System.arraycopy(indexedData, segmentStart, segment, 0, segmentLength); + + builder.write(characteristic, segment); + } + } + + private MakibesHR3DeviceSupport factoryReset(TransactionBuilder transaction) { + transaction.write(this.ctrlCharacteristic, this.craftData(MakibesHR3Constants.CMD_FACTORY_RESET)); + + return this.reboot(transaction); + } + + private MakibesHR3DeviceSupport findDevice(TransactionBuilder transaction) { + transaction.write(this.ctrlCharacteristic, this.craftData(MakibesHR3Constants.CMD_FIND_DEVICE)); + + return this; + } + + private MakibesHR3DeviceSupport sendNotification(TransactionBuilder transaction, + byte source, String message) { + byte[] data = new byte[message.length() + 2]; + data[0] = source; + data[1] = (byte) 0x02; + + for (int i = 0; i < message.length(); ++i) { + data[i + 2] = (byte) message.charAt(i); + } + + this.writeSafe( + this.ctrlCharacteristic, + transaction, + this.craftData(MakibesHR3Constants.CMD_SEND_NOTIFICATION, data)); + + return this; + } + + private MakibesHR3DeviceSupport setAlarmReminder(TransactionBuilder transaction, + int id, boolean enable, int hour, int minute, byte repeat) { + transaction.write(this.ctrlCharacteristic, + this.craftData(MakibesHR3Constants.CMD_SET_ALARM_REMINDER, new byte[]{ + (byte) id, + (byte) (enable ? 0x01 : 0x00), + (byte) hour, + (byte) minute, + repeat + })); + + return this; + } + + private MakibesHR3DeviceSupport setTimeMode(TransactionBuilder transaction) { + byte value = MakibesHR3Coordinator.getTimeMode(getDevice().getAddress()); + + byte[] data = this.craftData(MakibesHR3Constants.CMD_SET_TIMEMODE, new byte[]{value}); + + transaction.write(this.ctrlCharacteristic, data); + + return this; + } + + private MakibesHR3DeviceSupport setDateTime(TransactionBuilder transaction, + int year, + int month, + int day, + int hour, + int minute, + int second) { + + byte[] data = this.craftData(MakibesHR3Constants.CMD_SET_DATE_TIME, + new byte[]{ + (byte) 0x00, + (byte) (year & 0xff00), + (byte) (year & 0x00ff), + (byte) month, + (byte) day, + (byte) hour, + (byte) minute, + (byte) second + }); + + transaction.write(this.ctrlCharacteristic, data); + + return this; + } + + private MakibesHR3DeviceSupport setDateTime(TransactionBuilder transaction) { + + Calendar calendar = Calendar.getInstance(); + + return this.setDateTime(transaction, + calendar.get(Calendar.YEAR), + calendar.get(Calendar.MONTH) + 1, + calendar.get(Calendar.DAY_OF_MONTH), + calendar.get(Calendar.HOUR_OF_DAY), + calendar.get(Calendar.MINUTE), + calendar.get(Calendar.SECOND) + ); + } + + private MakibesHR3DeviceSupport reboot(TransactionBuilder transaction) { + transaction.write(this.ctrlCharacteristic, this.craftData(MakibesHR3Constants.CMD_REBOOT)); + + return this; + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/DeviceHelper.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/DeviceHelper.java index d2fbda23d..c77544798 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/DeviceHelper.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/DeviceHelper.java @@ -45,6 +45,7 @@ import nodomain.freeyourgadget.gadgetbridge.devices.casiogb6900.CasioGB6900Devic import nodomain.freeyourgadget.gadgetbridge.devices.hplus.EXRIZUK8Coordinator; import nodomain.freeyourgadget.gadgetbridge.devices.hplus.HPlusCoordinator; import nodomain.freeyourgadget.gadgetbridge.devices.hplus.MakibesF68Coordinator; +import nodomain.freeyourgadget.gadgetbridge.devices.makibeshr3.MakibesHR3Coordinator; import nodomain.freeyourgadget.gadgetbridge.devices.hplus.Q8Coordinator; import nodomain.freeyourgadget.gadgetbridge.devices.huami.amazfitbip.AmazfitBipCoordinator; import nodomain.freeyourgadget.gadgetbridge.devices.huami.amazfitcor.AmazfitCorCoordinator; @@ -230,6 +231,7 @@ public class DeviceHelper { result.add(new CasioGB6900DeviceCoordinator()); result.add(new BFH16DeviceCoordinator()); result.add(new MijiaLywsd02Coordinator()); + result.add(new MakibesHR3Coordinator()); return result; } diff --git a/app/src/main/res/values-bg/strings.xml b/app/src/main/res/values-bg/strings.xml index a68347685..e9af4037d 100644 --- a/app/src/main/res/values-bg/strings.xml +++ b/app/src/main/res/values-bg/strings.xml @@ -263,7 +263,7 @@ Инициализиране Извличане на данните за активност От %1$s До %2$s - На коя ръка - лява или дясна\? + На коя ръка - лява или дясна\? Профил на вибрациите Стакато Кратко diff --git a/app/src/main/res/values-ca/strings.xml b/app/src/main/res/values-ca/strings.xml index 0279dadba..e734ef05a 100644 --- a/app/src/main/res/values-ca/strings.xml +++ b/app/src/main/res/values-ca/strings.xml @@ -224,7 +224,7 @@ S\'està inicialitzant S\'estàn recollint les dades d\'activitat De %1$s a %2$s - A quina mà porteu l\'aparell\? + A quina mà porteu l\'aparell\? Perfil de vibració Molt curta Curta diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml index 93b2f5b08..81b524e83 100644 --- a/app/src/main/res/values-cs/strings.xml +++ b/app/src/main/res/values-cs/strings.xml @@ -200,7 +200,7 @@ Spouštím Stahuji data o aktivitě Od %1$s do %2$s - Nosíte vlevo nebo vpravo? + Nosíte vlevo nebo vpravo? Profil vibrací Staccato Krátké diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index cf3532c19..b5d9e0fd2 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -211,7 +211,7 @@ Initialisieren Aktivitätsdaten abrufen Von %1$s bis %2$s - Wird links oder rechts getragen\? + Wird links oder rechts getragen\? Vibrationsprofile Stakkato Kurz @@ -776,4 +776,6 @@ %d Std %d Std + Makibes HR3 Einstellungen + Makibes HR3 \ No newline at end of file diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml index 2608d314e..348ddb7df 100644 --- a/app/src/main/res/values-el/strings.xml +++ b/app/src/main/res/values-el/strings.xml @@ -229,7 +229,7 @@ Αρχικοποίηση Λήψη δεδομένων δραστηριότητας Από %1$s έως %2$s - Σε ποιο χέρι το φοράτε; + Σε ποιο χέρι το φοράτε; Προφίλ δόνησης Κοφτή Σύντομη diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index bf674ef09..b2b1f2863 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -207,7 +207,7 @@ Iniciando Recuperando datos de actividad Desde %1$s a %2$s - ¿En derecha o en izquierda? + ¿En derecha o en izquierda? Perfil de vibración Muy corto Corto diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 266048710..dfa720d8e 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -204,7 +204,7 @@ Initialisation Récupération des données d\'activité De %1$s à %2$s - Port main gauche ou droite ? + Port main gauche ou droite ? Profil de vibration Saccadé Court diff --git a/app/src/main/res/values-gl/strings.xml b/app/src/main/res/values-gl/strings.xml index a4b626a79..0146202aa 100644 --- a/app/src/main/res/values-gl/strings.xml +++ b/app/src/main/res/values-gl/strings.xml @@ -237,7 +237,7 @@ Inicializando Adquirindo datos de actividade De %1$s até %2$s - De que lado a usa? + De que lado a usa? Perfil de vibración Moi curto diff --git a/app/src/main/res/values-he/strings.xml b/app/src/main/res/values-he/strings.xml index afe9912a6..30c44b8d9 100644 --- a/app/src/main/res/values-he/strings.xml +++ b/app/src/main/res/values-he/strings.xml @@ -190,7 +190,7 @@ מתבצע אתחול נתוני הפעילות מתקבלים מ־%1$s עד %2$s - על יד ימין או שמאל? + על יד ימין או שמאל? פרופיל רטט סטקטו קצר @@ -757,4 +757,7 @@ %d שעות %d שעות + כדי לצפות בעקבות פעילות, עליך להתקין יישומון שיכול לטפל בקובצי GPX. + הגדרות של Makibes HR3 + Makibes HR3 \ No newline at end of file diff --git a/app/src/main/res/values-hu/strings.xml b/app/src/main/res/values-hu/strings.xml index e4ee3451f..f7dffee61 100644 --- a/app/src/main/res/values-hu/strings.xml +++ b/app/src/main/res/values-hu/strings.xml @@ -200,7 +200,7 @@ Inicializálás Aktivitási adatok lekérdezése. %1$s és %2$s között - Melyik kezeden hordod? + Melyik kezeden hordod? Rezgés profil Szaggatott Rövid diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index fdee9470d..1bb7c9532 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -201,7 +201,7 @@ Inizializzazione in corso Recupero dati attività Da %1$s a %2$s - Indossato sul braccio sinistro o destro? + Indossato sul braccio sinistro o destro? Profilo vibrazioni Staccato Breve diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index 47212420e..ff825b15e 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -204,7 +204,7 @@ 初期化中 アクティビティデータを取得中 %1$sから%2$sまで - 左または右に身に着けますか? + 左または右に身に着けますか? バイブレーション プロファイル スタッカート 短い diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index ee9fabf58..9cb41921a 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -115,7 +115,7 @@ 초기화 중 활동 데이터 가져오는 중 %1$s에서 %2$s(으)로 - 왼쪽과 오른쪽 중 어느 방향으로 착용합니까? + 왼쪽과 오른쪽 중 어느 방향으로 착용합니까? 진동 프로파일 스타카토 짧게 diff --git a/app/src/main/res/values-nb-rNO/strings.xml b/app/src/main/res/values-nb-rNO/strings.xml index 3cb585606..2dd015e29 100644 --- a/app/src/main/res/values-nb-rNO/strings.xml +++ b/app/src/main/res/values-nb-rNO/strings.xml @@ -214,7 +214,7 @@ Igangsetter Henter aktivitetsdato Fra %1$s til %2$s - Venstre- eller høyre-hånd? + Venstre- eller høyre-hånd? Vibrasjonsprofil Stakkato Kort @@ -760,4 +760,7 @@ %d time %d timer + For å vise aktivitetsspor, installer et program som kan håndtere GPX-filer. + Makibes HR3-innstillinger + Makibes HR3 \ No newline at end of file diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index 6a8556c20..a541a719f 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -236,7 +236,7 @@ Initialiseren Ophalen van activiteitsgegevens Van %1$s aan %2$s - Links of rechts dragen? + Links of rechts dragen? Vibratie profiel Staccato Kort diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index c5b3a1c3d..227ef9ede 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -148,7 +148,7 @@ Inicjalizacja Pobieranie danych o aktywności Od %1$s do %2$s - Na której ręce noszone jest urządzenie\? + Na której ręce noszone jest urządzenie\? Profil wibracji Słabe Krótkie diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index 6463b4e2f..9ffaae78c 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -197,7 +197,7 @@ Inicializando Coletando dados de atividade De %1$s a %2$s - Dispositivo na esquerda ou direita? + Dispositivo na esquerda ou direita? Perfil de vibração Destacado Pequeno @@ -768,4 +768,7 @@ % hora % horas + Para visualizar o rastreamento de atividade, instale um aplicativo que consegue manipular arquivos GPX. + Configurações de Makibes HR3 + Makibes HR3 \ No newline at end of file diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index 7de8f729e..33f44c025 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -197,7 +197,7 @@ Inicializando A Descarregar Dados de Atividade De %1$s até %2$s - De que lado a usa? + De que lado a usa? Perfil de Vibração Destacado Pequeno diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 1de4d1428..838b613e5 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -198,7 +198,7 @@ Запускается Получение данных активности От %1$s до %2$s - Носите на левой или правой руке? + Носите на левой или правой руке? Профиль настроек вибрации Стаккато Короткий diff --git a/app/src/main/res/values-sk/strings.xml b/app/src/main/res/values-sk/strings.xml index 673c38376..712427324 100644 --- a/app/src/main/res/values-sk/strings.xml +++ b/app/src/main/res/values-sk/strings.xml @@ -266,7 +266,7 @@ Spúšťanie Načítavanie údajov o aktivite Od %1$s do %2$s - Na ktorej ruke nosíte? + Na ktorej ruke nosíte? Profil vibrácií Staccato diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index e2273b69b..99377fe17 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -134,7 +134,7 @@ Ініціалізація Отримання даних активності Від %1$s до %2$s - На якій руці носите? + На якій руці носите? Профіль вібровідгуку Стакато Короткий diff --git a/app/src/main/res/values-vi/strings.xml b/app/src/main/res/values-vi/strings.xml index eb9502a4e..044bd21ad 100644 --- a/app/src/main/res/values-vi/strings.xml +++ b/app/src/main/res/values-vi/strings.xml @@ -79,7 +79,7 @@ Trình giám sát giấc ngủ đang khởi chạy Từ %1$s đến %2$s - Đeo bên trái hay phải? + Đeo bên trái hay phải? Ngắn Trung bình Dài diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index aa86bc899..00263d77f 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -217,7 +217,7 @@ 初始化中 获取活动数据 从 %1$s 到 %2$s - 佩戴在左手还是右手? + 佩戴在左手还是右手? @@ -765,4 +765,7 @@ %d 小时 + 若需要查看活动轨迹,请安装一个能查看 GPX 文件的应用。 + Makibes HR3 设置 + Makibes HR3 \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 2c0f99db3..ce4b9b82e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -186,6 +186,8 @@ Screen on duration All day heart rate measurement HPlus/Makibes settings + + Makibes HR3 settings ID115 settings Screen orientation @@ -316,7 +318,7 @@ Initializing Fetching activity data From %1$s to %2$s - Wearing left or right? + Wearing left or right? Vibration profile Staccato Short @@ -674,6 +676,7 @@ Mi Scale 2 BFH-16 Mijia Smart Clock + Makibes HR3 Choose export location Gadgetbridge notifications diff --git a/app/src/main/res/xml/devicesettings_timeformat.xml b/app/src/main/res/xml/devicesettings_timeformat.xml new file mode 100644 index 000000000..837fb5891 --- /dev/null +++ b/app/src/main/res/xml/devicesettings_timeformat.xml @@ -0,0 +1,12 @@ + + + + + diff --git a/app/src/main/res/xml/miband_preferences.xml b/app/src/main/res/xml/miband_preferences.xml index f0859df44..ff281d0cc 100644 --- a/app/src/main/res/xml/miband_preferences.xml +++ b/app/src/main/res/xml/miband_preferences.xml @@ -14,7 +14,7 @@ android:entries="@array/wearside" android:entryValues="@array/wearside_values" android:key="mi_wearside" - android:title="@string/miband_prefs_wearside" + android:title="@string/prefs_wearside" android:summary="%s" /> +