mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge
synced 2024-11-28 21:06:50 +01:00
ID115: notification support
This commit is contained in:
parent
4bea2a3407
commit
c9e7a2ff1d
@ -2,6 +2,8 @@ package nodomain.freeyourgadget.gadgetbridge.devices.id115;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.NotificationType;
|
||||
|
||||
import static nodomain.freeyourgadget.gadgetbridge.service.btle.AbstractBTLEDeviceSupport.BASE_UUID;
|
||||
|
||||
public class ID115Constants {
|
||||
@ -28,6 +30,53 @@ public class ID115Constants {
|
||||
public static final byte CMD_KEY_SET_TIME = 0x01;
|
||||
public static final byte CMD_KEY_SET_DISPLAY_MODE = 0x2B;
|
||||
|
||||
// CMD_ID_NOTIFY
|
||||
public static final byte CMD_KEY_NOTIFY_CALL = 0x01;
|
||||
public static final byte CMD_KEY_NOTIFY_STOP = 0x02;
|
||||
public static final byte CMD_KEY_NOTIFY_MSG = 0x03;
|
||||
|
||||
// CMD_ID_DEVICE_RESTART
|
||||
public static final byte CMD_KEY_REBOOT = 0x01;
|
||||
|
||||
public static byte getNotificationType(NotificationType type) {
|
||||
switch (type) {
|
||||
// case GENERIC_EMAIL:
|
||||
// return 2; // Icon is not supported
|
||||
case WECHAT:
|
||||
return 3;
|
||||
// case QQ:
|
||||
// return 4;
|
||||
case FACEBOOK:
|
||||
return 6;
|
||||
case TWITTER:
|
||||
return 7;
|
||||
case WHATSAPP:
|
||||
return 8;
|
||||
case FACEBOOK_MESSENGER:
|
||||
return 9;
|
||||
case INSTAGRAM:
|
||||
return 10;
|
||||
case LINKEDIN:
|
||||
return 11;
|
||||
// case GENERIC_CALENDAR:
|
||||
// return 12; // Icon is not supported
|
||||
// case SKYPE:
|
||||
// return 13; // Icon is not supported
|
||||
// case LINE:
|
||||
// return 17; // Icon is not supported
|
||||
// case VIBER:
|
||||
// return 18; // Icon is not supported
|
||||
// case KAKAO_TALK:
|
||||
// return 19; // Icon is not supported
|
||||
// case VK:
|
||||
// return 16; // Icon is not supported
|
||||
// case GMAIL:
|
||||
// return 20; // Icon is not supported
|
||||
// case OUTLOOK:
|
||||
// return 21; // Icon is not supported
|
||||
// case SNAPCHAT:
|
||||
// return 22; // Icon is not supported
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
@ -1,15 +1,17 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.id115;
|
||||
|
||||
import android.bluetooth.BluetoothGatt;
|
||||
import android.bluetooth.BluetoothGattCharacteristic;
|
||||
import android.net.Uri;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.TimeZone;
|
||||
import java.util.UUID;
|
||||
|
||||
@ -22,6 +24,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.CannedMessagesSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.NotificationType;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.AbstractBTLEDeviceSupport;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.GattService;
|
||||
@ -32,8 +35,14 @@ public class ID115Support extends AbstractBTLEDeviceSupport {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ID115Support.class);
|
||||
|
||||
public BluetoothGattCharacteristic normalWriteCharacteristic = null;
|
||||
public BluetoothGattCharacteristic normalNotifyCharacteristic = null;
|
||||
public BluetoothGattCharacteristic healthWriteCharacteristic = null;
|
||||
|
||||
byte[] currentNotificationBuffer;
|
||||
int currentNotificationSize;
|
||||
int currentNotificationIndex;
|
||||
byte currentNotificationType;
|
||||
|
||||
public ID115Support() {
|
||||
super(LOG);
|
||||
addSupportedService(GattService.UUID_SERVICE_GENERIC_ACCESS);
|
||||
@ -44,10 +53,14 @@ public class ID115Support extends AbstractBTLEDeviceSupport {
|
||||
@Override
|
||||
protected TransactionBuilder initializeDevice(TransactionBuilder builder) {
|
||||
normalWriteCharacteristic = getCharacteristic(ID115Constants.UUID_CHARACTERISTIC_WRITE_NORMAL);
|
||||
normalNotifyCharacteristic = getCharacteristic(ID115Constants.UUID_CHARACTERISTIC_NOTIFY_NORMAL);
|
||||
healthWriteCharacteristic = getCharacteristic(ID115Constants.UUID_CHARACTERISTIC_WRITE_HEALTH);
|
||||
|
||||
builder.add(new SetDeviceStateAction(getDevice(), GBDevice.State.INITIALIZING, getContext()));
|
||||
|
||||
builder.setGattCallback(this);
|
||||
builder.notify(normalNotifyCharacteristic, true);
|
||||
|
||||
setTime(builder)
|
||||
.setDisplayMode(builder, false)
|
||||
.setInitialized(builder);
|
||||
@ -62,7 +75,7 @@ public class ID115Support extends AbstractBTLEDeviceSupport {
|
||||
|
||||
@Override
|
||||
public void onNotification(NotificationSpec notificationSpec) {
|
||||
|
||||
sendMessageNotification(notificationSpec);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -87,7 +100,11 @@ public class ID115Support extends AbstractBTLEDeviceSupport {
|
||||
|
||||
@Override
|
||||
public void onSetCallState(CallSpec callSpec) {
|
||||
|
||||
if (callSpec.command == CallSpec.CALL_INCOMING) {
|
||||
sendCallNotification(callSpec);
|
||||
} else {
|
||||
sendStopCallNotification();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -219,6 +236,40 @@ public class ID115Support extends AbstractBTLEDeviceSupport {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCharacteristicChanged(BluetoothGatt gatt,
|
||||
BluetoothGattCharacteristic characteristic) {
|
||||
if (super.onCharacteristicChanged(gatt, characteristic)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
UUID characteristicUUID = characteristic.getUuid();
|
||||
byte[] data = characteristic.getValue();
|
||||
if (!characteristicUUID.equals(ID115Constants.UUID_CHARACTERISTIC_NOTIFY_NORMAL)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (data.length < 2) {
|
||||
LOG.warn("short GATT response");
|
||||
return false;
|
||||
}
|
||||
if (data[0] == ID115Constants.CMD_ID_NOTIFY) {
|
||||
if (data.length < 4) {
|
||||
LOG.warn("short GATT response for NOTIFY");
|
||||
return false;
|
||||
}
|
||||
if (data[1] == currentNotificationType) {
|
||||
if (data[3] == currentNotificationIndex) {
|
||||
if (currentNotificationIndex != currentNotificationSize) {
|
||||
sendNotificationChunk(currentNotificationIndex + 1);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void setInitialized(TransactionBuilder builder) {
|
||||
builder.add(new SetDeviceStateAction(getDevice(), GBDevice.State.INITIALIZED, getContext()));
|
||||
}
|
||||
@ -258,4 +309,140 @@ public class ID115Support extends AbstractBTLEDeviceSupport {
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
void sendCallNotification(CallSpec callSpec) {
|
||||
String number = "";
|
||||
if (callSpec.number != null) {
|
||||
number = callSpec.number;
|
||||
}
|
||||
|
||||
String name = "";
|
||||
if (callSpec.name != null) {
|
||||
name = callSpec.name;
|
||||
}
|
||||
|
||||
currentNotificationBuffer = encodeCallNotification(name, number);
|
||||
currentNotificationSize = (currentNotificationBuffer.length + 15) / 16;
|
||||
currentNotificationType = ID115Constants.CMD_KEY_NOTIFY_CALL;
|
||||
sendNotificationChunk(1);
|
||||
}
|
||||
|
||||
void sendStopCallNotification() {
|
||||
try {
|
||||
TransactionBuilder builder = performInitialized("stop_call_notification");
|
||||
builder.write(normalWriteCharacteristic, new byte[] {
|
||||
ID115Constants.CMD_ID_NOTIFY,
|
||||
ID115Constants.CMD_KEY_NOTIFY_STOP,
|
||||
1
|
||||
});
|
||||
performConnected(builder.getTransaction());
|
||||
} catch(IOException e) {
|
||||
}
|
||||
}
|
||||
|
||||
void sendMessageNotification(NotificationSpec notificationSpec) {
|
||||
String phone = "";
|
||||
if (notificationSpec.phoneNumber != null) {
|
||||
phone = notificationSpec.phoneNumber;
|
||||
}
|
||||
|
||||
String title = "";
|
||||
if (notificationSpec.sender != null) {
|
||||
title = notificationSpec.sender;
|
||||
} else if (notificationSpec.title != null) {
|
||||
title = notificationSpec.title;
|
||||
} else if (notificationSpec.subject != null) {
|
||||
title = notificationSpec.subject;
|
||||
}
|
||||
|
||||
String text = "";
|
||||
if (notificationSpec.body != null) {
|
||||
text = notificationSpec.body;
|
||||
}
|
||||
|
||||
currentNotificationBuffer = encodeMessageNotification(notificationSpec.type, title, phone, text);
|
||||
currentNotificationSize = (currentNotificationBuffer.length + 15) / 16;
|
||||
currentNotificationType = ID115Constants.CMD_KEY_NOTIFY_MSG;
|
||||
sendNotificationChunk(1);
|
||||
}
|
||||
|
||||
void sendNotificationChunk(int chunkIndex) {
|
||||
currentNotificationIndex = chunkIndex;
|
||||
|
||||
int offset = (chunkIndex - 1) * 16;
|
||||
int tailSize = currentNotificationBuffer.length - offset;
|
||||
int chunkSize = (tailSize > 16)? 16 : tailSize;
|
||||
|
||||
byte raw[] = new byte[16];
|
||||
System.arraycopy(currentNotificationBuffer, offset, raw, 0, chunkSize);
|
||||
|
||||
try {
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
outputStream.write(ID115Constants.CMD_ID_NOTIFY);
|
||||
outputStream.write(currentNotificationType);
|
||||
outputStream.write((byte)currentNotificationSize);
|
||||
outputStream.write((byte)currentNotificationIndex);
|
||||
outputStream.write(raw);
|
||||
byte cmd[] = outputStream.toByteArray();
|
||||
|
||||
TransactionBuilder builder = performInitialized("notification");
|
||||
builder.write(normalWriteCharacteristic, cmd);
|
||||
performConnected(builder.getTransaction());
|
||||
} catch (IOException e) {
|
||||
}
|
||||
}
|
||||
|
||||
byte[] encodeCallNotification(String name, String phone) {
|
||||
if (name.length() > 20) {
|
||||
name = name.substring(0, 20);
|
||||
}
|
||||
if (phone.length() > 20) {
|
||||
phone = phone.substring(0, 20);
|
||||
}
|
||||
|
||||
byte[] name_bytes = name.getBytes(StandardCharsets.UTF_8);
|
||||
byte[] phone_bytes = phone.getBytes(StandardCharsets.UTF_8);
|
||||
|
||||
try {
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
outputStream.write((byte) phone_bytes.length);
|
||||
outputStream.write((byte) name_bytes.length);
|
||||
outputStream.write(phone_bytes);
|
||||
outputStream.write(name_bytes);
|
||||
return outputStream.toByteArray();
|
||||
} catch (IOException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
byte[] encodeMessageNotification(NotificationType type, String title, String phone, String text) {
|
||||
if (title.length() > 20) {
|
||||
title = title.substring(0, 20);
|
||||
}
|
||||
if (phone.length() > 20) {
|
||||
phone = phone.substring(0, 20);
|
||||
}
|
||||
if (text.length() > 20) {
|
||||
text = text.substring(0, 20);
|
||||
}
|
||||
byte[] title_bytes = title.getBytes(StandardCharsets.UTF_8);
|
||||
byte[] phone_bytes = phone.getBytes(StandardCharsets.UTF_8);
|
||||
byte[] text_bytes = text.getBytes(StandardCharsets.UTF_8);
|
||||
|
||||
byte nativeType = ID115Constants.getNotificationType(type);
|
||||
|
||||
try {
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
outputStream.write(nativeType);
|
||||
outputStream.write((byte) text_bytes.length);
|
||||
outputStream.write((byte) phone_bytes.length);
|
||||
outputStream.write((byte) title_bytes.length);
|
||||
outputStream.write(phone_bytes);
|
||||
outputStream.write(title_bytes);
|
||||
outputStream.write(text_bytes);
|
||||
return outputStream.toByteArray();
|
||||
} catch (IOException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user