From 559ccda676366e85a1ad44e5785ac2789459a3b4 Mon Sep 17 00:00:00 2001 From: Me7c7 Date: Tue, 31 Dec 2024 21:41:09 +0200 Subject: [PATCH] Huawei: notifications: remove from watch and replies support --- .../devices/huawei/HuaweiCoordinator.java | 30 +++ .../devices/huawei/HuaweiPacket.java | 2 + .../devices/huawei/packets/Notifications.java | 174 ++++++++++++++++-- .../devices/huawei/AsynchronousResponse.java | 12 ++ .../devices/huawei/HuaweiBRSupport.java | 5 + .../huawei/HuaweiNotificationsManager.java | 140 ++++++++++++++ .../devices/huawei/HuaweiSupportProvider.java | 19 +- .../SendNotificationRemoveRequest.java | 55 ++++++ .../requests/SendNotificationRequest.java | 16 +- .../requests/StopNotificationRequest.java | 1 + .../huawei/packets/TestNotifications.java | 3 +- 11 files changed, 427 insertions(+), 30 deletions(-) create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiNotificationsManager.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/requests/SendNotificationRemoveRequest.java 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 36af87081..5640b7906 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 @@ -654,6 +654,36 @@ public class HuaweiCoordinator { return false; } + public boolean supportsNotificationsTimestamp() { + if (supportsExpandCapability()) + return supportsExpandCapability(77); + return false; + } + + public boolean supportsNotificationsReply() { + if (supportsExpandCapability()) + return supportsExpandCapability(73); + return false; + } + + public boolean supportsNotificationsRepeatedNotify() { + if (supportsExpandCapability()) + return supportsExpandCapability(94); + return false; + } + + public boolean supportsNotificationsSyncKey() { + if (supportsExpandCapability()) + return supportsExpandCapability(89); + return false; + } + public boolean supportsNotificationsRemoveSingle() { + if (supportsExpandCapability()) + return supportsExpandCapability(120); + return false; + } + + public boolean supportsPromptPushMessage () { // do not ask for capabilities under specific condition 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 ac074953e..37b9b53dd 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 @@ -482,6 +482,8 @@ public class HuaweiPacket { return new Notifications.NotificationConstraints.Response(paramsProvider).fromPacket(this); case Notifications.NotificationCapabilities.id: return new Notifications.NotificationCapabilities.Response(paramsProvider).fromPacket(this); + case Notifications.NotificationReply.id: + return new Notifications.NotificationReply.ReplyResponse(paramsProvider).fromPacket(this); default: return this; } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/packets/Notifications.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/packets/Notifications.java index 22a1b8f5f..b45c477ab 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/packets/Notifications.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/packets/Notifications.java @@ -16,6 +16,8 @@ along with this program. If not, see . */ package nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets; +import android.text.TextUtils; + import java.nio.ByteBuffer; import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiPacket; @@ -24,15 +26,32 @@ import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiTLV; public class Notifications { public static final byte id = 0x02; public static final byte[] defaultConstraints = new byte[]{ - 0x00, 0x02, 0x00, 0x0F, - 0x00, 0x00, 0x00, 0x02, 0x00, 0x1E, - 0x00, 0x00, 0x00, 0x02, 0x00, 0x1E, - 0x00, 0x00, 0x00, 0x02, 0x00, 0x1E + 0x00, 0x02, 0x00, 0x0F, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x1E, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x1E, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x1E }; public static class NotificationActionRequest extends HuaweiPacket { public static final byte id = 0x01; + public static class AdditionalParams { + + public boolean supportsSyncKey = false; + public boolean supportsRepeatedNotify = false; + public boolean supportsRemoveSingle = false; + public boolean supportsReply = false; + public boolean supportsTimestamp = false; + + public String notificationKey = ""; + public int notificationId = -1; + public String channelId = ""; + public byte subscriptionId = 0; + public String address = ""; + + + } + // TODO: support other types of notifications // public static final int send = 0x01; // public static final int notificationId = 0x01; @@ -54,13 +73,14 @@ public class Notifications { public NotificationActionRequest( ParamsProvider paramsProvider, - short notificationId, + short msgId, byte notificationType, int encoding, String titleContent, String senderContent, String bodyContent, - String sourceAppId + String sourceAppId, + AdditionalParams addParams ) { super(paramsProvider); @@ -70,7 +90,7 @@ public class Notifications { // TODO: Add notification information per type if necessary this.tlv = new HuaweiTLV() - .put(0x01, notificationId) + .put(0x01, msgId) .put(0x02, notificationType) .put(0x03, true); // This used to be vibrate, but doesn't work @@ -105,6 +125,32 @@ public class Notifications { if (sourceAppId != null) this.tlv.put(0x11, sourceAppId); + if(addParams != null) { + if (addParams.supportsSyncKey) + this.tlv.put(0x18, (addParams.notificationKey != null) ? addParams.notificationKey : ""); + + //this.tlv.put(0x12, "msg"); //"msg" or "imcall", maybe other - category, if not empty and productType>=34 + + //if(addParams.repeatedNotifySupports) { + // this.tlv.put(0x13, 0); // 0x13 - reminder 15 = vibrate, 0 - default + //} + + if (addParams.supportsReply && notificationType == NotificationType.sms) { + this.tlv.put(0x14, addParams.subscriptionId); + this.tlv.put(0x17, addParams.address); + } + + if (addParams.supportsRepeatedNotify || addParams.supportsRemoveSingle) { + this.tlv.put(0x19, (addParams.notificationKey != null) ? addParams.notificationKey : ""); + this.tlv.put(0x20, addParams.notificationId); + this.tlv.put(0x1d, (addParams.channelId != null) ? addParams.channelId : ""); + } + + if (addParams.supportsTimestamp) { + this.tlv.put(0x15, (int) (System.currentTimeMillis() / 1000)); + } + } + this.complete = true; } } @@ -118,7 +164,7 @@ public class Notifications { this.serviceId = Notifications.id; this.commandId = id; this.tlv = new HuaweiTLV() - .put(0x01); + .put(0x01); this.complete = true; } } @@ -158,23 +204,23 @@ public class Notifications { .getObject(0x90); for (HuaweiTLV subContainer : container.getObjects(0x91)) { if (subContainer.getByte(0x12) == 0x01) { - putByteBuffer(constraints, NotificationConstraintsType.contentFormat, new byte[] {0x02}); //Always 0x02 even if gadget report 0x03 + putByteBuffer(constraints, NotificationConstraintsType.contentFormat, new byte[]{0x02}); //Always 0x02 even if gadget report 0x03 putByteBuffer(constraints, NotificationConstraintsType.contentLength, subContainer.getBytes(0x14)); } if (subContainer.getByte(0x12) == 0x05) { - constraints.putShort(NotificationConstraintsType.yellowPagesSupport,(short)0x01); - putByteBuffer(constraints, NotificationConstraintsType.yellowPagesFormat,subContainer.getBytes(0x13)); - putByteBuffer(constraints, NotificationConstraintsType.yellowPagesLength,subContainer.getBytes(0x14)); + constraints.putShort(NotificationConstraintsType.yellowPagesSupport, (short) 0x01); + putByteBuffer(constraints, NotificationConstraintsType.yellowPagesFormat, subContainer.getBytes(0x13)); + putByteBuffer(constraints, NotificationConstraintsType.yellowPagesLength, subContainer.getBytes(0x14)); } if (subContainer.getByte(0x12) == 0x06) { - constraints.putShort(NotificationConstraintsType.contentSignSupport,(short)0x01); - putByteBuffer(constraints, NotificationConstraintsType.contentSignFormat,subContainer.getBytes(0x13)); - putByteBuffer(constraints, NotificationConstraintsType.contentSignLength,subContainer.getBytes(0x14)); + constraints.putShort(NotificationConstraintsType.contentSignSupport, (short) 0x01); + putByteBuffer(constraints, NotificationConstraintsType.contentSignFormat, subContainer.getBytes(0x13)); + putByteBuffer(constraints, NotificationConstraintsType.contentSignLength, subContainer.getBytes(0x14)); } - if (subContainer.getByte(0x12) == 0x07 ) { - constraints.putShort(NotificationConstraintsType.incomingNumberSupport,(short)0x01); - putByteBuffer(constraints, NotificationConstraintsType.incomingNumberFormat,subContainer.getBytes(0x13)); - putByteBuffer(constraints, NotificationConstraintsType.incomingNumberLength,subContainer.getBytes(0x14)); + if (subContainer.getByte(0x12) == 0x07) { + constraints.putShort(NotificationConstraintsType.incomingNumberSupport, (short) 0x01); + putByteBuffer(constraints, NotificationConstraintsType.incomingNumberFormat, subContainer.getBytes(0x13)); + putByteBuffer(constraints, NotificationConstraintsType.incomingNumberLength, subContainer.getBytes(0x14)); } } constraints.rewind(); @@ -250,7 +296,7 @@ public class Notifications { public static class Request extends HuaweiPacket { public Request( ParamsProvider paramsProvider - ){ + ) { super(paramsProvider); this.serviceId = Notifications.id; this.commandId = id; @@ -278,6 +324,36 @@ public class Notifications { } } + public static class NotificationRemoveAction extends HuaweiPacket { + public static final byte id = 0x06; + + public NotificationRemoveAction( + ParamsProvider paramsProvider, + byte msgType, + String sourceAppId, + String notificationKey, + int notificationId, + String notificationChannelId, + String notificationCategory + ) { + super(paramsProvider); + + this.serviceId = Notifications.id; + this.commandId = id; + + this.tlv = new HuaweiTLV() + .put(0x01, msgType) + .put(0x02, sourceAppId) + .put(0x03, notificationKey) + .put(0x04, notificationId) + .put(0x05, notificationChannelId); + if (notificationCategory != null && !TextUtils.isEmpty(notificationCategory)) + this.tlv.put(0x06, notificationCategory); // category + + this.complete = true; + } + } + public static class WearMessagePushRequest extends HuaweiPacket { public static final byte id = 0x08; @@ -297,4 +373,62 @@ public class Notifications { this.complete = true; } } + + public static class NotificationReply { + public static final byte id = 0x10; + public static class ReplyResponse extends HuaweiPacket { + public int type = 0; + public int encoding = 0; // 3 - "utf-16" + public int subId = 0; + public String sender; + public String key; + public String text; + + public ReplyResponse(ParamsProvider paramsProvider) { + super(paramsProvider); + + this.serviceId = MusicControl.id; + this.commandId = id; + } + + @Override + public void parseTlv() throws ParseException { + if (this.tlv.contains(0x01)) + this.type = this.tlv.getAsInteger(0x01); + if (this.tlv.contains(0x02)) + this.encoding = this.tlv.getAsInteger(0x02); + if (this.tlv.contains(0x03)) + this.subId = this.tlv.getAsInteger(0x03); + if (this.tlv.contains(0x04)) + this.key = this.tlv.getString(0x04); + if (this.tlv.contains(0x05)) + this.sender = this.tlv.getString(0x05); + if (this.tlv.contains(0x06)) + this.text = this.tlv.getString(0x06); + } + } + + //TODO: send ack if required, 7f on error. + public static class ReplyAck extends HuaweiPacket { + + public ReplyAck( + ParamsProvider paramsProvider, + byte code + ) { + super(paramsProvider); + + this.serviceId = Notifications.id; + this.commandId = id; + + this.tlv = new HuaweiTLV() + .put(0x07, code); + + this.complete = true; + } + } + + } + + + } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/AsynchronousResponse.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/AsynchronousResponse.java index 8847df036..7688eeb08 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/AsynchronousResponse.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/AsynchronousResponse.java @@ -57,6 +57,7 @@ import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.GpsAndTime; import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.Menstrual; import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.MusicControl; import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.FileUpload; +import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.Notifications; import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.P2P; import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.Watchface; import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.Weather; @@ -127,6 +128,7 @@ public class AsynchronousResponse { handleEphemeris(response); handleEphemerisUploadService(response); handleAsyncBattery(response); + handleNotifications(response); } catch (Request.ResponseParseException e) { LOG.error("Response parse exception", e); } @@ -725,4 +727,14 @@ public class AsynchronousResponse { } } } + + private void handleNotifications(HuaweiPacket response) { + if (response.serviceId == Notifications.id && response.commandId == Notifications.NotificationReply.id) { + if (!(response instanceof Notifications.NotificationReply.ReplyResponse)) { + return; + } + LOG.info("Notification response"); + support.getHuaweiNotificationsManager().onReplyResponse((Notifications.NotificationReply.ReplyResponse) response); + } + } } 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 bdc37f94d..a06adf7e2 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 @@ -102,6 +102,11 @@ public class HuaweiBRSupport extends AbstractBTBRDeviceSupport { supportProvider.onNotification(notificationSpec); } + @Override + public void onDeleteNotification(int id) { + supportProvider.onDeleteNotification(id); + } + @Override public void onSetTime() { supportProvider.onSetTime(); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiNotificationsManager.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiNotificationsManager.java new file mode 100644 index 000000000..2813d6af7 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiNotificationsManager.java @@ -0,0 +1,140 @@ +package nodomain.freeyourgadget.gadgetbridge.service.devices.huawei; + +import android.text.TextUtils; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.Queue; + +import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventNotificationControl; +import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.Notifications; +import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec; +import nodomain.freeyourgadget.gadgetbridge.model.NotificationType; +import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SendNotificationRequest; +import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SendNotificationRemoveRequest; + +public class HuaweiNotificationsManager { + private static final Logger LOG = LoggerFactory.getLogger(HuaweiNotificationsManager.class); + + private final HuaweiSupportProvider support; + private final Queue notificationSpecCache = new LinkedList<>(); + + public HuaweiNotificationsManager(HuaweiSupportProvider support) { + this.support = support; + } + + private void addNotificationToCache(NotificationSpec notificationSpec) { + // TODO: rewrite this + if (notificationSpecCache.size() > 10) + notificationSpecCache.poll(); + + Iterator iterator = notificationSpecCache.iterator(); + while (iterator.hasNext()) { + NotificationSpec e = iterator.next(); + if (e.getId() == notificationSpec.getId()) { + iterator.remove(); + } + } + notificationSpecCache.offer(notificationSpec); + } + + + public void onNotification(NotificationSpec notificationSpec) { + + addNotificationToCache(notificationSpec); + + SendNotificationRequest sendNotificationReq = new SendNotificationRequest(this.support); + try { + sendNotificationReq.buildNotificationTLVFromNotificationSpec(notificationSpec); + sendNotificationReq.doPerform(); + } catch (IOException e) { + LOG.error("Sending notification failed", e); + } + } + + public void onDeleteNotification(int id) { + if (!support.getHuaweiCoordinator().supportsNotificationsRepeatedNotify() && !support.getHuaweiCoordinator().supportsNotificationsRemoveSingle()) { + LOG.info("Delete notification is not supported"); + return; + } + NotificationSpec notificationSpec = null; + Iterator iterator = notificationSpecCache.iterator(); + while (iterator.hasNext()) { + notificationSpec = iterator.next(); + if (notificationSpec.getId() == id) { + iterator.remove(); + break; + } + } + if (notificationSpec == null) { + LOG.info("Notification is not found"); + return; + } + + try { + SendNotificationRemoveRequest sendNotificationReq = new SendNotificationRemoveRequest(this.support, + SendNotificationRequest.getNotificationType(notificationSpec.type), // notificationType + notificationSpec.sourceAppId, + notificationSpec.key, + id, + "", // TODO: + null); + sendNotificationReq.doPerform(); + } catch (IOException e) { + LOG.error("Sending notification remove failed", e); + } + } + + void onReplyResponse(Notifications.NotificationReply.ReplyResponse response) { + LOG.info(" KEY: {}, Text: {}", response.key, response.text); + if(!this.support.getHuaweiCoordinator().supportsNotificationsReply()) { + LOG.info("Reply is not supported"); + return; + } + if (TextUtils.isEmpty(response.key) || TextUtils.isEmpty(response.text)) { + LOG.info("Reply is empty"); + return; + } + if(response.type != 1 && response.type != 2) { + LOG.info("Reply: only type 1 and 2 supported"); + return; + } + NotificationSpec notificationSpec = null; + for (NotificationSpec spec : notificationSpecCache) { + notificationSpec = spec; + if (notificationSpec.key.equals(response.key)) { + break; + } + } + if (notificationSpec == null) { + LOG.info("Notification for reply is not found"); + return; + } + final GBDeviceEventNotificationControl deviceEvtNotificationControl = new GBDeviceEventNotificationControl(); + deviceEvtNotificationControl.handle = notificationSpec.getId(); + deviceEvtNotificationControl.event = GBDeviceEventNotificationControl.Event.REPLY; + deviceEvtNotificationControl.reply = response.text; + if (notificationSpec.type.equals(NotificationType.GENERIC_PHONE) || notificationSpec.type.equals(NotificationType.GENERIC_SMS)) { + deviceEvtNotificationControl.phoneNumber = notificationSpec.phoneNumber; + } else { + final boolean hasActions = (null != notificationSpec.attachedActions && !notificationSpec.attachedActions.isEmpty()); + if (hasActions) { + for (int i = 0; i < notificationSpec.attachedActions.size(); i++) { + final NotificationSpec.Action action = notificationSpec.attachedActions.get(i); + if (action.type == NotificationSpec.Action.TYPE_WEARABLE_REPLY || action.type == NotificationSpec.Action.TYPE_SYNTECTIC_REPLY_PHONENR) { + deviceEvtNotificationControl.handle = action.handle; //handle of wearable action is needed + break; + } + } + } + + } + this.support.evaluateGBDeviceEvent(deviceEvtNotificationControl); + //TODO: maybe should be send reply. Service: 0x2, command: 0x10, tlv 7 and/or 1, type byte, 7f on error + } + +} 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 015d9a837..f1e39629c 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 @@ -245,9 +245,12 @@ public class HuaweiSupportProvider { protected HuaweiMusicManager huaweiMusicManager = new HuaweiMusicManager(this); + protected HuaweiNotificationsManager huaweiNotificationsManager = new HuaweiNotificationsManager(this); + //TODO: we need only one instance of manager and all it services. protected HuaweiP2PManager huaweiP2PManager = new HuaweiP2PManager(this); + public HuaweiCoordinatorSupplier getCoordinator() { return ((HuaweiCoordinatorSupplier) this.gbDevice.getDeviceCoordinator()); } @@ -276,6 +279,10 @@ public class HuaweiSupportProvider { return huaweiEphemerisManager; } + public HuaweiNotificationsManager getHuaweiNotificationsManager() { + return huaweiNotificationsManager; + } + public HuaweiMusicManager getHuaweiMusicManager() { return huaweiMusicManager; } @@ -1408,21 +1415,17 @@ public class HuaweiSupportProvider { } return msgId; } - public void onNotification(NotificationSpec notificationSpec) { if (!GBApplication.getDeviceSpecificSharedPrefs(getDevice().getAddress()).getBoolean(DeviceSettingsPreferenceConst.PREF_NOTIFICATION_ENABLE, false)) { // Don't send notifications when they are disabled LOG.info("Stopped notification as they are disabled."); return; } + huaweiNotificationsManager.onNotification(notificationSpec); + } - SendNotificationRequest sendNotificationReq = new SendNotificationRequest(this); - try { - sendNotificationReq.buildNotificationTLVFromNotificationSpec(notificationSpec); - sendNotificationReq.doPerform(); - } catch (IOException e) { - LOG.error("Sending notification failed", e); - } + public void onDeleteNotification(int id) { + huaweiNotificationsManager.onDeleteNotification(id); } public void setDateFormat() { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/requests/SendNotificationRemoveRequest.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/requests/SendNotificationRemoveRequest.java new file mode 100644 index 000000000..cd2444916 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/requests/SendNotificationRemoveRequest.java @@ -0,0 +1,55 @@ +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.Notifications; +import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.HuaweiSupportProvider; + +public class SendNotificationRemoveRequest extends Request { + + private static final Logger LOG = LoggerFactory.getLogger(SendNotificationRemoveRequest.class); + + private final byte notificationType; + private final String sourceAppId; + private final String notificationKey; + private final int notificationId; + private final String notificationChannelId; + private final String notificationCategory; + + public SendNotificationRemoveRequest(HuaweiSupportProvider support, byte notificationType, String sourceAppId, String notificationKey, int notificationId, String notificationChannelId, String notificationCategory) { + super(support); + this.serviceId = Notifications.id; + this.commandId = Notifications.NotificationRemoveAction.id; + this.notificationType = notificationType; + this.sourceAppId = sourceAppId; + this.notificationKey = notificationKey; + this.notificationId = notificationId; + this.notificationChannelId = notificationChannelId; + this.notificationCategory = notificationCategory; + } + + @Override + protected List createRequest() throws RequestCreationException { + try { + return new Notifications.NotificationRemoveAction( + paramsProvider, + this.notificationType, + this.sourceAppId, + this.notificationKey, + this.notificationId, + this.notificationChannelId, + this.notificationCategory).serialize(); + } catch (HuaweiPacket.CryptoException e) { + throw new RequestCreationException(e); + } + } + + @Override + protected void processResponse() { + LOG.debug("handle NotificationRemove"); + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/requests/SendNotificationRequest.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/requests/SendNotificationRequest.java index 1eb3040ab..3fa9f6caa 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/requests/SendNotificationRequest.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/requests/SendNotificationRequest.java @@ -66,6 +66,18 @@ public class SendNotificationRequest extends Request { body = notificationSpec.body.substring(0x0, supportProvider.getHuaweiCoordinator().getContentLength() - 0xD); body += "..."; } + Notifications.NotificationActionRequest.AdditionalParams params = new Notifications.NotificationActionRequest.AdditionalParams(); + + params.supportsSyncKey = supportProvider.getHuaweiCoordinator().supportsNotificationsSyncKey(); + params.supportsRepeatedNotify = supportProvider.getHuaweiCoordinator().supportsNotificationsRepeatedNotify(); + params.supportsRemoveSingle = supportProvider.getHuaweiCoordinator().supportsNotificationsRemoveSingle(); + params.supportsReply = supportProvider.getHuaweiCoordinator().supportsNotificationsReply(); + params.supportsTimestamp = supportProvider.getHuaweiCoordinator().supportsNotificationsTimestamp(); + + params.notificationId = notificationSpec.getId(); + params.notificationKey = notificationSpec.key; + + this.packet = new Notifications.NotificationActionRequest( paramsProvider, supportProvider.getNotificationId(), @@ -74,7 +86,8 @@ public class SendNotificationRequest extends Request { title, notificationSpec.sender, body, - notificationSpec.sourceAppId + notificationSpec.sourceAppId, + params ); } @@ -88,6 +101,7 @@ public class SendNotificationRequest extends Request { callSpec.name, callSpec.name, callSpec.name, + null, null ); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/requests/StopNotificationRequest.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/requests/StopNotificationRequest.java index a153c7f27..72d522c71 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/requests/StopNotificationRequest.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/requests/StopNotificationRequest.java @@ -41,6 +41,7 @@ public class StopNotificationRequest extends Request { null, null, null, + null, null ).serialize(); } catch (HuaweiPacket.CryptoException e) { diff --git a/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/packets/TestNotifications.java b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/packets/TestNotifications.java index 29793da17..6f65f640b 100644 --- a/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/packets/TestNotifications.java +++ b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/packets/TestNotifications.java @@ -106,7 +106,8 @@ public class TestNotifications { titleContent, senderContent, bodyContent, - sourceAppId + sourceAppId, + null ); Assert.assertEquals(0x02, request.serviceId);