mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge
synced 2024-11-24 10:56:50 +01:00
Pebble: unify code for 2.x and >= 3.x notification encoding
Not very clean but deduplicated a lot of code which was no longer maintainable twice
This commit is contained in:
parent
206b718155
commit
fcfcc5cb0b
@ -504,15 +504,11 @@ public class PebbleProtocol extends GBDeviceProtocol {
|
|||||||
}
|
}
|
||||||
ts /= 1000;
|
ts /= 1000;
|
||||||
|
|
||||||
if (mFwMajor >= 3) {
|
if (mFwMajor >= 3 || mForceProtocol || notificationSpec.type != NotificationType.GENERIC_EMAIL) {
|
||||||
// 3.x notification
|
// 3.x notification
|
||||||
return encodeBlobdbNotification(id, (int) (ts & 0xffffffffL), title, subtitle, notificationSpec.body,
|
return encodeNotification(id, (int) (ts & 0xffffffffL), title, subtitle, notificationSpec.body,
|
||||||
notificationSpec.sourceName, hasHandle, notificationSpec.type, notificationSpec.pebbleColor,
|
notificationSpec.sourceName, hasHandle, notificationSpec.type, notificationSpec.pebbleColor,
|
||||||
notificationSpec.cannedReplies, notificationSpec.attachedActions);
|
notificationSpec.cannedReplies, notificationSpec.attachedActions);
|
||||||
} else if (mForceProtocol || notificationSpec.type != NotificationType.GENERIC_EMAIL) {
|
|
||||||
// 2.x notification
|
|
||||||
return encodeExtensibleNotification(id, (int) (ts & 0xffffffffL), title, subtitle, notificationSpec.body,
|
|
||||||
notificationSpec.sourceName, hasHandle, notificationSpec.cannedReplies, notificationSpec.attachedActions);
|
|
||||||
} else {
|
} else {
|
||||||
// 1.x notification on FW 2.X
|
// 1.x notification on FW 2.X
|
||||||
String[] parts = {title, notificationSpec.body, String.valueOf(ts), subtitle};
|
String[] parts = {title, notificationSpec.body, String.valueOf(ts), subtitle};
|
||||||
@ -595,138 +591,6 @@ public class PebbleProtocol extends GBDeviceProtocol {
|
|||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: add support for attachedActions
|
|
||||||
private byte[] encodeExtensibleNotification(int id, int timestamp, String title, String subtitle, String body, String sourceName, boolean hasHandle, String[] cannedReplies, ArrayList attachedActions) {
|
|
||||||
final short ACTION_LENGTH_MIN = 6;
|
|
||||||
|
|
||||||
String[] parts = {title, subtitle, body};
|
|
||||||
|
|
||||||
// Calculate length first
|
|
||||||
byte actions_count;
|
|
||||||
short actions_length;
|
|
||||||
String dismiss_string;
|
|
||||||
String open_string = GBApplication.getContext().getString(R.string._pebble_watch_open_on_phone);
|
|
||||||
String mute_string = GBApplication.getContext().getString(R.string._pebble_watch_mute);
|
|
||||||
String reply_string = GBApplication.getContext().getString(R.string._pebble_watch_reply);
|
|
||||||
if (sourceName != null) {
|
|
||||||
mute_string += " " + sourceName;
|
|
||||||
}
|
|
||||||
|
|
||||||
byte dismiss_action_id;
|
|
||||||
|
|
||||||
if (hasHandle && !"ALARMCLOCKRECEIVER".equals(sourceName)) {
|
|
||||||
actions_count = 3;
|
|
||||||
dismiss_string = "Dismiss";
|
|
||||||
dismiss_action_id = 0x02;
|
|
||||||
actions_length = (short) (ACTION_LENGTH_MIN * actions_count + dismiss_string.getBytes().length + open_string.getBytes().length + mute_string.getBytes().length);
|
|
||||||
} else {
|
|
||||||
actions_count = 1;
|
|
||||||
dismiss_string = "Dismiss all";
|
|
||||||
dismiss_action_id = 0x03;
|
|
||||||
actions_length = (short) (ACTION_LENGTH_MIN * actions_count + dismiss_string.getBytes().length);
|
|
||||||
}
|
|
||||||
|
|
||||||
int replies_length = -1;
|
|
||||||
if (cannedReplies != null && cannedReplies.length > 0) {
|
|
||||||
actions_count++;
|
|
||||||
for (String reply : cannedReplies) {
|
|
||||||
replies_length += reply.getBytes().length + 1;
|
|
||||||
}
|
|
||||||
actions_length += (short) (ACTION_LENGTH_MIN + reply_string.getBytes().length + replies_length + 3); // 3 = attribute id (byte) + length(short)
|
|
||||||
}
|
|
||||||
|
|
||||||
byte attributes_count = 0;
|
|
||||||
|
|
||||||
int length = 21 + 10 + actions_length;
|
|
||||||
for (String s : parts) {
|
|
||||||
if (s == null || s.equals("")) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
attributes_count++;
|
|
||||||
length += (3 + s.getBytes().length);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Encode Prefix
|
|
||||||
ByteBuffer buf = ByteBuffer.allocate(length + LENGTH_PREFIX);
|
|
||||||
|
|
||||||
buf.order(ByteOrder.BIG_ENDIAN);
|
|
||||||
buf.putShort((short) (length));
|
|
||||||
buf.putShort(ENDPOINT_EXTENSIBLENOTIFS);
|
|
||||||
|
|
||||||
buf.order(ByteOrder.LITTLE_ENDIAN); // !
|
|
||||||
|
|
||||||
buf.put((byte) 0x00); // ?
|
|
||||||
buf.put((byte) 0x01); // add notifications
|
|
||||||
buf.putInt(0x00000000); // flags - ?
|
|
||||||
buf.putInt(id);
|
|
||||||
buf.putInt(0x00000000); // ANCS id
|
|
||||||
buf.putInt(timestamp);
|
|
||||||
buf.put((byte) 0x01); // layout - ?
|
|
||||||
buf.put(attributes_count);
|
|
||||||
buf.put(actions_count);
|
|
||||||
|
|
||||||
byte attribute_id = 0;
|
|
||||||
// Encode Pascal-Style Strings
|
|
||||||
for (String s : parts) {
|
|
||||||
attribute_id++;
|
|
||||||
if (s == null || s.equals("")) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
int partlength = s.getBytes().length;
|
|
||||||
if (partlength > 255) partlength = 255;
|
|
||||||
buf.put(attribute_id);
|
|
||||||
buf.putShort((short) partlength);
|
|
||||||
buf.put(s.getBytes(), 0, partlength);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// dismiss action
|
|
||||||
buf.put(dismiss_action_id);
|
|
||||||
buf.put((byte) 0x04); // dismiss
|
|
||||||
buf.put((byte) 0x01); // number attributes
|
|
||||||
buf.put((byte) 0x01); // attribute id (title)
|
|
||||||
buf.putShort((short) dismiss_string.getBytes().length);
|
|
||||||
buf.put(dismiss_string.getBytes());
|
|
||||||
|
|
||||||
// open and mute actions
|
|
||||||
if (hasHandle && !"ALARMCLOCKRECEIVER".equals(sourceName)) {
|
|
||||||
buf.put((byte) 0x01);
|
|
||||||
buf.put((byte) 0x02); // generic
|
|
||||||
buf.put((byte) 0x01); // number attributes
|
|
||||||
buf.put((byte) 0x01); // attribute id (title)
|
|
||||||
buf.putShort((short) open_string.getBytes().length);
|
|
||||||
buf.put(open_string.getBytes());
|
|
||||||
|
|
||||||
buf.put((byte) 0x04);
|
|
||||||
buf.put((byte) 0x02); // generic
|
|
||||||
buf.put((byte) 0x01); // number attributes
|
|
||||||
buf.put((byte) 0x01); // attribute id (title)
|
|
||||||
buf.putShort((short) mute_string.getBytes().length);
|
|
||||||
buf.put(mute_string.getBytes());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cannedReplies != null && replies_length > 0) {
|
|
||||||
buf.put((byte) 0x05);
|
|
||||||
buf.put((byte) 0x03); // reply action
|
|
||||||
buf.put((byte) 0x02); // number attributes
|
|
||||||
buf.put((byte) 0x01); // title
|
|
||||||
buf.putShort((short) reply_string.getBytes().length);
|
|
||||||
buf.put(reply_string.getBytes());
|
|
||||||
buf.put((byte) 0x08); // canned replies
|
|
||||||
buf.putShort((short) replies_length);
|
|
||||||
for (int i = 0; i < cannedReplies.length - 1; i++) {
|
|
||||||
buf.put(cannedReplies[i].getBytes());
|
|
||||||
buf.put((byte) 0x00);
|
|
||||||
}
|
|
||||||
// last one must not be zero terminated, else we get an additional emply reply
|
|
||||||
buf.put(cannedReplies[cannedReplies.length - 1].getBytes());
|
|
||||||
}
|
|
||||||
|
|
||||||
return buf.array();
|
|
||||||
}
|
|
||||||
|
|
||||||
private byte[] encodeBlobdb(Object key, byte command, byte db, byte[] blob) {
|
private byte[] encodeBlobdb(Object key, byte command, byte db, byte[] blob) {
|
||||||
|
|
||||||
int length = 5;
|
int length = 5;
|
||||||
@ -930,9 +794,9 @@ public class PebbleProtocol extends GBDeviceProtocol {
|
|||||||
return encodeBlobdb(uuid, BLOBDB_INSERT, BLOBDB_PIN, buf.array());
|
return encodeBlobdb(uuid, BLOBDB_INSERT, BLOBDB_PIN, buf.array());
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte[] encodeBlobdbNotification(int id, int timestamp, String title, String subtitle, String body, String sourceName,
|
private byte[] encodeNotification(int id, int timestamp, String title, String subtitle, String body, String sourceName,
|
||||||
boolean hasHandle, NotificationType notificationType, byte backgroundColor,
|
boolean hasHandle, NotificationType notificationType, byte backgroundColor,
|
||||||
String[] cannedReplies, ArrayList<Action> attachedActions) {
|
String[] cannedReplies, ArrayList<Action> attachedActions) {
|
||||||
final short NOTIFICATION_PIN_LENGTH = 46;
|
final short NOTIFICATION_PIN_LENGTH = 46;
|
||||||
final short ACTION_LENGTH_MIN = 6;
|
final short ACTION_LENGTH_MIN = 6;
|
||||||
|
|
||||||
@ -948,8 +812,8 @@ public class PebbleProtocol extends GBDeviceProtocol {
|
|||||||
int actions_count = 0;
|
int actions_count = 0;
|
||||||
short actions_length = 0;
|
short actions_length = 0;
|
||||||
String dismiss_string;
|
String dismiss_string;
|
||||||
String open_string = "Open on phone";
|
String open_string = GBApplication.getContext().getString(R.string._pebble_watch_open_on_phone);
|
||||||
String mute_string = "Mute";
|
String mute_string = GBApplication.getContext().getString(R.string._pebble_watch_mute);
|
||||||
if (sourceName != null) {
|
if (sourceName != null) {
|
||||||
mute_string += " " + sourceName;
|
mute_string += " " + sourceName;
|
||||||
}
|
}
|
||||||
@ -983,8 +847,13 @@ public class PebbleProtocol extends GBDeviceProtocol {
|
|||||||
actions_length += (short) (replies_length + 3); // 3 = attribute id (byte) + length(short)
|
actions_length += (short) (replies_length + 3); // 3 = attribute id (byte) + length(short)
|
||||||
}
|
}
|
||||||
|
|
||||||
byte attributes_count = 2; // icon
|
byte attributes_count = 0;
|
||||||
short attributes_length = (short) (11 + actions_length);
|
short attributes_length = actions_length;
|
||||||
|
if (mFwMajor >= 3) {
|
||||||
|
attributes_count += 2; // icon
|
||||||
|
attributes_length += 11;
|
||||||
|
}
|
||||||
|
|
||||||
for (String s : parts) {
|
for (String s : parts) {
|
||||||
if (s == null || s.equals("")) {
|
if (s == null || s.equals("")) {
|
||||||
continue;
|
continue;
|
||||||
@ -993,23 +862,52 @@ public class PebbleProtocol extends GBDeviceProtocol {
|
|||||||
attributes_length += (short) (3 + s.getBytes().length);
|
attributes_length += (short) (3 + s.getBytes().length);
|
||||||
}
|
}
|
||||||
|
|
||||||
short pin_length = (short) (NOTIFICATION_PIN_LENGTH + attributes_length);
|
short length;
|
||||||
|
int max_partlength;
|
||||||
|
byte dismiss_action_type;
|
||||||
|
ByteBuffer buf;
|
||||||
|
if (mFwMajor >= 3) {
|
||||||
|
length = (short) (NOTIFICATION_PIN_LENGTH + attributes_length);
|
||||||
|
max_partlength = 512;
|
||||||
|
dismiss_action_type = 0x02; // generic action, dismiss did not do anything
|
||||||
|
buf = ByteBuffer.allocate(length);
|
||||||
|
} else {
|
||||||
|
length = (short) (21 + attributes_length);
|
||||||
|
max_partlength = 256;
|
||||||
|
dismiss_action_type = 0x04; // dismiss
|
||||||
|
buf = ByteBuffer.allocate(length + LENGTH_PREFIX);
|
||||||
|
}
|
||||||
|
|
||||||
ByteBuffer buf = ByteBuffer.allocate(pin_length);
|
|
||||||
|
|
||||||
// pin - 46 bytes
|
|
||||||
buf.order(ByteOrder.BIG_ENDIAN);
|
buf.order(ByteOrder.BIG_ENDIAN);
|
||||||
buf.putLong(GB_UUID_MASK);
|
|
||||||
buf.putLong(id);
|
if (mFwMajor >= 3) {
|
||||||
buf.putLong(UUID_NOTIFICATIONS.getMostSignificantBits());
|
// pin - 46 bytes
|
||||||
buf.putLong(UUID_NOTIFICATIONS.getLeastSignificantBits());
|
buf.putLong(GB_UUID_MASK);
|
||||||
buf.order(ByteOrder.LITTLE_ENDIAN);
|
buf.putLong(id);
|
||||||
buf.putInt(timestamp); // 32-bit timestamp
|
buf.putLong(UUID_NOTIFICATIONS.getMostSignificantBits());
|
||||||
buf.putShort((short) 0); // duration
|
buf.putLong(UUID_NOTIFICATIONS.getLeastSignificantBits());
|
||||||
buf.put((byte) 0x01); // type (0x01 = notification)
|
buf.order(ByteOrder.LITTLE_ENDIAN);
|
||||||
buf.putShort((short) 0x0001); // flags 0x0001 = ?
|
buf.putInt(timestamp); // 32-bit timestamp
|
||||||
buf.put((byte) 0x04); // layout (0x04 = notification?)
|
buf.putShort((short) 0); // duration
|
||||||
buf.putShort(attributes_length); // total length of all attributes and actions in bytes
|
buf.put((byte) 0x01); // type (0x01 = notification)
|
||||||
|
buf.putShort((short) 0x0001); // flags 0x0001 = ?
|
||||||
|
buf.put((byte) 0x04); // layout (0x04 = notification?)
|
||||||
|
buf.putShort(attributes_length); // total length of all attributes and actions in bytes
|
||||||
|
} else {
|
||||||
|
buf.putShort(length);
|
||||||
|
buf.putShort(ENDPOINT_EXTENSIBLENOTIFS);
|
||||||
|
|
||||||
|
buf.order(ByteOrder.LITTLE_ENDIAN); // !
|
||||||
|
|
||||||
|
buf.put((byte) 0x00); // ?
|
||||||
|
buf.put((byte) 0x01); // add notifications
|
||||||
|
buf.putInt(0x00000000); // flags - ?
|
||||||
|
buf.putInt(id);
|
||||||
|
buf.putInt(0x00000000); // ANCS id
|
||||||
|
buf.putInt(timestamp);
|
||||||
|
buf.put((byte) 0x01); // layout - ?
|
||||||
|
|
||||||
|
}
|
||||||
buf.put(attributes_count);
|
buf.put(attributes_count);
|
||||||
buf.put((byte) actions_count);
|
buf.put((byte) actions_count);
|
||||||
|
|
||||||
@ -1022,23 +920,25 @@ public class PebbleProtocol extends GBDeviceProtocol {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int partlength = s.getBytes().length;
|
int partlength = s.getBytes().length;
|
||||||
if (partlength > 512) partlength = 512;
|
if (partlength > max_partlength) partlength = max_partlength;
|
||||||
buf.put(attribute_id);
|
buf.put(attribute_id);
|
||||||
buf.putShort((short) partlength);
|
buf.putShort((short) partlength);
|
||||||
buf.put(s.getBytes(), 0, partlength);
|
buf.put(s.getBytes(), 0, partlength);
|
||||||
}
|
}
|
||||||
|
|
||||||
buf.put((byte) 4); // icon
|
if (mFwMajor >= 3) {
|
||||||
buf.putShort((short) 4); // length of int
|
buf.put((byte) 4); // icon
|
||||||
buf.putInt(0x80000000 | icon_id);
|
buf.putShort((short) 4); // length of int
|
||||||
|
buf.putInt(0x80000000 | icon_id);
|
||||||
|
|
||||||
buf.put((byte) 28); // background_color
|
buf.put((byte) 28); // background_color
|
||||||
buf.putShort((short) 1); // length of int
|
buf.putShort((short) 1); // length of int
|
||||||
buf.put(backgroundColor);
|
buf.put(backgroundColor);
|
||||||
|
}
|
||||||
|
|
||||||
// dismiss action
|
// dismiss action
|
||||||
buf.put(dismiss_action_id);
|
buf.put(dismiss_action_id);
|
||||||
buf.put((byte) 0x02); // generic action, dismiss did not do anything
|
buf.put(dismiss_action_type);
|
||||||
buf.put((byte) 0x01); // number attributes
|
buf.put((byte) 0x01); // number attributes
|
||||||
buf.put((byte) 0x01); // attribute id (title)
|
buf.put((byte) 0x01); // attribute id (title)
|
||||||
buf.putShort((short) dismiss_string.getBytes().length);
|
buf.putShort((short) dismiss_string.getBytes().length);
|
||||||
@ -1087,8 +987,11 @@ public class PebbleProtocol extends GBDeviceProtocol {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (mFwMajor >= 3) {
|
||||||
return encodeBlobdb(UUID.randomUUID(), BLOBDB_INSERT, BLOBDB_NOTIFICATION, buf.array());
|
return encodeBlobdb(UUID.randomUUID(), BLOBDB_INSERT, BLOBDB_NOTIFICATION, buf.array());
|
||||||
|
} else {
|
||||||
|
return buf.array();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte[] encodeActionResponse2x(int id, byte actionId, int iconId, String caption) {
|
private byte[] encodeActionResponse2x(int id, byte actionId, int iconId, String caption) {
|
||||||
|
Loading…
Reference in New Issue
Block a user