/* Copyright (C) 2023-2024 akasaka / Genjitsu Labs
This file is part of Gadgetbridge.
Gadgetbridge is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Gadgetbridge is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see . */
package nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import android.text.TextUtils;
import android.widget.Toast;
import androidx.annotation.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.Locale;
import java.util.TimeZone;
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst;
import nodomain.freeyourgadget.gadgetbridge.database.DBHandler;
import nodomain.freeyourgadget.gadgetbridge.database.DBHelper;
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventFindPhone;
import nodomain.freeyourgadget.gadgetbridge.devices.sony.wena3.SonyWena3ActivitySampleProvider;
import nodomain.freeyourgadget.gadgetbridge.devices.sony.wena3.SonyWena3BehaviorSampleProvider;
import nodomain.freeyourgadget.gadgetbridge.devices.sony.wena3.SonyWena3CaloriesSampleProvider;
import nodomain.freeyourgadget.gadgetbridge.devices.sony.wena3.SonyWena3Constants;
import nodomain.freeyourgadget.gadgetbridge.devices.sony.wena3.SonyWena3EnergySampleProvider;
import nodomain.freeyourgadget.gadgetbridge.devices.sony.wena3.SonyWena3HeartRateSampleProvider;
import nodomain.freeyourgadget.gadgetbridge.devices.sony.wena3.SonyWena3SettingKeys;
import nodomain.freeyourgadget.gadgetbridge.devices.sony.wena3.SonyWena3StressSampleProvider;
import nodomain.freeyourgadget.gadgetbridge.devices.sony.wena3.SonyWena3Vo2SampleProvider;
import nodomain.freeyourgadget.gadgetbridge.database.AppSpecificNotificationSettingsRepository;
import nodomain.freeyourgadget.gadgetbridge.entities.Wena3BehaviorSample;
import nodomain.freeyourgadget.gadgetbridge.entities.Wena3CaloriesSample;
import nodomain.freeyourgadget.gadgetbridge.entities.Wena3EnergySample;
import nodomain.freeyourgadget.gadgetbridge.entities.Wena3HeartRateSample;
import nodomain.freeyourgadget.gadgetbridge.entities.Wena3ActivitySample;
import nodomain.freeyourgadget.gadgetbridge.entities.AppSpecificNotificationSetting;
import nodomain.freeyourgadget.gadgetbridge.entities.Wena3StressSample;
import nodomain.freeyourgadget.gadgetbridge.entities.Wena3Vo2Sample;
import nodomain.freeyourgadget.gadgetbridge.externalevents.CalendarReceiver;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.model.ActivityUser;
import nodomain.freeyourgadget.gadgetbridge.model.Alarm;
import nodomain.freeyourgadget.gadgetbridge.model.CalendarEventSpec;
import nodomain.freeyourgadget.gadgetbridge.model.CallSpec;
import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec;
import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec;
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
import nodomain.freeyourgadget.gadgetbridge.service.btle.AbstractBTLEDeviceSupport;
import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.SetDeviceStateAction;
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.logic.ActivitySyncPacketProcessor;
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.logic.parsers.BehaviorPacketParser;
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.logic.parsers.CaloriesPacketParser;
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.logic.parsers.EnergyPacketParser;
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.logic.parsers.HeartRatePacketParser;
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.logic.parsers.StepsPacketParser;
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.logic.parsers.StressPacketParser;
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.logic.parsers.Vo2MaxPacketParser;
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.activity.ActivitySyncDataPacket;
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.activity.ActivitySyncStartPacket;
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.activity.ActivitySyncTimePacketTypeA;
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.activity.ActivitySyncTimePacketTypeB;
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.calendar.CalendarEntry;
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.notification.NotificationArrival;
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.notification.NotificationRemoval;
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.notification.defines.LedColor;
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.notification.defines.NotificationFlags;
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.notification.defines.NotificationKind;
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.notification.defines.VibrationKind;
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.notification.defines.VibrationOptions;
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.settings.AlarmListSettings;
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.settings.AutoPowerOffSettings;
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.settings.BodyPropertiesSetting;
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.settings.CalendarNotificationEnableSetting;
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.settings.CameraAppTypeSetting;
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.settings.DayStartHourSetting;
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.settings.DeviceButtonActionSetting;
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.settings.DisplaySetting;
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.settings.DoNotDisturbSettings;
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.settings.GoalStepsSetting;
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.settings.HomeIconOrderSetting;
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.settings.MenuIconSetting;
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.settings.SingleAlarmSetting;
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.settings.StatusPageOrderSetting;
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.settings.TimeSetting;
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.settings.TimeZoneSetting;
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.settings.VibrationSetting;
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.settings.defines.DeviceButtonActionId;
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.settings.defines.DisplayDesign;
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.settings.defines.DisplayOrientation;
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.settings.defines.FontSize;
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.settings.defines.GenderSetting;
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.settings.defines.HomeIconId;
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.settings.defines.Language;
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.settings.defines.MenuIconId;
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.settings.defines.StatusPageId;
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.settings.defines.VibrationStrength;
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.status.BatteryLevelInfo;
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.status.DeviceInfo;
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.status.MusicInfo;
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.status.NotificationServiceStatusRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.status.StatusRequestType;
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.status.Weather;
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.status.WeatherDay;
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.status.WeatherReport;
import nodomain.freeyourgadget.gadgetbridge.util.GB;
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
public class SonyWena3DeviceSupport extends AbstractBTLEDeviceSupport {
private static final int INCOMING_CALL_ID = 3939;
private static final Logger LOG = LoggerFactory.getLogger(SonyWena3DeviceSupport.class);
private String lastMusicInfo = null;
private MusicStateSpec lastMusicState = null;
private final List calendarEvents = new ArrayList<>();
private final ActivitySyncPacketProcessor activitySyncHandler = new ActivitySyncPacketProcessor();
private AppSpecificNotificationSettingsRepository perAppNotificationSettingsRepository = null;
public SonyWena3DeviceSupport() {
super(LoggerFactory.getLogger(SonyWena3DeviceSupport.class));
addSupportedService(SonyWena3Constants.COMMON_SERVICE_UUID);
addSupportedService(SonyWena3Constants.NOTIFICATION_SERVICE_UUID);
addSupportedService(SonyWena3Constants.ACTIVITY_LOG_SERVICE_UUID);
activitySyncHandler.registerParser(new StepsPacketParser());
activitySyncHandler.registerParser(new HeartRatePacketParser());
activitySyncHandler.registerParser(new StressPacketParser());
activitySyncHandler.registerParser(new EnergyPacketParser());
activitySyncHandler.registerParser(new BehaviorPacketParser());
activitySyncHandler.registerParser(new CaloriesPacketParser());
activitySyncHandler.registerParser(new Vo2MaxPacketParser());
}
@Override
public boolean useAutoConnect() {
return true;
}
@Override
protected TransactionBuilder initializeDevice(TransactionBuilder builder) {
builder.add(new SetDeviceStateAction(getDevice(), GBDevice.State.INITIALIZING, getContext()));
if(perAppNotificationSettingsRepository == null) {
perAppNotificationSettingsRepository = new AppSpecificNotificationSettingsRepository(getDevice());
}
getDevice().setFirmwareVersion("...");
getDevice().setFirmwareVersion2("...");
sendAllSettings(builder);
sendAllCalendarEvents(builder);
// Get battery state
builder.read(getCharacteristic(SonyWena3Constants.COMMON_SERVICE_CHARACTERISTIC_STATE_UUID));
// Subscribe to updates
builder.notify(getCharacteristic(SonyWena3Constants.COMMON_SERVICE_CHARACTERISTIC_STATE_UUID), true);
builder.notify(getCharacteristic(SonyWena3Constants.COMMON_SERVICE_CHARACTERISTIC_CONTROL_UUID), true);
builder.notify(getCharacteristic(SonyWena3Constants.COMMON_SERVICE_CHARACTERISTIC_INFO_UUID), true);
builder.notify(getCharacteristic(SonyWena3Constants.COMMON_SERVICE_CHARACTERISTIC_MODE_UUID), true);
builder.notify(getCharacteristic(SonyWena3Constants.NOTIFICATION_SERVICE_CHARACTERISTIC_UUID), true);
builder.notify(getCharacteristic(SonyWena3Constants.ACTIVITY_LOG_CHARACTERISTIC_UUID), true);
// Get serial number and firmware version
builder.read(getCharacteristic(SonyWena3Constants.COMMON_SERVICE_CHARACTERISTIC_INFO_UUID));
// Finally, sync activity data
requestActivityDataDownload(builder, false);
builder.add(new SetDeviceStateAction(getDevice(), GBDevice.State.INITIALIZED, getContext()));
CalendarReceiver.forceSync();
return builder;
}
@Override
public boolean onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
if(characteristic.getUuid().equals(SonyWena3Constants.COMMON_SERVICE_CHARACTERISTIC_STATE_UUID)) {
BatteryLevelInfo stateInfo = new BatteryLevelInfo(characteristic.getValue());
handleGBDeviceEvent(stateInfo.toDeviceEvent());
return true;
}
else if (characteristic.getUuid().equals(SonyWena3Constants.NOTIFICATION_SERVICE_CHARACTERISTIC_UUID)) {
NotificationServiceStatusRequest request = new NotificationServiceStatusRequest(characteristic.getValue());
if(request.requestType == StatusRequestType.MUSIC_INFO_FETCH.value) {
LOG.debug("Request for music info received");
if(lastMusicState != null && lastMusicState.state == MusicStateSpec.STATE_PLAYING && lastMusicInfo != null) {
sendMusicInfo(lastMusicInfo);
}
return true;
}
else if(request.requestType == StatusRequestType.LOCATE_PHONE.value) {
LOG.debug("Request for find phone received");
GBDeviceEventFindPhone findPhoneEvent = new GBDeviceEventFindPhone();
findPhoneEvent.event = GBDeviceEventFindPhone.Event.START;
evaluateGBDeviceEvent(findPhoneEvent);
return true;
}
else if(request.requestType == StatusRequestType.BACKGROUND_SYNC_REQUEST.value) {
Prefs prefs = new Prefs(GBApplication.getDeviceSpecificSharedPrefs(getDevice().getAddress()));
boolean enableSync = prefs.getBoolean(SonyWena3SettingKeys.BACKGROUND_SYNC, true);
if(enableSync) {
LOG.info("Request for background activity sync received");
requestActivityDataDownload(null, false);
}
return true;
}
else if(request.requestType == StatusRequestType.GET_CALENDAR.value) {
CalendarReceiver.forceSync();
sendAllCalendarEvents(null);
}
else {
LOG.warn("Unknown NotificationServiceStatusRequest " + request.requestType);
}
} else if(characteristic.getUuid().equals(SonyWena3Constants.ACTIVITY_LOG_CHARACTERISTIC_UUID)) {
ActivitySyncDataPacket asdp = new ActivitySyncDataPacket(characteristic.getValue());
activitySyncHandler.receivePacket(asdp, getDevice());
}
return false;
}
@Override
public boolean onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
if(characteristic.getUuid().equals(SonyWena3Constants.COMMON_SERVICE_CHARACTERISTIC_STATE_UUID)) {
BatteryLevelInfo stateInfo = new BatteryLevelInfo(characteristic.getValue());
handleGBDeviceEvent(stateInfo.toDeviceEvent());
return true;
} else if(characteristic.getUuid().equals(SonyWena3Constants.COMMON_SERVICE_CHARACTERISTIC_INFO_UUID)) {
DeviceInfo deviceInfo = new DeviceInfo(characteristic.getValue());
handleGBDeviceEvent(deviceInfo.toDeviceEvent());
return true;
}
return false;
}
@Override
public boolean onCharacteristicWriteRequest(BluetoothDevice device, int requestId, BluetoothGattCharacteristic characteristic, boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) {
return super.onCharacteristicWriteRequest(device, requestId, characteristic, preparedWrite, responseNeeded, offset, value);
}
private void sendCurrentTime(@Nullable TransactionBuilder b) {
try {
TransactionBuilder builder = b == null ? performInitialized("updateDateTime") : b;
TimeZone tz = TimeZone.getDefault();
Date currentTime = new Date();
builder.write(
getCharacteristic(SonyWena3Constants.COMMON_SERVICE_CHARACTERISTIC_CONTROL_UUID),
new TimeSetting(currentTime).toByteArray()
);
builder.write(
getCharacteristic(SonyWena3Constants.COMMON_SERVICE_CHARACTERISTIC_CONTROL_UUID),
new TimeZoneSetting(tz, currentTime).toByteArray()
);
if(b == null) performImmediately(builder);
} catch (IOException e) {
LOG.warn("Unable to send current time", e);
}
}
private void sendMusicInfo(@Nullable String musicInfo) {
try {
TransactionBuilder builder = performInitialized("updateMusic");
builder.write(
getCharacteristic(SonyWena3Constants.NOTIFICATION_SERVICE_CHARACTERISTIC_UUID),
new MusicInfo(musicInfo != null ? musicInfo: "").toByteArray()
);
performImmediately(builder);
} catch (IOException e) {
LOG.warn("Unable to send music info", e);
}
}
@Override
public void onFetchRecordedData(int dataTypes) {
requestActivityDataDownload(null, false);
}
private void requestActivityDataDownload(@Nullable TransactionBuilder b, boolean syncAll) {
try {
TransactionBuilder builder = b == null ? performInitialized("activitySync") : b;
BluetoothGattCharacteristic sportsCharacteristic = getCharacteristic(SonyWena3Constants.ACTIVITY_LOG_CHARACTERISTIC_UUID);
Date stepLastSyncTime = null;
Date heartLastSyncTime = null;
Date behaviorLastSyncTime = null;
Date vo2LastSyncTime = null;
Date stressLastSyncTime = null;
Date energyLastSyncTime = null;
Date caloriesLastSyncTime = null;
Date eventsLastSyncTime = null; // TODO: find out what this is
if(!syncAll) {
try (DBHandler db = GBApplication.acquireDB()) {
Wena3HeartRateSample heartSample = new SonyWena3HeartRateSampleProvider(getDevice(), db.getDaoSession()).getLatestSample();
if(heartSample != null) {
heartLastSyncTime = new Date(heartSample.getTimestamp());
}
Wena3StressSample stressSample = new SonyWena3StressSampleProvider(getDevice(), db.getDaoSession()).getLatestSample();
if(stressSample != null) {
stressLastSyncTime = new Date(stressSample.getTimestamp());
}
Wena3ActivitySample stepsSample = new SonyWena3ActivitySampleProvider(getDevice(), db.getDaoSession()).getLatestActivitySample();
if(stepsSample != null) {
stepLastSyncTime = new Date(stepsSample.getTimestamp() * 1000L);
}
Wena3BehaviorSample behaviorSample = new SonyWena3BehaviorSampleProvider(getDevice(), db.getDaoSession()).getLatestSample();
if(behaviorSample != null) {
behaviorLastSyncTime = new Date(behaviorSample.getTimestamp());
}
Wena3Vo2Sample vo2Sample = new SonyWena3Vo2SampleProvider(getDevice(), db.getDaoSession()).getLatestSample();
if(vo2Sample != null) {
vo2LastSyncTime = new Date(vo2Sample.getTimestamp());
}
Wena3EnergySample energySample = new SonyWena3EnergySampleProvider(getDevice(), db.getDaoSession()).getLatestSample();
if(energySample != null) {
energyLastSyncTime = new Date(energySample.getTimestamp());
}
Wena3CaloriesSample caloriesSample = new SonyWena3CaloriesSampleProvider(getDevice(), db.getDaoSession()).getLatestSample();
if(caloriesSample != null) {
caloriesLastSyncTime = new Date(caloriesSample.getTimestamp());
}
LOG.info(
"Found last sync dates: " +
"\nsteps = " + stepLastSyncTime +
"\nheart = " + heartLastSyncTime +
"\nbehavior = " + behaviorLastSyncTime +
"\nvo2 = " + vo2LastSyncTime +
"\nstress = " + stressLastSyncTime +
"\nenergy = " + energyLastSyncTime +
"\ncalories = " + caloriesLastSyncTime +
"\nevents = " + eventsLastSyncTime
);
} catch (Exception e) {
LOG.warn("Failed to communicate with DB to find last sync timestamps -- syncing everything:", e);
}
}
builder.write(
sportsCharacteristic,
new ActivitySyncTimePacketTypeA(stepLastSyncTime, heartLastSyncTime, behaviorLastSyncTime, vo2LastSyncTime).toByteArray()
);
builder.write(
sportsCharacteristic,
new ActivitySyncTimePacketTypeB(stressLastSyncTime, energyLastSyncTime, caloriesLastSyncTime, eventsLastSyncTime).toByteArray()
);
builder.write(sportsCharacteristic, new ActivitySyncStartPacket().toByteArray());
if(b == null) performImmediately(builder);
} catch (IOException e) {
LOG.warn("Unable to force request a sync", e);
}
}
private void sendWeatherInfo(WeatherReport weather, @Nullable TransactionBuilder b) {
try {
TransactionBuilder builder = b == null ? performInitialized("updateWeather") : b;
builder.write(
getCharacteristic(SonyWena3Constants.NOTIFICATION_SERVICE_CHARACTERISTIC_UUID),
weather.toByteArray()
);
if(b == null) performImmediately(builder);
} catch (IOException e) {
LOG.warn("Unable to send current weather", e);
}
}
@Override
public void onSetMusicInfo(MusicSpec musicSpec) {
StringBuilder sb = new StringBuilder();
boolean hasTrackName = musicSpec.track != null && musicSpec.track.trim().length() > 0;
boolean hasArtistName = musicSpec.artist != null && musicSpec.artist.trim().length() > 0;
if(hasTrackName) {
sb.append(musicSpec.track.trim());
}
if(hasArtistName && hasTrackName) {
sb.append(" / ");
}
if(hasArtistName) {
sb.append(musicSpec.artist.trim());
}
lastMusicInfo = sb.toString();
sendMusicInfo(lastMusicInfo);
}
@Override
public void onSetMusicState(MusicStateSpec stateSpec) {
if(stateSpec.state == MusicStateSpec.STATE_PLAYING && lastMusicInfo != null) {
sendMusicInfo(lastMusicInfo);
} else if (stateSpec.state == MusicStateSpec.STATE_STOPPED || stateSpec.state == MusicStateSpec.STATE_PAUSED) {
sendMusicInfo("");
}
lastMusicState = stateSpec;
}
@Override
public void onSetCallState(CallSpec callSpec) {
Prefs prefs = new Prefs(GBApplication.getDeviceSpecificSharedPrefs(getDevice().getAddress()));
boolean enableNotifications = prefs.getBoolean(DeviceSettingsPreferenceConst.PREF_NOTIFICATION_ENABLE, false);
boolean enableCalls = prefs.getBoolean(SonyWena3SettingKeys.RECEIVE_CALLS, true);
if(!enableCalls || !enableNotifications) {
LOG.info("Calls are disabled, ignoring");
return;
}
try {
TransactionBuilder builder = performInitialized("sendCall");
if(callSpec.command == CallSpec.CALL_INCOMING) {
LedColor led = LedColor.valueOf(prefs.getString(SonyWena3SettingKeys.DEFAULT_CALL_LED_COLOR, LedColor.WHITE.name()).toUpperCase());
VibrationKind vibra = VibrationKind.valueOf(prefs.getString(SonyWena3SettingKeys.DEFAULT_CALL_VIBRATION_PATTERN, VibrationKind.CONTINUOUS.name()).toUpperCase());
boolean vibraContinuous = false;
int vibraRepeats = prefs.getInt(SonyWena3SettingKeys.DEFAULT_CALL_VIBRATION_REPETITION, 0);
if(vibraRepeats == 0) {
vibraContinuous = true;
}
builder.write(
getCharacteristic(SonyWena3Constants.NOTIFICATION_SERVICE_CHARACTERISTIC_UUID),
new NotificationArrival(
NotificationKind.CALL,
INCOMING_CALL_ID,
callSpec.number,
callSpec.name,
"",
new Date(),
new VibrationOptions(vibra, vibraRepeats, vibraContinuous),
led,
NotificationFlags.NONE
).toByteArray()
);
} else {
builder.write(
getCharacteristic(SonyWena3Constants.NOTIFICATION_SERVICE_CHARACTERISTIC_UUID),
new NotificationRemoval(NotificationKind.CALL, INCOMING_CALL_ID).toByteArray()
);
}
performImmediately(builder);
} catch (IOException e) {
LOG.warn("Unable to send call", e);
}
}
@Override
public void onNotification(NotificationSpec notificationSpec) {
Prefs prefs = new Prefs(GBApplication.getDeviceSpecificSharedPrefs(getDevice().getAddress()));
boolean enableNotifications = prefs.getBoolean(DeviceSettingsPreferenceConst.PREF_NOTIFICATION_ENABLE, false);
if(!enableNotifications) return;
try {
TransactionBuilder builder = performInitialized("sendNotify");
StringBuilder bodyBuilder = new StringBuilder();
if(notificationSpec.sender != null && notificationSpec.sender.length() > 0) {
bodyBuilder.append(notificationSpec.sender);
bodyBuilder.append(":");
}
if(notificationSpec.title != null && notificationSpec.title.length() > 0) {
if(bodyBuilder.length() > 0) {
bodyBuilder.append("\n");
}
bodyBuilder.append(notificationSpec.title);
bodyBuilder.append(":");
}
if(notificationSpec.subject != null && notificationSpec.subject.length() > 0) {
if(bodyBuilder.length() > 0) {
bodyBuilder.append("\n");
}
bodyBuilder.append("- ");
bodyBuilder.append(notificationSpec.subject);
}
if(notificationSpec.body != null) {
if(bodyBuilder.length() > 0) {
bodyBuilder.append("\n");
}
bodyBuilder.append(notificationSpec.body);
}
String actionLabel = notificationSpec.attachedActions.isEmpty() ? "" :
notificationSpec.attachedActions.get(0).title;
boolean hasAction = !notificationSpec.attachedActions.isEmpty();
NotificationFlags flags = NotificationFlags.NONE;
// TODO: Figure out how actions work
LedColor led = LedColor.valueOf(prefs.getString(SonyWena3SettingKeys.DEFAULT_LED_COLOR, LedColor.BLUE.name()).toUpperCase());
VibrationKind vibra = VibrationKind.valueOf(prefs.getString(SonyWena3SettingKeys.DEFAULT_VIBRATION_PATTERN, VibrationKind.BASIC.name()).toUpperCase());
boolean vibraContinuous = false;
int vibraRepeats = prefs.getInt(SonyWena3SettingKeys.DEFAULT_VIBRATION_REPETITION, 1);
if(notificationSpec.sourceAppId != null) {
AppSpecificNotificationSetting appSpecificSetting = perAppNotificationSettingsRepository.getSettingsForAppId(notificationSpec.sourceAppId);
if(appSpecificSetting != null) {
if(appSpecificSetting.getLedPattern() != null) {
led = LedColor.valueOf(appSpecificSetting.getLedPattern().toUpperCase());
}
if(appSpecificSetting.getVibrationPattern() != null) {
vibra = VibrationKind.valueOf(appSpecificSetting.getVibrationPattern().toUpperCase());
}
if(appSpecificSetting.getVibrationRepetition() != null) {
vibraRepeats = Integer.valueOf(appSpecificSetting.getVibrationRepetition());
}
}
}
if(vibraRepeats == 0) {
vibraContinuous = true;
}
builder.write(
getCharacteristic(SonyWena3Constants.NOTIFICATION_SERVICE_CHARACTERISTIC_UUID),
new NotificationArrival(
NotificationKind.APP,
notificationSpec.getId(),
notificationSpec.sourceName,
bodyBuilder.toString(),
actionLabel,
new Date(notificationSpec.when),
new VibrationOptions(vibra, vibraRepeats, vibraContinuous),
led,
flags
).toByteArray()
);
performImmediately(builder);
} catch (IOException e) {
LOG.warn("Unable to send notification", e);
}
}
@Override
public void onDeleteNotification(int id) {
Prefs prefs = new Prefs(GBApplication.getDeviceSpecificSharedPrefs(getDevice().getAddress()));
boolean enableNotifications = prefs.getBoolean(DeviceSettingsPreferenceConst.PREF_NOTIFICATION_ENABLE, false);
if(!enableNotifications) return;
try {
TransactionBuilder builder = performInitialized("delNotify");
builder.write(
getCharacteristic(SonyWena3Constants.NOTIFICATION_SERVICE_CHARACTERISTIC_UUID),
new NotificationRemoval(NotificationKind.APP, id).toByteArray()
);
performImmediately(builder);
} catch (IOException e) {
LOG.warn("Unable to send notification", e);
}
}
@Override
public void onSendWeather(ArrayList weatherSpecs) {
WeatherSpec weatherSpec = weatherSpecs.get(0);
if(weatherSpec.forecasts.size() < 4) return;
ArrayList days = new ArrayList<>();
// Add today
days.add(
new WeatherDay(
Weather.fromOpenWeatherMap(weatherSpec.currentConditionCode),
Weather.fromOpenWeatherMap(weatherSpec.currentConditionCode),
weatherSpec.todayMaxTemp,
weatherSpec.todayMinTemp
)
);
// Add other days
for(int i = 0; i < 4; i++) {
days.add(WeatherDay.fromSpec(weatherSpec.forecasts.get(i)));
}
WeatherReport report = new WeatherReport(days);
sendWeatherInfo(report, null);
}
@Override
public void onSetAlarms(ArrayList extends Alarm> alarms) {
try {
Prefs prefs = new Prefs(GBApplication.getDeviceSpecificSharedPrefs(getDevice().getAddress()));
TransactionBuilder builder = performInitialized("alarmSetting");
assert alarms.size() <= SonyWena3Constants.ALARM_SLOTS;
int wakeupMargin = prefs.getInt(SonyWena3SettingKeys.SMART_WAKEUP_MARGIN_MINUTES,
SonyWena3Constants.ALARM_DEFAULT_SMART_WAKEUP_MARGIN_MINUTES);
for(
int i = 0;
i < SonyWena3Constants.ALARM_SLOTS;
i += AlarmListSettings.MAX_ALARMS_IN_PACKET
) {
AlarmListSettings pkt = new AlarmListSettings(new ArrayList<>(), i);
for(int j = 0; j < AlarmListSettings.MAX_ALARMS_IN_PACKET; j++) {
if(i + j < alarms.size()) {
Alarm alarm = alarms.get(i + j);
SingleAlarmSetting sas = new SingleAlarmSetting(
alarm.getEnabled(),
(byte) alarm.getRepetition(),
alarm.getSmartWakeup() ? wakeupMargin : 0,
alarm.getHour(),
alarm.getMinute()
);
pkt.alarms.add(sas);
}
}
builder.write(
getCharacteristic(SonyWena3Constants.COMMON_SERVICE_CHARACTERISTIC_CONTROL_UUID),
pkt.toByteArray()
);
}
performImmediately(builder);
} catch (IOException e) {
LOG.warn("Unable to send alarms", e);
GB.toast("Failed to save alarms", Toast.LENGTH_SHORT, GB.ERROR);
}
}
private void sendDisplaySettings(TransactionBuilder b) {
Prefs prefs = new Prefs(GBApplication.getDeviceSpecificSharedPrefs(getDevice().getAddress()));
String localeString = prefs.getString(DeviceSettingsPreferenceConst.PREF_LANGUAGE, DeviceSettingsPreferenceConst.PREF_LANGUAGE_AUTO);
if (localeString == null || localeString.equals(DeviceSettingsPreferenceConst.PREF_LANGUAGE_AUTO)) {
String language = Locale.getDefault().getLanguage();
String country = Locale.getDefault().getCountry();
if (country == null) {
country = language;
}
localeString = language + "_" + country.toUpperCase();
}
LOG.info("Setting device to locale: " + localeString);
Language languageCode = Language.ENGLISH;
switch (localeString.substring(0, 2)) {
case "en":
languageCode = Language.ENGLISH;
break;
case "ja":
languageCode = Language.JAPANESE;
break;
}
LOG.info("Resolved locale: " + languageCode.name());
DisplaySetting pkt = new DisplaySetting(
prefs.getBoolean(DeviceSettingsPreferenceConst.PREF_SCREEN_LIFT_WRIST, false),
languageCode,
prefs.getInt(DeviceSettingsPreferenceConst.PREF_SCREEN_TIMEOUT, 5),
(prefs.getString(DeviceSettingsPreferenceConst.PREF_WEARLOCATION, "left")
.equals("left") ? DisplayOrientation.LEFT_HAND : DisplayOrientation.RIGHT_HAND),
(prefs.getBoolean(SonyWena3SettingKeys.RICH_DESIGN_MODE, false) ? DisplayDesign.RICH : DisplayDesign.NORMAL),
(prefs.getBoolean(SonyWena3SettingKeys.LARGE_FONT_SIZE, false) ? FontSize.LARGE : FontSize.NORMAL),
prefs.getBoolean(SonyWena3SettingKeys.WEATHER_IN_STATUSBAR, true)
);
b.write(
getCharacteristic(SonyWena3Constants.COMMON_SERVICE_CHARACTERISTIC_CONTROL_UUID),
pkt.toByteArray()
);
}
private void sendDnDSettings(TransactionBuilder b) {
Prefs prefs = new Prefs(GBApplication.getDeviceSpecificSharedPrefs(getDevice().getAddress()));
String dndMode = prefs.getString(DeviceSettingsPreferenceConst.PREF_DO_NOT_DISTURB_NOAUTO, DeviceSettingsPreferenceConst.PREF_DO_NOT_DISTURB_OFF);
boolean isDndOn = (dndMode != null && dndMode.equals(DeviceSettingsPreferenceConst.PREF_DO_NOT_DISTURB_SCHEDULED));
String start = prefs.getString(DeviceSettingsPreferenceConst.PREF_DO_NOT_DISTURB_NOAUTO_START, "22:00");
String end = prefs.getString(DeviceSettingsPreferenceConst.PREF_DO_NOT_DISTURB_NOAUTO_END, "06:00");
Calendar startCalendar = GregorianCalendar.getInstance();
Calendar endCalendar = GregorianCalendar.getInstance();
DateFormat df = new SimpleDateFormat("HH:mm");
try {
startCalendar.setTime(df.parse(start));
endCalendar.setTime(df.parse(end));
} catch (ParseException e) {
LOG.error("settings error: " + e);
}
byte startH = (byte)startCalendar.get(Calendar.HOUR_OF_DAY);
byte startM = (byte)startCalendar.get(Calendar.MINUTE);
byte endH = (byte)endCalendar.get(Calendar.HOUR_OF_DAY);
byte endM = (byte)endCalendar.get(Calendar.MINUTE);
DoNotDisturbSettings dndPkt = new DoNotDisturbSettings(isDndOn, startH, startM, endH, endM);
b.write(
getCharacteristic(SonyWena3Constants.COMMON_SERVICE_CHARACTERISTIC_CONTROL_UUID),
dndPkt.toByteArray()
);
}
private void sendAutoPowerSettings(TransactionBuilder b) {
Prefs prefs = new Prefs(GBApplication.getDeviceSpecificSharedPrefs(getDevice().getAddress()));
String autoPowerMode = prefs.getString(SonyWena3SettingKeys.AUTO_POWER_SCHEDULE_KIND, DeviceSettingsPreferenceConst.PREF_DO_NOT_DISTURB_OFF);
boolean isAutoPowerOffEnabled = (autoPowerMode != null && autoPowerMode.equals(DeviceSettingsPreferenceConst.PREF_DO_NOT_DISTURB_SCHEDULED));
String start = prefs.getString(SonyWena3SettingKeys.AUTO_POWER_SCHEDULE_START_HHMM, "22:00");
String end = prefs.getString(SonyWena3SettingKeys.AUTO_POWER_SCHEDULE_END_HHMM, "06:00");
Calendar startCalendar = GregorianCalendar.getInstance();
Calendar endCalendar = GregorianCalendar.getInstance();
DateFormat df = new SimpleDateFormat("HH:mm");
try {
startCalendar.setTime(df.parse(start));
endCalendar.setTime(df.parse(end));
} catch (ParseException e) {
LOG.error("settings error: " + e);
}
byte startH = (byte)startCalendar.get(Calendar.HOUR_OF_DAY);
byte startM = (byte)startCalendar.get(Calendar.MINUTE);
byte endH = (byte)endCalendar.get(Calendar.HOUR_OF_DAY);
byte endM = (byte)endCalendar.get(Calendar.MINUTE);
AutoPowerOffSettings powerOffPkt = new AutoPowerOffSettings(isAutoPowerOffEnabled, startH, startM, endH, endM);
b.write(
getCharacteristic(SonyWena3Constants.COMMON_SERVICE_CHARACTERISTIC_CONTROL_UUID),
powerOffPkt.toByteArray()
);
}
private void sendVibrationSettings(TransactionBuilder b) {
Prefs prefs = new Prefs(GBApplication.getDeviceSpecificSharedPrefs(getDevice().getAddress()));
boolean smartVibration = prefs.getBoolean(SonyWena3SettingKeys.SMART_VIBRATION, true);
VibrationStrength strength = VibrationStrength.valueOf(prefs.getString(SonyWena3SettingKeys.VIBRATION_STRENGTH, VibrationStrength.NORMAL.name()).toUpperCase());
VibrationSetting pkt = new VibrationSetting(smartVibration, strength);
b.write(
getCharacteristic(SonyWena3Constants.COMMON_SERVICE_CHARACTERISTIC_CONTROL_UUID),
pkt.toByteArray()
);
}
private void sendHomeScreenSettings(TransactionBuilder b) {
Prefs prefs = new Prefs(GBApplication.getDeviceSpecificSharedPrefs(getDevice().getAddress()));
String leftIdName = prefs.getString(SonyWena3SettingKeys.LEFT_HOME_ICON, HomeIconId.MUSIC.name()).toUpperCase();
String centerIdName = prefs.getString(SonyWena3SettingKeys.CENTER_HOME_ICON, HomeIconId.PEDOMETER.name()).toUpperCase();
String rightIdName = prefs.getString(SonyWena3SettingKeys.RIGHT_HOME_ICON, HomeIconId.CALORIES.name()).toUpperCase();
b.write(
getCharacteristic(SonyWena3Constants.COMMON_SERVICE_CHARACTERISTIC_CONTROL_UUID),
new HomeIconOrderSetting(
HomeIconId.valueOf(leftIdName),
HomeIconId.valueOf(centerIdName),
HomeIconId.valueOf(rightIdName)
).toByteArray()
);
}
private void sendMenuSettings(TransactionBuilder b) {
Prefs prefs = new Prefs(GBApplication.getDeviceSpecificSharedPrefs(getDevice().getAddress()));
String[] csv = prefs.getString(SonyWena3SettingKeys.MENU_ICON_CSV_KEY,
TextUtils.join(",", getContext().getResources().getStringArray(R.array.prefs_wena3_menu_icons_default_list)))
.toUpperCase()
.split(",");
MenuIconSetting menu = new MenuIconSetting();
for(String iconIdName: csv) {
if(!iconIdName.equals(MenuIconId.NONE.name())) {
menu.iconList.add(MenuIconId.valueOf(iconIdName));
}
}
b.write(
getCharacteristic(SonyWena3Constants.COMMON_SERVICE_CHARACTERISTIC_CONTROL_UUID),
menu.toByteArray()
);
}
private void sendStatusPageSettings(TransactionBuilder b) {
Prefs prefs = new Prefs(GBApplication.getDeviceSpecificSharedPrefs(getDevice().getAddress()));
StatusPageOrderSetting pageOrderSetting = new StatusPageOrderSetting();
String[] csv = prefs.getString(SonyWena3SettingKeys.STATUS_PAGE_CSV_KEY,
TextUtils.join(",", getContext().getResources().getStringArray(R.array.prefs_wena3_status_page_default_list)))
.toUpperCase()
.split(",");
for(String idName: csv) {
if(!idName.equals(StatusPageId.NONE.name())) {
pageOrderSetting.pages.add(StatusPageId.valueOf(idName));
}
}
b.write(
getCharacteristic(SonyWena3Constants.COMMON_SERVICE_CHARACTERISTIC_CONTROL_UUID),
pageOrderSetting.toByteArray()
);
}
private void sendActivityGoalSettings(TransactionBuilder b) {
Prefs prefs = new Prefs(GBApplication.getDeviceSpecificSharedPrefs(getDevice().getAddress()));
ActivityUser user = new ActivityUser();
LocalDate dateOfBirth = user.getDateOfBirth();
if(dateOfBirth.getYear() < 1920) {
LOG.error("Device does not support this year of birth");
return;
}
boolean stepsNotification = prefs.getBoolean(DeviceSettingsPreferenceConst.PREF_USER_FITNESS_GOAL_NOTIFICATION, false);
GenderSetting gender = user.getGender() == ActivityUser.GENDER_FEMALE ? GenderSetting.FEMALE : GenderSetting.MALE;
// Maybe we need to set the full birth date?
BodyPropertiesSetting bodyPropertiesSetting = new BodyPropertiesSetting(
gender,
(short)dateOfBirth.getYear(),
(short)dateOfBirth.getMonthValue(),
(short)dateOfBirth.getDayOfMonth(),
(short)user.getHeightCm(),
(short)user.getWeightKg()
);
GoalStepsSetting stepsSetting = new GoalStepsSetting(stepsNotification, user.getStepsGoal());
b.write(
getCharacteristic(SonyWena3Constants.COMMON_SERVICE_CHARACTERISTIC_CONTROL_UUID),
bodyPropertiesSetting.toByteArray()
);
b.write(
getCharacteristic(SonyWena3Constants.COMMON_SERVICE_CHARACTERISTIC_CONTROL_UUID),
stepsSetting.toByteArray()
);
}
private void sendDayStartHour(TransactionBuilder b) {
Prefs prefs = new Prefs(GBApplication.getDeviceSpecificSharedPrefs(getDevice().getAddress()));
int hour = prefs.getInt(SonyWena3SettingKeys.DAY_START_HOUR, 6);
DayStartHourSetting setting = new DayStartHourSetting(hour);
b.write(
getCharacteristic(SonyWena3Constants.COMMON_SERVICE_CHARACTERISTIC_CONTROL_UUID),
setting.toByteArray()
);
}
private void sendButtonActions(TransactionBuilder b) {
Prefs prefs = new Prefs(GBApplication.getDeviceSpecificSharedPrefs(getDevice().getAddress()));
String doubleIdName = prefs.getString(SonyWena3SettingKeys.BUTTON_DOUBLE_PRESS_ACTION, DeviceButtonActionId.NONE.name()).toUpperCase();
String longIdName = prefs.getString(SonyWena3SettingKeys.BUTTON_LONG_PRESS_ACTION, DeviceButtonActionId.NONE.name()).toUpperCase();
DeviceButtonActionSetting setting = new DeviceButtonActionSetting(
DeviceButtonActionId.valueOf(longIdName),
DeviceButtonActionId.valueOf(doubleIdName)
);
b.write(
getCharacteristic(SonyWena3Constants.COMMON_SERVICE_CHARACTERISTIC_CONTROL_UUID),
setting.toByteArray()
);
}
private void sendCalendarNotificationToggles(TransactionBuilder b) {
Prefs prefs = new Prefs(GBApplication.getDeviceSpecificSharedPrefs(getDevice().getAddress()));
boolean enableCalendar = prefs.getBoolean(DeviceSettingsPreferenceConst.PREF_SYNC_CALENDAR, false);
boolean enableNotifications = prefs.getBoolean(DeviceSettingsPreferenceConst.PREF_NOTIFICATION_ENABLE, false);
CalendarNotificationEnableSetting setting = new CalendarNotificationEnableSetting(enableCalendar, enableNotifications);
b.write(
getCharacteristic(SonyWena3Constants.COMMON_SERVICE_CHARACTERISTIC_CONTROL_UUID),
setting.toByteArray()
);
}
private void sendAllSettings(TransactionBuilder builder) {
sendCurrentTime(builder);
builder.write(
getCharacteristic(SonyWena3Constants.COMMON_SERVICE_CHARACTERISTIC_CONTROL_UUID),
CameraAppTypeSetting.findOut(getContext().getPackageManager()).toByteArray()
);
sendMenuSettings(builder);
sendStatusPageSettings(builder);
sendDisplaySettings(builder);
sendDnDSettings(builder);
sendAutoPowerSettings(builder);
sendVibrationSettings(builder);
sendHomeScreenSettings(builder);
sendActivityGoalSettings(builder);
sendDayStartHour(builder);
sendButtonActions(builder);
sendCalendarNotificationToggles(builder);
}
private void sendAllCalendarEvents(TransactionBuilder b) {
try {
Prefs prefs = new Prefs(GBApplication.getDeviceSpecificSharedPrefs(getDevice().getAddress()));
boolean enableCalendar = prefs.getBoolean(DeviceSettingsPreferenceConst.PREF_SYNC_CALENDAR, false);
TransactionBuilder builder = b == null ? performInitialized("updateCalendarEvents") : b;
if(!enableCalendar || calendarEvents.isEmpty()) {
builder.write(
getCharacteristic(SonyWena3Constants.NOTIFICATION_SERVICE_CHARACTERISTIC_UUID),
CalendarEntry.byteArrayForEmptyEvent((byte) 0, (byte) 0)
);
}
else {
int i = 1;
int total = Math.min(calendarEvents.size(), 255);
for(CalendarEventSpec evt: calendarEvents) {
builder.write(
getCharacteristic(SonyWena3Constants.NOTIFICATION_SERVICE_CHARACTERISTIC_UUID),
new CalendarEntry(
new Date(evt.timestamp * 1000L),
new Date((evt.timestamp * 1000L) + (evt.durationInSeconds * 1000L)),
evt.allDay,
(evt.title == null ? "" : evt.title),
(evt.location == null ? "" : evt.location),
(byte) i,
(byte) total
).toByteArray()
);
if(i == 255) break;
else i++;
}
}
if(b == null) performImmediately(builder);
} catch (IOException e) {
LOG.warn("Unable to send calendar events", e);
}
}
@Override
public void onSetTime() {
sendCurrentTime(null);
}
@Override
public void onAddCalendarEvent(CalendarEventSpec calendarEventSpec) {
calendarEvents.add(calendarEventSpec);
sendAllCalendarEvents(null);
}
@Override
public void onDeleteCalendarEvent(byte type, long id) {
for(CalendarEventSpec evt : calendarEvents) {
if(evt.type == type && evt.id == id) {
calendarEvents.remove(evt);
}
}
sendAllCalendarEvents(null);
}
@Override
public void onSendConfiguration(String config) {
try {
TransactionBuilder builder = performInitialized("sendConfig");
switch (config) {
case SonyWena3SettingKeys.STATUS_PAGE_CSV_KEY:
sendStatusPageSettings(builder);
break;
case SonyWena3SettingKeys.MENU_ICON_CSV_KEY:
sendMenuSettings(builder);
break;
case DeviceSettingsPreferenceConst.PREF_SCREEN_LIFT_WRIST:
case DeviceSettingsPreferenceConst.PREF_LANGUAGE:
case DeviceSettingsPreferenceConst.PREF_SCREEN_TIMEOUT:
case DeviceSettingsPreferenceConst.PREF_WEARLOCATION:
case SonyWena3SettingKeys.RICH_DESIGN_MODE:
case SonyWena3SettingKeys.LARGE_FONT_SIZE:
case SonyWena3SettingKeys.WEATHER_IN_STATUSBAR:
sendDisplaySettings(builder);
break;
case SonyWena3SettingKeys.SMART_WAKEUP_MARGIN_MINUTES:
// Resend alarms
onSetAlarms(new ArrayList<>(DBHelper.getAlarms(gbDevice)));
break;
case DeviceSettingsPreferenceConst.PREF_DO_NOT_DISTURB_NOAUTO:
case DeviceSettingsPreferenceConst.PREF_DO_NOT_DISTURB_NOAUTO_END:
case DeviceSettingsPreferenceConst.PREF_DO_NOT_DISTURB_NOAUTO_START:
sendDnDSettings(builder);
break;
case SonyWena3SettingKeys.AUTO_POWER_SCHEDULE_KIND:
case SonyWena3SettingKeys.AUTO_POWER_SCHEDULE_START_HHMM:
case SonyWena3SettingKeys.AUTO_POWER_SCHEDULE_END_HHMM:
sendAutoPowerSettings(builder);
break;
case SonyWena3SettingKeys.VIBRATION_STRENGTH:
case SonyWena3SettingKeys.SMART_VIBRATION:
sendVibrationSettings(builder);
break;
case SonyWena3SettingKeys.LEFT_HOME_ICON:
case SonyWena3SettingKeys.CENTER_HOME_ICON:
case SonyWena3SettingKeys.RIGHT_HOME_ICON:
sendHomeScreenSettings(builder);
break;
case ActivityUser.PREF_USER_DATE_OF_BIRTH:
case ActivityUser.PREF_USER_GENDER:
case ActivityUser.PREF_USER_HEIGHT_CM:
case ActivityUser.PREF_USER_WEIGHT_KG:
case ActivityUser.PREF_USER_STEPS_GOAL:
case DeviceSettingsPreferenceConst.PREF_USER_FITNESS_GOAL_NOTIFICATION:
sendActivityGoalSettings(builder);
break;
case SonyWena3SettingKeys.DAY_START_HOUR:
sendDayStartHour(builder);
break;
case SonyWena3SettingKeys.BUTTON_DOUBLE_PRESS_ACTION:
case SonyWena3SettingKeys.BUTTON_LONG_PRESS_ACTION:
sendButtonActions(builder);
break;
case DeviceSettingsPreferenceConst.PREF_NOTIFICATION_ENABLE:
case DeviceSettingsPreferenceConst.PREF_SYNC_CALENDAR:
sendCalendarNotificationToggles(builder);
sendAllCalendarEvents(builder);
break;
default:
LOG.warn("Unsupported setting %s", config);
return;
}
performImmediately(builder);
} catch(Exception e) {
GB.toast("Failed to send settings update", Toast.LENGTH_SHORT, GB.ERROR);
}
}
@Override
public boolean getImplicitCallbackModify() {
return true;
}
@Override
public boolean getSendWriteRequestResponse() {
return false;
}
}