/* Copyright (C) 2023-2024 Frank Ertl This file is part of Gadgetbridge. Gadgetbridge is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Gadgetbridge is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ package nodomain.freeyourgadget.gadgetbridge.service.devices.withingssteelhr.communication.notification; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.HashMap; import java.util.List; import java.util.Map; import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec; import nodomain.freeyourgadget.gadgetbridge.model.NotificationType; import nodomain.freeyourgadget.gadgetbridge.service.devices.withingssteelhr.WithingsSteelHRDeviceSupport; import nodomain.freeyourgadget.gadgetbridge.util.GB; public class NotificationProvider { private static final Logger logger = LoggerFactory.getLogger(NotificationProvider.class); private final WithingsSteelHRDeviceSupport support; private final Map pendingNotifications = new HashMap<>(); private static NotificationProvider instance; public static NotificationProvider getInstance(WithingsSteelHRDeviceSupport support) { if (instance == null) { instance = new NotificationProvider(support); } return instance; } private NotificationProvider(WithingsSteelHRDeviceSupport support) { this.support = support; } public void notifyClient(NotificationSpec spec) { NotificationSource notificationSource = new NotificationSource(spec.getId(), AncsConstants.EVENT_ID_NOTIFICATION_ADDED, AncsConstants.EVENT_FLAGS_IMPORTANT, mapNotificationType(spec.type), (byte)1); pendingNotifications.put(notificationSource.getNotificationUID(), spec); support.sendAncsNotificationSourceNotification(notificationSource); } public void handleNotificationAttributeRequest(GetNotificationAttributes request) { logger.debug("Request has ID: " + request.getNotificationUID()); NotificationSpec spec = pendingNotifications.get(request.getNotificationUID()); if (spec == null) { logger.info("No pending notification with notificationUID " + request.getNotificationUID()); NotificationSource notificationSource = new NotificationSource(request.getNotificationUID(), AncsConstants.EVENT_ID_NOTIFICATION_REMOVED, AncsConstants.EVENT_FLAGS_IMPORTANT, (byte)0, (byte)1); support.sendAncsNotificationSourceNotification(notificationSource); return; } GetNotificationAttributesResponse response = new GetNotificationAttributesResponse(request.getNotificationUID()); List requestedAttributes = request.getAttributes(); logger.debug(requestedAttributes.size() + " attributes requested."); boolean complete = false; for (RequestedNotificationAttribute requestedAttribute : requestedAttributes) { NotificationAttribute attribute = new NotificationAttribute(); attribute.setAttributeID(requestedAttribute.getAttributeID()); attribute.setAttributeMaxLength(requestedAttribute.getAttributeMaxLength()); logger.debug("Handling attribute " + attribute.getAttributeID() + " with maxLength " + attribute.getAttributeLength()); String value = ""; if (requestedAttribute.getAttributeID() == 0) { value = spec.sourceAppId; } if (requestedAttribute.getAttributeID() == 1) { complete = true; value = spec.sender != null? spec.sender : (spec.phoneNumber != null? spec.phoneNumber : (spec.sourceName != null? spec.sourceName : "Unknown")); } if (requestedAttribute.getAttributeID() == 2) { complete = true; value = spec.title != null? spec.title : (spec.subject != null? spec.subject : " "); } if (requestedAttribute.getAttributeID() == 3) { complete = true; value = (spec.body != null? spec.body : " "); } if (value != null) { // Remove linefeed and carriage returns as the watch cannot display this: value = value.replace("\n", " "); value = value.replace("\r", " "); if (requestedAttribute.getAttributeMaxLength() == 0 || requestedAttribute.getAttributeMaxLength() >= value.length()) { attribute.setValue(value); } else { attribute.setValue(value.substring(0, requestedAttribute.getAttributeMaxLength())); } } logger.debug("Sending attribute " + attribute.getAttributeID() + " with value " + attribute.getValue()); response.addAttribute(attribute); } support.sendAncsDataSourceNotification(response); if (complete) { pendingNotifications.remove(request.getNotificationUID()); } } public NotificationSpec getNotificationSpecForSourceAppId(String sourceAppId) { for (NotificationSpec notificationSpec : pendingNotifications.values()) { if (notificationSpec.sourceAppId != null && notificationSpec.sourceAppId.equalsIgnoreCase(sourceAppId)) { return notificationSpec; } } return null; } private byte mapNotificationType(NotificationType type) { switch (type) { case GENERIC_ALARM_CLOCK: case BUSINESS_CALENDAR: case GENERIC_CALENDAR: return AncsConstants.CATEGORY_ID_SCHEDULE; case GENERIC_EMAIL: case YAHOO_MAIL: case GOOGLE_INBOX: case GMAIL: case OUTLOOK: return AncsConstants.CATEGORY_ID_EMAIL; case GENERIC_NAVIGATION: return AncsConstants.CATEGORY_ID_LOCATION; case GENERIC_PHONE: return AncsConstants.CATEGORY_ID_INCOMING_CALL; case MAILBOX: return AncsConstants.CATEGORY_ID_MISSED_CALL; case LINE: case RIOT: case SIGNAL: case WIRE: case SKYPE: case SLACK: case SNAPCHAT: case TELEGRAM: case THREEMA: case KONTALK: case ANTOX: case DISCORD: case TRANSIT: case TWITTER: case VIBER: case WECHAT: case WHATSAPP: case FACEBOOK: case FACEBOOK_MESSENGER: case LINKEDIN: case HIPCHAT: case INSTAGRAM: case KAKAO_TALK: case GENERIC_SMS: case GOOGLE_MESSENGER: case GOOGLE_HANGOUTS: return AncsConstants.CATEGORY_ID_SOCIAL; default: return AncsConstants.CATEGORY_ID_OTHER; } } }