1
0
mirror of https://codeberg.org/Freeyourgadget/Gadgetbridge synced 2024-06-02 11:26:09 +02:00
Gadgetbridge/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/sony/wena3/SonyWena3DeviceSupport.java
José Rebelo 81aef0bf35 Add support for multiple weather locations
Introduce the concept of primary and secondary weathers:

* Primary weather keeps the same behavior as previously across all weather providers, so it's non-breaking. This location is not necessarily the current location, just the primary weather location set by the user.
* The GenericWeatherReceiver now has a new extra WeatherSecondaryJson, that receives a json list with secondary weather locations.

It's guaranteed that the primary weather always exists, so the list of WeatherSpecs provided to devices is never empty. Update all support classes accordingly.
2024-03-29 21:10:40 +00:00

1072 lines
53 KiB
Java

/* 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 <https://www.gnu.org/licenses/>. */
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.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<CalendarEventSpec> 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<WeatherSpec> weatherSpecs) {
WeatherSpec weatherSpec = weatherSpecs.get(0);
if(weatherSpec.forecasts.size() < 4) return;
ArrayList<WeatherDay> 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();
if(user.getYearOfBirth() < 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)user.getYearOfBirth(), (short)0, (short)1, (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_YEAR_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);
}
}
}