mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge.git
synced 2025-01-10 09:01:55 +01:00
Garmin/Zepp OS: Background notifications
This commit is contained in:
parent
f99b43fc56
commit
0a9d08f67b
@ -875,6 +875,11 @@ public abstract class AbstractDeviceCoordinator implements DeviceCoordinator {
|
||||
return R.drawable.ic_device_default_disabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsBackgroundNotifications(final GBDevice device) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsNotificationVibrationPatterns() {
|
||||
return false;
|
||||
|
@ -786,6 +786,11 @@ public interface DeviceCoordinator {
|
||||
@DrawableRes
|
||||
int getDisabledIconResource();
|
||||
|
||||
/**
|
||||
* Whether the device supports silent background notifications.
|
||||
*/
|
||||
boolean supportsBackgroundNotifications(GBDevice device);
|
||||
|
||||
/**
|
||||
* Whether the device supports a variety of vibration patterns for notifications.
|
||||
*/
|
||||
|
@ -372,6 +372,11 @@ public abstract class GarminCoordinator extends AbstractBLEDeviceCoordinator {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsBackgroundNotifications(final GBDevice device) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCannedRepliesSlotCount(final GBDevice device) {
|
||||
if (getPrefs(device).getBoolean(GarminPreferences.PREF_FEAT_CANNED_MESSAGES, false)) {
|
||||
|
@ -68,6 +68,7 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.service
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.services.ZeppOsContactsService;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.services.ZeppOsLogsService;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.services.ZeppOsLoyaltyCardService;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.services.ZeppOsNotificationService;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.services.ZeppOsRemindersService;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.services.ZeppOsShortcutCardsService;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.services.ZeppOsConfigService;
|
||||
@ -621,6 +622,11 @@ public abstract class ZeppOsCoordinator extends HuamiCoordinator {
|
||||
return getPrefs(device).getBoolean("zepp_os_experimental_features", false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsBackgroundNotifications(final GBDevice device) {
|
||||
return ZeppOsNotificationService.supportsBackgroundNotifications(getPrefs(device));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validateAuthKey(final String authKey) {
|
||||
final byte[] authKeyBytes = authKey.trim().getBytes();
|
||||
|
@ -54,7 +54,6 @@ import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
@ -354,6 +353,8 @@ public class NotificationListener extends NotificationListenerService {
|
||||
return;
|
||||
}
|
||||
|
||||
NotificationSpec notificationSpec = new NotificationSpec();
|
||||
|
||||
// Ignore too frequent notifications, according to user preference
|
||||
long curTime = System.nanoTime();
|
||||
Long notificationBurstPreventionValue = notificationBurstPrevention.get(source);
|
||||
@ -361,11 +362,10 @@ public class NotificationListener extends NotificationListenerService {
|
||||
long diff = curTime - notificationBurstPreventionValue;
|
||||
if (diff < TimeUnit.SECONDS.toNanos(prefs.getInt("notifications_timeout", 0))) {
|
||||
LOG.info("Ignoring frequent notification, last one was {} ms ago", TimeUnit.NANOSECONDS.toMillis(diff));
|
||||
return;
|
||||
notificationSpec.background = true;
|
||||
}
|
||||
}
|
||||
|
||||
NotificationSpec notificationSpec = new NotificationSpec();
|
||||
notificationSpec.key = sbn.getKey();
|
||||
notificationSpec.when = notification.when;
|
||||
|
||||
|
@ -180,7 +180,8 @@ public class GBDeviceService implements DeviceService {
|
||||
.putExtra(EXTRA_NOTIFICATION_SOURCEAPPID, notificationSpec.sourceAppId)
|
||||
.putExtra(EXTRA_NOTIFICATION_ICONID, notificationSpec.iconId)
|
||||
.putExtra(NOTIFICATION_PICTURE_PATH, notificationSpec.picturePath)
|
||||
.putExtra(EXTRA_NOTIFICATION_DNDSUPPRESSED, notificationSpec.dndSuppressed);
|
||||
.putExtra(EXTRA_NOTIFICATION_DNDSUPPRESSED, notificationSpec.dndSuppressed)
|
||||
.putExtra(EXTRA_NOTIFICATION_BACKGROUND, notificationSpec.background);
|
||||
invokeService(intent);
|
||||
}
|
||||
|
||||
|
@ -101,6 +101,7 @@ public interface DeviceService extends EventHandler {
|
||||
String EXTRA_NOTIFICATION_ICONID = "notification_iconid";
|
||||
String NOTIFICATION_PICTURE_PATH = "notification_picture_path";
|
||||
String EXTRA_NOTIFICATION_DNDSUPPRESSED = "notification_dndsuppressed";
|
||||
String EXTRA_NOTIFICATION_BACKGROUND = "notification_background";
|
||||
String EXTRA_FIND_START = "find_start";
|
||||
String EXTRA_VIBRATION_INTENSITY = "vibration_intensity";
|
||||
String EXTRA_CALL_COMMAND = "call_command";
|
||||
|
@ -56,6 +56,8 @@ public class NotificationSpec {
|
||||
|
||||
public int dndSuppressed;
|
||||
|
||||
public boolean background;
|
||||
|
||||
public NotificationSpec() {
|
||||
this(-1);
|
||||
}
|
||||
|
@ -813,6 +813,7 @@ public class DeviceCommunicationService extends Service implements SharedPrefere
|
||||
}
|
||||
|
||||
DeviceSupport deviceSupport = getDeviceSupport(device);
|
||||
DeviceCoordinator coordinator = getDeviceCoordinator(device);
|
||||
|
||||
Prefs devicePrefs = new Prefs(GBApplication.getDeviceSpecificSharedPrefs(device.getAddress()));
|
||||
|
||||
@ -861,6 +862,7 @@ public class DeviceCommunicationService extends Service implements SharedPrefere
|
||||
notificationSpec.iconId = intentCopy.getIntExtra(EXTRA_NOTIFICATION_ICONID, 0);
|
||||
notificationSpec.picturePath = intent.getStringExtra(NOTIFICATION_PICTURE_PATH);
|
||||
notificationSpec.dndSuppressed = intentCopy.getIntExtra(EXTRA_NOTIFICATION_DNDSUPPRESSED, 0);
|
||||
notificationSpec.background = intentCopy.getBooleanExtra(EXTRA_NOTIFICATION_BACKGROUND, false);
|
||||
|
||||
if (notificationSpec.type == NotificationType.GENERIC_SMS && notificationSpec.phoneNumber != null) {
|
||||
GBApplication.getIDSenderLookup().add(notificationSpec.getId(), notificationSpec.phoneNumber);
|
||||
@ -882,7 +884,9 @@ public class DeviceCommunicationService extends Service implements SharedPrefere
|
||||
notificationSpec.cannedReplies = replies.toArray(new String[0]);
|
||||
}
|
||||
|
||||
if (!notificationSpec.background || coordinator.supportsBackgroundNotifications(device)) {
|
||||
deviceSupport.onNotification(notificationSpec);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ACTION_DELETE_NOTIFICATION: {
|
||||
|
@ -118,7 +118,15 @@ public class NotificationsHandler implements MessageHandler {
|
||||
}
|
||||
|
||||
final boolean hasPicture = !StringUtils.isEmpty(notificationSpec.picturePath);
|
||||
return new NotificationUpdateMessage(notificationUpdateType, notificationSpec.type, getNotificationsCount(notificationSpec.type), notificationSpec.getId(), hasActions, hasPicture);
|
||||
return new NotificationUpdateMessage(
|
||||
notificationUpdateType,
|
||||
notificationSpec.type,
|
||||
getNotificationsCount(notificationSpec.type),
|
||||
notificationSpec.getId(),
|
||||
notificationSpec.background,
|
||||
hasActions,
|
||||
hasPicture
|
||||
);
|
||||
}
|
||||
|
||||
private int getNotificationsCount(NotificationType notificationType) {
|
||||
@ -155,7 +163,14 @@ public class NotificationsHandler implements MessageHandler {
|
||||
NotificationSpec e = iterator.next();
|
||||
if (e.getId() == id) {
|
||||
iterator.remove();
|
||||
return new NotificationUpdateMessage(NotificationUpdateMessage.NotificationUpdateType.REMOVE, e.type, getNotificationsCount(e.type), id, false, false);
|
||||
return new NotificationUpdateMessage(
|
||||
NotificationUpdateMessage.NotificationUpdateType.REMOVE,
|
||||
e.type, getNotificationsCount(e.type),
|
||||
id,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
@ -13,15 +13,23 @@ public class NotificationUpdateMessage extends GFDIMessage {
|
||||
final private int count; //how many notifications of the same type are present
|
||||
final private int notificationId;
|
||||
final private boolean hasActions;
|
||||
final private boolean background;
|
||||
final private boolean hasPicture;
|
||||
final private boolean useLegacyActions = false;
|
||||
|
||||
public NotificationUpdateMessage(NotificationUpdateType notificationUpdateType, NotificationType notificationType, int count, int notificationId, boolean hasActions, boolean hasPicture) {
|
||||
public NotificationUpdateMessage(NotificationUpdateType notificationUpdateType,
|
||||
NotificationType notificationType,
|
||||
int count,
|
||||
int notificationId,
|
||||
boolean background,
|
||||
boolean hasActions,
|
||||
boolean hasPicture) {
|
||||
this.garminMessage = GarminMessage.NOTIFICATION_UPDATE;
|
||||
this.notificationUpdateType = notificationUpdateType;
|
||||
this.notificationType = notificationType;
|
||||
this.count = count;
|
||||
this.notificationId = notificationId;
|
||||
this.background = background;
|
||||
this.hasActions = hasActions;
|
||||
this.hasPicture = hasPicture;
|
||||
}
|
||||
@ -32,7 +40,7 @@ public class NotificationUpdateMessage extends GFDIMessage {
|
||||
writer.writeShort(0); // packet size will be filled below
|
||||
writer.writeShort(this.garminMessage.getId());
|
||||
writer.writeByte(this.notificationUpdateType.ordinal());
|
||||
writer.writeByte(getCategoryFlags(this.notificationType));
|
||||
writer.writeByte(getCategoryFlags(this.notificationType, this.background));
|
||||
writer.writeByte(getCategoryValue(this.notificationType));
|
||||
writer.writeByte(this.count);
|
||||
writer.writeInt(this.notificationId);
|
||||
@ -54,13 +62,16 @@ public class NotificationUpdateMessage extends GFDIMessage {
|
||||
|
||||
}
|
||||
|
||||
private int getCategoryFlags(NotificationType notificationType) {
|
||||
private int getCategoryFlags(NotificationType notificationType, boolean background) {
|
||||
EnumSet<NotificationFlag> flags = EnumSet.noneOf(NotificationFlag.class);
|
||||
if (this.hasActions && this.useLegacyActions) { //only needed for legacy actions
|
||||
flags.add(NotificationFlag.ACTION_ACCEPT);
|
||||
}
|
||||
flags.add(NotificationFlag.ACTION_DECLINE);
|
||||
|
||||
if (background) {
|
||||
flags.add(NotificationFlag.BACKGROUND);
|
||||
} else {
|
||||
switch (notificationType.getGenericType()) {
|
||||
case "generic_phone":
|
||||
case "generic_email":
|
||||
@ -76,6 +87,8 @@ public class NotificationUpdateMessage extends GFDIMessage {
|
||||
// to be foreground, sending them as background was generating bug reports.
|
||||
flags.add(NotificationFlag.FOREGROUND);
|
||||
}
|
||||
}
|
||||
|
||||
return (int) EnumUtils.generateBitVector(NotificationFlag.class, flags);
|
||||
}
|
||||
|
||||
|
@ -39,6 +39,7 @@ import nodomain.freeyourgadget.gadgetbridge.BuildConfig;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst;
|
||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventCallControl;
|
||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventNotificationControl;
|
||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventUpdatePreferences;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.CallSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.NotificationType;
|
||||
@ -47,9 +48,9 @@ import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.ZeppOsSupport;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.AbstractZeppOsService;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.BitmapUtil;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.LimitedQueue;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.NotificationUtils;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.StringUtils;
|
||||
|
||||
public class ZeppOsNotificationService extends AbstractZeppOsService {
|
||||
@ -78,6 +79,8 @@ public class ZeppOsNotificationService extends AbstractZeppOsService {
|
||||
public static final byte NOTIFICATION_CALL_STATE_START = 0x00;
|
||||
public static final byte NOTIFICATION_CALL_STATE_END = 0x02;
|
||||
|
||||
public static final String PREF_VERSION = "zepp_os_notifications_version";
|
||||
|
||||
private int version = -1;
|
||||
private boolean supportsPictures = false;
|
||||
private boolean supportsNotificationKey = false;
|
||||
@ -121,6 +124,7 @@ public class ZeppOsNotificationService extends AbstractZeppOsService {
|
||||
switch (cmd) {
|
||||
case NOTIFICATION_CMD_CAPABILITIES_RESPONSE: {
|
||||
version = buf.get() & 0xff;
|
||||
getSupport().evaluateGBDeviceEvent(new GBDeviceEventUpdatePreferences(PREF_VERSION, version));
|
||||
if (version < 4 || version > 5) {
|
||||
// Untested, might work, might not..
|
||||
LOG.warn("Unsupported notification service version {}", version);
|
||||
@ -357,7 +361,7 @@ public class ZeppOsNotificationService extends AbstractZeppOsService {
|
||||
|
||||
baos.write((byte) (hasReply ? 1 : 0));
|
||||
if (version >= 5) {
|
||||
baos.write(0); // 1 for silent
|
||||
baos.write(notificationSpec.background ? 1 : 0); // 1 for silent
|
||||
}
|
||||
if (supportsPictures) {
|
||||
baos.write((byte) (notificationSpec.picturePath != null ? 1 : 0));
|
||||
@ -597,4 +601,9 @@ public class ZeppOsNotificationService extends AbstractZeppOsService {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean supportsBackgroundNotifications(final Prefs devicePrefs) {
|
||||
final int version = devicePrefs.getInt(PREF_VERSION, 0);
|
||||
return version >= 5;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user