1
0
mirror of https://codeberg.org/Freeyourgadget/Gadgetbridge synced 2024-10-19 01:39:39 +02:00
Gadgetbridge/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/vivomovehr/ancs/AncsControlCommand.java
2024-01-10 19:01:48 +01:00

138 lines
6.2 KiB
Java

/* Copyright (C) 2023-2024 Petr Kadlec
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.vivomovehr.ancs;
import nodomain.freeyourgadget.gadgetbridge.service.btle.BLETypeConversions;
import nodomain.freeyourgadget.gadgetbridge.service.devices.vivomovehr.messages.MessageReader;
import nodomain.freeyourgadget.gadgetbridge.util.ArrayUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
public abstract class AncsControlCommand {
private static final Logger LOG = LoggerFactory.getLogger(AncsControlCommand.class);
private static final AncsAppAttribute[] APP_ATTRIBUTE_VALUES = AncsAppAttribute.values();
private static final AncsAction[] ACTION_VALUES = AncsAction.values();
public final AncsCommand command;
protected AncsControlCommand(AncsCommand command) {
this.command = command;
}
public static AncsControlCommand parseCommand(byte[] buffer, int offset, int size) {
final int commandID = BLETypeConversions.toUnsigned(buffer, offset);
final AncsCommand command = AncsCommand.getByCode(commandID);
if (command == null) {
LOG.error("Unknown ANCS command {}", commandID);
return null;
}
switch (command) {
case GET_NOTIFICATION_ATTRIBUTES:
return createGetNotificationAttributesCommand(buffer, offset + 1, size - 1);
case GET_APP_ATTRIBUTES:
return createGetAppAttributesCommand(buffer, offset + 1, size - 1);
case PERFORM_NOTIFICATION_ACTION:
return createPerformNotificationAction(buffer, offset + 1, size - 1);
case PERFORM_ANDROID_ACTION:
return createPerformAndroidAction(buffer, offset + 1, size - 1);
default:
LOG.error("Unknown ANCS command {}", command);
return null;
}
}
private static AncsPerformAndroidAction createPerformAndroidAction(byte[] buffer, int offset, int size) {
final int notificationUID = BLETypeConversions.toUint32(buffer, offset);
final int actionID = BLETypeConversions.toUnsigned(buffer, offset + 4);
final AncsAndroidAction action = AncsAndroidAction.getByCode(actionID);
if (action == null) {
LOG.error("Unknown ANCS Android action {}", actionID);
return null;
}
int zero = ArrayUtils.indexOf((byte) 0, buffer, offset + 6, size - offset - 6);
if (zero < 0) zero = size;
final String text = new String(buffer, offset + 6, zero - offset - 6);
return new AncsPerformAndroidAction(notificationUID, action, text);
}
private static AncsPerformNotificationAction createPerformNotificationAction(byte[] buffer, int offset, int size) {
final MessageReader reader = new MessageReader(buffer, offset);
final int notificationUID = reader.readInt();
final int actionID = reader.readByte();
if (actionID < 0 || actionID >= ACTION_VALUES.length) {
LOG.error("Unknown ANCS action {}", actionID);
return null;
}
return new AncsPerformNotificationAction(notificationUID, ACTION_VALUES[actionID]);
}
private static AncsGetAppAttributesCommand createGetAppAttributesCommand(byte[] buffer, int offset, int size) {
int zero = ArrayUtils.indexOf((byte) 0, buffer, offset, size - offset);
if (zero < 0) zero = size;
final String appIdentifier = new String(buffer, offset, zero - offset, StandardCharsets.UTF_8);
final int attributeCount = size - (zero - offset);
final List<AncsAppAttribute> requestedAttributes = new ArrayList<>(attributeCount);
for (int i = 0; i < attributeCount; ++i) {
final int attributeID = BLETypeConversions.toUnsigned(buffer, zero + 1 + i);
if (attributeID < 0 || attributeID >= APP_ATTRIBUTE_VALUES.length) {
LOG.error("Unknown ANCS app attribute {}", attributeID);
return null;
}
final AncsAppAttribute attribute = APP_ATTRIBUTE_VALUES[attributeID];
requestedAttributes.add(attribute);
}
return new AncsGetAppAttributesCommand(appIdentifier, requestedAttributes);
}
private static AncsGetNotificationAttributeCommand createGetNotificationAttributesCommand(byte[] buffer, int offset, int size) {
final MessageReader reader = new MessageReader(buffer, offset);
final int notificationUID = reader.readInt();
int pos = 4;
final List<AncsAttributeRequest> attributes = new ArrayList<>(size);
while (pos < size) {
final int attributeID = reader.readByte();
++pos;
final AncsAttribute attribute = AncsAttribute.getByCode(attributeID);
if (attribute == null) {
LOG.error("Unknown ANCS attribute {}", attributeID);
return null;
}
final int maxLength;
if (attribute.hasLengthParam) {
maxLength = reader.readShort();
pos += 2;
} else if (attribute.hasAdditionalParams) {
maxLength = reader.readByte();
// TODO: What is this??
reader.readByte();
reader.readByte();
pos += 3;
} else {
maxLength = 0;
}
attributes.add(new AncsAttributeRequest(attribute, maxLength));
}
return new AncsGetNotificationAttributeCommand(notificationUID, attributes);
}
}