1
0
mirror of https://codeberg.org/Freeyourgadget/Gadgetbridge synced 2024-12-28 19:45:50 +01:00

Add support for sending some generic notifications for incoming calls, missed calls, sms, email, social and messenger.

This commit is contained in:
Sebastian Kranz 2018-07-03 13:09:46 +02:00
parent 59095dc29b
commit 497372f377
2 changed files with 386 additions and 5 deletions

View File

@ -55,10 +55,35 @@ public class ZeTimeConstants {
public static final byte CMD_INACTIVITY_ALERT = (byte) 0x5E; public static final byte CMD_INACTIVITY_ALERT = (byte) 0x5E;
public static final byte CMD_CALORIES_TYPE = (byte) 0x60; public static final byte CMD_CALORIES_TYPE = (byte) 0x60;
public static final byte CMD_GET_HEARTRATE_EXDATA = (byte) 0x61; public static final byte CMD_GET_HEARTRATE_EXDATA = (byte) 0x61;
public static final byte CMD_PUSH_EX_MSG = (byte) 0x76;
// here are the action commands // here are the action commands
public static final byte CMD_REQUEST = (byte) 0x70; public static final byte CMD_REQUEST = (byte) 0x70;
public static final byte CMD_SEND = (byte) 0x71;
public static final byte CMD_REQUEST_RESPOND = (byte) 0x80; public static final byte CMD_REQUEST_RESPOND = (byte) 0x80;
// further commands // further commands
public static final byte CMD_END = (byte) 0x8f; public static final byte CMD_END = (byte) 0x8f;
public static final byte CMD_ACK_WRITE = (byte) 0x03; public static final byte CMD_ACK_WRITE = (byte) 0x03;
// notification types and icons
public static final byte NOTIFICATION_MISSED_CALL = (byte) 0x00;
public static final byte NOTIFICATION_SMS = (byte) 0x01;
public static final byte NOTIFICATION_SOCIAL = (byte) 0x02;
public static final byte NOTIFICATION_EMAIL = (byte) 0x03;
public static final byte NOTIFICATION_CALENDAR = (byte) 0x04;
public static final byte NOTIFICATION_INCOME_CALL = (byte) 0x05;
public static final byte NOTIFICATION_CALL_OFF = (byte) 0x06;
public static final byte NOTIFICATION_WECHAT = (byte) 0x07;
public static final byte NOTIFICATION_VIBER = (byte) 0x08;
public static final byte NOTIFICATION_SNAPCHAT = (byte) 0x09;
public static final byte NOTIFICATION_WHATSAPP = (byte) 0x0A;
public static final byte NOTIFICATION_QQ = (byte) 0x0B;
public static final byte NOTIFICATION_FACEBOOK = (byte) 0x0C;
public static final byte NOTIFICATION_HANGOUTS = (byte) 0x0D;
public static final byte NOTIFICATION_GMAIL = (byte) 0x0E;
public static final byte NOTIFICATION_MESSENGER = (byte) 0x0F;
public static final byte NOTIFICATION_INSTAGRAM = (byte) 0x10;
public static final byte NOTIFICATION_TWITTER = (byte) 0x11;
public static final byte NOTIFICATION_LINKEDIN = (byte) 0x12;
public static final byte NOTIFICATION_UBER = (byte) 0x13;
public static final byte NOTIFICATION_LINE = (byte) 0x14;
public static final byte NOTIFICATION_SKYPE = (byte) 0x15;
} }

View File

@ -9,8 +9,11 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.UUID; import java.util.UUID;
import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.GBApplication;
@ -55,6 +58,8 @@ public class ZeTimeDeviceSupport extends AbstractBTLEDeviceSupport {
private int progressSteps; private int progressSteps;
private int progressSleep; private int progressSleep;
private int progressHeartRate; private int progressHeartRate;
private final int maxMsgLength = 20;
private boolean callIncoming = false;
public BluetoothGattCharacteristic notifyCharacteristic = null; public BluetoothGattCharacteristic notifyCharacteristic = null;
public BluetoothGattCharacteristic writeCharacteristic = null; public BluetoothGattCharacteristic writeCharacteristic = null;
@ -151,6 +156,84 @@ public class ZeTimeDeviceSupport extends AbstractBTLEDeviceSupport {
@Override @Override
public void onSetCallState(CallSpec callSpec) { public void onSetCallState(CallSpec callSpec) {
int subject_length = 0;
int notification_length = 0;
byte[] subject = null;
byte[] notification = null;
Calendar time = GregorianCalendar.getInstance();
byte[] datetimeBytes = new byte[]{
(byte) ((time.get(Calendar.YEAR) / 1000) + '0'),
(byte) (((time.get(Calendar.YEAR) / 100)%10) + '0'),
(byte) (((time.get(Calendar.YEAR) / 10)%10) + '0'),
(byte) ((time.get(Calendar.YEAR)%10) + '0'),
(byte) (((time.get(Calendar.MONTH)+1)/10) + '0'),
(byte) (((time.get(Calendar.MONTH)+1)%10) + '0'),
(byte) ((time.get(Calendar.DAY_OF_MONTH)/10) + '0'),
(byte) ((time.get(Calendar.DAY_OF_MONTH)%10) + '0'),
(byte) 'T',
(byte) ((time.get(Calendar.HOUR_OF_DAY)/10) + '0'),
(byte) ((time.get(Calendar.HOUR_OF_DAY)%10) + '0'),
(byte) ((time.get(Calendar.MINUTE)/10) + '0'),
(byte) ((time.get(Calendar.MINUTE)%10) + '0'),
(byte) ((time.get(Calendar.SECOND)/10) + '0'),
(byte) ((time.get(Calendar.SECOND)%10) + '0'),
};
if(callIncoming || (callSpec.command == CallSpec.CALL_INCOMING)) {
if (callSpec.command == CallSpec.CALL_INCOMING) {
if (callSpec.name != null) {
notification_length += callSpec.name.length();
subject_length = callSpec.name.length();
subject = new byte[subject_length];
System.arraycopy(callSpec.name.getBytes(StandardCharsets.UTF_8), 0, subject, 0, subject_length);
} else if (callSpec.number != null) {
notification_length += callSpec.number.length();
subject_length = callSpec.number.length();
subject = new byte[subject_length];
System.arraycopy(callSpec.number.getBytes(StandardCharsets.UTF_8), 0, subject, 0, subject_length);
}
notification_length += datetimeBytes.length + 10; // add message overhead
notification = new byte[notification_length];
notification[0] = ZeTimeConstants.CMD_PREAMBLE;
notification[1] = ZeTimeConstants.CMD_PUSH_EX_MSG;
notification[2] = ZeTimeConstants.CMD_SEND;
notification[3] = (byte) ((notification_length - 6) & 0xff);
notification[4] = (byte) ((notification_length - 6) >> 8);
notification[5] = ZeTimeConstants.NOTIFICATION_INCOME_CALL;
notification[6] = 1;
notification[7] = (byte) subject_length;
notification[8] = (byte) 0;
System.arraycopy(subject, 0, notification, 9, subject_length);
System.arraycopy(datetimeBytes, 0, notification, 9 + subject_length, datetimeBytes.length);
notification[notification_length - 1] = ZeTimeConstants.CMD_END;
callIncoming = true;
} else {
notification_length = datetimeBytes.length + 10; // add message overhead
notification = new byte[notification_length];
notification[0] = ZeTimeConstants.CMD_PREAMBLE;
notification[1] = ZeTimeConstants.CMD_PUSH_EX_MSG;
notification[2] = ZeTimeConstants.CMD_SEND;
notification[3] = (byte) ((notification_length - 6) & 0xff);
notification[4] = (byte) ((notification_length - 6) >> 8);
notification[5] = ZeTimeConstants.NOTIFICATION_CALL_OFF;
notification[6] = 1;
notification[7] = (byte) 0;
notification[8] = (byte) 0;
System.arraycopy(datetimeBytes, 0, notification, 9, datetimeBytes.length);
notification[notification_length - 1] = ZeTimeConstants.CMD_END;
callIncoming = false;
}
if(notification != null)
{
try {
TransactionBuilder builder = performInitialized("setCallState");
sendMsgToWatch(builder, notification);
performConnected(builder.getTransaction());
} catch (IOException e) {
GB.toast(getContext(), "Error set call state: " + e.getLocalizedMessage(), Toast.LENGTH_LONG, GB.ERROR);
}
}
}
} }
@ -248,6 +331,254 @@ public class ZeTimeDeviceSupport extends AbstractBTLEDeviceSupport {
@Override @Override
public void onNotification(NotificationSpec notificationSpec) { public void onNotification(NotificationSpec notificationSpec) {
int subject_length = 0;
int body_length = notificationSpec.body.length();
int notification_length = notificationSpec.body.length();
byte[] subject = null;
byte[] notification = null;
Calendar time = GregorianCalendar.getInstance();
byte[] datetimeBytes = new byte[]{
(byte) ((time.get(Calendar.YEAR) / 1000) + '0'),
(byte) (((time.get(Calendar.YEAR) / 100)%10) + '0'),
(byte) (((time.get(Calendar.YEAR) / 10)%10) + '0'),
(byte) ((time.get(Calendar.YEAR)%10) + '0'),
(byte) (((time.get(Calendar.MONTH)+1)/10) + '0'),
(byte) (((time.get(Calendar.MONTH)+1)%10) + '0'),
(byte) ((time.get(Calendar.DAY_OF_MONTH)/10) + '0'),
(byte) ((time.get(Calendar.DAY_OF_MONTH)%10) + '0'),
(byte) 'T',
(byte) ((time.get(Calendar.HOUR_OF_DAY)/10) + '0'),
(byte) ((time.get(Calendar.HOUR_OF_DAY)%10) + '0'),
(byte) ((time.get(Calendar.MINUTE)/10) + '0'),
(byte) ((time.get(Calendar.MINUTE)%10) + '0'),
(byte) ((time.get(Calendar.SECOND)/10) + '0'),
(byte) ((time.get(Calendar.SECOND)%10) + '0'),
};
switch(notificationSpec.type)
{
case GENERIC_SMS:
if (notificationSpec.sender != null)
{
notification_length += notificationSpec.sender.length();
subject_length = notificationSpec.sender.length();
subject = new byte[subject_length];
System.arraycopy(notificationSpec.sender.getBytes(StandardCharsets.UTF_8), 0, subject, 0, subject_length);
} else if(notificationSpec.phoneNumber != null)
{
notification_length += notificationSpec.phoneNumber.length();
subject_length = notificationSpec.phoneNumber.length();
subject = new byte[subject_length];
System.arraycopy(notificationSpec.phoneNumber.getBytes(StandardCharsets.UTF_8), 0, subject, 0, subject_length);
}
notification_length += datetimeBytes.length + 10; // add message overhead
notification = new byte[notification_length];
notification[0] = ZeTimeConstants.CMD_PREAMBLE;
notification[1] = ZeTimeConstants.CMD_PUSH_EX_MSG;
notification[2] = ZeTimeConstants.CMD_SEND;
notification[3] = (byte)((notification_length-6) & 0xff);
notification[4] = (byte)((notification_length-6) >> 8);
notification[5] = ZeTimeConstants.NOTIFICATION_SMS;
notification[6] = 1;
notification[7] = (byte)subject_length;
notification[8] = (byte)body_length;
System.arraycopy(subject, 0, notification, 9, subject_length);
System.arraycopy(notificationSpec.body.getBytes(StandardCharsets.UTF_8), 0, notification, 9+subject_length, body_length);
System.arraycopy(datetimeBytes, 0, notification, 9+subject_length+body_length, datetimeBytes.length);
notification[notification_length-1] = ZeTimeConstants.CMD_END;
break;
case GENERIC_PHONE:
if (notificationSpec.sender != null)
{
notification_length += notificationSpec.sender.length();
subject_length = notificationSpec.sender.length();
subject = new byte[subject_length];
System.arraycopy(notificationSpec.sender.getBytes(StandardCharsets.UTF_8), 0, subject, 0, subject_length);
} else if(notificationSpec.phoneNumber != null)
{
notification_length += notificationSpec.phoneNumber.length();
subject_length = notificationSpec.phoneNumber.length();
subject = new byte[subject_length];
System.arraycopy(notificationSpec.phoneNumber.getBytes(StandardCharsets.UTF_8), 0, subject, 0, subject_length);
}
notification_length += datetimeBytes.length + 10; // add message overhead
notification = new byte[notification_length];
notification[0] = ZeTimeConstants.CMD_PREAMBLE;
notification[1] = ZeTimeConstants.CMD_PUSH_EX_MSG;
notification[2] = ZeTimeConstants.CMD_SEND;
notification[3] = (byte)((notification_length-6) & 0xff);
notification[4] = (byte)((notification_length-6) >> 8);
notification[5] = ZeTimeConstants.NOTIFICATION_MISSED_CALL;
notification[6] = 1;
notification[7] = (byte)subject_length;
notification[8] = (byte)body_length;
System.arraycopy(subject, 0, notification, 9, subject_length);
System.arraycopy(notificationSpec.body.getBytes(StandardCharsets.UTF_8), 0, notification, 9+subject_length, body_length);
System.arraycopy(datetimeBytes, 0, notification, 9+subject_length+body_length, datetimeBytes.length);
notification[notification_length-1] = ZeTimeConstants.CMD_END;
break;
case GMAIL:
case GOOGLE_INBOX:
case MAILBOX:
case OUTLOOK:
case YAHOO_MAIL:
case GENERIC_EMAIL:
if (notificationSpec.sender != null)
{
notification_length += notificationSpec.sender.length();
subject_length = notificationSpec.sender.length();
subject = new byte[subject_length];
System.arraycopy(notificationSpec.sender.getBytes(StandardCharsets.UTF_8), 0, subject, 0, subject_length);
} else if(notificationSpec.subject != null)
{
notification_length += notificationSpec.subject.length();
subject_length = notificationSpec.subject.length();
subject = new byte[subject_length];
System.arraycopy(notificationSpec.subject.getBytes(StandardCharsets.UTF_8), 0, subject, 0, subject_length);
}
notification_length += datetimeBytes.length + 10; // add message overhead
notification = new byte[notification_length];
notification[0] = ZeTimeConstants.CMD_PREAMBLE;
notification[1] = ZeTimeConstants.CMD_PUSH_EX_MSG;
notification[2] = ZeTimeConstants.CMD_SEND;
notification[3] = (byte)((notification_length-6) & 0xff);
notification[4] = (byte)((notification_length-6) >> 8);
notification[5] = ZeTimeConstants.NOTIFICATION_EMAIL;
notification[6] = 1;
notification[7] = (byte)subject_length;
notification[8] = (byte)body_length;
System.arraycopy(subject, 0, notification, 9, subject_length);
System.arraycopy(notificationSpec.body.getBytes(StandardCharsets.UTF_8), 0, notification, 9+subject_length, body_length);
System.arraycopy(datetimeBytes, 0, notification, 9+subject_length+body_length, datetimeBytes.length);
notification[notification_length-1] = ZeTimeConstants.CMD_END;
break;
case CONVERSATIONS:
case FACEBOOK_MESSENGER:
case RIOT:
case SIGNAL:
case TELEGRAM:
case THREEMA:
case KONTALK:
case ANTOX:
case WHATSAPP:
case GOOGLE_MESSENGER:
case GOOGLE_HANGOUTS:
case HIPCHAT:
case SKYPE:
case WECHAT:
case KIK:
case KAKAO_TALK:
case SLACK:
case LINE:
case VIBER:
if (notificationSpec.sender != null)
{
notification_length += notificationSpec.sender.length();
subject_length = notificationSpec.sender.length();
subject = new byte[subject_length];
System.arraycopy(notificationSpec.sender.getBytes(StandardCharsets.UTF_8), 0, subject, 0, subject_length);
} else if(notificationSpec.subject != null)
{
notification_length += notificationSpec.subject.length();
subject_length = notificationSpec.subject.length();
subject = new byte[subject_length];
System.arraycopy(notificationSpec.subject.getBytes(StandardCharsets.UTF_8), 0, subject, 0, subject_length);
}
notification_length += datetimeBytes.length + 10; // add message overhead
notification = new byte[notification_length];
notification[0] = ZeTimeConstants.CMD_PREAMBLE;
notification[1] = ZeTimeConstants.CMD_PUSH_EX_MSG;
notification[2] = ZeTimeConstants.CMD_SEND;
notification[3] = (byte)((notification_length-6) & 0xff);
notification[4] = (byte)((notification_length-6) >> 8);
notification[5] = ZeTimeConstants.NOTIFICATION_MESSENGER;
notification[6] = 1;
notification[7] = (byte)subject_length;
notification[8] = (byte)body_length;
System.arraycopy(subject, 0, notification, 9, subject_length);
System.arraycopy(notificationSpec.body.getBytes(StandardCharsets.UTF_8), 0, notification, 9+subject_length, body_length);
System.arraycopy(datetimeBytes, 0, notification, 9+subject_length+body_length, datetimeBytes.length);
notification[notification_length-1] = ZeTimeConstants.CMD_END;
break;
case FACEBOOK:
case TWITTER:
case SNAPCHAT:
case INSTAGRAM:
case LINKEDIN:
if (notificationSpec.sender != null)
{
notification_length += notificationSpec.sender.length();
subject_length = notificationSpec.sender.length();
subject = new byte[subject_length];
System.arraycopy(notificationSpec.sender.getBytes(StandardCharsets.UTF_8), 0, subject, 0, subject_length);
} else if(notificationSpec.subject != null)
{
notification_length += notificationSpec.subject.length();
subject_length = notificationSpec.subject.length();
subject = new byte[subject_length];
System.arraycopy(notificationSpec.subject.getBytes(StandardCharsets.UTF_8), 0, subject, 0, subject_length);
}
notification_length += datetimeBytes.length + 10; // add message overhead
notification = new byte[notification_length];
notification[0] = ZeTimeConstants.CMD_PREAMBLE;
notification[1] = ZeTimeConstants.CMD_PUSH_EX_MSG;
notification[2] = ZeTimeConstants.CMD_SEND;
notification[3] = (byte)((notification_length-6) & 0xff);
notification[4] = (byte)((notification_length-6) >> 8);
notification[5] = ZeTimeConstants.NOTIFICATION_SOCIAL;
notification[6] = 1;
notification[7] = (byte)subject_length;
notification[8] = (byte)body_length;
System.arraycopy(subject, 0, notification, 9, subject_length);
System.arraycopy(notificationSpec.body.getBytes(StandardCharsets.UTF_8), 0, notification, 9+subject_length, body_length);
System.arraycopy(datetimeBytes, 0, notification, 9+subject_length+body_length, datetimeBytes.length);
notification[notification_length-1] = ZeTimeConstants.CMD_END;
break;
case GENERIC_CALENDAR:
if (notificationSpec.sender != null)
{
notification_length += notificationSpec.sender.length();
subject_length = notificationSpec.sender.length();
subject = new byte[subject_length];
System.arraycopy(notificationSpec.sender.getBytes(StandardCharsets.UTF_8), 0, subject, 0, subject_length);
} else if(notificationSpec.subject != null)
{
notification_length += notificationSpec.subject.length();
subject_length = notificationSpec.subject.length();
subject = new byte[subject_length];
System.arraycopy(notificationSpec.subject.getBytes(StandardCharsets.UTF_8), 0, subject, 0, subject_length);
}
notification_length += datetimeBytes.length + 10; // add message overhead
notification = new byte[notification_length];
notification[0] = ZeTimeConstants.CMD_PREAMBLE;
notification[1] = ZeTimeConstants.CMD_PUSH_EX_MSG;
notification[2] = ZeTimeConstants.CMD_SEND;
notification[3] = (byte)((notification_length-6) & 0xff);
notification[4] = (byte)((notification_length-6) >> 8);
notification[5] = ZeTimeConstants.NOTIFICATION_CALENDAR;
notification[6] = 1;
notification[7] = (byte)subject_length;
notification[8] = (byte)body_length;
System.arraycopy(subject, 0, notification, 9, subject_length);
System.arraycopy(notificationSpec.body.getBytes(StandardCharsets.UTF_8), 0, notification, 9+subject_length, body_length);
System.arraycopy(datetimeBytes, 0, notification, 9+subject_length+body_length, datetimeBytes.length);
notification[notification_length-1] = ZeTimeConstants.CMD_END;
break;
default:
break;
}
if(notification != null)
{
try {
TransactionBuilder builder = performInitialized("sendNotification");
//builder.write(writeCharacteristic, notification);
//builder.write(ackCharacteristic, new byte[]{ZeTimeConstants.CMD_ACK_WRITE});
sendMsgToWatch(builder, notification);
performConnected(builder.getTransaction());
} catch (IOException e) {
GB.toast(getContext(), "Error sending notification: " + e.getLocalizedMessage(), Toast.LENGTH_LONG, GB.ERROR);
}
}
} }
@Override @Override
@ -370,7 +701,7 @@ public class ZeTimeDeviceSupport extends AbstractBTLEDeviceSupport {
ZeTimeConstants.CMD_REQUEST, ZeTimeConstants.CMD_REQUEST,
0x01, 0x01,
0x00, 0x00,
0x00, 0x02,
ZeTimeConstants.CMD_END}); ZeTimeConstants.CMD_END});
builder.write(ackCharacteristic, new byte[]{ZeTimeConstants.CMD_ACK_WRITE}); builder.write(ackCharacteristic, new byte[]{ZeTimeConstants.CMD_ACK_WRITE});
return this; return this;
@ -414,8 +745,8 @@ public class ZeTimeDeviceSupport extends AbstractBTLEDeviceSupport {
private void handleDeviceInfo(byte[] value) { private void handleDeviceInfo(byte[] value) {
value[value.length-1] = 0; // convert the end to a String end value[value.length-1] = 0; // convert the end to a String end
byte[] string = Arrays.copyOfRange(value,5, value.length-1); byte[] string = Arrays.copyOfRange(value,6, value.length-1);
if(string.length > 6) if(value[5] == 5)
{ {
versionCmd.fwVersion = new String(string); versionCmd.fwVersion = new String(string);
} else{ } else{
@ -452,7 +783,6 @@ public class ZeTimeDeviceSupport extends AbstractBTLEDeviceSupport {
0x00, 0x00,
0x00, 0x00,
ZeTimeConstants.CMD_END}); ZeTimeConstants.CMD_END});
performConnected(builder.getTransaction());
builder.write(ackCharacteristic, new byte[]{ZeTimeConstants.CMD_ACK_WRITE}); builder.write(ackCharacteristic, new byte[]{ZeTimeConstants.CMD_ACK_WRITE});
performConnected(builder.getTransaction()); performConnected(builder.getTransaction());
} catch (IOException e) { } catch (IOException e) {
@ -471,7 +801,6 @@ public class ZeTimeDeviceSupport extends AbstractBTLEDeviceSupport {
0x00, 0x00,
0x00, 0x00,
ZeTimeConstants.CMD_END}); ZeTimeConstants.CMD_END});
performConnected(builder.getTransaction());
builder.write(ackCharacteristic, new byte[]{ZeTimeConstants.CMD_ACK_WRITE}); builder.write(ackCharacteristic, new byte[]{ZeTimeConstants.CMD_ACK_WRITE});
performConnected(builder.getTransaction()); performConnected(builder.getTransaction());
} catch (IOException e) { } catch (IOException e) {
@ -606,4 +935,31 @@ public class ZeTimeDeviceSupport extends AbstractBTLEDeviceSupport {
} }
} }
} }
private void sendMsgToWatch(TransactionBuilder builder, byte[] msg)
{
if(msg.length > maxMsgLength)
{
int msgpartlength = 0;
byte[] msgpart = null;
do {
if((msg.length - msgpartlength) < maxMsgLength)
{
msgpart = new byte[msg.length - msgpartlength];
System.arraycopy(msg, msgpartlength, msgpart, 0, msg.length - msgpartlength);
msgpartlength += (msg.length - msgpartlength);
} else {
msgpart = new byte[maxMsgLength];
System.arraycopy(msg, msgpartlength, msgpart, 0, maxMsgLength);
msgpartlength += maxMsgLength;
}
builder.write(writeCharacteristic, msgpart);
}while(msgpartlength < msg.length);
} else
{
builder.write(writeCharacteristic, msg);
}
builder.write(ackCharacteristic, new byte[]{ZeTimeConstants.CMD_ACK_WRITE});
}
} }