From fc450882cb82c37ea81324ce66565c0bb96615f5 Mon Sep 17 00:00:00 2001 From: Me7c7 Date: Fri, 6 Sep 2024 10:58:49 +0300 Subject: [PATCH] Huawei: Contacts uploading support --- .../devices/huawei/HuaweiBRCoordinator.java | 5 + .../devices/huawei/HuaweiCoordinator.java | 23 +++++ .../devices/huawei/HuaweiLECoordinator.java | 5 + .../devices/huawei/HuaweiPacket.java | 10 ++ .../devices/huawei/packets/Contacts.java | 93 +++++++++++++++++++ .../devices/huawei/HuaweiBRSupport.java | 7 ++ .../devices/huawei/HuaweiLESupport.java | 6 ++ .../devices/huawei/HuaweiSupportProvider.java | 71 ++++++++++++-- .../huawei/requests/GetContactsCount.java | 40 ++++++++ .../requests/SendSetContactsRequest.java | 49 ++++++++++ 10 files changed, 301 insertions(+), 8 deletions(-) create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/packets/Contacts.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/requests/GetContactsCount.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/requests/SendSetContactsRequest.java diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/HuaweiBRCoordinator.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/HuaweiBRCoordinator.java index aba72e415..212b1fc8c 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/HuaweiBRCoordinator.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/HuaweiBRCoordinator.java @@ -169,6 +169,11 @@ public abstract class HuaweiBRCoordinator extends AbstractBLClassicDeviceCoordin return huaweiCoordinator.getAlarmSlotCount(device); } + @Override + public int getContactsSlotCount(GBDevice device) { + return huaweiCoordinator.getContactsSlotCount(device); + } + @Override public boolean supportsActivityDataFetching() { return true; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/HuaweiCoordinator.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/HuaweiCoordinator.java index 70c49c4f4..0acc70ce6 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/HuaweiCoordinator.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/HuaweiCoordinator.java @@ -65,6 +65,8 @@ public class HuaweiCoordinator { private boolean transactionCrypted=true; + private int maxContactsCount = 0; + public HuaweiCoordinator(HuaweiCoordinatorSupplier parent) { this.parent = parent; for (String key : getCapabilitiesSharedPreferences().getAll().keySet()) { @@ -84,6 +86,9 @@ public class HuaweiCoordinator { key, GB.hexdump(Notifications.defaultConstraints) ))); + if (key.equals("maxContactsCount")) + this.maxContactsCount = getCapabilitiesSharedPreferences().getInt(key, 0); + } } } @@ -121,6 +126,11 @@ public class HuaweiCoordinator { getCapabilitiesSharedPreferences().edit().putString("notificationConstraints", GB.hexdump(constraints.array())).apply(); } + public void saveMaxContactsCount(int maxContactsCount) { + this.maxContactsCount = maxContactsCount; + getCapabilitiesSharedPreferences().edit().putInt("maxContactsCount", maxContactsCount).apply(); + } + public void addCommandsForService(int service, byte[] commands) { if (!commandsPerService.containsKey(service)) { saveCommandsForService(service, commands); @@ -232,6 +242,11 @@ public class HuaweiCoordinator { if (supportsCameraRemote()) deviceSpecificSettings.addRootScreen(R.xml.devicesettings_camera_remote); + //Contacts + if (getContactsSlotCount(device) > 0) { + deviceSpecificSettings.addRootScreen(R.xml.devicesettings_contacts); + } + // Time if (supportsDateFormat()) { final List dateTime = deviceSpecificSettings.addRootScreen(DeviceSpecificSettingsScreen.DATE_TIME); @@ -297,6 +312,10 @@ public class HuaweiCoordinator { return supportsCommandForService(0x01, 0x29) && CameraActivity.supportsCamera(); } + public boolean supportsContacts() { + return supportsCommandForService(0x03, 0x1); + } + public boolean supportsAcceptAgreement() { return supportsCommandForService(0x01, 0x30); } @@ -550,6 +569,10 @@ public class HuaweiCoordinator { return alarmCount; } + public int getContactsSlotCount(GBDevice device) { + return supportsContacts()?maxContactsCount:0; + } + public void setTransactionCrypted(boolean crypted) { this.transactionCrypted = crypted; } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/HuaweiLECoordinator.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/HuaweiLECoordinator.java index 2ee890f11..9c4c71a1b 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/HuaweiLECoordinator.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/HuaweiLECoordinator.java @@ -175,6 +175,11 @@ public abstract class HuaweiLECoordinator extends AbstractBLEDeviceCoordinator i return huaweiCoordinator.getAlarmSlotCount(device); } + @Override + public int getContactsSlotCount(GBDevice device) { + return huaweiCoordinator.getContactsSlotCount(device); + } + @Override public boolean supportsActivityDataFetching() { return true; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/HuaweiPacket.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/HuaweiPacket.java index 7b1962638..705929ec1 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/HuaweiPacket.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/HuaweiPacket.java @@ -34,6 +34,7 @@ import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.AccountRelate import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.App; import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.Calls; import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.CameraRemote; +import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.Contacts; import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.FileDownloadService0A; import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.FileDownloadService2C; import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.GpsAndTime; @@ -476,6 +477,15 @@ public class HuaweiPacket { default: return this; } + case Contacts.id: + switch (this.commandId) { + case Contacts.ContactsSet.id: + return new Contacts.ContactsSet.Response(paramsProvider).fromPacket(this); + case Contacts.ContactsCount.id: + return new Contacts.ContactsCount.Response(paramsProvider).fromPacket(this); + } + this.isEncrypted = this.attemptDecrypt(); // Helps with debugging + return this; case Calls.id: if (this.commandId == Calls.AnswerCallResponse.id) return new Calls.AnswerCallResponse(paramsProvider).fromPacket(this); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/packets/Contacts.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/packets/Contacts.java new file mode 100644 index 000000000..4de952b0b --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/packets/Contacts.java @@ -0,0 +1,93 @@ +package nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets; + +import java.util.ArrayList; + +import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiPacket; +import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiTLV; +import nodomain.freeyourgadget.gadgetbridge.model.Contact; + +public class Contacts { + public static final byte id = 0x03; + + public static class ContactsSet { + public static final byte id = 0x01; + + public static class Request extends HuaweiPacket { + public Request(ParamsProvider paramsProvider, ArrayList contacts, int maxCount) { + super(paramsProvider); + + this.serviceId = Contacts.id; + this.commandId = id; + + HuaweiTLV contacts_tlv = new HuaweiTLV(); + for(int i = 0; i < maxCount; i++) { + HuaweiTLV contact= new HuaweiTLV() + .put(0x03, (byte) (i + 1)); + if(i < contacts.size()) { + contact.put(0x4, contacts.get(i).getName()) + .put(0x85, new HuaweiTLV().put(0x86, new HuaweiTLV().put(0x7, "Mobile").put(0x8, contacts.get(i).getNumber()))); + } + contacts_tlv.put(0x82, contact); + } + + this.tlv = new HuaweiTLV() + .put(0x81, contacts_tlv); + + this.complete = true; + this.isEncrypted = true; + } + } + + public static class Response extends HuaweiPacket { + + public boolean isOk; + + public Response(ParamsProvider paramsProvider) { + super(paramsProvider); + this.serviceId = Contacts.id; + this.commandId = id; + } + + @Override + public void parseTlv() throws ParseException { + isOk = this.tlv.getInteger(0x7f) == 0x000186A0; + } + } + } + + public static class ContactsCount { + public static final byte id = 0x02; + + public static class Request extends HuaweiPacket { + public Request(ParamsProvider paramsProvider) { + super(paramsProvider); + + this.serviceId = Contacts.id; + this.commandId = id; + + this.tlv = new HuaweiTLV() + .put(0x1) + .put(0x2); + + this.complete = true; + this.isEncrypted = true; + } + } + + public static class Response extends HuaweiPacket { + + public int maxCount; + + public Response(ParamsProvider paramsProvider) { + super(paramsProvider); + this.serviceId = Contacts.id; + this.commandId = id; + } + + @Override + public void parseTlv() throws ParseException { + maxCount = this.tlv.getByte(0x01); + } + } + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiBRSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiBRSupport.java index 0a4a287cd..89e45f68b 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiBRSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiBRSupport.java @@ -24,12 +24,14 @@ import android.net.Uri; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; +import java.util.List; import java.util.UUID; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventCameraRemote; import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiConstants; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.model.CallSpec; +import nodomain.freeyourgadget.gadgetbridge.model.Contact; import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec; import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec; import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec; @@ -170,6 +172,11 @@ public class HuaweiBRSupport extends AbstractBTBRDeviceSupport { supportProvider.onCameraStatusChange(event, filename); } + @Override + public void onSetContacts(ArrayList contacts) { + supportProvider.onSetContacts(contacts); + } + @Override public void dispose() { supportProvider.dispose(); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiLESupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiLESupport.java index ff5fb9a42..3ead56d17 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiLESupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiLESupport.java @@ -34,6 +34,7 @@ import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventCameraRemo import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiConstants; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.model.CallSpec; +import nodomain.freeyourgadget.gadgetbridge.model.Contact; import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec; import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec; import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec; @@ -178,6 +179,11 @@ public class HuaweiLESupport extends AbstractBTLEDeviceSupport { supportProvider.onCameraStatusChange(event, filename); } + @Override + public void onSetContacts(ArrayList contacts) { + supportProvider.onSetContacts(contacts); + } + @Override public void dispose() { supportProvider.dispose(); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiSupportProvider.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiSupportProvider.java index 6c5b12b15..178a0e8a4 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiSupportProvider.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiSupportProvider.java @@ -85,6 +85,7 @@ import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceApp; import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample; import nodomain.freeyourgadget.gadgetbridge.model.ActivityUser; import nodomain.freeyourgadget.gadgetbridge.model.CallSpec; +import nodomain.freeyourgadget.gadgetbridge.model.Contact; import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec; import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec; import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec; @@ -94,6 +95,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec; import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.SetDeviceStateAction; import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.AcceptAgreementsRequest; import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.GetAppInfoParams; +import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.GetContactsCount; import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.GetEventAlarmList; import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.GetGpsParameterRequest; import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.GetNotificationConstraintsRequest; @@ -105,6 +107,7 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.Send import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SendGpsAndTimeToDeviceRequest; import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SendGpsDataRequest; import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SendFileUploadInfo; +import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SendSetContactsRequest; import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SendWeatherCurrentRequest; import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SendNotifyHeartRateCapabilityRequest; import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SendNotifyRestHeartRateCapabilityRequest; @@ -791,6 +794,7 @@ public class HuaweiSupportProvider { if (getHuaweiCoordinator().supportsActivityReminder()) { setActivityReminder(); } + if (getHuaweiCoordinator().supportsTruSleep()) { setTrusleep(); } @@ -803,20 +807,55 @@ public class HuaweiSupportProvider { getNotificationConstraintsReq.doPerform(); } - if (getHuaweiCoordinator().supportsWatchfaceParams()) { - GetWatchfaceParams getWatchfaceParams = new GetWatchfaceParams(this); - getWatchfaceParams.doPerform(); - } - if (getHuaweiCoordinator().supportsCameraRemote() && GBApplication.getDeviceSpecificSharedPrefs(gbDevice.getAddress()).getBoolean(DeviceSettingsPreferenceConst.PREF_CAMERA_REMOTE, false)) { SendCameraRemoteSetupEvent sendCameraRemoteSetupEvent = new SendCameraRemoteSetupEvent(this, CameraRemote.CameraRemoteSetup.Request.Event.ENABLE_CAMERA); sendCameraRemoteSetupEvent.doPerform(); } - if (getHuaweiCoordinator().supportsAppParams()) { - GetAppInfoParams getAppInfoParams = new GetAppInfoParams(this); - getAppInfoParams.doPerform(); + // FIXME: Limit number of simultaneous commands + // Huawei watch, for example the Watch GT4 has limited buffer for incoming commands. + // So sending a lot of command broke connection or cause that watch does not answer to requests. + // To avoid this issue I perform some commands in the chain, but we should limit number of simultaneous commands + + RequestCallback contactsCallback = new RequestCallback() { + @Override + public void call() { + if (getHuaweiCoordinator().supportsContacts()) { + GetContactsCount getContactsCount = new GetContactsCount(HuaweiSupportProvider.this); + try { + getContactsCount.doPerform(); + } catch (IOException e) { + LOG.error("Error perform contacts count request", e); + } + } + } + }; + + RequestCallback appsCallback= new RequestCallback() { + @Override + public void call() { + if (getHuaweiCoordinator().supportsAppParams()) { + GetAppInfoParams getAppInfoParams = new GetAppInfoParams(HuaweiSupportProvider.this); + getAppInfoParams.setFinalizeReq(contactsCallback); + try { + getAppInfoParams.doPerform(); + } catch (IOException e) { + LOG.error("Error perform app info request", e); + } + } else { + contactsCallback.call(); + } + } + }; + + if (getHuaweiCoordinator().supportsWatchfaceParams()) { + GetWatchfaceParams getWatchfaceParams = new GetWatchfaceParams(this); + getWatchfaceParams.setFinalizeReq(appsCallback); + getWatchfaceParams.doPerform(); + } else { + appsCallback.call(); } + } catch (IOException e) { GB.toast(getContext(), "Initialize dynamic services of Huawei device failed", Toast.LENGTH_SHORT, GB.ERROR, e); @@ -2103,6 +2142,22 @@ public class HuaweiSupportProvider { } } + public void onSetContacts(ArrayList contacts) { + SendSetContactsRequest sendSetContactsRequest = new SendSetContactsRequest( + this, + contacts, + this.getHuaweiCoordinator().getContactsSlotCount(getDevice()) + ); + try { + sendSetContactsRequest.doPerform(); + } catch (IOException e) { + // TODO: Use translatable string + GB.toast(context, "Failed to set contacts", Toast.LENGTH_SHORT, GB.ERROR, e); + LOG.error("Failed to send set contacts request", e); + } + + } + public boolean startBatteryRunnerDelayed() { int interval_minutes = GBApplication.getDevicePrefs(gbDevice).getBatteryPollingIntervalMinutes(); int interval = interval_minutes * 60 * 1000; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/requests/GetContactsCount.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/requests/GetContactsCount.java new file mode 100644 index 000000000..a57526058 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/requests/GetContactsCount.java @@ -0,0 +1,40 @@ +package nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; + +import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiPacket; +import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.Contacts; +import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.HuaweiSupportProvider; + +public class GetContactsCount extends Request { + private static final Logger LOG = LoggerFactory.getLogger(GetContactsCount.class); + + public GetContactsCount(HuaweiSupportProvider support) { + super(support); + this.serviceId = Contacts.id; + this.commandId = Contacts.ContactsCount.id; + } + + @Override + protected List createRequest() throws RequestCreationException { + try { + return new Contacts.ContactsCount.Request(paramsProvider).serialize(); + } catch (HuaweiPacket.CryptoException e) { + throw new RequestCreationException(e); + } + } + + @Override + protected void processResponse() throws ResponseParseException { + LOG.debug("handle contacts count"); + + if (!(receivedPacket instanceof Contacts.ContactsCount.Response)) + throw new ResponseTypeMismatchException(receivedPacket, Contacts.ContactsCount.Response.class); + + int count = ((Contacts.ContactsCount.Response) receivedPacket).maxCount; + this.supportProvider.getHuaweiCoordinator().saveMaxContactsCount(count); + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/requests/SendSetContactsRequest.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/requests/SendSetContactsRequest.java new file mode 100644 index 000000000..a56a23f5d --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/requests/SendSetContactsRequest.java @@ -0,0 +1,49 @@ +package nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.List; + +import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiPacket; +import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.Contacts; +import nodomain.freeyourgadget.gadgetbridge.model.Contact; +import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.HuaweiSupportProvider; + +public class SendSetContactsRequest extends Request { + private static final Logger LOG = LoggerFactory.getLogger(SendSetContactsRequest.class); + + private final ArrayList contacts; + int maxCount; + + public SendSetContactsRequest(HuaweiSupportProvider support,ArrayList contacts, int maxCount) { + super(support); + this.serviceId = Contacts.id; + this.commandId = Contacts.ContactsSet.id; + this.contacts = contacts; + this.maxCount = maxCount; + } + + @Override + protected List createRequest() throws RequestCreationException { + try { + return new Contacts.ContactsSet.Request(paramsProvider, this.contacts, this.maxCount).serialize(); + } catch (HuaweiPacket.CryptoException e) { + throw new RequestCreationException(e); + } + } + + @Override + protected void processResponse() { + if (receivedPacket instanceof Contacts.ContactsSet.Response) { + if (((Contacts.ContactsSet.Response) receivedPacket).isOk) { + LOG.debug("Contacts set"); + } else { + LOG.warn("Error set contacts"); + } + } else { + LOG.error("Set Contacts response is not of type ContactsSet response"); + } + } +}