From b892748b15cacfbded4a3e4c52ceaf8ecf469332 Mon Sep 17 00:00:00 2001 From: Arjan Schrijver Date: Fri, 31 Mar 2023 21:07:56 +0200 Subject: [PATCH] Cache notifications while devices are out of range (opt-in) --- CHANGELOG.md | 1 + .../externalevents/NotificationListener.java | 2 +- .../service/DeviceCommunicationService.java | 47 +++++++++++++++++++ app/src/main/res/values/strings.xml | 2 + .../res/xml/notifications_preferences.xml | 7 +++ 5 files changed, 58 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 262a01f70..7baaaf47f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ * Zepp OS: Fix setting of unknown configuration values * Add Croatian transliterator * Fix restoring app notification/pebble blacklist preferences on import +* Cache notifications while devices are out of range (opt-in) #### 0.73.0 * Initial support for Amazfit T-Rex 2 diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/NotificationListener.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/NotificationListener.java index 4363bb331..5e16d4492 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/NotificationListener.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/NotificationListener.java @@ -772,7 +772,7 @@ public class NotificationListener extends NotificationListenerService { notificationsActive.removeAll(notificationsToRemove); // Send notification remove request to device - List devices = GBApplication.app().getDeviceManager().getSelectedDevices(); + List devices = GBApplication.app().getDeviceManager().getDevices(); for(GBDevice device : devices){ Prefs devicePrefs = new Prefs(GBApplication.getDeviceSpecificSharedPrefs(device.getAddress())); if (devicePrefs.getBoolean("autoremove_notifications", true)) { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java index 91f55d527..23bf7e921 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java @@ -45,6 +45,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.UUID; @@ -310,6 +311,7 @@ public class DeviceCommunicationService extends Service implements SharedPrefere private DeviceSupportFactory mFactory; private final ArrayList deviceStructs = new ArrayList<>(1); + private final HashMap> cachedNotifications = new HashMap<>(); private PhoneCallReceiver mPhoneCallReceiver = null; private SMSReceiver mSMSReceiver = null; @@ -347,6 +349,7 @@ public class DeviceCommunicationService extends Service implements SharedPrefere private final String COMMAND_BLUETOOTH_CONNECT = "nodomain.freeyourgadget.gadgetbridge.BLUETOOTH_CONNECT"; private final String ACTION_DEVICE_CONNECTED = "nodomain.freeyourgadget.gadgetbridge.BLUETOOTH_CONNECTED"; + private final int NOTIFICATIONS_CACHE_MAX = 10; // maximum amount of notifications to cache per device while disconnected private boolean allowBluetoothIntentApi = false; private void sendDeviceConnectedBroadcast(String address){ @@ -442,6 +445,7 @@ public class DeviceCommunicationService extends Service implements SharedPrefere if(subject == GBDevice.DeviceUpdateSubject.DEVICE_STATE && device.isInitialized()){ LOG.debug("device state update reason"); sendDeviceConnectedBroadcast(device.getAddress()); + sendCachedNotifications(device); } } } @@ -626,6 +630,28 @@ public class DeviceCommunicationService extends Service implements SharedPrefere for(GBDevice device : getGBDevices()){ if(isDeviceInitialized(device)){ targetedDevices.add(device); + } else if (isDeviceReconnecting(device) && action.equals(ACTION_NOTIFICATION) && GBApplication.getPrefs().getBoolean("notification_cache_while_disconnected", false)) { + if (!cachedNotifications.containsKey(device.getAddress())) { + cachedNotifications.put(device.getAddress(), new ArrayList<>()); + } + ArrayList notifCache = cachedNotifications.get(device.getAddress()); + notifCache.add(intent); + if (notifCache.size() > NOTIFICATIONS_CACHE_MAX) { + // remove the oldest notification if the maximum is reached + notifCache.remove(0); + } + } else if (action.equals(ACTION_DELETE_NOTIFICATION)) { + ArrayList notifCache = cachedNotifications.get(device.getAddress()); + if (notifCache != null) { + int notifId = intent.getIntExtra(EXTRA_NOTIFICATION_ID, -1); + ArrayList toRemove = new ArrayList<>(); + for (Intent cached : notifCache) { + if (notifId == cached.getIntExtra(EXTRA_NOTIFICATION_ID, -1)) { + toRemove.add(cached); + } + } + notifCache.removeAll(toRemove); + } } } } @@ -1088,6 +1114,15 @@ public class DeviceCommunicationService extends Service implements SharedPrefere return false; } + private boolean isDeviceReconnecting(GBDevice device) { + for(DeviceStruct struct : deviceStructs){ + if(struct.getDevice().getAddress().compareToIgnoreCase(device.getAddress()) == 0){ + return struct.getDevice().getStateOrdinal() == GBDevice.State.WAITING_FOR_RECONNECT.ordinal(); + } + } + return false; + } + private boolean deviceHasCalendarReceiverRegistered(GBDevice device){ for (CalendarReceiver receiver: mCalendarReceiver){ if(receiver.getGBDevice().equals(device)){ @@ -1275,6 +1310,18 @@ public class DeviceCommunicationService extends Service implements SharedPrefere } } + private void sendCachedNotifications(GBDevice device) { + ArrayList notifCache = cachedNotifications.get(device.getAddress()); + if (notifCache == null) return; + try { + while (notifCache.size() > 0) { + handleAction(notifCache.remove(0), ACTION_NOTIFICATION, device); + } + } catch (DeviceNotFoundException e) { + LOG.error("Error while sending cached notifications to "+device.getAliasOrName(), e); + } + } + @Override public void onDestroy() { if (hasPrefs()) { diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index e42147057..a6d71e300 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -247,6 +247,8 @@ Do not send low and minimum priority notifications to the watch Prefer long notification text If available, send the long notification text to the device + Cache while out of range + Send missed notifications when a device reconnects after being out of range Do Not Disturb Block all notifications when Do Not Disturb is enabled on the phone Media notifications ignore app list diff --git a/app/src/main/res/xml/notifications_preferences.xml b/app/src/main/res/xml/notifications_preferences.xml index e5217c9c7..4f965068a 100644 --- a/app/src/main/res/xml/notifications_preferences.xml +++ b/app/src/main/res/xml/notifications_preferences.xml @@ -31,6 +31,13 @@ android:title="@string/pref_title_notification_prefer_long_text" android:summary="@string/pref_summary_notification_prefer_long_text" /> + +