From 2f37d4c839d35a1b0a0f5dadd1dd3d0ccdd2846d Mon Sep 17 00:00:00 2001 From: Arjan Schrijver Date: Tue, 27 Apr 2021 12:51:14 +0200 Subject: [PATCH] Fossil Hybrid HR: Dismiss incoming call with a quick SMS reply (#2264) Merge branch 'master' into fossil_hr_quick_replies Fossil Hybrid HR: Allow between 1 and 16 quick replies to be configured Fossil Hybrid HR: Dismiss incoming call with a quick SMS reply Co-authored-by: Arjan Schrijver Reviewed-on: https://codeberg.org/Freeyourgadget/Gadgetbridge/pulls/2264 Co-Authored-By: Arjan Schrijver Co-Committed-By: Arjan Schrijver --- .../devices/qhybrid/QHybridCoordinator.java | 1 + .../devices/qhybrid/QHybridSupport.java | 7 ++ .../fossil_hr/FossilHRWatchAdapter.java | 59 ++++++++++++++- .../SupportedFileVersionsInfo.java | 3 + .../requests/fossil/file/FilePutRequest.java | 6 +- .../DismissTextNotificationRequest.java | 2 +- .../fossil/notification/NotificationType.java | 37 ++++++++++ .../PlayCallNotificationRequest.java | 14 +++- .../notification/PlayNotificationRequest.java | 12 ++-- .../PlayTextNotificationRequest.java | 4 +- .../notification/NotificationImage.java | 2 + .../NotificationImagePutRequest.java | 4 ++ .../QuickReplyConfigurationPutRequest.java | 71 +++++++++++++++++++ .../QuickReplyConfirmationPutRequest.java | 55 ++++++++++++++ app/src/main/res/values/strings.xml | 2 +- 15 files changed, 264 insertions(+), 15 deletions(-) create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil/notification/NotificationType.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/quickreply/QuickReplyConfigurationPutRequest.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/quickreply/QuickReplyConfirmationPutRequest.java diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/qhybrid/QHybridCoordinator.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/qhybrid/QHybridCoordinator.java index e1ab05aa4..03aada28b 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/qhybrid/QHybridCoordinator.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/qhybrid/QHybridCoordinator.java @@ -196,6 +196,7 @@ public class QHybridCoordinator extends AbstractDeviceCoordinator { return new int[]{ R.xml.devicesettings_fossilhybridhr, R.xml.devicesettings_autoremove_notifications, + R.xml.devicesettings_canned_dismisscall_16, R.xml.devicesettings_pairingkey, R.xml.devicesettings_custom_deviceicon }; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/QHybridSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/QHybridSupport.java index 6d750867b..2c778d9f6 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/QHybridSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/QHybridSupport.java @@ -58,6 +58,7 @@ import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.model.Alarm; import nodomain.freeyourgadget.gadgetbridge.model.BatteryState; import nodomain.freeyourgadget.gadgetbridge.model.CallSpec; +import nodomain.freeyourgadget.gadgetbridge.model.CannedMessagesSpec; import nodomain.freeyourgadget.gadgetbridge.model.GenericItem; import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec; import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec; @@ -767,4 +768,10 @@ public class QHybridSupport extends QHybridBaseSupport { return watchAdapter.onCharacteristicChanged(gatt, characteristic); } + @Override + public void onSetCannedMessages(CannedMessagesSpec cannedMessagesSpec) { + if(this.watchAdapter instanceof FossilHRWatchAdapter){ + ((FossilHRWatchAdapter) watchAdapter).setQuickRepliesConfiguration(); + } + } } 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 1a219fe67..bbfd91788 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 @@ -64,6 +64,7 @@ import nodomain.freeyourgadget.gadgetbridge.database.DBHelper; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventCallControl; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventFindPhone; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventMusicControl; +import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventNotificationControl; import nodomain.freeyourgadget.gadgetbridge.devices.qhybrid.HRConfigActivity; import nodomain.freeyourgadget.gadgetbridge.devices.qhybrid.HybridHRActivitySampleProvider; import nodomain.freeyourgadget.gadgetbridge.devices.qhybrid.NotificationHRConfiguration; @@ -114,6 +115,8 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fos import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.notification.NotificationFilterPutHRRequest; import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.notification.NotificationImage; import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.notification.NotificationImagePutRequest; +import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.quickreply.QuickReplyConfigurationPutRequest; +import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.quickreply.QuickReplyConfirmationPutRequest; import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.widget.CustomBackgroundWidgetElement; import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.widget.CustomTextWidgetElement; import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.widget.CustomWidget; @@ -139,6 +142,7 @@ public class FossilHRWatchAdapter extends FossilWatchAdapter { private NotificationHRConfiguration[] notificationConfigurations; + private CallSpec currentCallSpec = null; private MusicSpec currentSpec = null; int imageNameIndex = 0; @@ -201,6 +205,7 @@ public class FossilHRWatchAdapter extends FossilWatchAdapter { GB.toast(getContext().getString(R.string.fossil_hr_auth_failed), Toast.LENGTH_LONG, GB.ERROR); setNotificationConfigurations(); + setQuickRepliesConfiguration(); if (authenticated) { setVibrationStrength(); @@ -290,6 +295,27 @@ public class FossilHRWatchAdapter extends FossilWatchAdapter { queueWrite(new NotificationFilterPutHRRequest(this.notificationConfigurations, this)); } + private String[] getQuickReplies() { + ArrayList configuredReplies = new ArrayList<>(); + Prefs prefs = new Prefs(getDeviceSpecificPreferences()); + for (int i=1; i<=16; i++) { + String quickReply = prefs.getString("canned_message_dismisscall_" + i, null); + if (quickReply != null) { + configuredReplies.add(quickReply); + } + } + return configuredReplies.toArray(new String[0]); + } + + public void setQuickRepliesConfiguration() { + String[] quickReplies = getQuickReplies(); + if (quickReplies.length > 0) { + NotificationImage quickReplyIcon = new NotificationImage("icMessage.icon", NotificationImage.getEncodedIconFromDrawable(getContext().getResources().getDrawable(R.drawable.ic_message_outline)), 24, 24); + queueWrite(new NotificationImagePutRequest(quickReplyIcon, this)); + queueWrite(new QuickReplyConfigurationPutRequest(quickReplies, this)); + } + } + private File getBackgroundFile() { return new File(getContext().getExternalFilesDir(null), "hr_background.bin"); } @@ -994,7 +1020,15 @@ public class FossilHRWatchAdapter extends FossilWatchAdapter { @Override public void onSetCallState(CallSpec callSpec) { super.onSetCallState(callSpec); - queueWrite(new PlayCallNotificationRequest(StringUtils.getFirstOf(callSpec.name, callSpec.number), callSpec.command == CallSpec.CALL_INCOMING, this)); + String[] quickReplies = getQuickReplies(); + boolean quickRepliesEnabled = quickReplies.length > 0 && callSpec.number != null && callSpec.number.matches("^\\+(?:[0-9] ?){6,14}[0-9]$"); + if (callSpec.command == CallSpec.CALL_INCOMING) { + currentCallSpec = callSpec; + queueWrite(new PlayCallNotificationRequest(StringUtils.getFirstOf(callSpec.name, callSpec.number), true, quickRepliesEnabled, this)); + } else { + currentCallSpec = null; + queueWrite(new PlayCallNotificationRequest(StringUtils.getFirstOf(callSpec.name, callSpec.number), false, quickRepliesEnabled, this)); + } } // this method is based on the one from AppMessageHandlerYWeather.java @@ -1314,6 +1348,8 @@ public class FossilHRWatchAdapter extends FossilWatchAdapter { handleCallRequest(value); } else if (value[7] == 0x02) { handleDeleteNotification(value); + } else if (value[7] == 0x03) { + handleQuickReplyRequest(value); } } else if (requestType == (byte) 0x05) { handleMusicRequest(value); @@ -1410,7 +1446,7 @@ public class FossilHRWatchAdapter extends FossilWatchAdapter { private void handleCallRequest(byte[] value) { boolean acceptCall = value[7] == (byte) 0x00; - queueWrite(new PlayCallNotificationRequest("", false, this)); + queueWrite(new PlayCallNotificationRequest("", false, false, this)); GBDeviceEventCallControl callControlEvent = new GBDeviceEventCallControl(); callControlEvent.event = acceptCall ? GBDeviceEventCallControl.Event.START : GBDeviceEventCallControl.Event.REJECT; @@ -1418,6 +1454,25 @@ public class FossilHRWatchAdapter extends FossilWatchAdapter { getDeviceSupport().evaluateGBDeviceEvent(callControlEvent); } + private void handleQuickReplyRequest(byte[] value) { + if (currentCallSpec == null) { + return; + } + String[] quickReplies = getQuickReplies(); + byte callId = value[3]; + byte replyChoice = value[8]; + if (replyChoice >= quickReplies.length) { + return; + } + GBDeviceEventNotificationControl devEvtNotificationControl = new GBDeviceEventNotificationControl(); + devEvtNotificationControl.handle = callId; + devEvtNotificationControl.phoneNumber = currentCallSpec.number; + devEvtNotificationControl.reply = quickReplies[replyChoice]; + devEvtNotificationControl.event = GBDeviceEventNotificationControl.Event.REPLY; + getDeviceSupport().evaluateGBDeviceEvent(devEvtNotificationControl); + queueWrite(new QuickReplyConfirmationPutRequest(callId)); + } + private void handleMusicRequest(byte[] value) { byte command = value[3]; LOG.info("got music command: " + command); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil/device_info/SupportedFileVersionsInfo.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil/device_info/SupportedFileVersionsInfo.java index b80f84a09..72d8863b7 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil/device_info/SupportedFileVersionsInfo.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil/device_info/SupportedFileVersionsInfo.java @@ -36,6 +36,9 @@ public class SupportedFileVersionsInfo implements DeviceInfo { supportedFileVersions.put(handle, version); } + // Add quick replies packet type + supportedFileVersions.put((byte) 0x13, (short) 0x0002); + // Add phone app packet type supportedFileVersions.put((byte) 0x15, (short) 0x0003); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil/file/FilePutRequest.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil/file/FilePutRequest.java index 2b1d060f4..f8583c570 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil/file/FilePutRequest.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil/file/FilePutRequest.java @@ -42,7 +42,11 @@ public class FilePutRequest extends FilePutRawRequest { buffer.putShort(fileHandle.getHandle()); buffer.putShort(fileVersion); - buffer.putInt(0); + if (fileHandle == FileHandle.REPLY_MESSAGES) { + buffer.put(new byte[]{(byte) 0x00, (byte) 0x00, (byte) 0x0d, (byte) 0x00}); + } else { + buffer.putInt(0); + } buffer.putInt(file.length); buffer.put(file); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil/notification/DismissTextNotificationRequest.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil/notification/DismissTextNotificationRequest.java index 96dee0520..f9e374f15 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil/notification/DismissTextNotificationRequest.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil/notification/DismissTextNotificationRequest.java @@ -20,6 +20,6 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.adapter.foss public class DismissTextNotificationRequest extends PlayNotificationRequest { public DismissTextNotificationRequest(int messageId, FossilWatchAdapter adapter) { - super(7, 2, "", "", "", messageId, adapter); + super(NotificationType.DISMISS_NOTIFICATION, 2, "", "", "", messageId, adapter); } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil/notification/NotificationType.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil/notification/NotificationType.java new file mode 100644 index 000000000..ff3c4bf0d --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil/notification/NotificationType.java @@ -0,0 +1,37 @@ +/* Copyright (C) 2020-2021 Arjan Schrijver + + 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 . */ +package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil.notification; + +public enum NotificationType { + INCOMING_CALL(1), + TEXT(2), + NOTIFICATION(3), + EMAIL(4), + CALENDAR(5), + MISSED_CALL(6), + DISMISS_NOTIFICATION(7); + + private int type; + + NotificationType(int type) { + this.type = type; + } + + public int getType() { + return type; + } +} 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 0f9e545be..15d2d0994 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 @@ -24,8 +24,18 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.adapter.foss public class PlayCallNotificationRequest extends PlayNotificationRequest { private final static int MESSAGE_ID_CALL = 1; - public PlayCallNotificationRequest(String number, boolean callStart, FossilWatchAdapter adapter) { - super(callStart ? 1 : 7, callStart ? 0b00011000 : 2, + private static int notificationFlags(boolean callStart, boolean quickReplies) { + if (callStart && quickReplies) { + return 0b00111000; + } else if (callStart) { + return 0b00011000; + } else { + return 0b00000010; + } + } + + public PlayCallNotificationRequest(String number, boolean callStart, boolean quickReplies, FossilWatchAdapter adapter) { + super(callStart ? NotificationType.INCOMING_CALL : NotificationType.DISMISS_NOTIFICATION, notificationFlags(callStart, quickReplies), ByteBuffer.wrap(new byte[]{(byte) 0x80, (byte) 0x00, (byte) 0x59, (byte) 0xB7}).order(ByteOrder.LITTLE_ENDIAN).getInt(), number, "Incoming Call", MESSAGE_ID_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 e05bd4f02..3fdd845d8 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 @@ -28,15 +28,15 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fos import nodomain.freeyourgadget.gadgetbridge.util.StringUtils; public abstract class PlayNotificationRequest extends FilePutRequest { - public PlayNotificationRequest(int notificationType, int flags, String packageName, FossilWatchAdapter adapter) { + public PlayNotificationRequest(NotificationType notificationType, int flags, String packageName, FossilWatchAdapter adapter) { super(FileHandle.NOTIFICATION_PLAY, createFile(notificationType, flags, packageName, packageName, packageName, getCurrentMessageId()), adapter); } - public PlayNotificationRequest(int notificationType, int flags, String packageName, String sender, String message, int notificationId, FossilWatchAdapter adapter) { + public PlayNotificationRequest(NotificationType notificationType, int flags, String packageName, String sender, String message, int notificationId, FossilWatchAdapter adapter) { super(FileHandle.NOTIFICATION_PLAY, createFile(notificationType, flags, packageName, sender, message, notificationId), adapter); } - public PlayNotificationRequest(int notificationType, int flags, int packageCRC, String sender, String message, int messageId, FossilWatchAdapter adapter) { + public PlayNotificationRequest(NotificationType notificationType, int flags, int packageCRC, String sender, String message, int messageId, FossilWatchAdapter adapter) { super(FileHandle.NOTIFICATION_PLAY, createFile(notificationType, flags, "whatever", sender, message, packageCRC, messageId), adapter); } @@ -44,13 +44,13 @@ public abstract class PlayNotificationRequest extends FilePutRequest { return (int) System.currentTimeMillis(); } - private static byte[] createFile(int notificationType, int flags, String packageName, String sender, String message, int messageId){ + private static byte[] createFile(NotificationType notificationType, int flags, String packageName, String sender, String message, int messageId){ CRC32 crc = new CRC32(); crc.update(packageName.getBytes()); return createFile(notificationType, flags, packageName, sender, message, (int)crc.getValue(), messageId); } - private static byte[] createFile(int notificationType, int flags, String title, String sender, String message, int packageCrc, int messageId) { + private static byte[] createFile(NotificationType notificationType, int flags, String title, String sender, String message, int packageCrc, int messageId) { byte lengthBufferLength = (byte) 10; byte uidLength = (byte) 4; byte appBundleCRCLength = (byte) 4; @@ -74,7 +74,7 @@ public abstract class PlayNotificationRequest extends FilePutRequest { mainBuffer.putShort(mainBufferLength); mainBuffer.put(lengthBufferLength); - mainBuffer.put((byte) notificationType); + mainBuffer.put((byte) notificationType.getType()); mainBuffer.put((byte) flags); mainBuffer.put(uidLength); mainBuffer.put(appBundleCRCLength); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil/notification/PlayTextNotificationRequest.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil/notification/PlayTextNotificationRequest.java index c1645895e..80ae8cba7 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil/notification/PlayTextNotificationRequest.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil/notification/PlayTextNotificationRequest.java @@ -20,10 +20,10 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.adapter.foss public class PlayTextNotificationRequest extends PlayNotificationRequest { public PlayTextNotificationRequest(String packageName, String sender, String message, int messageId, FossilWatchAdapter adapter) { - super(3, 2, packageName, sender, message, messageId, adapter); + super(NotificationType.NOTIFICATION, 2, packageName, sender, message, messageId, adapter); } public PlayTextNotificationRequest(String packageName, FossilWatchAdapter adapter) { - super(3, 2, packageName, adapter); + super(NotificationType.NOTIFICATION, 2, packageName, adapter); } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/notification/NotificationImage.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/notification/NotificationImage.java index 061e33cfc..fac127c9b 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/notification/NotificationImage.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/notification/NotificationImage.java @@ -64,6 +64,8 @@ public class NotificationImage extends AssetFile { ColorMatrixColorFilter f = new ColorMatrixColorFilter(cm); paint.setColorFilter(f); c.drawBitmap(bitmap, 0, 0, paint); + // Increase brightness +// bitmap = changeBitmapContrastBrightness(bitmap, 1, -50); // Return result return bitmap; } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/notification/NotificationImagePutRequest.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/notification/NotificationImagePutRequest.java index e2b65f1c8..f3d2a11ec 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/notification/NotificationImagePutRequest.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/notification/NotificationImagePutRequest.java @@ -30,6 +30,10 @@ public class NotificationImagePutRequest extends FilePutRequest { super(FileHandle.ASSET_NOTIFICATION_IMAGES, prepareFileData(images), adapter); } + public NotificationImagePutRequest(NotificationImage image, FossilWatchAdapter adapter) { + super(FileHandle.ASSET_REPLY_IMAGES, prepareFileData(image), adapter); + } + private static byte[] prepareFileData(NotificationImage[] images) throws IOException { ByteArrayOutputStream stream = new ByteArrayOutputStream(); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/quickreply/QuickReplyConfigurationPutRequest.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/quickreply/QuickReplyConfigurationPutRequest.java new file mode 100644 index 000000000..066bfd2f1 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/quickreply/QuickReplyConfigurationPutRequest.java @@ -0,0 +1,71 @@ +/* Copyright (C) 2019-2021 Arjan Schrijver + + 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 . */ +package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.quickreply; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.charset.Charset; + +import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.adapter.fossil_hr.FossilHRWatchAdapter; +import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.file.FileHandle; +import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil.file.FilePutRequest; +import nodomain.freeyourgadget.gadgetbridge.util.StringUtils; + +public class QuickReplyConfigurationPutRequest extends FilePutRequest { + public QuickReplyConfigurationPutRequest(String[] replies, FossilHRWatchAdapter adapter) { + super(FileHandle.REPLY_MESSAGES, createFile(replies), adapter); + } + + private static byte[] createFile(String[] replies) { + String[] processedReplies = new String[replies.length]; + int fileLength = 0; + + byte[] mysteryHeader = new byte[]{(byte) 0x02, (byte) 0x0b, (byte) 0x46, (byte) 0x00, (byte) 0x03, (byte) 0x19, (byte) 0x00, (byte) 0x00, (byte) 0x00}; + + Charset charsetUTF8 = Charset.forName("UTF-8"); + String iconName = StringUtils.terminateNull("icMessage.icon"); + byte[] iconNameBytes = iconName.getBytes(charsetUTF8); + + for (int index=0; index< replies.length; index++) { + String reply = replies[index]; + if (reply.length() > 50) { + reply = reply.substring(0, 50); + } + processedReplies[index] = StringUtils.terminateNull(reply); + fileLength += 8 + processedReplies[index].length() + iconNameBytes.length; + } + + ByteBuffer mainBuffer = ByteBuffer.allocate(mysteryHeader.length + 4 + fileLength); + mainBuffer.order(ByteOrder.LITTLE_ENDIAN); + + mainBuffer.put(mysteryHeader); + mainBuffer.putInt(fileLength); + + for (int index=0; index < processedReplies.length; index++) { + byte[] msgBytes = processedReplies[index].getBytes(charsetUTF8); + mainBuffer.putShort((short) (8 + msgBytes.length + iconNameBytes.length)); + mainBuffer.put((byte) 0x08); + mainBuffer.put((byte) index); + mainBuffer.putShort((short) msgBytes.length); + mainBuffer.putShort((short) iconNameBytes.length); + mainBuffer.put(msgBytes); + mainBuffer.put(iconNameBytes); + } + + return mainBuffer.array(); + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/quickreply/QuickReplyConfirmationPutRequest.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/quickreply/QuickReplyConfirmationPutRequest.java new file mode 100644 index 000000000..b9fc0f85a --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/quickreply/QuickReplyConfirmationPutRequest.java @@ -0,0 +1,55 @@ +/* Copyright (C) 2019-2021 Arjan Schrijver + + 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 . */ +package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.quickreply; + +import java.util.UUID; +import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil.FossilRequest; + + +public class QuickReplyConfirmationPutRequest extends FossilRequest { + /** + * Contains the bytes to confirm to the watch that a quick reply SMS has been sent. + * @param callId + */ + public QuickReplyConfirmationPutRequest(byte callId) { + this.data = new byte[]{ + (byte) 0x02, + (byte) 0x04, + callId, + (byte) 0x00, + (byte) 0x00, + (byte) 0x00, + (byte) 0x03, + (byte) 0x00 + }; + } + + @Override + public boolean isFinished() { + return true; + } + + @Override + public byte[] getStartSequence() { + return null; + } + + @Override + public UUID getRequestUUID() { + return UUID.fromString("3dda0006-957f-7d4a-34a6-74696673696d"); + } +} \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 09a667429..a5c6fb331 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -150,7 +150,7 @@ Replies Common suffix Call Dismissal - Update on Pebble + Update on device Developer options Mi Band address Pebble settings