From f9a4c1ad35beff5baf533511191f2a0a477da5e3 Mon Sep 17 00:00:00 2001 From: Daniel Dakhno Date: Sun, 16 Feb 2020 01:17:45 +0100 Subject: [PATCH] added call notification support (doesnt work on all phones) --- .../qhybrid/NotificationHRConfiguration.java | 27 +++++++-- .../fossil_hr/FossilHRWatchAdapter.java | 56 ++++++------------- .../PlayCallNotificationRequest.java | 7 ++- .../notification/PlayNotificationRequest.java | 7 ++- .../NotificationFilterPutHRRequest.java | 17 ++---- .../receivers/GBCallControlReceiver.java | 2 +- 6 files changed, 57 insertions(+), 59 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/qhybrid/NotificationHRConfiguration.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/qhybrid/NotificationHRConfiguration.java index ad62c548f..03fe551a3 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/qhybrid/NotificationHRConfiguration.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/qhybrid/NotificationHRConfiguration.java @@ -1,18 +1,33 @@ package nodomain.freeyourgadget.gadgetbridge.devices.qhybrid; -import android.util.Log; - import java.io.Serializable; - -import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit.PlayNotificationRequest; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.zip.CRC32; public class NotificationHRConfiguration implements Serializable { private String packageName; private long id = -1; + private byte[] packageCrc; public NotificationHRConfiguration(String packageName, long id) { this.packageName = packageName; this.id = id; + + CRC32 crc = new CRC32(); + crc.update(packageName.getBytes()); + + this.packageCrc = ByteBuffer + .allocate(4) + .order(ByteOrder.LITTLE_ENDIAN) + .putInt((int) crc.getValue()) + .array(); + } + + public NotificationHRConfiguration(String packageName, byte[] packageCrc, long id) { + this.id = id; + this.packageCrc = packageCrc; + this.packageName = packageName; } public String getPackageName() { @@ -22,4 +37,8 @@ public class NotificationHRConfiguration implements Serializable { public long getId() { return id; } + + public byte[] getPackageCrc() { + return packageCrc; + } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/adapter/fossil_hr/FossilHRWatchAdapter.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/adapter/fossil_hr/FossilHRWatchAdapter.java index 963769dc1..4d30bfca7 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/adapter/fossil_hr/FossilHRWatchAdapter.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/adapter/fossil_hr/FossilHRWatchAdapter.java @@ -26,6 +26,7 @@ import java.util.Iterator; import java.util.TimeZone; import nodomain.freeyourgadget.gadgetbridge.GBApplication; +import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventCallControl; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventFindPhone; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventMusicControl; import nodomain.freeyourgadget.gadgetbridge.devices.qhybrid.HRConfigActivity; @@ -37,9 +38,11 @@ import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec; import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec; import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.QHybridSupport; import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.adapter.fossil.FossilWatchAdapter; +import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil.FossilRequest; import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil.RequestMtuRequest; import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil.SetDeviceStateRequest; import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil.configuration.ConfigurationPutRequest.TimeConfigItem; +import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil.file.FilePutRequest; import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil.notification.PlayCallNotificationRequest; import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil.notification.PlayNotificationRequest; import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil.notification.PlayTextNotificationRequest; @@ -99,46 +102,8 @@ public class FossilHRWatchAdapter extends FossilWatchAdapter { queueWrite(new SetDeviceStateRequest(GBDevice.State.INITIALIZING)); - // icons - loadNotificationConfigurations(); queueWrite(new NotificationFilterPutHRRequest(this.notificationConfigurations, this)); - // queueWrite(new NotificationFilterPutHRRequest(this.notificationConfigurations,this)); - - /*try { - final String[] appNames = {"instagram", "snapchat", "line", "whatsapp"}; - final String[] paths = { - "/storage/emulated/0/Q/images/icInstagram.icon", - "/storage/emulated/0/Q/images/icSnapchat.icon", - "/storage/emulated/0/Q/images/icLine.icon", - "/storage/emulated/0/Q/images/icWhatsapp.icon" - }; - - NotificationHRConfiguration[] configs = new NotificationHRConfiguration[4]; - NotificationImage[] images = new NotificationImage[4]; - for(int i = 0; i < 4; i++){ - FileInputStream fis = new FileInputStream(paths[i]); - byte[] imageData = new byte[fis.available()]; - fis.read(imageData); - fis.close(); - configs[i] = new NotificationHRConfiguration(appNames[i], i); - images[i] = new NotificationImage(appNames[i], imageData); - } - queueWrite(new NotificationImagePutRequest(images, this)); - queueWrite(new NotificationFilterPutHRRequest(configs, this)); - - for(String appName : appNames){ - queueWrite(new PlayNotificationHRRequest( - appName, - appName.toUpperCase(), - "this is some strange message", - this - )); - } - } catch (Exception e) { - e.printStackTrace(); - }*/ - setVibrationStrength((short) 75); syncSettings(); @@ -165,6 +130,7 @@ public class FossilHRWatchAdapter extends FossilWatchAdapter { private void loadNotificationConfigurations(){ this.notificationConfigurations = new NotificationHRConfiguration[]{ new NotificationHRConfiguration("generic", 0), + new NotificationHRConfiguration("call", new byte[]{(byte)0x80, (byte) 0x00, (byte) 0x59, (byte) 0xB7}, 0) }; } @@ -539,7 +505,9 @@ public class FossilHRWatchAdapter extends FossilWatchAdapter { byte requestType = value[1]; - if (requestType == (byte) 0x05) { + if(requestType == (byte) 0x04){ + handleCallRequest(value); + }else if (requestType == (byte) 0x05) { handleMusicRequest(value); } else if (requestType == (byte) 0x01) { int eventId = value[2]; @@ -608,6 +576,16 @@ public class FossilHRWatchAdapter extends FossilWatchAdapter { } } + private void handleCallRequest(byte[] value) { + boolean acceptCall = value[7] == (byte) 0x00; + queueWrite(new PlayCallNotificationRequest("", false, this)); + + GBDeviceEventCallControl callControlEvent = new GBDeviceEventCallControl(); + callControlEvent.event = acceptCall ? GBDeviceEventCallControl.Event.START : GBDeviceEventCallControl.Event.REJECT; + + getDeviceSupport().evaluateGBDeviceEvent(callControlEvent); + } + private void handleMusicRequest(byte[] value) { byte command = value[3]; logger.info("got music command: " + command); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil/notification/PlayCallNotificationRequest.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil/notification/PlayCallNotificationRequest.java index e4b8c9aa2..52dda71be 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil/notification/PlayCallNotificationRequest.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil/notification/PlayCallNotificationRequest.java @@ -1,9 +1,14 @@ package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil.notification; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.adapter.fossil.FossilWatchAdapter; public class PlayCallNotificationRequest extends PlayNotificationRequest { public PlayCallNotificationRequest(String number, boolean callStart, FossilWatchAdapter adapter) { - super(callStart ? 1 : 7, callStart ? 8 : 2, "generic", number, "Incoming Call", adapter); + super(callStart ? 1 : 7, callStart ? 8 : 2, + ByteBuffer.wrap(new byte[]{(byte) 0x80, (byte) 0x00, (byte) 0x59, (byte) 0xB7}).order(ByteOrder.LITTLE_ENDIAN).getInt(), + number, "Incoming Call", adapter); } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil/notification/PlayNotificationRequest.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil/notification/PlayNotificationRequest.java index 61434dba4..977c6e0d2 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil/notification/PlayNotificationRequest.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil/notification/PlayNotificationRequest.java @@ -26,8 +26,6 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fos import nodomain.freeyourgadget.gadgetbridge.util.StringUtils; public abstract class PlayNotificationRequest extends FilePutRequest { - static int id = 0; - public PlayNotificationRequest(int notificationType, int flags, String packageName, FossilWatchAdapter adapter) { super((short) 0x0900, createFile(notificationType, flags, packageName, packageName, packageName), adapter); } @@ -36,6 +34,9 @@ public abstract class PlayNotificationRequest extends FilePutRequest { super((short) 0x0900, createFile(notificationType, flags, packageName, sender, message), adapter); } + public PlayNotificationRequest(int notificationType, int flags, int packageCRC, String sender, String message, FossilWatchAdapter adapter) { + super((short) 0x0900, createFile(notificationType, flags, "whatever", sender, message, packageCRC), adapter); + } private static byte[] createFile(int notificationType, int flags, String packageName, String sender, String message){ CRC32 crc = new CRC32(); @@ -73,7 +74,7 @@ public abstract class PlayNotificationRequest extends FilePutRequest { mainBuffer.put((byte) senderBytes.length); mainBuffer.put((byte) messageBytes.length); - mainBuffer.putInt(id++); // messageId + mainBuffer.putInt(0); // messageId mainBuffer.putInt(packageCrc); mainBuffer.put(titleBytes); mainBuffer.put(senderBytes); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/notification/NotificationFilterPutHRRequest.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/notification/NotificationFilterPutHRRequest.java index 5b6bc25d3..1d6cacb12 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/notification/NotificationFilterPutHRRequest.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/notification/NotificationFilterPutHRRequest.java @@ -3,7 +3,6 @@ package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fo import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.ArrayList; -import java.util.zip.CRC32; import nodomain.freeyourgadget.gadgetbridge.devices.qhybrid.NotificationHRConfiguration; import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.adapter.fossil.FossilWatchAdapter; @@ -21,20 +20,16 @@ public class NotificationFilterPutHRRequest extends FilePutRequest { } private static byte[] createFile(NotificationHRConfiguration[] configs) { - ByteBuffer buffer = ByteBuffer.allocate(configs.length * 28); + int payloadLength = configs.length * 28; + ByteBuffer buffer = ByteBuffer.allocate(payloadLength); buffer.order(ByteOrder.LITTLE_ENDIAN); for (NotificationHRConfiguration config : configs) { - buffer.putShort((short) 28); //packet length + payloadLength = 26; - CRC32 crc = new CRC32(); - crc.update(config.getPackageName().getBytes()); + buffer.putShort((short) payloadLength); //packet length - byte[] crcBytes = ByteBuffer - .allocate(4) - .order(ByteOrder.LITTLE_ENDIAN) - .putInt((int) crc.getValue()) - .array(); + byte[] crcBytes = config.getPackageCrc(); // 6 bytes buffer.put(PacketID.PACKAGE_NAME_CRC.id) @@ -44,7 +39,7 @@ public class NotificationFilterPutHRRequest extends FilePutRequest { // 3 bytes buffer.put(PacketID.GROUP_ID.id) .put((byte) 1) - .put((byte) 2); + .put((byte) 0); // 3 bytes buffer.put(PacketID.PRIORITY.id) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/receivers/GBCallControlReceiver.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/receivers/GBCallControlReceiver.java index f26a2d5da..569b6c95e 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/receivers/GBCallControlReceiver.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/receivers/GBCallControlReceiver.java @@ -53,7 +53,7 @@ public class GBCallControlReceiver extends BroadcastReceiver { telephonyService.answerRingingCall(); } } catch (Exception e) { - LOG.warn("could not start or hangup call"); + LOG.warn("could not start or hangup call", e); } break; default: