From 06a12300a1c22e1bad9922a10f536aaf2055c766 Mon Sep 17 00:00:00 2001 From: opavlov Date: Tue, 1 Sep 2020 23:15:20 +0300 Subject: [PATCH] added support for sony swr12 --- .../gadgetbridge/daogen/GBDaoGenerator.java | 12 + app/src/main/AndroidManifest.xml | 3 + .../activities/SettingsActivity.java | 10 + .../sonyswr12/SonySWR12DeviceCoordinator.java | 122 ++++++ .../sonyswr12/SonySWR12PrefActivity.java | 98 +++++ .../sonyswr12/SonySWR12SampleProvider.java | 83 +++++ .../gadgetbridge/model/DeviceType.java | 1 + .../service/DeviceSupportFactory.java | 4 + .../devices/sonyswr12/SonySWR12Constants.java | 22 ++ .../sonyswr12/SonySWR12DeviceSupport.java | 351 ++++++++++++++++++ .../sonyswr12/SonySWR12HandlerThread.java | 135 +++++++ .../devices/sonyswr12/SonySWR12Util.java | 22 ++ .../entities/activity/ActivityBase.java | 35 ++ .../entities/activity/ActivityHeartRate.java | 22 ++ .../entities/activity/ActivitySleep.java | 22 ++ .../entities/activity/ActivityType.java | 23 ++ .../entities/activity/ActivityWithData.java | 22 ++ .../entities/activity/EventBase.java | 21 ++ .../entities/activity/EventCode.java | 21 ++ .../entities/activity/EventFactory.java | 26 ++ .../entities/activity/EventWithActivity.java | 62 ++++ .../entities/activity/EventWithValue.java | 18 + .../entities/activity/SleepLevel.java | 21 ++ .../sonyswr12/entities/alarm/AlarmRepeat.java | 53 +++ .../sonyswr12/entities/alarm/AlarmState.java | 13 + .../sonyswr12/entities/alarm/BandAlarm.java | 60 +++ .../sonyswr12/entities/alarm/BandAlarms.java | 35 ++ .../entities/control/CommandCode.java | 15 + .../entities/control/ControlPoint.java | 17 + .../control/ControlPointLowVibration.java | 28 ++ .../control/ControlPointWithValue.java | 21 ++ .../entities/time/BandDaylightSavingTime.java | 24 ++ .../sonyswr12/entities/time/BandTime.java | 62 ++++ .../sonyswr12/entities/time/BandTimeZone.java | 61 +++ .../sonyswr12/util/ByteArrayReader.java | 53 +++ .../sonyswr12/util/ByteArrayWriter.java | 61 +++ .../devices/sonyswr12/util/IntFormat.java | 35 ++ .../devices/sonyswr12/util/UIntBitReader.java | 27 ++ .../devices/sonyswr12/util/UIntBitWriter.java | 37 ++ .../gadgetbridge/util/DeviceHelper.java | 2 + .../layout/activity_sonyswr12_settings.xml | 55 +++ app/src/main/res/values-bg/strings.xml | 5 + app/src/main/res/values-ca/strings.xml | 5 + app/src/main/res/values-cs/strings.xml | 6 + app/src/main/res/values-de/strings.xml | 6 + app/src/main/res/values-el/strings.xml | 6 + app/src/main/res/values-en-rGB/strings.xml | 6 + app/src/main/res/values-es/strings.xml | 6 + app/src/main/res/values-et/strings.xml | 6 + app/src/main/res/values-fa/strings.xml | 1 + app/src/main/res/values-fi/strings.xml | 5 + app/src/main/res/values-fr-rCA/strings.xml | 6 + app/src/main/res/values-fr/strings.xml | 6 + app/src/main/res/values-gl/strings.xml | 5 + app/src/main/res/values-he/strings.xml | 6 + app/src/main/res/values-hi/strings.xml | 2 + app/src/main/res/values-hr/strings.xml | 3 + app/src/main/res/values-hu/strings.xml | 5 + app/src/main/res/values-id/strings.xml | 3 + app/src/main/res/values-it/strings.xml | 6 + app/src/main/res/values-ja/strings.xml | 6 + app/src/main/res/values-ka/strings.xml | 3 + app/src/main/res/values-ko/strings.xml | 1 + app/src/main/res/values-lt/strings.xml | 6 + app/src/main/res/values-my/strings.xml | 2 + app/src/main/res/values-nb-rNO/strings.xml | 6 + app/src/main/res/values-nl/strings.xml | 6 + app/src/main/res/values-pl/strings.xml | 6 + app/src/main/res/values-pt-rBR/strings.xml | 6 + app/src/main/res/values-pt/strings.xml | 6 + app/src/main/res/values-ro/strings.xml | 4 + app/src/main/res/values-ru/strings.xml | 6 + app/src/main/res/values-sk/strings.xml | 6 + app/src/main/res/values-sv/strings.xml | 5 + app/src/main/res/values-tr/strings.xml | 9 +- app/src/main/res/values-uk/strings.xml | 6 + app/src/main/res/values-vi/strings.xml | 4 + app/src/main/res/values-zh-rCN/strings.xml | 6 + app/src/main/res/values-zh-rTW/strings.xml | 2 + app/src/main/res/values/arrays.xml | 9 + app/src/main/res/values/strings.xml | 6 + app/src/main/res/xml/preferences.xml | 8 +- 82 files changed, 2024 insertions(+), 4 deletions(-) create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/sonyswr12/SonySWR12DeviceCoordinator.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/sonyswr12/SonySWR12PrefActivity.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/sonyswr12/SonySWR12SampleProvider.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/SonySWR12Constants.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/SonySWR12DeviceSupport.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/SonySWR12HandlerThread.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/SonySWR12Util.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/activity/ActivityBase.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/activity/ActivityHeartRate.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/activity/ActivitySleep.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/activity/ActivityType.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/activity/ActivityWithData.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/activity/EventBase.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/activity/EventCode.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/activity/EventFactory.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/activity/EventWithActivity.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/activity/EventWithValue.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/activity/SleepLevel.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/alarm/AlarmRepeat.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/alarm/AlarmState.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/alarm/BandAlarm.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/alarm/BandAlarms.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/control/CommandCode.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/control/ControlPoint.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/control/ControlPointLowVibration.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/control/ControlPointWithValue.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/time/BandDaylightSavingTime.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/time/BandTime.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/time/BandTimeZone.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/util/ByteArrayReader.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/util/ByteArrayWriter.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/util/IntFormat.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/util/UIntBitReader.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/util/UIntBitWriter.java create mode 100644 app/src/main/res/layout/activity_sonyswr12_settings.xml diff --git a/GBDaoGenerator/src/nodomain/freeyourgadget/gadgetbridge/daogen/GBDaoGenerator.java b/GBDaoGenerator/src/nodomain/freeyourgadget/gadgetbridge/daogen/GBDaoGenerator.java index 1b7c08465..5184aecaa 100644 --- a/GBDaoGenerator/src/nodomain/freeyourgadget/gadgetbridge/daogen/GBDaoGenerator.java +++ b/GBDaoGenerator/src/nodomain/freeyourgadget/gadgetbridge/daogen/GBDaoGenerator.java @@ -77,6 +77,7 @@ public class GBDaoGenerator { addLefunActivitySample(schema, user, device); addLefunBiometricSample(schema,user,device); addLefunSleepSample(schema, user, device); + addSonySWR12Sample(schema, user, device); addHybridHRActivitySample(schema, user, device); addCalendarSyncState(schema, device); @@ -407,6 +408,17 @@ public class GBDaoGenerator { return activitySample; } + private static Entity addSonySWR12Sample(Schema schema, Entity user, Entity device) { + Entity activitySample = addEntity(schema, "SonySWR12Sample"); + activitySample.implementsSerializable(); + addCommonActivitySampleProperties("AbstractActivitySample", activitySample, user, device); + addHeartRateProperties(activitySample); + activitySample.addIntProperty(SAMPLE_STEPS).notNull().codeBeforeGetterAndSetter(OVERRIDE); + activitySample.addIntProperty(SAMPLE_RAW_KIND).notNull().codeBeforeGetterAndSetter(OVERRIDE); + activitySample.addIntProperty(SAMPLE_RAW_INTENSITY).notNull().codeBeforeGetterAndSetter(OVERRIDE); + return activitySample; + } + private static Entity addLefunActivitySample(Schema schema, Entity user, Entity device) { Entity activitySample = addEntity(schema, "LefunActivitySample"); activitySample.implementsSerializable(); diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 5e61bf86c..f0479d146 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -567,5 +567,8 @@ + \ No newline at end of file diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/SettingsActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/SettingsActivity.java index 277404ee8..39f3c99ff 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/SettingsActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/SettingsActivity.java @@ -59,6 +59,7 @@ import nodomain.freeyourgadget.gadgetbridge.database.PeriodicExporter; import nodomain.freeyourgadget.gadgetbridge.devices.DeviceManager; import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandPreferencesActivity; import nodomain.freeyourgadget.gadgetbridge.devices.qhybrid.ConfigActivity; +import nodomain.freeyourgadget.gadgetbridge.devices.sonyswr12.SonySWR12PrefActivity; import nodomain.freeyourgadget.gadgetbridge.devices.zetime.ZeTimePreferenceActivity; import nodomain.freeyourgadget.gadgetbridge.model.CannedMessagesSpec; import nodomain.freeyourgadget.gadgetbridge.util.AndroidUtils; @@ -137,6 +138,15 @@ public class SettingsActivity extends AbstractSettingsActivity { } }); + pref = findPreference("pref_key_sonyswr12"); + pref.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { + public boolean onPreferenceClick(Preference preference) { + Intent intent = new Intent(SettingsActivity.this, SonySWR12PrefActivity.class); + startActivity(intent); + return true; + } + }); + pref = findPreference("pref_key_blacklist"); pref.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { public boolean onPreferenceClick(Preference preference) { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/sonyswr12/SonySWR12DeviceCoordinator.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/sonyswr12/SonySWR12DeviceCoordinator.java new file mode 100644 index 000000000..67e936d7a --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/sonyswr12/SonySWR12DeviceCoordinator.java @@ -0,0 +1,122 @@ +package nodomain.freeyourgadget.gadgetbridge.devices.sonyswr12; + +import android.app.Activity; +import android.content.Context; +import android.net.Uri; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import nodomain.freeyourgadget.gadgetbridge.GBException; +import nodomain.freeyourgadget.gadgetbridge.devices.AbstractDeviceCoordinator; +import nodomain.freeyourgadget.gadgetbridge.devices.InstallHandler; +import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider; +import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession; +import nodomain.freeyourgadget.gadgetbridge.entities.Device; +import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; +import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceCandidate; +import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample; +import nodomain.freeyourgadget.gadgetbridge.model.DeviceType; + +public class SonySWR12DeviceCoordinator extends AbstractDeviceCoordinator { + + @Override + public DeviceType getDeviceType() { + return DeviceType.SONY_SWR12; + } + + @NonNull + @Override + public DeviceType getSupportedType(GBDeviceCandidate candidate) { + String name = candidate.getDevice().getName(); + if (!name.isEmpty() && name.toLowerCase().contains("swr12")) + return getDeviceType(); + return DeviceType.UNKNOWN; + } + + @Override + public String getManufacturer() { + return "Sony"; + } + + @Override + protected void deleteDevice(@NonNull GBDevice gbDevice, @NonNull Device device, @NonNull DaoSession session) throws GBException { + + } + + @Nullable + @Override + public Class getPairingActivity() { + return null; + } + + @Override + public boolean supportsActivityDataFetching() { + return true; + } + + @Override + public boolean supportsActivityTracking() { + return true; + } + + @Override + public SampleProvider getSampleProvider(GBDevice device, DaoSession session) { + return new SonySWR12SampleProvider(device, session); + } + + @Override + public InstallHandler findInstallHandler(Uri uri, Context context) { + return null; + } + + @Override + public boolean supportsScreenshots() { + return false; + } + + @Override + public int getAlarmSlotCount() { + return 5; + } + + @Override + public boolean supportsSmartWakeup(GBDevice device) { + return true; + } + + @Override + public boolean supportsHeartRateMeasurement(GBDevice device) { + return true; + } + + @Override + public boolean supportsAppsManagement() { + return false; + } + + @Override + public Class getAppsManagementActivity() { + return null; + } + + @Override + public boolean supportsCalendarEvents() { + return false; + } + + @Override + public boolean supportsRealtimeData() { + return true; + } + + @Override + public boolean supportsWeather() { + return false; + } + + @Override + public boolean supportsFindDevice() { + return false; + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/sonyswr12/SonySWR12PrefActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/sonyswr12/SonySWR12PrefActivity.java new file mode 100644 index 000000000..4611a88ed --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/sonyswr12/SonySWR12PrefActivity.java @@ -0,0 +1,98 @@ +package nodomain.freeyourgadget.gadgetbridge.devices.sonyswr12; + +import android.os.Bundle; +import android.view.View; +import android.widget.AdapterView; +import android.widget.CompoundButton; + +import androidx.appcompat.app.ActionBar; +import androidx.appcompat.widget.AppCompatSpinner; +import androidx.appcompat.widget.SwitchCompat; + +import java.util.Arrays; +import java.util.List; + +import nodomain.freeyourgadget.gadgetbridge.GBApplication; +import nodomain.freeyourgadget.gadgetbridge.R; +import nodomain.freeyourgadget.gadgetbridge.activities.AbstractGBActivity; +import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; +import nodomain.freeyourgadget.gadgetbridge.model.DeviceType; +import nodomain.freeyourgadget.gadgetbridge.service.devices.sonyswr12.SonySWR12Constants; + +public class SonySWR12PrefActivity extends AbstractGBActivity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_sonyswr12_settings); + setTitle(getString(R.string.sonyswr12_settings_title)); + ActionBar actionBar = getSupportActionBar(); + if (actionBar != null) { + actionBar.setDisplayHomeAsUpEnabled(true); + actionBar.setDisplayShowHomeEnabled(true); + } + setVibrationSetting(); + setStaminaSetting(); + setAlarmIntervalSetting(); + GBDevice device = GBApplication.app().getDeviceManager().getSelectedDevice(); + int disablerVisibility = (device != null + && device.isConnected() + && device.getType() == DeviceType.SONY_SWR12) ? View.GONE : View.VISIBLE; + findViewById(R.id.settingsDisabler).setVisibility(disablerVisibility); + } + + @Override + public boolean onSupportNavigateUp() { + onBackPressed(); + return true; + } + + private void setVibrationSetting() { + boolean isLow = GBApplication.getPrefs().getBoolean(SonySWR12Constants.VIBRATION_PREFERENCE, false); + SwitchCompat switchVibration = ((SwitchCompat) findViewById(R.id.lowVibration)); + switchVibration.setChecked(isLow); + switchVibration.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + GBApplication.getPrefs().getPreferences().edit() + .putBoolean(SonySWR12Constants.VIBRATION_PREFERENCE, isChecked).apply(); + GBApplication.deviceService().onSendConfiguration(SonySWR12Constants.VIBRATION_PREFERENCE); + } + }); + } + + private void setStaminaSetting() { + boolean isOn = GBApplication.getPrefs().getBoolean(SonySWR12Constants.STAMINA_PREFERENCE, false); + SwitchCompat switchStamina = ((SwitchCompat) findViewById(R.id.staminaOn)); + switchStamina.setChecked(isOn); + switchStamina.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + GBApplication.getPrefs().getPreferences().edit() + .putBoolean(SonySWR12Constants.STAMINA_PREFERENCE, isChecked).apply(); + GBApplication.deviceService().onSendConfiguration(SonySWR12Constants.STAMINA_PREFERENCE); + } + }); + } + + private void setAlarmIntervalSetting() { + String interval = GBApplication.getPrefs().getString(SonySWR12Constants.SMART_ALARM_INTERVAL_PREFERENCE, "0"); + List intervalsArray = Arrays.asList(GBApplication.getContext().getResources().getStringArray(R.array.sonyswr12_smart_alarm_intervals)); + int position = intervalsArray.indexOf(interval); + final AppCompatSpinner spinner = ((AppCompatSpinner) findViewById(R.id.smartAlarmSpinner)); + spinner.setSelection(position); + spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { + @Override + public void onItemSelected(AdapterView parent, View view, int position, long id) { + String interval = (String) spinner.getItemAtPosition(position); + GBApplication.getPrefs().getPreferences().edit() + .putString(SonySWR12Constants.SMART_ALARM_INTERVAL_PREFERENCE, interval).apply(); + GBApplication.deviceService().onSendConfiguration(SonySWR12Constants.SMART_ALARM_INTERVAL_PREFERENCE); + } + + @Override + public void onNothingSelected(AdapterView parent) { + } + }); + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/sonyswr12/SonySWR12SampleProvider.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/sonyswr12/SonySWR12SampleProvider.java new file mode 100644 index 000000000..1f0bacf62 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/sonyswr12/SonySWR12SampleProvider.java @@ -0,0 +1,83 @@ +package nodomain.freeyourgadget.gadgetbridge.devices.sonyswr12; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import de.greenrobot.dao.AbstractDao; +import de.greenrobot.dao.Property; +import nodomain.freeyourgadget.gadgetbridge.devices.AbstractSampleProvider; +import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession; +import nodomain.freeyourgadget.gadgetbridge.entities.SonySWR12Sample; +import nodomain.freeyourgadget.gadgetbridge.entities.SonySWR12SampleDao; +import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; +import nodomain.freeyourgadget.gadgetbridge.model.ActivityKind; +import nodomain.freeyourgadget.gadgetbridge.service.devices.sonyswr12.SonySWR12Constants; + +public class SonySWR12SampleProvider extends AbstractSampleProvider { + public SonySWR12SampleProvider(GBDevice device, DaoSession session) { + super(device, session); + } + + @Override + public AbstractDao getSampleDao() { + return getSession().getSonySWR12SampleDao(); + } + + @Nullable + @Override + protected Property getRawKindSampleProperty() { + return SonySWR12SampleDao.Properties.RawKind; + } + + @NonNull + @Override + protected Property getTimestampSampleProperty() { + return SonySWR12SampleDao.Properties.Timestamp; + } + + @NonNull + @Override + protected Property getDeviceIdentifierSampleProperty() { + return SonySWR12SampleDao.Properties.DeviceId; + } + + @Override + public int normalizeType(int rawType) { + switch (rawType) { + case SonySWR12Constants.TYPE_ACTIVITY: + return ActivityKind.TYPE_ACTIVITY; + case SonySWR12Constants.TYPE_LIGHT: + return ActivityKind.TYPE_LIGHT_SLEEP; + case SonySWR12Constants.TYPE_DEEP: + return ActivityKind.TYPE_DEEP_SLEEP; + case SonySWR12Constants.TYPE_NOT_WORN: + return ActivityKind.TYPE_NOT_WORN; + } + return ActivityKind.TYPE_UNKNOWN; + } + + @Override + public int toRawActivityKind(int activityKind) { + switch (activityKind) { + case ActivityKind.TYPE_ACTIVITY: + return SonySWR12Constants.TYPE_ACTIVITY; + case ActivityKind.TYPE_LIGHT_SLEEP: + return SonySWR12Constants.TYPE_LIGHT; + case ActivityKind.TYPE_DEEP_SLEEP: + return SonySWR12Constants.TYPE_DEEP; + case ActivityKind.TYPE_NOT_WORN: + return SonySWR12Constants.TYPE_NOT_WORN; + } + return SonySWR12Constants.TYPE_ACTIVITY; + } + + @Override + public float normalizeIntensity(int rawIntensity) { + return rawIntensity; + } + + @Override + public SonySWR12Sample createActivitySample() { + return new SonySWR12Sample(); + } +} 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 02607887f..ef48af631 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/DeviceType.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/DeviceType.java @@ -76,6 +76,7 @@ public enum DeviceType { LEFUN(210, R.drawable.ic_device_h30_h10, R.drawable.ic_device_h30_h10_disabled, R.string.devicetype_lefun), ITAG(250, R.drawable.ic_device_itag, R.drawable.ic_device_itag_disabled, R.string.devicetype_itag), VIBRATISSIMO(300, R.drawable.ic_device_lovetoy, R.drawable.ic_device_lovetoy_disabled, R.string.devicetype_vibratissimo), + SONY_SWR12(310, R.drawable.ic_device_default, R.drawable.ic_device_default_disabled, R.string.devicetype_sonyswr12), TEST(1000, R.drawable.ic_device_default, R.drawable.ic_device_default_disabled, R.string.devicetype_test); private final int key; @DrawableRes 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 44b1b3ef4..e39f5fdcf 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceSupportFactory.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceSupportFactory.java @@ -62,6 +62,7 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.pebble.PebbleSupport import nodomain.freeyourgadget.gadgetbridge.service.devices.pinetime.PineTimeJFSupport; import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.QHybridSupport; import nodomain.freeyourgadget.gadgetbridge.service.devices.roidmi.RoidmiSupport; +import nodomain.freeyourgadget.gadgetbridge.service.devices.sonyswr12.SonySWR12DeviceSupport; import nodomain.freeyourgadget.gadgetbridge.service.devices.tlw64.TLW64Support; import nodomain.freeyourgadget.gadgetbridge.service.devices.vibratissimo.VibratissimoSupport; import nodomain.freeyourgadget.gadgetbridge.service.devices.watch9.Watch9DeviceSupport; @@ -264,6 +265,9 @@ public class DeviceSupportFactory { case LEFUN: deviceSupport = new ServiceDeviceSupport(new LefunDeviceSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING)); break; + case SONY_SWR12: + deviceSupport = new ServiceDeviceSupport(new SonySWR12DeviceSupport(), 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/sonyswr12/SonySWR12Constants.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/SonySWR12Constants.java new file mode 100644 index 000000000..1c01e4811 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/SonySWR12Constants.java @@ -0,0 +1,22 @@ +package nodomain.freeyourgadget.gadgetbridge.service.devices.sonyswr12; + +import java.util.UUID; + +public class SonySWR12Constants { + //accessory host service + public static final String BASE_UUID_AHS = "0000%s-37CB-11E3-8682-0002A5D5C51B"; + public static final UUID UUID_SERVICE_AHS = UUID.fromString(String.format(BASE_UUID_AHS, "0200")); + public static final UUID UUID_CHARACTERISTIC_ALARM = UUID.fromString(String.format(BASE_UUID_AHS, "0204")); + public static final UUID UUID_CHARACTERISTIC_EVENT = UUID.fromString(String.format(BASE_UUID_AHS, "0205")); + public static final UUID UUID_CHARACTERISTIC_TIME = UUID.fromString(String.format(BASE_UUID_AHS, "020B")); + public static final UUID UUID_CHARACTERISTIC_CONTROL_POINT = UUID.fromString(String.format(BASE_UUID_AHS, "0208")); + + public static final String VIBRATION_PREFERENCE = "vibration_preference"; + public static final String STAMINA_PREFERENCE = "stamina_preference"; + public static final String SMART_ALARM_INTERVAL_PREFERENCE = "smart_alarm_interval_preference"; + + public static final int TYPE_ACTIVITY = 0; + public static final int TYPE_LIGHT = 1; + public static final int TYPE_DEEP = 2; + public static final int TYPE_NOT_WORN = 3; +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/SonySWR12DeviceSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/SonySWR12DeviceSupport.java new file mode 100644 index 000000000..6e47e6ba1 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/SonySWR12DeviceSupport.java @@ -0,0 +1,351 @@ +package nodomain.freeyourgadget.gadgetbridge.service.devices.sonyswr12; + +import android.bluetooth.BluetoothGatt; +import android.bluetooth.BluetoothGattCharacteristic; +import android.content.Intent; +import android.net.Uri; +import android.widget.Toast; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.UUID; + +import nodomain.freeyourgadget.gadgetbridge.GBApplication; +import nodomain.freeyourgadget.gadgetbridge.database.DBHelper; +import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventBatteryInfo; +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.GattService; +import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder; +import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.IntentListener; +import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.battery.BatteryInfo; +import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.battery.BatteryInfoProfile; +import nodomain.freeyourgadget.gadgetbridge.service.devices.sonyswr12.entities.activity.EventBase; +import nodomain.freeyourgadget.gadgetbridge.service.devices.sonyswr12.entities.activity.EventFactory; +import nodomain.freeyourgadget.gadgetbridge.service.devices.sonyswr12.entities.alarm.BandAlarm; +import nodomain.freeyourgadget.gadgetbridge.service.devices.sonyswr12.entities.alarm.BandAlarms; +import nodomain.freeyourgadget.gadgetbridge.service.devices.sonyswr12.entities.control.CommandCode; +import nodomain.freeyourgadget.gadgetbridge.service.devices.sonyswr12.entities.control.ControlPointLowVibration; +import nodomain.freeyourgadget.gadgetbridge.service.devices.sonyswr12.entities.control.ControlPointWithValue; +import nodomain.freeyourgadget.gadgetbridge.service.devices.sonyswr12.entities.time.BandTime; +import nodomain.freeyourgadget.gadgetbridge.util.GB; + +// done: +// - time sync +// - alarms (also smart) +// - fetching activity(walking, sleep) +// - stamina mode +// - vibration intensity +// - realtime heart rate +// todo options: +// - "get moving" +// - get notified: -call, -notification, -notification from, -do not disturb +// - media control: media/find phone(tap once for play pause, tap twice for next, tap triple for previous) + +public class SonySWR12DeviceSupport extends AbstractBTLEDeviceSupport { + private static final Logger LOG = LoggerFactory.getLogger(SonySWR12DeviceSupport.class); + private SonySWR12HandlerThread processor = null; + + private final BatteryInfoProfile batteryInfoProfile; + private final IntentListener mListener = new IntentListener() { + @Override + public void notify(Intent intent) { + if (intent.getAction().equals(BatteryInfoProfile.ACTION_BATTERY_INFO)) { + BatteryInfo info = intent.getParcelableExtra(BatteryInfoProfile.EXTRA_BATTERY_INFO); + GBDeviceEventBatteryInfo gbInfo = new GBDeviceEventBatteryInfo(); + gbInfo.level = (short) info.getPercentCharged(); + handleGBDeviceEvent(gbInfo); + } + } + }; + + public SonySWR12DeviceSupport() { + super(LOG); + addSupportedService(GattService.UUID_SERVICE_BATTERY_SERVICE); + addSupportedService(SonySWR12Constants.UUID_SERVICE_AHS); + batteryInfoProfile = new BatteryInfoProfile<>(this); + batteryInfoProfile.addListener(mListener); + addSupportedProfile(batteryInfoProfile); + } + + @Override + protected TransactionBuilder initializeDevice(TransactionBuilder builder) { + initialize(); + setTime(builder); + batteryInfoProfile.requestBatteryInfo(builder); + return builder; + } + + private SonySWR12HandlerThread getProcessor() { + if (processor == null) { + processor = new SonySWR12HandlerThread(getDevice(), getContext()); + processor.start(); + } + return processor; + } + + private void initialize() { + if (gbDevice.getState() != GBDevice.State.INITIALIZED) { + gbDevice.setFirmwareVersion("N/A"); + gbDevice.setFirmwareVersion2("N/A"); + gbDevice.setState(GBDevice.State.INITIALIZED); + gbDevice.sendDeviceUpdateIntent(getContext()); + } + } + + @Override + public boolean useAutoConnect() { + return false; + } + + @Override + public void onNotification(NotificationSpec notificationSpec) { + + } + + @Override + public void onDeleteNotification(int id) { + + } + + @Override + public void onSetTime() { + try { + TransactionBuilder builder = performInitialized("setTime"); + setTime(builder); + builder.queue(getQueue()); + } catch (Exception e) { + GB.toast(getContext(), "Error setting time: " + e.getLocalizedMessage(), Toast.LENGTH_LONG, GB.ERROR); + } + } + + private void setTime(TransactionBuilder builder) { + BluetoothGattCharacteristic timeCharacteristic = getCharacteristic(SonySWR12Constants.UUID_CHARACTERISTIC_TIME); + builder.write(timeCharacteristic, new BandTime(Calendar.getInstance()).toByteArray()); + } + + @Override + public void onSetAlarms(ArrayList alarms) { + try { + BluetoothGattCharacteristic alarmCharacteristic = getCharacteristic(SonySWR12Constants.UUID_CHARACTERISTIC_ALARM); + TransactionBuilder builder = performInitialized("alarm"); + int prefInterval = Integer.valueOf(GBApplication.getPrefs().getString(SonySWR12Constants.SMART_ALARM_INTERVAL_PREFERENCE, "0")); + ArrayList bandAlarmList = new ArrayList<>(); + for (Alarm alarm : alarms) { + BandAlarm bandAlarm = BandAlarm.fromAppAlarm(alarm, bandAlarmList.size(), alarm.getSmartWakeup() ? prefInterval : 0); + if (bandAlarm != null) + bandAlarmList.add(bandAlarm); + } + builder.write(alarmCharacteristic, new BandAlarms(bandAlarmList).toByteArray()); + builder.queue(getQueue()); + } catch (Exception e) { + GB.toast(getContext(), "Error setting alarms: " + e.getLocalizedMessage(), Toast.LENGTH_LONG, GB.ERROR); + } + } + + @Override + public boolean onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { + return super.onCharacteristicRead(gatt, characteristic, status); + } + + @Override + public boolean onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { + if (super.onCharacteristicChanged(gatt, characteristic)) + return true; + UUID uuid = characteristic.getUuid(); + if (uuid.equals(SonySWR12Constants.UUID_CHARACTERISTIC_EVENT)) { + try { + EventBase event = EventFactory.readEventFromByteArray(characteristic.getValue()); + getProcessor().process(event); + } catch (Exception e) { + return false; + } + return true; + } + return false; + } + + @Override + public void onSetCallState(CallSpec callSpec) { + + } + + @Override + public void onSetCannedMessages(CannedMessagesSpec cannedMessagesSpec) { + + } + + @Override + public void onSetMusicState(MusicStateSpec stateSpec) { + + } + + @Override + public void onSetMusicInfo(MusicSpec musicSpec) { + + } + + @Override + public void onEnableRealtimeSteps(boolean enable) { + //doesn't support realtime steps + //supports only realtime heart rate + } + + @Override + public void onInstallApp(Uri uri) { + + } + + @Override + public void onAppInfoReq() { + + } + + @Override + public void onAppStart(UUID uuid, boolean start) { + + } + + @Override + public void onAppDelete(UUID uuid) { + + } + + @Override + public void onAppConfiguration(UUID appUuid, String config, Integer id) { + + } + + @Override + public void onAppReorder(UUID[] uuids) { + + } + + @Override + public void onFetchRecordedData(int dataTypes) { + try { + TransactionBuilder builder = performInitialized("fetchActivity"); + builder.notify(getCharacteristic(SonySWR12Constants.UUID_CHARACTERISTIC_EVENT), true); + ControlPointWithValue flushControl = new ControlPointWithValue(CommandCode.FLUSH_ACTIVITY, 0); + builder.write(getCharacteristic(SonySWR12Constants.UUID_CHARACTERISTIC_CONTROL_POINT), flushControl.toByteArray()); + builder.queue(getQueue()); + } catch (Exception e) { + LOG.error("failed to fetch activity data", e); + } + } + + @Override + public void onReset(int flags) { + + } + + @Override + public void onHeartRateTest() { + } + + @Override + public void onEnableRealtimeHeartRateMeasurement(boolean enable) { + try { + TransactionBuilder builder = performInitialized("HeartRateTest"); + builder.notify(getCharacteristic(SonySWR12Constants.UUID_CHARACTERISTIC_EVENT), enable); + ControlPointWithValue controlPointHeart = new ControlPointWithValue(CommandCode.HEARTRATE_REALTIME, enable ? 1 : 0); + builder.write(getCharacteristic(SonySWR12Constants.UUID_CHARACTERISTIC_CONTROL_POINT), controlPointHeart.toByteArray()); + builder.queue(getQueue()); + } catch (IOException ex) { + LOG.error("Unable to read heart rate from Sony device", ex); + } + } + + @Override + public void onFindDevice(boolean start) { + + } + + @Override + public void onSetConstantVibration(int integer) { + + } + + @Override + public void onScreenshotReq() { + + } + + @Override + public void onEnableHeartRateSleepSupport(boolean enable) { + + } + + @Override + public void onSetHeartRateMeasurementInterval(int seconds) { + + } + + @Override + public void onAddCalendarEvent(CalendarEventSpec calendarEventSpec) { + + } + + @Override + public void onDeleteCalendarEvent(byte type, long id) { + + } + + @Override + public void onSendConfiguration(String config) { + try { + switch (config) { + case SonySWR12Constants.STAMINA_PREFERENCE: { + //stamina can be: + //disabled = 0, enabled = 1 or todo auto on low battery = 2 + int status = GBApplication.getPrefs().getBoolean(config, false) ? 1 : 0; + TransactionBuilder builder = performInitialized(config); + ControlPointWithValue vibrationControl = new ControlPointWithValue(CommandCode.STAMINA_MODE, status); + builder.write(getCharacteristic(SonySWR12Constants.UUID_CHARACTERISTIC_CONTROL_POINT), vibrationControl.toByteArray()); + builder.queue(getQueue()); + break; + } + case SonySWR12Constants.VIBRATION_PREFERENCE: { + boolean isEnabled = GBApplication.getPrefs().getBoolean(config, false); + TransactionBuilder builder = performInitialized(config); + ControlPointLowVibration vibrationControl = new ControlPointLowVibration(isEnabled); + builder.write(getCharacteristic(SonySWR12Constants.UUID_CHARACTERISTIC_CONTROL_POINT), vibrationControl.toByteArray()); + builder.queue(getQueue()); + break; + } + case SonySWR12Constants.SMART_ALARM_INTERVAL_PREFERENCE: { + onSetAlarms(new ArrayList(DBHelper.getAlarms(gbDevice))); + } + } + } catch (Exception exc) { + LOG.error("failed to send config " + config, exc); + } + } + + @Override + public void onReadConfiguration(String config) { + + } + + @Override + public void onTestNewFunction() { + + } + + @Override + public void onSendWeather(WeatherSpec weatherSpec) { + + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/SonySWR12HandlerThread.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/SonySWR12HandlerThread.java new file mode 100644 index 000000000..2ce1816bd --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/SonySWR12HandlerThread.java @@ -0,0 +1,135 @@ +package nodomain.freeyourgadget.gadgetbridge.service.devices.sonyswr12; + +import android.content.Context; +import android.content.Intent; + +import androidx.localbroadcastmanager.content.LocalBroadcastManager; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; + +import nodomain.freeyourgadget.gadgetbridge.GBApplication; +import nodomain.freeyourgadget.gadgetbridge.database.DBHandler; +import nodomain.freeyourgadget.gadgetbridge.database.DBHelper; +import nodomain.freeyourgadget.gadgetbridge.devices.sonyswr12.SonySWR12SampleProvider; +import nodomain.freeyourgadget.gadgetbridge.entities.SonySWR12Sample; +import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; +import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample; +import nodomain.freeyourgadget.gadgetbridge.model.DeviceService; +import nodomain.freeyourgadget.gadgetbridge.service.devices.sonyswr12.entities.activity.ActivityBase; +import nodomain.freeyourgadget.gadgetbridge.service.devices.sonyswr12.entities.activity.ActivitySleep; +import nodomain.freeyourgadget.gadgetbridge.service.devices.sonyswr12.entities.activity.ActivityWithData; +import nodomain.freeyourgadget.gadgetbridge.service.devices.sonyswr12.entities.activity.EventBase; +import nodomain.freeyourgadget.gadgetbridge.service.devices.sonyswr12.entities.activity.EventCode; +import nodomain.freeyourgadget.gadgetbridge.service.devices.sonyswr12.entities.activity.EventWithActivity; +import nodomain.freeyourgadget.gadgetbridge.service.devices.sonyswr12.entities.activity.EventWithValue; +import nodomain.freeyourgadget.gadgetbridge.service.serial.GBDeviceIoThread; + +public class SonySWR12HandlerThread extends GBDeviceIoThread { + private static final Logger LOG = LoggerFactory.getLogger(SonySWR12HandlerThread.class); + + public SonySWR12HandlerThread(GBDevice gbDevice, Context context) { + super(gbDevice, context); + } + + public void process(EventBase event) { + if (event instanceof EventWithValue) { + if (event.getCode() == EventCode.HEART_RATE) { + processRealTimeHeartRate((EventWithValue) event); + } + } else if (event instanceof EventWithActivity) { + processWithActivity((EventWithActivity) event); + } + } + + private void processRealTimeHeartRate(EventWithValue event) { + try { + DBHandler dbHandler = GBApplication.acquireDB(); + Long userId = DBHelper.getUser(dbHandler.getDaoSession()).getId(); + Long deviceId = DBHelper.getDevice(getDevice(), dbHandler.getDaoSession()).getId(); + SonySWR12SampleProvider provider = new SonySWR12SampleProvider(getDevice(), dbHandler.getDaoSession()); + int timestamp = getTimestamp(); + SonySWR12Sample sample = new SonySWR12Sample(timestamp, deviceId, userId, (int) event.value, ActivitySample.NOT_MEASURED, 0, 1); + provider.addGBActivitySample(sample); + GBApplication.releaseDB(); + Intent intent = new Intent(DeviceService.ACTION_REALTIME_SAMPLES) + .putExtra(DeviceService.EXTRA_REALTIME_SAMPLE, sample) + .putExtra(DeviceService.EXTRA_TIMESTAMP, timestamp); + LocalBroadcastManager.getInstance(getContext()).sendBroadcast(intent); + } catch (Exception e) { + LOG.error(e.getMessage(), e); + } + } + + private int getTimestamp() { + return (int) (System.currentTimeMillis() / 1000); + } + + private void processWithActivity(EventWithActivity event) { + List payloadList = event.activityList; + for (ActivityBase activity : payloadList) { + switch (activity.getType()) { + case WALK: + case RUN: + addActivity((ActivityWithData) activity); + break; + case SLEEP: + addSleep((ActivitySleep) activity); + break; + } + } + } + + private void addActivity(ActivityWithData activity) { + try { + DBHandler dbHandler = GBApplication.acquireDB(); + Long userId = DBHelper.getUser(dbHandler.getDaoSession()).getId(); + Long deviceId = DBHelper.getDevice(getDevice(), dbHandler.getDaoSession()).getId(); + SonySWR12SampleProvider provider = new SonySWR12SampleProvider(getDevice(), dbHandler.getDaoSession()); + int kind = SonySWR12Constants.TYPE_ACTIVITY; + SonySWR12Sample sample = new SonySWR12Sample(activity.getTimeStampSec(), deviceId, userId, ActivitySample.NOT_MEASURED, activity.data, kind, 1); + provider.addGBActivitySample(sample); + GBApplication.releaseDB(); + } catch (Exception e) { + LOG.error(e.getMessage(), e); + } + } + + private void addSleep(ActivitySleep activity) { + try { + DBHandler dbHandler = GBApplication.acquireDB(); + Long userId = DBHelper.getUser(dbHandler.getDaoSession()).getId(); + Long deviceId = DBHelper.getDevice(getDevice(), dbHandler.getDaoSession()).getId(); + SonySWR12SampleProvider provider = new SonySWR12SampleProvider(getDevice(), dbHandler.getDaoSession()); + int kind; + switch (activity.sleepLevel) { + case LIGHT: + kind = SonySWR12Constants.TYPE_LIGHT; + break; + case DEEP: + kind = SonySWR12Constants.TYPE_DEEP; + break; + default: + kind = SonySWR12Constants.TYPE_ACTIVITY; + break; + } + if (kind == SonySWR12Constants.TYPE_LIGHT || kind == SonySWR12Constants.TYPE_DEEP) { + //need so much samples because sleep has exact duration + //so empty samples are for right representation of sleep on activity charts + SonySWR12Sample sample = new SonySWR12Sample(activity.getTimeStampSec(), deviceId, userId, ActivitySample.NOT_MEASURED, 0, SonySWR12Constants.TYPE_NOT_WORN, 1); + provider.addGBActivitySample(sample); + sample = new SonySWR12Sample(activity.getTimeStampSec() + 2, deviceId, userId, ActivitySample.NOT_MEASURED, 0, kind, 1); + provider.addGBActivitySample(sample); + sample = new SonySWR12Sample(activity.getTimeStampSec() + activity.durationMin * 60 - 2, deviceId, userId, ActivitySample.NOT_MEASURED, 0, kind, 1); + provider.addGBActivitySample(sample); + sample = new SonySWR12Sample(activity.getTimeStampSec() + activity.durationMin * 60, deviceId, userId, ActivitySample.NOT_MEASURED, 0, SonySWR12Constants.TYPE_NOT_WORN, 1); + provider.addGBActivitySample(sample); + } + GBApplication.releaseDB(); + } catch (Exception e) { + LOG.error(e.getMessage(), e); + } + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/SonySWR12Util.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/SonySWR12Util.java new file mode 100644 index 000000000..7f2497c4b --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/SonySWR12Util.java @@ -0,0 +1,22 @@ +package nodomain.freeyourgadget.gadgetbridge.service.devices.sonyswr12; + +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; +import java.util.TimeZone; + +public class SonySWR12Util { + + public static long secSince2013() { + //sony uses time on band since 2013 for some reason + final Calendar instance = Calendar.getInstance(TimeZone.getTimeZone("UTC")); + instance.set(2013, 0, 1, 0, 0, 0); + instance.set(14, 0); + return instance.getTimeInMillis()/1000; + } + + public static String timeToString(long sec) { + SimpleDateFormat format = new SimpleDateFormat("MM-dd HH:mm:ss"); + return format.format(new Date(sec * 1000)); + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/activity/ActivityBase.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/activity/ActivityBase.java new file mode 100644 index 000000000..1cb102fb6 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/activity/ActivityBase.java @@ -0,0 +1,35 @@ +package nodomain.freeyourgadget.gadgetbridge.service.devices.sonyswr12.entities.activity; + +import nodomain.freeyourgadget.gadgetbridge.service.devices.sonyswr12.util.UIntBitWriter; + +public abstract class ActivityBase { + protected final ActivityType type; + protected final int timeOffsetMin; + private final long timeStampSec; + + public ActivityBase(ActivityType type, int timeOffsetMin, long timeStampSec) { + if (timeOffsetMin < 0 || timeOffsetMin > 1440) { + throw new IllegalArgumentException("activity time offset out of range: " + timeOffsetMin); + } + this.type = type; + this.timeOffsetMin = timeOffsetMin; + this.timeStampSec = timeStampSec + this.timeOffsetMin * 60; + } + + public final int getTimeStampSec() { + return (int) (timeStampSec); + } + + public final ActivityType getType() { + return this.type; + } + + protected final UIntBitWriter getWriterWithTypeAndOffset() { + UIntBitWriter uIntBitWriter = new UIntBitWriter(32); + uIntBitWriter.append(4, this.type.value); + uIntBitWriter.append(12, this.timeOffsetMin); + return uIntBitWriter; + } + + public abstract long toLong(); +} \ No newline at end of file diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/activity/ActivityHeartRate.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/activity/ActivityHeartRate.java new file mode 100644 index 000000000..611c64c33 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/activity/ActivityHeartRate.java @@ -0,0 +1,22 @@ +package nodomain.freeyourgadget.gadgetbridge.service.devices.sonyswr12.entities.activity; + +import nodomain.freeyourgadget.gadgetbridge.service.devices.sonyswr12.util.UIntBitWriter; + +public class ActivityHeartRate extends ActivityBase { + public final int bpm; + + public ActivityHeartRate(int timeOffsetMin, int bpm, Long timeStampSec) { + super(ActivityType.HEART_RATE, timeOffsetMin, timeStampSec); + if (bpm < 0 || bpm > 65535) { + throw new IllegalArgumentException("bpm out of range: " + bpm); + } + this.bpm = bpm; + } + + @Override + public long toLong() { + UIntBitWriter writerWithTypeAndOffset = this.getWriterWithTypeAndOffset(); + writerWithTypeAndOffset.append(16, this.bpm); + return writerWithTypeAndOffset.getValue(); + } +} \ No newline at end of file diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/activity/ActivitySleep.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/activity/ActivitySleep.java new file mode 100644 index 000000000..f8afb9703 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/activity/ActivitySleep.java @@ -0,0 +1,22 @@ +package nodomain.freeyourgadget.gadgetbridge.service.devices.sonyswr12.entities.activity; + +import nodomain.freeyourgadget.gadgetbridge.service.devices.sonyswr12.util.UIntBitWriter; + +public class ActivitySleep extends ActivityBase { + public final SleepLevel sleepLevel; + public final int durationMin; + + public ActivitySleep(int timeOffsetMin, int durationMin, SleepLevel sleepLevel, Long timeStampSec) { + super(ActivityType.SLEEP, timeOffsetMin, timeStampSec); + this.durationMin = durationMin; + this.sleepLevel = sleepLevel; + } + + @Override + public long toLong() { + UIntBitWriter writerWithTypeAndOffset = this.getWriterWithTypeAndOffset(); + writerWithTypeAndOffset.append(14, this.durationMin); + writerWithTypeAndOffset.append(2, this.sleepLevel.value); + return writerWithTypeAndOffset.getValue(); + } +} \ No newline at end of file diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/activity/ActivityType.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/activity/ActivityType.java new file mode 100644 index 000000000..e9c6d92e3 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/activity/ActivityType.java @@ -0,0 +1,23 @@ +package nodomain.freeyourgadget.gadgetbridge.service.devices.sonyswr12.entities.activity; + +public enum ActivityType { + WALK(1), + RUN(2), + SLEEP(3), + HEART_RATE(10), + END(14); + + final int value; + + ActivityType(int value) { + this.value = value; + } + + public static ActivityType fromInt(int i) { + for (ActivityType type : values()){ + if (type.value == i) + return type; + } + throw new IllegalArgumentException("wrong activity type: " + i); + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/activity/ActivityWithData.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/activity/ActivityWithData.java new file mode 100644 index 000000000..37348177b --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/activity/ActivityWithData.java @@ -0,0 +1,22 @@ +package nodomain.freeyourgadget.gadgetbridge.service.devices.sonyswr12.entities.activity; + +import nodomain.freeyourgadget.gadgetbridge.service.devices.sonyswr12.util.UIntBitWriter; + +public class ActivityWithData extends ActivityBase { + public final int data; + + public ActivityWithData(ActivityType activityType, int timeOffsetMin, int data, Long timeStampSec) { + super(activityType, timeOffsetMin, timeStampSec); + if (data < 0 || data > 65535) { + throw new IllegalArgumentException("data out of range: " + data); + } + this.data = data; + } + + @Override + public long toLong() { + UIntBitWriter writerWithTypeAndOffset = this.getWriterWithTypeAndOffset(); + writerWithTypeAndOffset.append(16, this.data); + return writerWithTypeAndOffset.getValue(); + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/activity/EventBase.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/activity/EventBase.java new file mode 100644 index 000000000..1b1d31161 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/activity/EventBase.java @@ -0,0 +1,21 @@ +package nodomain.freeyourgadget.gadgetbridge.service.devices.sonyswr12.entities.activity; + +import nodomain.freeyourgadget.gadgetbridge.service.devices.sonyswr12.util.ByteArrayWriter; + +public abstract class EventBase { + protected final EventCode eventCode; + + protected EventBase(EventCode eventCode) { + this.eventCode = eventCode; + } + + public EventCode getCode() { + return this.eventCode; + } + + protected ByteArrayWriter getValueWriter() { + ByteArrayWriter byteArrayWriter = new ByteArrayWriter(); + byteArrayWriter.appendUint8(this.eventCode.value); + return byteArrayWriter; + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/activity/EventCode.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/activity/EventCode.java new file mode 100644 index 000000000..777d0dba6 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/activity/EventCode.java @@ -0,0 +1,21 @@ +package nodomain.freeyourgadget.gadgetbridge.service.devices.sonyswr12.entities.activity; + +public enum EventCode { + STEPS(3), + ACTIVITY_DATA(5), + HEART_RATE(9); + + final int value; + + EventCode(int value) { + this.value = value; + } + + static EventCode fromInt(int i) { + for (EventCode code : values()){ + if (code.value == i) + return code; + } + throw new RuntimeException("wrong event code: " + i); + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/activity/EventFactory.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/activity/EventFactory.java new file mode 100644 index 000000000..03e09e61a --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/activity/EventFactory.java @@ -0,0 +1,26 @@ +package nodomain.freeyourgadget.gadgetbridge.service.devices.sonyswr12.entities.activity; + +import nodomain.freeyourgadget.gadgetbridge.service.devices.sonyswr12.util.IntFormat; +import nodomain.freeyourgadget.gadgetbridge.service.devices.sonyswr12.util.ByteArrayReader; + +public class EventFactory { + + public static EventBase readEventFromByteArray(byte[] array) { + try { + ByteArrayReader byteArrayReader = new ByteArrayReader(array); + EventCode eventCode = EventCode.fromInt(byteArrayReader.readUint8()); + switch (eventCode) { + case HEART_RATE: { + long value = byteArrayReader.readInt(IntFormat.UINT32); + return new EventWithValue(eventCode, value); + } + case ACTIVITY_DATA: { + return EventWithActivity.fromByteArray(byteArrayReader); + } + default: return null; + } + } catch (Exception ex) { + return null; + } + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/activity/EventWithActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/activity/EventWithActivity.java new file mode 100644 index 000000000..e7c804ddd --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/activity/EventWithActivity.java @@ -0,0 +1,62 @@ +package nodomain.freeyourgadget.gadgetbridge.service.devices.sonyswr12.entities.activity; + +import java.util.ArrayList; +import java.util.List; + +import nodomain.freeyourgadget.gadgetbridge.service.devices.sonyswr12.SonySWR12Util; +import nodomain.freeyourgadget.gadgetbridge.service.devices.sonyswr12.util.IntFormat; +import nodomain.freeyourgadget.gadgetbridge.service.devices.sonyswr12.util.UIntBitReader; +import nodomain.freeyourgadget.gadgetbridge.service.devices.sonyswr12.util.ByteArrayReader; +import nodomain.freeyourgadget.gadgetbridge.service.devices.sonyswr12.util.ByteArrayWriter; + +public class EventWithActivity extends EventBase { + public final long timeStampSec; + public final List activityList; + + private EventWithActivity(long timeStampSec, List activityList) { + super(EventCode.ACTIVITY_DATA); + this.timeStampSec = timeStampSec; + this.activityList = activityList; + } + + public static EventWithActivity fromByteArray(ByteArrayReader byteArrayReader) { + long timeOffset = byteArrayReader.readInt(IntFormat.UINT32); + long timeStampSec = SonySWR12Util.secSince2013() + timeOffset; + ArrayList activities = new ArrayList<>(); + while (byteArrayReader.getBytesLeft() > 0) { + UIntBitReader uIntBitReader = new UIntBitReader(byteArrayReader.readInt(IntFormat.UINT32), 32); + ActivityType activityType = ActivityType.fromInt(uIntBitReader.read(4)); + int offsetMin = uIntBitReader.read(12); + ActivityBase activityPayload; + switch (activityType) { + case SLEEP: { + SleepLevel sleepLevel = SleepLevel.fromInt(uIntBitReader.read(2)); + int duration = uIntBitReader.read(14); + activityPayload = new ActivitySleep(offsetMin, duration, sleepLevel, timeStampSec); + break; + } + case HEART_RATE: { + int bpm = uIntBitReader.read(16); + activityPayload = new ActivityHeartRate(offsetMin, bpm, timeStampSec); + break; + } + default: { + int data = uIntBitReader.read(16); + activityPayload = new ActivityWithData(activityType, offsetMin, data, timeStampSec); + break; + } + } + activities.add(activityPayload); + } + return new EventWithActivity(timeStampSec, activities); + } + + public byte[] toByteArray() { + ByteArrayWriter byteArrayWriter = this.getValueWriter(); + byteArrayWriter.appendUint32(this.timeStampSec); + for (ActivityBase activity : activityList){ + byteArrayWriter.appendUint32(activity.toLong()); + } + return byteArrayWriter.getByteArray(); + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/activity/EventWithValue.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/activity/EventWithValue.java new file mode 100644 index 000000000..cf81e5eb0 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/activity/EventWithValue.java @@ -0,0 +1,18 @@ +package nodomain.freeyourgadget.gadgetbridge.service.devices.sonyswr12.entities.activity; + +import nodomain.freeyourgadget.gadgetbridge.service.devices.sonyswr12.util.ByteArrayWriter; + +public class EventWithValue extends EventBase { + public final long value; + + public EventWithValue(EventCode eventCode, long value) { + super(eventCode); + this.value = value; + } + + public byte[] toByteArray() { + ByteArrayWriter byteArrayWriter = this.getValueWriter(); + byteArrayWriter.appendUint32(this.value); + return byteArrayWriter.getByteArray(); + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/activity/SleepLevel.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/activity/SleepLevel.java new file mode 100644 index 000000000..c8565467f --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/activity/SleepLevel.java @@ -0,0 +1,21 @@ +package nodomain.freeyourgadget.gadgetbridge.service.devices.sonyswr12.entities.activity; + +public enum SleepLevel { + AWAKE(0), + LIGHT(1), + DEEP(2); + + final int value; + + SleepLevel(int value){ + this.value = value; + } + + public static SleepLevel fromInt(int i) { + for (SleepLevel level : values()){ + if (level.value == i) + return level; + } + throw new RuntimeException("wrong sleep level: " + i); + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/alarm/AlarmRepeat.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/alarm/AlarmRepeat.java new file mode 100644 index 000000000..28ef12656 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/alarm/AlarmRepeat.java @@ -0,0 +1,53 @@ +package nodomain.freeyourgadget.gadgetbridge.service.devices.sonyswr12.entities.alarm; + +import java.util.Arrays; + +import nodomain.freeyourgadget.gadgetbridge.model.Alarm; +import nodomain.freeyourgadget.gadgetbridge.service.devices.sonyswr12.util.UIntBitWriter; + +public class AlarmRepeat { + private final boolean[] repeat = new boolean[7]; + + public AlarmRepeat(Alarm alarm) { + super(); + setRepeatOnDay(0, alarm.getRepetition(Alarm.ALARM_MON)); + setRepeatOnDay(1, alarm.getRepetition(Alarm.ALARM_TUE)); + setRepeatOnDay(2, alarm.getRepetition(Alarm.ALARM_WED)); + setRepeatOnDay(3, alarm.getRepetition(Alarm.ALARM_THU)); + setRepeatOnDay(4, alarm.getRepetition(Alarm.ALARM_FRI)); + setRepeatOnDay(5, alarm.getRepetition(Alarm.ALARM_SAT)); + setRepeatOnDay(6, alarm.getRepetition(Alarm.ALARM_SUN)); + } + + @Override + public boolean equals(Object o) { + if (this != o) { + if (o == null || this.getClass() != o.getClass()) { + return false; + } + return Arrays.equals(this.repeat, ((AlarmRepeat) o).repeat); + } + return true; + } + + @Override + public int hashCode() { + return Arrays.hashCode(this.repeat); + } + + public void setRepeatOnDay(int i, boolean b) { + this.repeat[i] = b; + } + + public int toInt() { + UIntBitWriter uIntBitWriter = new UIntBitWriter(7); + uIntBitWriter.appendBoolean(this.repeat[6]); + uIntBitWriter.appendBoolean(this.repeat[5]); + uIntBitWriter.appendBoolean(this.repeat[4]); + uIntBitWriter.appendBoolean(this.repeat[3]); + uIntBitWriter.appendBoolean(this.repeat[2]); + uIntBitWriter.appendBoolean(this.repeat[1]); + uIntBitWriter.appendBoolean(this.repeat[0]); + return (int) uIntBitWriter.getValue(); + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/alarm/AlarmState.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/alarm/AlarmState.java new file mode 100644 index 000000000..1564207f6 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/alarm/AlarmState.java @@ -0,0 +1,13 @@ +package nodomain.freeyourgadget.gadgetbridge.service.devices.sonyswr12.entities.alarm; + +public enum AlarmState { + TRIGGERED( 0), + SNOOZED(1), + IDLE(2); + + final int value; + + AlarmState(int value) { + this.value = value; + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/alarm/BandAlarm.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/alarm/BandAlarm.java new file mode 100644 index 000000000..306ba6d94 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/alarm/BandAlarm.java @@ -0,0 +1,60 @@ +package nodomain.freeyourgadget.gadgetbridge.service.devices.sonyswr12.entities.alarm; + +import nodomain.freeyourgadget.gadgetbridge.model.Alarm; + +public class BandAlarm { + public static BandAlarm fromAppAlarm(Alarm alarm, int index, int interval) { + if (!alarm.getEnabled()) return null; + //smart wakeup = (0,10..60 min)/5 + int ahsInterval = interval / 5; + return new BandAlarm(AlarmState.IDLE, index, ahsInterval, alarm.getHour(), alarm.getMinute(), new AlarmRepeat(alarm)); + } + + public AlarmState state; + public int index; + public int interval; + public int hour; + public int minute; + public AlarmRepeat repeat; + + public BandAlarm(AlarmState state, int index, int interval, int hour, int minute, AlarmRepeat repeat) { + this.state = state; + this.index = index; + this.interval = interval; + this.hour = hour; + this.minute = minute; + this.repeat = repeat; + } + + @Override + public boolean equals(Object o) { + if (this != o) { + if (o == null || this.getClass() != o.getClass()) { + return false; + } + BandAlarm bandAlarm = (BandAlarm) o; + if (this.index != bandAlarm.index) { + return false; + } + if (this.hour != bandAlarm.hour) { + return false; + } + if (this.interval != bandAlarm.interval) { + return false; + } + if (this.minute != bandAlarm.minute) { + return false; + } + if (!this.repeat.equals(bandAlarm.repeat)) { + return false; + } + return this.state == bandAlarm.state; + } + return true; + } + + @Override + public int hashCode() { + return ((((this.state.hashCode() * 31 + this.index) * 31 + this.interval) * 31 + this.hour) * 31 + this.minute) * 31 + this.repeat.hashCode(); + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/alarm/BandAlarms.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/alarm/BandAlarms.java new file mode 100644 index 000000000..7cd7676dc --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/alarm/BandAlarms.java @@ -0,0 +1,35 @@ +package nodomain.freeyourgadget.gadgetbridge.service.devices.sonyswr12.entities.alarm; + +import java.util.List; + +import nodomain.freeyourgadget.gadgetbridge.service.devices.sonyswr12.util.UIntBitWriter; +import nodomain.freeyourgadget.gadgetbridge.service.devices.sonyswr12.util.ByteArrayWriter; + +public class BandAlarms { + public final List alarms; + + public BandAlarms(List alarms) { + this.alarms = alarms; + } + + public byte[] toByteArray() { + ByteArrayWriter byteArrayWriter = new ByteArrayWriter(); + if (this.alarms.size() == 0) { + byteArrayWriter.appendUint32(1073741824L); + } else { + for (BandAlarm bandAlarm : this.alarms) { + UIntBitWriter uIntBitWriter = new UIntBitWriter(32); + uIntBitWriter.append(2, 0); + uIntBitWriter.append(4, bandAlarm.index); + uIntBitWriter.append(2, bandAlarm.state.value); + uIntBitWriter.append(4, bandAlarm.interval); + uIntBitWriter.append(6, bandAlarm.hour); + uIntBitWriter.append(6, bandAlarm.minute); + uIntBitWriter.append(1, 0); + uIntBitWriter.append(7, bandAlarm.repeat.toInt()); + byteArrayWriter.appendUint32(uIntBitWriter.getValue()); + } + } + return byteArrayWriter.getByteArray(); + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/control/CommandCode.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/control/CommandCode.java new file mode 100644 index 000000000..fdd5979c3 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/control/CommandCode.java @@ -0,0 +1,15 @@ +package nodomain.freeyourgadget.gadgetbridge.service.devices.sonyswr12.entities.control; + +public enum CommandCode { + FLUSH_ACTIVITY(7), + HEARTRATE_REALTIME(11), + STAMINA_MODE(17), + MANUAL_ALARM(19), + LOW_VIBRATION(25); + + public final int value; + + CommandCode(int value) { + this.value = value; + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/control/ControlPoint.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/control/ControlPoint.java new file mode 100644 index 000000000..038a3dace --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/control/ControlPoint.java @@ -0,0 +1,17 @@ +package nodomain.freeyourgadget.gadgetbridge.service.devices.sonyswr12.entities.control; + +import nodomain.freeyourgadget.gadgetbridge.service.devices.sonyswr12.util.ByteArrayWriter; + +public abstract class ControlPoint { + protected final CommandCode code; + + public ControlPoint(CommandCode code) { + this.code = code; + } + + protected final ByteArrayWriter getValueWriter() { + final ByteArrayWriter byteArrayWriter = new ByteArrayWriter(); + byteArrayWriter.appendUint8(this.code.value); + return byteArrayWriter; + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/control/ControlPointLowVibration.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/control/ControlPointLowVibration.java new file mode 100644 index 000000000..7addaf1ed --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/control/ControlPointLowVibration.java @@ -0,0 +1,28 @@ +package nodomain.freeyourgadget.gadgetbridge.service.devices.sonyswr12.entities.control; + +import nodomain.freeyourgadget.gadgetbridge.service.devices.sonyswr12.util.UIntBitWriter; +import nodomain.freeyourgadget.gadgetbridge.service.devices.sonyswr12.util.ByteArrayWriter; + +public final class ControlPointLowVibration extends ControlPoint { + public boolean smartWakeUp; + public boolean incomingCall; + public boolean notification; + + public ControlPointLowVibration(boolean isEnabled){ + super(CommandCode.LOW_VIBRATION); + this.smartWakeUp = isEnabled; + this.incomingCall = isEnabled; + this.notification = isEnabled; + } + + public final byte[] toByteArray() { + final UIntBitWriter uIntBitWriter = new UIntBitWriter(16); + uIntBitWriter.append(13, 0); + uIntBitWriter.appendBoolean(this.smartWakeUp); + uIntBitWriter.appendBoolean(this.incomingCall); + uIntBitWriter.appendBoolean(this.notification); + final ByteArrayWriter byteArrayWriter = this.getValueWriter(); + byteArrayWriter.appendUint16((int) uIntBitWriter.getValue()); + return byteArrayWriter.getByteArray(); + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/control/ControlPointWithValue.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/control/ControlPointWithValue.java new file mode 100644 index 000000000..ed4536924 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/control/ControlPointWithValue.java @@ -0,0 +1,21 @@ +package nodomain.freeyourgadget.gadgetbridge.service.devices.sonyswr12.entities.control; + +import nodomain.freeyourgadget.gadgetbridge.service.devices.sonyswr12.util.ByteArrayWriter; + +public class ControlPointWithValue extends ControlPoint { + protected final int value; + + public ControlPointWithValue(final CommandCode commandCode, final int value) { + super(commandCode); + if (value < 0 || value > 65535) { + throw new IllegalArgumentException("command value out of range " + value); + } + this.value = value; + } + + public final byte[] toByteArray() { + final ByteArrayWriter byteArrayWriter = this.getValueWriter(); + byteArrayWriter.appendUint16(this.value); + return byteArrayWriter.getByteArray(); + } +} \ No newline at end of file diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/time/BandDaylightSavingTime.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/time/BandDaylightSavingTime.java new file mode 100644 index 000000000..39ef3605f --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/time/BandDaylightSavingTime.java @@ -0,0 +1,24 @@ +package nodomain.freeyourgadget.gadgetbridge.service.devices.sonyswr12.entities.time; + +public enum BandDaylightSavingTime { + STANDARD_TIME(0, 0), + HALF_AN_HOUR_DST(2, 30), + DST(4, 60), + DOUBLE_DST( 8, 120); + + final int key; + private final long saving; + + BandDaylightSavingTime(int key, int min) { + this.key = key; + this.saving = 60000L * min; + } + + public static BandDaylightSavingTime fromOffset(final int dstSaving) { + for (BandDaylightSavingTime dst: values()){ + if (dst.saving == dstSaving) + return dst; + } + throw new RuntimeException("wrong dst saving: " + dstSaving); + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/time/BandTime.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/time/BandTime.java new file mode 100644 index 000000000..315b48726 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/time/BandTime.java @@ -0,0 +1,62 @@ +package nodomain.freeyourgadget.gadgetbridge.service.devices.sonyswr12.entities.time; + +import java.util.Calendar; +import java.util.TimeZone; + +import nodomain.freeyourgadget.gadgetbridge.service.devices.sonyswr12.util.IntFormat; +import nodomain.freeyourgadget.gadgetbridge.service.devices.sonyswr12.util.ByteArrayWriter; + +public class BandTime { + private final int year; + private final int month; + private final int dayOfMonth; + private final int hour; + private final int min; + private final int sec; + private final int dayOfWeek; + private final BandTimeZone timeZone; + private final BandDaylightSavingTime dst; + + public BandTime(Calendar calendar) { + int dayOfWeek = 7; + if (calendar == null) { + throw new IllegalArgumentException("Calendar cant be null"); + } + this.year = calendar.get(1); + if (this.year > 2099 || this.year < 2013) { + throw new RuntimeException("out of 2013-2099"); + } + this.month = calendar.get(2) + 1; + this.dayOfMonth = calendar.get(5); + int value = calendar.get(7); + if (value != 1) { + dayOfWeek = value - 1; + } + this.dayOfWeek = dayOfWeek; + this.hour = calendar.get(11); + this.min = calendar.get(12); + this.sec = calendar.get(13); + TimeZone timeZone = calendar.getTimeZone(); + this.timeZone = BandTimeZone.fromOffset(timeZone.getRawOffset()); + if (timeZone.inDaylightTime(calendar.getTime())) { + this.dst = BandDaylightSavingTime.fromOffset(timeZone.getDSTSavings()); + return; + } + this.dst = BandDaylightSavingTime.STANDARD_TIME; + } + + public byte[] toByteArray() { + ByteArrayWriter byteArrayWriter = new ByteArrayWriter(); + byteArrayWriter.appendUint16(this.year); + byteArrayWriter.appendUint8(this.month); + byteArrayWriter.appendUint8(this.dayOfMonth); + byteArrayWriter.appendUint8(this.hour); + byteArrayWriter.appendUint8(this.min); + byteArrayWriter.appendUint8(this.sec); + byteArrayWriter.appendUint8(this.dayOfWeek); + byteArrayWriter.appendValue(this.timeZone.key, IntFormat.SINT8); + byteArrayWriter.appendUint8(this.dst.key); + return byteArrayWriter.getByteArray(); + } +} + diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/time/BandTimeZone.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/time/BandTimeZone.java new file mode 100644 index 000000000..1040f5af4 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/entities/time/BandTimeZone.java @@ -0,0 +1,61 @@ +package nodomain.freeyourgadget.gadgetbridge.service.devices.sonyswr12.entities.time; + +public enum BandTimeZone { + UTC_PLUS_06_30(26, 6, 30), + UTC_PLUS_07_00(28, 7, 0), + UTC_PLUS_08_00(32, 8, 0), + UTC_PLUS_08_45(35, 8, 45), + UTC_PLUS_09_00(36, 9, 0), + UTC_PLUS_09_30(38, 9, 30), + UTC_PLUS_10_00(40, 10, 0), + UTC_PLUS_10_30(42, 10, 30), + UTC_PLUS_11_00(44, 11, 0), + UTC_PLUS_11_30(46, 11, 30), + UTC_PLUS_12_00(48, 12, 0), + UTC_PLUS_12_45(51, 12, 45), + UTC_PLUS_13_00( 52, 13, 0), + UTC_PLUS_14_00(56, 14, 0), + UTC_MINUS_12_00(-48, -12, 0), + UTC_MINUS_11_00(-44, -11, 0), + UTC_MINUS_10_00(-40, -10, 0), + UTC_MINUS_09_30(-38, -9, -30), + UTC_MINUS_09_00(-36, -9, 0), + UTC_MINUS_08_00(-32, -8, 0), + UTC_MINUS_07_00(-28, -7, 0), + UTC_MINUS_06_00(-24, -6, 0), + UTC_MINUS_05_00(-20, -5, 0), + UTC_MINUS_04_30(-18, -4, -30), + UTC_MINUS_04_00(-16, -4, 0), + UTC_MINUS_03_30(-14, -3, -30), + UTC_MINUS_03_00(-12, -3, 0), + UTC_MINUS_02_00(-8, -2, 0), + UTC_MINUS_01_00(-4, -1, 0), + UTC_PLUS_00_00(0, 0, 0), + UTC_PLUS_01_00(4, 1, 0), + UTC_PLUS_02_00(8, 2, 0), + UTC_PLUS_03_00(12, 3, 0), + UTC_PLUS_03_30(14, 3, 30), + UTC_PLUS_04_00(16, 4, 0), + UTC_PLUS_04_30(18, 4, 30), + UTC_PLUS_05_00(20, 5, 0), + UTC_PLUS_05_30(22, 5, 30), + UTC_PLUS_05_45(23, 5, 45), + UTC_PLUS_06_00(24, 6, 0); + + final int key; + private final long rawOffset; + + BandTimeZone(int key, int hourOffset, int minOffset) { + this.key = key; + this.rawOffset = 3600000L * hourOffset + 60000L * minOffset; + } + + public static BandTimeZone fromOffset(long rawOffset) { + for (BandTimeZone zone : values()){ + if (zone.rawOffset == rawOffset) + return zone; + } + throw new RuntimeException("wrong raw offset: " + rawOffset); + } +} + diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/util/ByteArrayReader.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/util/ByteArrayReader.java new file mode 100644 index 000000000..edf1edb45 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/util/ByteArrayReader.java @@ -0,0 +1,53 @@ +package nodomain.freeyourgadget.gadgetbridge.service.devices.sonyswr12.util; + +public class ByteArrayReader { + public final byte[] byteArray; + public int bytesRead; + + public ByteArrayReader(byte[] array) { + this.bytesRead = 0; + if (array == null || array.length <= 0) { + throw new IllegalArgumentException("wrong byte array"); + } + this.byteArray = array.clone(); + } + + public int getBytesLeft() { + return this.byteArray.length - this.bytesRead; + } + + public long readInt(IntFormat intFormat) { + if (intFormat == null) { + throw new IllegalArgumentException("wrong intFormat"); + } + int i = 0; + long n = 0L; + try { + while (i < intFormat.bytesCount) { + long n2 = this.byteArray[this.bytesRead++] & 0xFF; + int n3 = i + 1; + n += n2 << i * 8; + i = n3; + } + long n4 = n; + if (intFormat.isSigned) { + int n5 = intFormat.bytesCount * 8; + n4 = n; + if (((long) (1 << n5 - 1) & n) != 0x0L) { + n4 = ((1 << n5 - 1) - (n & (long) ((1 << n5 - 1) - 1))) * -1L; + } + } + return n4; + } catch (ArrayIndexOutOfBoundsException ex) { + throw new RuntimeException("reading outside of byte array", ex.getCause()); + } + } + + public int readUint16() { + return (int) this.readInt(IntFormat.UINT16); + } + + public int readUint8() { + return (int) this.readInt(IntFormat.UINT8); + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/util/ByteArrayWriter.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/util/ByteArrayWriter.java new file mode 100644 index 000000000..762f41136 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/util/ByteArrayWriter.java @@ -0,0 +1,61 @@ +package nodomain.freeyourgadget.gadgetbridge.service.devices.sonyswr12.util; + +import java.util.Arrays; + +public class ByteArrayWriter { + public byte[] byteArray; + private int bytesWritten; + + public ByteArrayWriter() { + this.bytesWritten = 0; + } + + private void addIntToValue(long n, IntFormat intFormat) { + for (int i = 0; i < intFormat.bytesCount; ++i) { + this.byteArray[this.bytesWritten++] = (byte) (n >> i * 8 & 0xFFL); + } + } + + public void appendUint16(int n) { + this.appendValue(n, IntFormat.UINT16); + } + + public void appendUint32(long n) { + this.appendValue(n, IntFormat.UINT32); + } + + public void appendUint8(int n) { + this.appendValue(n, IntFormat.UINT8); + } + + public void appendValue(long lng, IntFormat intFormat) { + if (intFormat == null) { + throw new IllegalArgumentException("wrong int format"); + } + if (lng > intFormat.max || lng < intFormat.min) { + throw new IllegalArgumentException("wrong value for intFormat. max: " + intFormat.max + " min: " + intFormat.min + " value: " + lng); + } + this.increaseByteArray(intFormat.bytesCount); + long n = lng; + if (intFormat.isSigned) { + int n2 = intFormat.bytesCount * 8; + n = lng; + if (lng < 0L) { + n = (1 << n2 - 1) + ((long) ((1 << n2 - 1) - 1) & lng); + } + } + this.addIntToValue(n, intFormat); + } + + public void increaseByteArray(int n) { + if (this.byteArray == null) { + this.byteArray = new byte[n]; + return; + } + this.byteArray = Arrays.copyOf(this.byteArray, this.byteArray.length + n); + } + + public byte[] getByteArray() { + return this.byteArray.clone(); + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/util/IntFormat.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/util/IntFormat.java new file mode 100644 index 000000000..284238753 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/util/IntFormat.java @@ -0,0 +1,35 @@ +package nodomain.freeyourgadget.gadgetbridge.service.devices.sonyswr12.util; + +public enum IntFormat { + UINT8(1, false), + SINT8(1, true), + UINT16( 2, false), + SINT16( 2, true), + UINT32(4, false), + SINT32(4, true); + + final int bytesCount; + final boolean isSigned; + final long max; + final long min; + + IntFormat(int bytesCount, boolean isSigned) { + this.bytesCount = bytesCount; + this.isSigned = isSigned; + int bitsCount = bytesCount * 8; + long max; + if (isSigned) { + max = (long) Math.pow(2.0, bitsCount - 1) - 1L; + } else { + max = (long) (Math.pow(2.0, bitsCount) - 1.0); + } + this.max = max; + long min; + if (isSigned) { + min = (long) (-1.0 * Math.pow(2.0, bitsCount - 1)); + } else { + min = 0L; + } + this.min = min; + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/util/UIntBitReader.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/util/UIntBitReader.java new file mode 100644 index 000000000..645d24599 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/util/UIntBitReader.java @@ -0,0 +1,27 @@ +package nodomain.freeyourgadget.gadgetbridge.service.devices.sonyswr12.util; + +public class UIntBitReader { + private final long value; + private int offset; + + public UIntBitReader(long value, int offset) { + this.value = value; + this.offset = offset; + } + + public int read(int offset) { + this.offset -= offset; + if (this.offset < 0) { + throw new IllegalArgumentException("Read out of range"); + } + return (int) ((long) ((1 << offset) - 1) & this.value >>> this.offset); + } + + public boolean readBoolean() { + boolean b = true; + if (this.read(1) == 0) { + b = false; + } + return b; + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/util/UIntBitWriter.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/util/UIntBitWriter.java new file mode 100644 index 000000000..21ae241f4 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sonyswr12/util/UIntBitWriter.java @@ -0,0 +1,37 @@ +package nodomain.freeyourgadget.gadgetbridge.service.devices.sonyswr12.util; + +public class UIntBitWriter { + private long value; + private long offset; + + public UIntBitWriter(int offset) { + this.value = 0L; + this.offset = offset; + } + + public void append(int offset, int value) { + if (value < 0 || value > (1 << offset) - 1) { + throw new IllegalArgumentException("value is out of range: " + value); + } + this.offset -= offset; + if (this.offset < 0L) { + throw new IllegalArgumentException("Write offset out of range"); + } + this.value |= (long) value << (int) this.offset; + } + + public void appendBoolean(boolean b) { + if (b) { + this.append(1, 1); + return; + } + this.append(1, 0); + } + + public long getValue() { + if (this.offset != 0L) { + throw new IllegalStateException("value is not complete yet: " + this.offset); + } + return this.value; + } +} \ No newline at end of file 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 921702b23..a30d79823 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/DeviceHelper.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/DeviceHelper.java @@ -82,6 +82,7 @@ import nodomain.freeyourgadget.gadgetbridge.devices.pinetime.PineTimeJFCoordinat import nodomain.freeyourgadget.gadgetbridge.devices.qhybrid.QHybridCoordinator; import nodomain.freeyourgadget.gadgetbridge.devices.roidmi.Roidmi1Coordinator; import nodomain.freeyourgadget.gadgetbridge.devices.roidmi.Roidmi3Coordinator; +import nodomain.freeyourgadget.gadgetbridge.devices.sonyswr12.SonySWR12DeviceCoordinator; import nodomain.freeyourgadget.gadgetbridge.devices.tlw64.TLW64Coordinator; import nodomain.freeyourgadget.gadgetbridge.devices.vibratissimo.VibratissimoCoordinator; import nodomain.freeyourgadget.gadgetbridge.devices.watch9.Watch9DeviceCoordinator; @@ -258,6 +259,7 @@ public class DeviceHelper { result.add(new PineTimeJFCoordinator()); result.add(new SG2Coordinator()); result.add(new LefunDeviceCoordinator()); + result.add(new SonySWR12DeviceCoordinator()); return result; } diff --git a/app/src/main/res/layout/activity_sonyswr12_settings.xml b/app/src/main/res/layout/activity_sonyswr12_settings.xml new file mode 100644 index 000000000..2c1ab8994 --- /dev/null +++ b/app/src/main/res/layout/activity_sonyswr12_settings.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values-bg/strings.xml b/app/src/main/res/values-bg/strings.xml index 151c838f7..757eeaea4 100644 --- a/app/src/main/res/values-bg/strings.xml +++ b/app/src/main/res/values-bg/strings.xml @@ -595,4 +595,9 @@ Изкл. Вкл. Няма данни + Настройки Sony SWR12 + Активирана ниска вибрация + Режимът за пестене на енергия е включен + Интелигентен алармен интервал в минути + За да промените настройките, първо трябва да се свържете с устройството! \ No newline at end of file diff --git a/app/src/main/res/values-ca/strings.xml b/app/src/main/res/values-ca/strings.xml index a1d51c956..b1e63f5a3 100644 --- a/app/src/main/res/values-ca/strings.xml +++ b/app/src/main/res/values-ca/strings.xml @@ -874,4 +874,9 @@ Repeteix la notificació de trucada Notificacions i trucades Calibració del Watch X Plus + Sony SWR12 + Configuració de Sony SWR12 + Vibració baixa activada + Interval d\'alarma intel·ligent en minuts + Per canviar la configuració, primer us heu de connectar al dispositiu. \ No newline at end of file diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml index cd11fa671..792bbc5c4 100644 --- a/app/src/main/res/values-cs/strings.xml +++ b/app/src/main/res/values-cs/strings.xml @@ -1047,4 +1047,10 @@ Kriket Veslovací trenažér Fotbal + Sony SWR12 + Sony SWR12 nastavení + Nízké vibrace povoleny + Režim úspory energie je zapnutý + Interval inteligentního alarmu v minutách + Chcete-li změnit nastavení, měli byste se nejprve připojit k zařízení! \ No newline at end of file diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 65c43c032..2e0632114 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -1059,4 +1059,10 @@ Heute Vergangenheit Keine Aktivitäten gefunden. + Sony SWR12 + Sony SWR12 Einstellungen + Geringe Vibration aktiviert + Der Energiesparmodus ist aktiviert + Intelligentes Alarmintervall in Minuten + Um Einstellungen zu ändern, sollten Sie zuerst eine Verbindung zum Gerät herstellen! \ 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 5227c67c3..c4e91c4ba 100644 --- a/app/src/main/res/values-el/strings.xml +++ b/app/src/main/res/values-el/strings.xml @@ -988,4 +988,10 @@ Ελλειπτικό μηχάνημα Ποδηλασία εσωτερικού χώρου Κολύμβηση (ανοιχτό νερό) + Sony SWR12 + Ρυθμίσεις Sony SWR12 + Ενεργοποιήθηκε χαμηλή δόνηση + Η λειτουργία εξοικονόμησης ενέργειας είναι ενεργοποιημένη + Έξυπνο διάστημα συναγερμού σε λίγα λεπτά + Για να αλλάξετε τις ρυθμίσεις πρέπει πρώτα να συνδεθείτε στη συσκευή! \ No newline at end of file diff --git a/app/src/main/res/values-en-rGB/strings.xml b/app/src/main/res/values-en-rGB/strings.xml index fbd4a9a98..7b15cc575 100644 --- a/app/src/main/res/values-en-rGB/strings.xml +++ b/app/src/main/res/values-en-rGB/strings.xml @@ -896,4 +896,10 @@ Choose the shortcuts on the band screen Shortcuts Set Alias + Sony SWR12 + Sony SWR12 settings + Low vibration enabled + Power saving mode on + Smart alarm interval in minutes + To change settings you should first connect to device! \ No newline at end of file diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 49416171d..061fd5f73 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -851,4 +851,10 @@ Llamadas y Notificaciones Calibracion Watch X Plus Establecer Alias + Sony SWR12 + Configuración de Sony SWR12 + Baja vibración habilitada + El modo de ahorro de energía está activado + Intervalo de alarma inteligente en minutos + Para cambiar la configuración, primero debe conectarse al dispositivo. \ No newline at end of file diff --git a/app/src/main/res/values-et/strings.xml b/app/src/main/res/values-et/strings.xml index 0c49d70ed..c9347cca4 100644 --- a/app/src/main/res/values-et/strings.xml +++ b/app/src/main/res/values-et/strings.xml @@ -855,4 +855,10 @@ Nimi Filter Statistika + Sony SWR12 + Sony SWR12 sätted + Madal vibratsioon on lubatud + Energiasäästurežiim on sisse lülitatud + Nutika häire intervall minutites + Seadete muutmiseks peaksite kõigepealt seadmega ühenduse looma! \ No newline at end of file diff --git a/app/src/main/res/values-fa/strings.xml b/app/src/main/res/values-fa/strings.xml index 0da36995b..a47dcba1c 100644 --- a/app/src/main/res/values-fa/strings.xml +++ b/app/src/main/res/values-fa/strings.xml @@ -125,4 +125,5 @@ مکان تعیین شده برای هواشناسی (CM/LOS) اضافه کردن برنامه‌ها به لیست سیاه nodomain.freeyourgadget.gadgetbridge.ButtonPressed + برای تغییر تنظیمات ابتدا باید به دستگاه متصل شوید! \ No newline at end of file diff --git a/app/src/main/res/values-fi/strings.xml b/app/src/main/res/values-fi/strings.xml index 1c8f36875..344ed368d 100644 --- a/app/src/main/res/values-fi/strings.xml +++ b/app/src/main/res/values-fi/strings.xml @@ -36,4 +36,9 @@ Määritä Siirrä ylös nodomain.freeyourgadget.gadgetbridge.ButtonPressed + Sony SWR12 asetukset + Matala tärinä käytössä + Virransäästötila on päällä + Älykäs hälytysväli minuutteina + Muuta asetuksia muodostamalla ensin yhteys laitteeseen! \ No newline at end of file diff --git a/app/src/main/res/values-fr-rCA/strings.xml b/app/src/main/res/values-fr-rCA/strings.xml index ab07b88ba..049f76618 100644 --- a/app/src/main/res/values-fr-rCA/strings.xml +++ b/app/src/main/res/values-fr-rCA/strings.xml @@ -885,4 +885,10 @@ Notifications et appels Calibrage de Watch X Plus Système + Sony SWR12 + Paramètres Sony SWR12 + Faible vibration activée + Le mode d\'économie d\'énergie est activé + Intervalle d\'alarme intelligente en minutes + Pour modifier les paramètres, vous devez d\'abord vous connecter à l\'appareil! \ No newline at end of file diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 1e2022a45..601893395 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -1057,4 +1057,10 @@ Temps de sommeil préféré en heures Intervalle de rappel d\'hydratation (en minutes) Le bracelet vibrera pour vous rappeler de boire de l\'eau Rappel d\'hydratation + Sony SWR12 + Paramètres Sony SWR12 + Faible vibration activée + Le mode d\'économie d\'énergie est activé + Intervalle d\'alarme intelligente en minutes + Pour modifier les paramètres, vous devez d\'abord vous connecter à l\'appareil! \ No newline at end of file diff --git a/app/src/main/res/values-gl/strings.xml b/app/src/main/res/values-gl/strings.xml index d5d321704..007d460e2 100644 --- a/app/src/main/res/values-gl/strings.xml +++ b/app/src/main/res/values-gl/strings.xml @@ -515,4 +515,9 @@ Axustes Alipay nodomain.freeyourgadget.gadgetbridge.ButtonPressed + Sony SWR12 + Axustes Sony SWR12 + Vibración baixa habilitada + Intervalo de alarma intelixente en minutos + Para cambiar a configuración, primeiro debes conectarte ao dispositivo. \ No newline at end of file diff --git a/app/src/main/res/values-he/strings.xml b/app/src/main/res/values-he/strings.xml index 7e47f278e..cbc089e4c 100644 --- a/app/src/main/res/values-he/strings.xml +++ b/app/src/main/res/values-he/strings.xml @@ -1058,4 +1058,10 @@ הפרש תזכורת שתייה (בדקות) הצמיד ירטוט כדי להזכיר לך לשתות מים תזכורת שתייה + Sony SWR12 + Sony SWR12 הגדרות + רטט נמוך מופעל + מצב חיסכון בחשמל פועל + מרווח אזעקה חכם בדקות + כדי לשנות הגדרות כדאי להתחבר תחילה למכשיר! \ No newline at end of file diff --git a/app/src/main/res/values-hi/strings.xml b/app/src/main/res/values-hi/strings.xml index 7506e24bd..d83731f29 100644 --- a/app/src/main/res/values-hi/strings.xml +++ b/app/src/main/res/values-hi/strings.xml @@ -152,4 +152,6 @@ अपनी गतिविधि को युक्ति में रखें सभी अलार्म बंद है कनेक्ट नहीं. + मिनटों में स्मार्ट अलार्म अंतराल + सेटिंग्स बदलने के लिए आपको पहले डिवाइस से कनेक्ट करना चाहिए! \ No newline at end of file diff --git a/app/src/main/res/values-hr/strings.xml b/app/src/main/res/values-hr/strings.xml index 1220c86fd..a0bb62fe7 100644 --- a/app/src/main/res/values-hr/strings.xml +++ b/app/src/main/res/values-hr/strings.xml @@ -61,4 +61,7 @@ Sinkroniziraj Doniraj Postavke + Uključen je način uštede energije + Pametni interval alarma u minutama + Da biste promijenili postavke, prvo se povežite s uređajem! \ 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 c099464d0..e50fbbb41 100644 --- a/app/src/main/res/values-hu/strings.xml +++ b/app/src/main/res/values-hu/strings.xml @@ -495,4 +495,9 @@ Értesítések közötti legrövidebb idő Rendszer Feketelistás Naptárak + Beállítások Sony SWR12 + Alacsony rezgés engedélyezve + Az energiatakarékos mód be van kapcsolva + Intelligens riasztási intervallum percekben + A beállítások módosításához először csatlakoznia kell az eszközhöz! \ No newline at end of file diff --git a/app/src/main/res/values-id/strings.xml b/app/src/main/res/values-id/strings.xml index 424b97f2f..8576b444f 100644 --- a/app/src/main/res/values-id/strings.xml +++ b/app/src/main/res/values-id/strings.xml @@ -34,4 +34,7 @@ Manajer App Melakukan factory reset akan menghapus seluruh data dari perangkat terkoneksi (jika didukung). Perangkat Xiaomi/Huami juga mengganti MAC address Bluetooth, sehingga akan muncul sebagai aplikasi baru di GadgetBridge. Debug + Pengaturan Sony SWR12 + Interval alarm pintar dalam beberapa menit + Untuk mengubah pengaturan, Anda harus menghubungkan ke perangkat terlebih dahulu! \ No newline at end of file diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 0c26bc3dd..f6a784e94 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -1041,4 +1041,10 @@ Nuoto (all\'aperto) No km + Sony SWR12 + Impostazioni Sony SWR12 + Bassa vibrazione abilitata + La modalità di risparmio energetico è attiva + Intervallo di allarme intelligente in pochi minuti + Per modificare le impostazioni devi prima connetterti al dispositivo! \ No newline at end of file diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index 9d8bc111f..c536cd4da 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -755,4 +755,10 @@ インドネシア語 切断通知 距離 + Sony SWR12 + Sony SWR12 設定 + 低振動対応 + 省電力モードがオンになっている + 分単位のスマートアラーム間隔 + 設定を変更するには、最初にデバイスに接続する必要があります! \ No newline at end of file diff --git a/app/src/main/res/values-ka/strings.xml b/app/src/main/res/values-ka/strings.xml index 6d833162d..ebc6e7d9f 100644 --- a/app/src/main/res/values-ka/strings.xml +++ b/app/src/main/res/values-ka/strings.xml @@ -30,4 +30,7 @@ გააქტიურება გამორტვა კონფიგურაცია + Sony SWR12 პარამეტრები + სიგნალის ჭკვიანი ინტერვალი წუთებში + პარამეტრების შესაცვლელად ჯერ უნდა დაუკავშირდეთ მოწყობილობას! \ No newline at end of file diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index 099eedb83..4f98f62a7 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -609,4 +609,5 @@ 올바르지 않은 주파수 87.5와 108.0 사이의 주파수를 입력하세요 nodomain.freeyourgadget.gadgetbridge.ButtonPressed + Sony SWR12 \ No newline at end of file diff --git a/app/src/main/res/values-lt/strings.xml b/app/src/main/res/values-lt/strings.xml index 1ba57eb79..fd2051d31 100644 --- a/app/src/main/res/values-lt/strings.xml +++ b/app/src/main/res/values-lt/strings.xml @@ -308,4 +308,10 @@ Snūstelti Leisti didelį MTU Padidinti perkėlimo greitį, bet gali ir neveikti kai kuriuose android įrenginiuose.. + Sony SWR12 + Sony SWR12 nustatymai + Įjungta maža vibracija + Įjungtas energijos taupymo režimas + Išmaniojo žadintuvo intervalas minutėmis + Norėdami pakeisti nustatymus, pirmiausia turite prisijungti prie įrenginio! \ No newline at end of file diff --git a/app/src/main/res/values-my/strings.xml b/app/src/main/res/values-my/strings.xml index fa089bd6e..e106ebc8b 100644 --- a/app/src/main/res/values-my/strings.xml +++ b/app/src/main/res/values-my/strings.xml @@ -37,4 +37,6 @@ အခ်က္အလက္မ်ားကိုသိမ္းဆည္းမည္ မခ်ိတ္ဆက္ထားျခင္းမရွိပါ , သတိေပးခ်က္မထားရေသးပါ nodomain.freeyourgadget.gadgetbridge.ButtonPressed + မိနစ်အတွင်းစမတ်နှိုးဆော်သံကြားကာလ + ချိန်ညှိချက်များကိုပြောင်းလဲရန်သင်ပထမ ဦး ဆုံးကိရိယာနှင့်ချိတ်ဆက်သင့်သည်! \ No newline at end of file diff --git a/app/src/main/res/values-nb-rNO/strings.xml b/app/src/main/res/values-nb-rNO/strings.xml index 097393a81..06f0bbb12 100644 --- a/app/src/main/res/values-nb-rNO/strings.xml +++ b/app/src/main/res/values-nb-rNO/strings.xml @@ -1016,4 +1016,10 @@ Drikkepåminnelseintervall (i minutter) Grensesnittspråk Brukt av LineageOS-værtilbyderen, andre Android-versjoner må bruke et program som «Ditt lokale vær». Mer info er å finne på Gadgetbridge-wiki-en. + Sony SWR12 + Sony SWR12 innstillinger + Lav vibrasjon aktivert + Strømsparingsmodus er på + Smart alarmintervall på få minutter + For å endre innstillinger, bør du først koble til enheten! \ 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 1127072a1..8599ece1c 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -956,4 +956,10 @@ Elliptische Trainer Binnenshuis fietsen Zwemmen (Open water) + Sony SWR12 + Sony SWR12 instellingen + Laag trillingsniveau ingeschakeld + Energiebesparende modus is ingeschakeld + Slimme alarminterval in minuten + Om instellingen te wijzigen, moet u eerst verbinding maken met het apparaat! \ No newline at end of file diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 625208a31..f7f2d0fb1 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -1029,4 +1029,10 @@ Krykiet Wiosłująca maszyna Trener eliptyczny + Sony SWR12 + Ustawienia Sony SWR12 + Włączono niski poziom wibracji + Tryb oszczędzania energii jest włączony + Inteligentny interwał alarmu w minutach + Aby zmienić ustawienia, należy najpierw połączyć się z urządzeniem! \ No newline at end of file diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index eedb5f51e..99fcc675a 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -1056,4 +1056,10 @@ hoje passado distante Links + Sony SWR12 + Configurações de Sony SWR12 + Baixa vibração habilitada + O modo de economia de energia está ativado + Intervalo de alarme inteligente em minutos + Para alterar as configurações, você deve primeiro se conectar ao dispositivo! \ 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 1e7a82d73..42cbd1ae8 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -1046,4 +1046,10 @@ Ritmo médio de voltas Média de braçadas Distância média das braçadas + Sony SWR12 + Configurações de Sony SWR12 + Baixa vibração habilitada + O modo de economia de energia está ativado + Intervalo de alarme inteligente em minutos + Para alterar as configurações, você deve primeiro se conectar ao dispositivo! \ No newline at end of file diff --git a/app/src/main/res/values-ro/strings.xml b/app/src/main/res/values-ro/strings.xml index 2edb5b68d..edeba4e2c 100644 --- a/app/src/main/res/values-ro/strings.xml +++ b/app/src/main/res/values-ro/strings.xml @@ -129,4 +129,8 @@ Salvare Configurație Deconectat(ă), alarma nu este setată. nodomain.freeyourgadget.gadgetbridge.ButtonPressed + Setari Sony SWR12 + Modul de economisire a energiei este activat + Interval de alarmă inteligentă în minute + Pentru a modifica setările, ar trebui să vă conectați mai întâi la dispozitiv! \ No newline at end of file diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 5014ccd76..1637bb9f9 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -1064,4 +1064,10 @@ Lefun Язык интерфейса Защита от потери + Sony SWR12 + Настройки Sony SWR12 + Слабая вибрация + Режима энергосбережения включен + Интервал умного будильника в минутах + Для изменения настроек необходимо сначала подключиться к устройству! \ No newline at end of file diff --git a/app/src/main/res/values-sk/strings.xml b/app/src/main/res/values-sk/strings.xml index c052e3fdf..aee8c2d55 100644 --- a/app/src/main/res/values-sk/strings.xml +++ b/app/src/main/res/values-sk/strings.xml @@ -491,4 +491,10 @@ Pripojiť Zap. nodomain.freeyourgadget.gadgetbridge.ButtonPressed + Sony SWR12 + Nastavenia Sony SWR12 + Nízke vibrácie sú povolené + Režim úspory energie je zapnutý + Interval inteligentného alarmu v minútach + Ak chcete zmeniť nastavenie, mali by ste sa najskôr pripojiť k zariadeniu! \ No newline at end of file diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index 61daafb9c..0df2fd4ba 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -48,4 +48,9 @@ Aktivera pulsmätare Avaktivera pulsmätare Konfigurera + Inställningar Sony SWR12 + Låg vibration aktiverad + Energisparläge är på + Smart larmintervall på några minuter + För att ändra inställningar bör du först ansluta till enheten! \ No newline at end of file diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index 83f1c5db1..fcab38fe3 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -296,7 +296,7 @@ \n \nLütfen önce .fw dosyasını, sonra .res dosyasını, ve son olarak .gps dosyasını kurun. .fw dosyasını kurduktan sonra bilekliğiniz yeniden başlatılacak. \n -\nNote: Bu dosyalar önceden kurulanlarla tamamen aynıysa .res ve .gps dosyalarını kurmanız gerekmez. +\nNote: Bu dosyalar önceden kurulanlarla tamamen aynıysa .res ve .gps dosyalarını kurmanız gerekmez. \n \nİLERLEMENİZ DURUMUNDA RİSK SİZE AİTTİR! Mi Band 4 aygıtınıza %s ürün yazılımını kurmak üzeresiniz. @@ -950,7 +950,7 @@ \n \nLütfen önce .fw dosyasını, sonra .res dosyasın kurun. .fw dosyasını kurduktan sonra bilekliğiniz yeniden başlatılacak. \n -\nNote: Bu dosyalar önceden kurulanlarla tamamen aynıysa .res dosyasını kurmanız gerekmez. +\nNote: Bu dosyalar önceden kurulanlarla tamamen aynıysa .res dosyasını kurmanız gerekmez. \n \nİLERLEMENİZ DURUMUNDA RİSK SİZE AİTTİR! TLW64 @@ -1088,4 +1088,9 @@ Sıvı alma hatırlatma aralığı (dakika olarak) Bileklik su içmenizi hatırlatmak için titreyecek Sıvı alma hatırlatıcı + Sony SWR12 + Sony SWR12 Ayarları + Düşük titreşim etkin + Dakikalar içinde akıllı alarm aralığı + Ayarları değiştirmek için önce cihaza bağlanmalısınız! \ No newline at end of file diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index 8ebf505b5..42b697c2a 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -1052,4 +1052,10 @@ \nПримітка: вам не потрібно встановлювати .res файл, якщо він такий самий був встановлений раніше. \n \nДІЄТЕ НА ВЛАСНИЙ РИЗИК! + Sony SWR12 + Sony SWR12 налаштування + Cлабка вібрація + Режим енергозбереження ввімкнено + Інтелектуальний інтервал тривоги в хвилинах + Щоб змінити налаштування, спочатку слід підключитися до пристрою! \ No newline at end of file diff --git a/app/src/main/res/values-vi/strings.xml b/app/src/main/res/values-vi/strings.xml index a5c98d6f0..72fe6b58b 100644 --- a/app/src/main/res/values-vi/strings.xml +++ b/app/src/main/res/values-vi/strings.xml @@ -190,4 +190,8 @@ Giờ Giờ và ngày nodomain.freeyourgadget.gadgetbridge.ButtonPressed + Cài đặt Sony SWR12 + Chế độ tiết kiệm pin đang bật + Khoảng thời gian báo thức thông minh trong vài phút + Để thay đổi cài đặt, trước tiên bạn nên kết nối với thiết bị! \ No newline at end of file diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index ab178e865..ae2662fd1 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -1069,4 +1069,10 @@ 水合提醒间隔(分钟) 当需要提醒喝水时,手环会震动 水合提醒 + Sony SWR12 + Sony SWR12 设置 + 低振动启用 + 省电模式已开启 + 智能警报间隔(以分钟为单位) + 要更改设置,您应该首先连接设备! \ No newline at end of file diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 1bba745d1..49edd533e 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -585,4 +585,6 @@ 游泳 這是一個來自 Gadgetbridge 的測試通知 測試通知 + Sony SWR12 + Sony SWR12 設定 \ No newline at end of file diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index fb85f5c2e..1afcadb36 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -986,4 +986,13 @@ 0 1 + + 0 + 10 + 20 + 30 + 40 + 50 + 60 + \ 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 24cd7e73c..56881c8f8 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -785,6 +785,7 @@ Bangle.js TLW64 PineTime (JF Firmware) + Sony SWR12 Choose export location Gadgetbridge notifications Gadgetbridge notifications high priority @@ -934,6 +935,11 @@ Ignore bonded devices Enabling this option will ignore devices that have been bonded/paired already when scanning Location must be turned on to scan for devices + Sony SWR12 Settings + Low vibration enabled + Power saving mode on + Smart alarm interval in minutes + To change settings you should first connect to device! Distance Uphill diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index 7573f8eec..dfbe19375 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -581,10 +581,14 @@ - + android:title="@string/zetime_title_settings" /> +