1
0
mirror of https://codeberg.org/Freeyourgadget/Gadgetbridge synced 2024-11-27 12:26:48 +01:00

added support for sony swr12

This commit is contained in:
opavlov 2020-09-01 23:15:20 +03:00
parent 8394928b94
commit 06a12300a1
82 changed files with 2024 additions and 4 deletions

View File

@ -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();

View File

@ -567,5 +567,8 @@
<activity
android:name=".devices.qhybrid.ImageEditActivity"
android:exported="true" />
<activity
android:name=".devices.sonyswr12.SonySWR12PrefActivity"
android:exported="true" />
</application>
</manifest>

View File

@ -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) {

View File

@ -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<? extends Activity> getPairingActivity() {
return null;
}
@Override
public boolean supportsActivityDataFetching() {
return true;
}
@Override
public boolean supportsActivityTracking() {
return true;
}
@Override
public SampleProvider<? extends ActivitySample> 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<? extends Activity> 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;
}
}

View File

@ -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<String> 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) {
}
});
}
}

View File

@ -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<SonySWR12Sample> {
public SonySWR12SampleProvider(GBDevice device, DaoSession session) {
super(device, session);
}
@Override
public AbstractDao<SonySWR12Sample, ?> 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();
}
}

View File

@ -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

View File

@ -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);

View File

@ -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;
}

View File

@ -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<SonySWR12DeviceSupport> 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<? extends Alarm> 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<BandAlarm> 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) {
}
}

View File

@ -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<ActivityBase> 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);
}
}
}

View File

@ -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));
}
}

View File

@ -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();
}

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -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);
}
}

View File

@ -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();
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}
}

View File

@ -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<ActivityBase> activityList;
private EventWithActivity(long timeStampSec, List<ActivityBase> 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<ActivityBase> 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();
}
}

View File

@ -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();
}
}

View File

@ -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);
}
}

View File

@ -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();
}
}

View File

@ -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;
}
}

View File

@ -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();
}
}

View File

@ -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<BandAlarm> alarms;
public BandAlarms(List<BandAlarm> 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();
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -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);
}
}

View File

@ -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();
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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();
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -0,0 +1,55 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_marginHorizontal="@dimen/activity_horizontal_margin"
android:layout_marginVertical="@dimen/activity_vertical_margin">
<androidx.appcompat.widget.SwitchCompat
android:id="@+id/lowVibration"
android:layout_width="match_parent"
android:layout_height="40dp"
android:text="@string/sonyswr12_settings_low_vibration"
app:layout_constraintTop_toTopOf="parent" />
<androidx.appcompat.widget.SwitchCompat
android:id="@+id/staminaOn"
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_marginTop="10dp"
android:text="@string/sonyswr12_settings_stamina"
app:layout_constraintTop_toBottomOf="@id/lowVibration" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/smartAlarmTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text="@string/sonyswr12_settings_alarm_interval"
android:textColor="@color/secondarytext"
app:layout_constraintTop_toBottomOf="@id/staminaOn" />
<androidx.appcompat.widget.AppCompatSpinner
android:id="@+id/smartAlarmSpinner"
android:layout_width="match_parent"
android:layout_height="40dp"
android:entries="@array/sonyswr12_smart_alarm_intervals"
app:layout_constraintTop_toBottomOf="@id/smartAlarmTitle" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/settingsDisabler"
android:layout_width="match_parent"
android:layout_height="0dp"
android:background="#cfff"
android:focusable="true"
android:clickable="true"
android:gravity="center"
android:textColor="@color/primarytext_light"
android:text="@string/sonyswr12_settings_alarm_warning"
android:visibility="gone"
tools:visibility="visible"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="@id/smartAlarmSpinner" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -595,4 +595,9 @@
<string name="off">Изкл.</string>
<string name="on">Вкл.</string>
<string name="no_data">Няма данни</string>
<string name="sonyswr12_settings_title">Настройки Sony SWR12</string>
<string name="sonyswr12_settings_low_vibration">Активирана ниска вибрация</string>
<string name="sonyswr12_settings_stamina">Режимът за пестене на енергия е включен</string>
<string name="sonyswr12_settings_alarm_interval">Интелигентен алармен интервал в минути</string>
<string name="sonyswr12_settings_alarm_warning">За да промените настройките, първо трябва да се свържете с устройството!</string>
</resources>

View File

@ -874,4 +874,9 @@
<string name="pref_title_notifications_and_calls_repeat_on_call">Repeteix la notificació de trucada</string>
<string name="pref_header_notifications_and_calls">Notificacions i trucades</string>
<string name="title_activity_LenovoWatch_calibration">Calibració del Watch X Plus</string>
<string name="devicetype_sonyswr12">Sony SWR12</string>
<string name="sonyswr12_settings_title">Configuració de Sony SWR12</string>
<string name="sonyswr12_settings_low_vibration">Vibració baixa activada</string>
<string name="sonyswr12_settings_alarm_interval">Interval d\'alarma intel·ligent en minuts</string>
<string name="sonyswr12_settings_alarm_warning">Per canviar la configuració, primer us heu de connectar al dispositiu.</string>
</resources>

View File

@ -1047,4 +1047,10 @@
<string name="activity_type_cricket">Kriket</string>
<string name="activity_type_rowing_machine">Veslovací trenažér</string>
<string name="activity_type_soccer">Fotbal</string>
<string name="devicetype_sonyswr12">Sony SWR12</string>
<string name="sonyswr12_settings_title">Sony SWR12 nastavení</string>
<string name="sonyswr12_settings_low_vibration">Nízké vibrace povoleny</string>
<string name="sonyswr12_settings_stamina">Režim úspory energie je zapnutý</string>
<string name="sonyswr12_settings_alarm_interval">Interval inteligentního alarmu v minutách</string>
<string name="sonyswr12_settings_alarm_warning">Chcete-li změnit nastavení, měli byste se nejprve připojit k zařízení!</string>
</resources>

View File

@ -1059,4 +1059,10 @@
<string name="activity_filter_to_placeholder">Heute</string>
<string name="activity_filter_from_placeholder">Vergangenheit</string>
<string name="chart_no_active_data">Keine Aktivitäten gefunden.</string>
<string name="devicetype_sonyswr12">Sony SWR12</string>
<string name="sonyswr12_settings_title">Sony SWR12 Einstellungen</string>
<string name="sonyswr12_settings_low_vibration">Geringe Vibration aktiviert</string>
<string name="sonyswr12_settings_stamina">Der Energiesparmodus ist aktiviert</string>
<string name="sonyswr12_settings_alarm_interval">Intelligentes Alarmintervall in Minuten</string>
<string name="sonyswr12_settings_alarm_warning">Um Einstellungen zu ändern, sollten Sie zuerst eine Verbindung zum Gerät herstellen!</string>
</resources>

View File

@ -988,4 +988,10 @@
<string name="activity_type_elliptical_trainer">Ελλειπτικό μηχάνημα</string>
<string name="activity_type_indoor_cycling">Ποδηλασία εσωτερικού χώρου</string>
<string name="activity_type_swimming_openwater">Κολύμβηση (ανοιχτό νερό)</string>
<string name="devicetype_sonyswr12">Sony SWR12</string>
<string name="sonyswr12_settings_title">Ρυθμίσεις Sony SWR12</string>
<string name="sonyswr12_settings_low_vibration">Ενεργοποιήθηκε χαμηλή δόνηση</string>
<string name="sonyswr12_settings_stamina">Η λειτουργία εξοικονόμησης ενέργειας είναι ενεργοποιημένη</string>
<string name="sonyswr12_settings_alarm_interval">Έξυπνο διάστημα συναγερμού σε λίγα λεπτά</string>
<string name="sonyswr12_settings_alarm_warning">Για να αλλάξετε τις ρυθμίσεις πρέπει πρώτα να συνδεθείτε στη συσκευή!</string>
</resources>

View File

@ -896,4 +896,10 @@
<string name="bip_prefs_shotcuts_summary">Choose the shortcuts on the band screen</string>
<string name="bip_prefs_shortcuts">Shortcuts</string>
<string name="controlcenter_set_alias">Set Alias</string>
<string name="devicetype_sonyswr12">Sony SWR12</string>
<string name="sonyswr12_settings_title">Sony SWR12 settings</string>
<string name="sonyswr12_settings_low_vibration">Low vibration enabled</string>
<string name="sonyswr12_settings_stamina">Power saving mode on</string>
<string name="sonyswr12_settings_alarm_interval">Smart alarm interval in minutes</string>
<string name="sonyswr12_settings_alarm_warning">To change settings you should first connect to device!</string>
</resources>

View File

@ -851,4 +851,10 @@
<string name="pref_header_notifications_and_calls">Llamadas y Notificaciones</string>
<string name="title_activity_LenovoWatch_calibration">Calibracion Watch X Plus</string>
<string name="controlcenter_set_alias">Establecer Alias</string>
<string name="devicetype_sonyswr12">Sony SWR12</string>
<string name="sonyswr12_settings_title">Configuración de Sony SWR12</string>
<string name="sonyswr12_settings_low_vibration">Baja vibración habilitada</string>
<string name="sonyswr12_settings_stamina">El modo de ahorro de energía está activado</string>
<string name="sonyswr12_settings_alarm_interval">Intervalo de alarma inteligente en minutos</string>
<string name="sonyswr12_settings_alarm_warning">Para cambiar la configuración, primero debe conectarse al dispositivo.</string>
</resources>

View File

@ -855,4 +855,10 @@
<string name="activity_filter_name_contains">Nimi</string>
<string name="activity_filter_filter_title">Filter</string>
<string name="activity_summaries_statistics">Statistika</string>
<string name="devicetype_sonyswr12">Sony SWR12</string>
<string name="sonyswr12_settings_title">Sony SWR12 sätted</string>
<string name="sonyswr12_settings_low_vibration">Madal vibratsioon on lubatud</string>
<string name="sonyswr12_settings_stamina">Energiasäästurežiim on sisse lülitatud</string>
<string name="sonyswr12_settings_alarm_interval">Nutika häire intervall minutites</string>
<string name="sonyswr12_settings_alarm_warning">Seadete muutmiseks peaksite kõigepealt seadmega ühenduse looma!</string>
</resources>

View File

@ -125,4 +125,5 @@
<string name="pref_title_weather_location">مکان تعیین شده برای هواشناسی (CM/LOS)</string>
<string name="pref_blacklist">اضافه کردن برنامه‌ها به لیست سیاه</string>
<string name="mi2_prefs_button_press_broadcast_default_value" translatable="false">nodomain.freeyourgadget.gadgetbridge.ButtonPressed</string>
<string name="sonyswr12_settings_alarm_warning">برای تغییر تنظیمات ابتدا باید به دستگاه متصل شوید!</string>
</resources>

View File

@ -36,4 +36,9 @@
<string name="app_configure">Määritä</string>
<string name="app_move_to_top">Siirrä ylös</string>
<string name="mi2_prefs_button_press_broadcast_default_value" translatable="false">nodomain.freeyourgadget.gadgetbridge.ButtonPressed</string>
<string name="sonyswr12_settings_title">Sony SWR12 asetukset</string>
<string name="sonyswr12_settings_low_vibration">Matala tärinä käytössä</string>
<string name="sonyswr12_settings_stamina">Virransäästötila on päällä</string>
<string name="sonyswr12_settings_alarm_interval">Älykäs hälytysväli minuutteina</string>
<string name="sonyswr12_settings_alarm_warning">Muuta asetuksia muodostamalla ensin yhteys laitteeseen!</string>
</resources>

View File

@ -885,4 +885,10 @@
<string name="pref_header_notifications_and_calls">Notifications et appels</string>
<string name="title_activity_LenovoWatch_calibration">Calibrage de Watch X Plus</string>
<string name="pref_theme_system">Système</string>
<string name="devicetype_sonyswr12">Sony SWR12</string>
<string name="sonyswr12_settings_title">Paramètres Sony SWR12</string>
<string name="sonyswr12_settings_low_vibration">Faible vibration activée</string>
<string name="sonyswr12_settings_stamina">Le mode d\'économie d\'énergie est activé</string>
<string name="sonyswr12_settings_alarm_interval">Intervalle d\'alarme intelligente en minutes</string>
<string name="sonyswr12_settings_alarm_warning">Pour modifier les paramètres, vous devez d\'abord vous connecter à l\'appareil!</string>
</resources>

View File

@ -1057,4 +1057,10 @@ Temps de sommeil préféré en heures</string>
<string name="lefun_prefs_hydration_reminder_interval_title">Intervalle de rappel d\'hydratation (en minutes)</string>
<string name="lefun_prefs_hydration_reminder_summary">Le bracelet vibrera pour vous rappeler de boire de l\'eau</string>
<string name="lefun_prefs_hydration_reminder_title">Rappel d\'hydratation</string>
<string name="devicetype_sonyswr12">Sony SWR12</string>
<string name="sonyswr12_settings_title">Paramètres Sony SWR12</string>
<string name="sonyswr12_settings_low_vibration">Faible vibration activée</string>
<string name="sonyswr12_settings_stamina">Le mode d\'économie d\'énergie est activé</string>
<string name="sonyswr12_settings_alarm_interval">Intervalle d\'alarme intelligente en minutes</string>
<string name="sonyswr12_settings_alarm_warning">Pour modifier les paramètres, vous devez d\'abord vous connecter à l\'appareil!</string>
</resources>

View File

@ -515,4 +515,9 @@
<string name="menuitem_settings">Axustes</string>
<string name="menuitem_alipay">Alipay</string>
<string name="mi2_prefs_button_press_broadcast_default_value" translatable="false">nodomain.freeyourgadget.gadgetbridge.ButtonPressed</string>
<string name="devicetype_sonyswr12">Sony SWR12</string>
<string name="sonyswr12_settings_title">Axustes Sony SWR12</string>
<string name="sonyswr12_settings_low_vibration">Vibración baixa habilitada</string>
<string name="sonyswr12_settings_alarm_interval">Intervalo de alarma intelixente en minutos</string>
<string name="sonyswr12_settings_alarm_warning">Para cambiar a configuración, primeiro debes conectarte ao dispositivo.</string>
</resources>

View File

@ -1058,4 +1058,10 @@
<string name="lefun_prefs_hydration_reminder_interval_title">הפרש תזכורת שתייה (בדקות)</string>
<string name="lefun_prefs_hydration_reminder_summary">הצמיד ירטוט כדי להזכיר לך לשתות מים</string>
<string name="lefun_prefs_hydration_reminder_title">תזכורת שתייה</string>
<string name="devicetype_sonyswr12">Sony SWR12</string>
<string name="sonyswr12_settings_title">Sony SWR12 הגדרות</string>
<string name="sonyswr12_settings_low_vibration">רטט נמוך מופעל</string>
<string name="sonyswr12_settings_stamina">מצב חיסכון בחשמל פועל</string>
<string name="sonyswr12_settings_alarm_interval">מרווח אזעקה חכם בדקות</string>
<string name="sonyswr12_settings_alarm_warning">כדי לשנות הגדרות כדאי להתחבר תחילה למכשיר!</string>
</resources>

View File

@ -152,4 +152,6 @@
<string name="pref_title_keep_data_on_device">अपनी गतिविधि को युक्ति में रखें</string>
<string name="user_feedback_all_alarms_disabled">सभी अलार्म बंद है</string>
<string name="device_not_connected">कनेक्ट नहीं.</string>
<string name="sonyswr12_settings_alarm_interval">मिनटों में स्मार्ट अलार्म अंतराल</string>
<string name="sonyswr12_settings_alarm_warning">सेटिंग्स बदलने के लिए आपको पहले डिवाइस से कनेक्ट करना चाहिए!</string>
</resources>

View File

@ -61,4 +61,7 @@
<string name="controlcenter_fetch_activity_data">Sinkroniziraj</string>
<string name="action_donate">Doniraj</string>
<string name="action_settings">Postavke</string>
<string name="sonyswr12_settings_stamina">Uključen je način uštede energije</string>
<string name="sonyswr12_settings_alarm_interval">Pametni interval alarma u minutama</string>
<string name="sonyswr12_settings_alarm_warning">Da biste promijenili postavke, prvo se povežite s uređajem!</string>
</resources>

View File

@ -495,4 +495,9 @@
<string name="pref_title_notifications_timeout">Értesítések közötti legrövidebb idő</string>
<string name="pref_theme_system">Rendszer</string>
<string name="title_activity_calblacklist">Feketelistás Naptárak</string>
<string name="sonyswr12_settings_title">Beállítások Sony SWR12</string>
<string name="sonyswr12_settings_low_vibration">Alacsony rezgés engedélyezve</string>
<string name="sonyswr12_settings_stamina">Az energiatakarékos mód be van kapcsolva</string>
<string name="sonyswr12_settings_alarm_interval">Intelligens riasztási intervallum percekben</string>
<string name="sonyswr12_settings_alarm_warning">A beállítások módosításához először csatlakoznia kell az eszközhöz!</string>
</resources>

View File

@ -34,4 +34,7 @@
<string name="title_activity_appmanager">Manajer App</string>
<string name="debugactivity_really_factoryreset">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.</string>
<string name="action_debug">Debug</string>
<string name="sonyswr12_settings_title">Pengaturan Sony SWR12</string>
<string name="sonyswr12_settings_alarm_interval">Interval alarm pintar dalam beberapa menit</string>
<string name="sonyswr12_settings_alarm_warning">Untuk mengubah pengaturan, Anda harus menghubungkan ke perangkat terlebih dahulu!</string>
</resources>

View File

@ -1041,4 +1041,10 @@
<string name="activity_type_swimming_openwater">Nuoto (all\'aperto)</string>
<string name="no">No</string>
<string name="km">km</string>
<string name="devicetype_sonyswr12">Sony SWR12</string>
<string name="sonyswr12_settings_title">Impostazioni Sony SWR12</string>
<string name="sonyswr12_settings_low_vibration">Bassa vibrazione abilitata</string>
<string name="sonyswr12_settings_stamina">La modalità di risparmio energetico è attiva</string>
<string name="sonyswr12_settings_alarm_interval">Intervallo di allarme intelligente in pochi minuti</string>
<string name="sonyswr12_settings_alarm_warning">Per modificare le impostazioni devi prima connetterti al dispositivo!</string>
</resources>

View File

@ -755,4 +755,10 @@
<string name="indonesian">インドネシア語</string>
<string name="prefs_disconnect_notification">切断通知</string>
<string name="Distance">距離</string>
<string name="devicetype_sonyswr12">Sony SWR12</string>
<string name="sonyswr12_settings_title">Sony SWR12 設定</string>
<string name="sonyswr12_settings_low_vibration">低振動対応</string>
<string name="sonyswr12_settings_stamina">省電力モードがオンになっている</string>
<string name="sonyswr12_settings_alarm_interval">分単位のスマートアラーム間隔</string>
<string name="sonyswr12_settings_alarm_warning">設定を変更するには、最初にデバイスに接続する必要があります!</string>
</resources>

View File

@ -30,4 +30,7 @@
<string name="appmanager_health_activate">გააქტიურება</string>
<string name="appmanager_health_deactivate">გამორტვა</string>
<string name="app_configure">კონფიგურაცია</string>
<string name="sonyswr12_settings_title">Sony SWR12 პარამეტრები</string>
<string name="sonyswr12_settings_alarm_interval">სიგნალის ჭკვიანი ინტერვალი წუთებში</string>
<string name="sonyswr12_settings_alarm_warning">პარამეტრების შესაცვლელად ჯერ უნდა დაუკავშირდეთ მოწყობილობას!</string>
</resources>

View File

@ -609,4 +609,5 @@
<string name="pref_invalid_frequency_title">올바르지 않은 주파수</string>
<string name="pref_invalid_frequency_message">87.5와 108.0 사이의 주파수를 입력하세요</string>
<string name="mi2_prefs_button_press_broadcast_default_value" translatable="false">nodomain.freeyourgadget.gadgetbridge.ButtonPressed</string>
<string name="devicetype_sonyswr12">Sony SWR12</string>
</resources>

View File

@ -308,4 +308,10 @@
<string name="alarm_snooze">Snūstelti</string>
<string name="pref_title_allow_high_mtu">Leisti didelį MTU</string>
<string name="pref_summary_allow_high_mtu">Padidinti perkėlimo greitį, bet gali ir neveikti kai kuriuose android įrenginiuose..</string>
<string name="devicetype_sonyswr12">Sony SWR12</string>
<string name="sonyswr12_settings_title">Sony SWR12 nustatymai</string>
<string name="sonyswr12_settings_low_vibration">Įjungta maža vibracija</string>
<string name="sonyswr12_settings_stamina">Įjungtas energijos taupymo režimas</string>
<string name="sonyswr12_settings_alarm_interval">Išmaniojo žadintuvo intervalas minutėmis</string>
<string name="sonyswr12_settings_alarm_warning">Norėdami pakeisti nustatymus, pirmiausia turite prisijungti prie įrenginio!</string>
</resources>

View File

@ -37,4 +37,6 @@
<string name="save_configuration">အခ်က္အလက္မ်ားကိုသိမ္းဆည္းမည္</string>
<string name="appwidget_not_connected">မခ်ိတ္ဆက္ထားျခင္းမရွိပါ , သတိေပးခ်က္မထားရေသးပါ</string>
<string name="mi2_prefs_button_press_broadcast_default_value" translatable="false">nodomain.freeyourgadget.gadgetbridge.ButtonPressed</string>
<string name="sonyswr12_settings_alarm_interval">မိနစ်အတွင်းစမတ်နှိုးဆော်သံကြားကာလ</string>
<string name="sonyswr12_settings_alarm_warning">ချိန်ညှိချက်များကိုပြောင်းလဲရန်သင်ပထမ ဦး ဆုံးကိရိယာနှင့်ချိတ်ဆက်သင့်သည်!</string>
</resources>

View File

@ -1016,4 +1016,10 @@
<string name="lefun_prefs_hydration_reminder_interval_title">Drikkepåminnelseintervall (i minutter)</string>
<string name="lefun_prefs_interface_language_title">Grensesnittspråk</string>
<string name="pref_title_weather_summary">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.</string>
<string name="devicetype_sonyswr12">Sony SWR12</string>
<string name="sonyswr12_settings_title">Sony SWR12 innstillinger</string>
<string name="sonyswr12_settings_low_vibration">Lav vibrasjon aktivert</string>
<string name="sonyswr12_settings_stamina">Strømsparingsmodus er på</string>
<string name="sonyswr12_settings_alarm_interval">Smart alarmintervall på få minutter</string>
<string name="sonyswr12_settings_alarm_warning">For å endre innstillinger, bør du først koble til enheten!</string>
</resources>

View File

@ -956,4 +956,10 @@
<string name="activity_type_elliptical_trainer">Elliptische Trainer</string>
<string name="activity_type_indoor_cycling">Binnenshuis fietsen</string>
<string name="activity_type_swimming_openwater">Zwemmen (Open water)</string>
<string name="devicetype_sonyswr12">Sony SWR12</string>
<string name="sonyswr12_settings_title">Sony SWR12 instellingen</string>
<string name="sonyswr12_settings_low_vibration">Laag trillingsniveau ingeschakeld</string>
<string name="sonyswr12_settings_stamina">Energiebesparende modus is ingeschakeld</string>
<string name="sonyswr12_settings_alarm_interval">Slimme alarminterval in minuten</string>
<string name="sonyswr12_settings_alarm_warning">Om instellingen te wijzigen, moet u eerst verbinding maken met het apparaat!</string>
</resources>

View File

@ -1029,4 +1029,10 @@
<string name="activity_type_cricket">Krykiet</string>
<string name="activity_type_rowing_machine">Wiosłująca maszyna</string>
<string name="activity_type_elliptical_trainer">Trener eliptyczny</string>
<string name="devicetype_sonyswr12">Sony SWR12</string>
<string name="sonyswr12_settings_title">Ustawienia Sony SWR12</string>
<string name="sonyswr12_settings_low_vibration">Włączono niski poziom wibracji</string>
<string name="sonyswr12_settings_stamina">Tryb oszczędzania energii jest włączony</string>
<string name="sonyswr12_settings_alarm_interval">Inteligentny interwał alarmu w minutach</string>
<string name="sonyswr12_settings_alarm_warning">Aby zmienić ustawienia, należy najpierw połączyć się z urządzeniem!</string>
</resources>

View File

@ -1056,4 +1056,10 @@
<string name="activity_filter_to_placeholder">hoje</string>
<string name="activity_filter_from_placeholder">passado distante</string>
<string name="about_links">Links</string>
<string name="devicetype_sonyswr12">Sony SWR12</string>
<string name="sonyswr12_settings_title">Configurações de Sony SWR12</string>
<string name="sonyswr12_settings_low_vibration">Baixa vibração habilitada</string>
<string name="sonyswr12_settings_stamina">O modo de economia de energia está ativado</string>
<string name="sonyswr12_settings_alarm_interval">Intervalo de alarme inteligente em minutos</string>
<string name="sonyswr12_settings_alarm_warning">Para alterar as configurações, você deve primeiro se conectar ao dispositivo!</string>
</resources>

View File

@ -1046,4 +1046,10 @@
<string name="averageLapPace">Ritmo médio de voltas</string>
<string name="averageStrokesPerSecond">Média de braçadas</string>
<string name="averageStrokeDistance">Distância média das braçadas</string>
<string name="devicetype_sonyswr12">Sony SWR12</string>
<string name="sonyswr12_settings_title">Configurações de Sony SWR12</string>
<string name="sonyswr12_settings_low_vibration">Baixa vibração habilitada</string>
<string name="sonyswr12_settings_stamina">O modo de economia de energia está ativado</string>
<string name="sonyswr12_settings_alarm_interval">Intervalo de alarme inteligente em minutos</string>
<string name="sonyswr12_settings_alarm_warning">Para alterar as configurações, você deve primeiro se conectar ao dispositivo!</string>
</resources>

View File

@ -129,4 +129,8 @@
<string name="save_configuration">Salvare Configurație</string>
<string name="appwidget_not_connected">Deconectat(ă), alarma nu este setată.</string>
<string name="mi2_prefs_button_press_broadcast_default_value" translatable="false">nodomain.freeyourgadget.gadgetbridge.ButtonPressed</string>
<string name="sonyswr12_settings_title">Setari Sony SWR12</string>
<string name="sonyswr12_settings_stamina">Modul de economisire a energiei este activat</string>
<string name="sonyswr12_settings_alarm_interval">Interval de alarmă inteligentă în minute</string>
<string name="sonyswr12_settings_alarm_warning">Pentru a modifica setările, ar trebui să vă conectați mai întâi la dispozitiv!</string>
</resources>

View File

@ -1064,4 +1064,10 @@
<string name="devicetype_lefun">Lefun</string>
<string name="lefun_prefs_interface_language_title">Язык интерфейса</string>
<string name="lefun_prefs_antilost_title">Защита от потери</string>
<string name="devicetype_sonyswr12">Sony SWR12</string>
<string name="sonyswr12_settings_title">Настройки Sony SWR12</string>
<string name="sonyswr12_settings_low_vibration">Слабая вибрация</string>
<string name="sonyswr12_settings_stamina">Режима энергосбережения включен</string>
<string name="sonyswr12_settings_alarm_interval">Интервал умного будильника в минутах</string>
<string name="sonyswr12_settings_alarm_warning">Для изменения настроек необходимо сначала подключиться к устройству!</string>
</resources>

View File

@ -491,4 +491,10 @@
<string name="controlcenter_connect">Pripojiť</string>
<string name="on">Zap.</string>
<string name="mi2_prefs_button_press_broadcast_default_value" translatable="false">nodomain.freeyourgadget.gadgetbridge.ButtonPressed</string>
<string name="devicetype_sonyswr12">Sony SWR12</string>
<string name="sonyswr12_settings_title">Nastavenia Sony SWR12</string>
<string name="sonyswr12_settings_low_vibration">Nízke vibrácie sú povolené</string>
<string name="sonyswr12_settings_stamina">Režim úspory energie je zapnutý</string>
<string name="sonyswr12_settings_alarm_interval">Interval inteligentného alarmu v minútach</string>
<string name="sonyswr12_settings_alarm_warning">Ak chcete zmeniť nastavenie, mali by ste sa najskôr pripojiť k zariadeniu!</string>
</resources>

View File

@ -48,4 +48,9 @@
<string name="appmanager_hrm_activate">Aktivera pulsmätare</string>
<string name="appmanager_hrm_deactivate">Avaktivera pulsmätare</string>
<string name="app_configure">Konfigurera</string>
<string name="sonyswr12_settings_title">Inställningar Sony SWR12</string>
<string name="sonyswr12_settings_low_vibration">Låg vibration aktiverad</string>
<string name="sonyswr12_settings_stamina">Energisparläge är på</string>
<string name="sonyswr12_settings_alarm_interval">Smart larmintervall på några minuter</string>
<string name="sonyswr12_settings_alarm_warning">För att ändra inställningar bör du först ansluta till enheten!</string>
</resources>

View File

@ -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!</string>
<string name="fw_upgrade_notice_miband4">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!</string>
<string name="devicetype_tlw64">TLW64</string>
@ -1088,4 +1088,9 @@
<string name="lefun_prefs_hydration_reminder_interval_title">Sıvı alma hatırlatma aralığı (dakika olarak)</string>
<string name="lefun_prefs_hydration_reminder_summary">Bileklik su içmenizi hatırlatmak için titreyecek</string>
<string name="lefun_prefs_hydration_reminder_title">Sıvı alma hatırlatıcı</string>
<string name="devicetype_sonyswr12">Sony SWR12</string>
<string name="sonyswr12_settings_title">Sony SWR12 Ayarları</string>
<string name="sonyswr12_settings_low_vibration">Düşük titreşim etkin</string>
<string name="sonyswr12_settings_alarm_interval">Dakikalar içinde akıllı alarm aralığı</string>
<string name="sonyswr12_settings_alarm_warning">Ayarları değiştirmek için önce cihaza bağlanmalısınız!</string>
</resources>

View File

@ -1052,4 +1052,10 @@
\nПримітка: вам не потрібно встановлювати .res файл, якщо він такий самий був встановлений раніше.
\n
\nДІЄТЕ НА ВЛАСНИЙ РИЗИК!</string>
<string name="devicetype_sonyswr12">Sony SWR12</string>
<string name="sonyswr12_settings_title">Sony SWR12 налаштування</string>
<string name="sonyswr12_settings_low_vibration">абка вібрація</string>
<string name="sonyswr12_settings_stamina">Режим енергозбереження ввімкнено</string>
<string name="sonyswr12_settings_alarm_interval">Інтелектуальний інтервал тривоги в хвилинах</string>
<string name="sonyswr12_settings_alarm_warning">Щоб змінити налаштування, спочатку слід підключитися до пристрою!</string>
</resources>

View File

@ -190,4 +190,8 @@
<string name="dateformat_time">Giờ</string>
<string name="dateformat_date_time">Giờ và ngày</string>
<string name="mi2_prefs_button_press_broadcast_default_value" translatable="false">nodomain.freeyourgadget.gadgetbridge.ButtonPressed</string>
<string name="sonyswr12_settings_title">Cài đặt Sony SWR12</string>
<string name="sonyswr12_settings_stamina">Chế độ tiết kiệm pin đang bật</string>
<string name="sonyswr12_settings_alarm_interval">Khoảng thời gian báo thức thông minh trong vài phút</string>
<string name="sonyswr12_settings_alarm_warning">Để thay đổi cài đặt, trước tiên bạn nên kết nối với thiết bị!</string>
</resources>

View File

@ -1069,4 +1069,10 @@
<string name="lefun_prefs_hydration_reminder_interval_title">水合提醒间隔(分钟)</string>
<string name="lefun_prefs_hydration_reminder_summary">当需要提醒喝水时,手环会震动</string>
<string name="lefun_prefs_hydration_reminder_title">水合提醒</string>
<string name="devicetype_sonyswr12">Sony SWR12</string>
<string name="sonyswr12_settings_title">Sony SWR12 设置</string>
<string name="sonyswr12_settings_low_vibration">低振动启用</string>
<string name="sonyswr12_settings_stamina">省电模式已开启</string>
<string name="sonyswr12_settings_alarm_interval">智能警报间隔(以分钟为单位)</string>
<string name="sonyswr12_settings_alarm_warning">要更改设置,您应该首先连接设备!</string>
</resources>

View File

@ -585,4 +585,6 @@
<string name="activity_type_swimming">游泳</string>
<string name="this_is_a_test_notification_from_gadgetbridge">這是一個來自 Gadgetbridge 的測試通知</string>
<string name="test_notification">測試通知</string>
<string name="devicetype_sonyswr12">Sony SWR12</string>
<string name="sonyswr12_settings_title">Sony SWR12 設定</string>
</resources>

View File

@ -986,4 +986,13 @@
<item>0</item>
<item>1</item>
</string-array>
<string-array name="sonyswr12_smart_alarm_intervals">
<item>0</item>
<item>10</item>
<item>20</item>
<item>30</item>
<item>40</item>
<item>50</item>
<item>60</item>
</string-array>
</resources>

View File

@ -785,6 +785,7 @@
<string name="devicetype_banglejs">Bangle.js</string>
<string name="devicetype_tlw64">TLW64</string>
<string name="devicetype_pinetime_jf">PineTime (JF Firmware)</string>
<string name="devicetype_sonyswr12">Sony SWR12</string>
<string name="choose_auto_export_location">Choose export location</string>
<string name="notification_channel_name">Gadgetbridge notifications</string>
<string name="notification_channel_high_priority_name">Gadgetbridge notifications high priority</string>
@ -934,6 +935,11 @@
<string name="ignore_bonded_devices">Ignore bonded devices</string>
<string name="ignore_bonded_devices_description">Enabling this option will ignore devices that have been bonded/paired already when scanning</string>
<string name="error_location_enabled_mandatory">Location must be turned on to scan for devices</string>
<string name="sonyswr12_settings_title">Sony SWR12 Settings</string>
<string name="sonyswr12_settings_low_vibration">Low vibration enabled</string>
<string name="sonyswr12_settings_stamina">Power saving mode on</string>
<string name="sonyswr12_settings_alarm_interval">Smart alarm interval in minutes</string>
<string name="sonyswr12_settings_alarm_warning">To change settings you should first connect to device!</string>
<!-- activity summary labels-->
<string name="distanceMeters">Distance</string>
<string name="ascentMeters">Uphill</string>

View File

@ -581,10 +581,14 @@
</PreferenceCategory>
</PreferenceScreen>
<Preference
<Preference
android:icon="@drawable/ic_device_zetime"
android:key="pref_key_zetime"
android:title="@string/zetime_title_settings"/>
android:title="@string/zetime_title_settings" />
<Preference
android:icon="@drawable/ic_device_default"
android:key="pref_key_sonyswr12"
android:title="@string/sonyswr12_settings_title" />
</PreferenceCategory>
<PreferenceCategory