mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge
synced 2024-08-26 09:11:37 +02:00
Mi2: Initial support for textual notifications #560
This commit is contained in:
parent
aa6e9608bd
commit
4419200624
@ -128,6 +128,8 @@ public class MiBand2Service {
|
||||
public static final byte[] COMMAND_ENABLE_DISPLAY_ON_LIFT_WRIST = new byte[]{0x06, 0x05, 0x00, 0x01};
|
||||
public static final byte[] COMMAND_DISABLE_DISPLAY_ON_LIFT_WRIST = new byte[]{0x06, 0x05, 0x00, 0x00};
|
||||
|
||||
public static final byte[] COMMAND_TEXT_NOTIFICATION = new byte[] {0x05, 0x01};
|
||||
public static final byte[] COMMAND_TEXT_NOTIFICATION_CONTINUATION = new byte[] {(byte) 0xfa, 0x01, 0x00};
|
||||
|
||||
static {
|
||||
MIBAND_DEBUG = new HashMap<>();
|
||||
|
@ -5,6 +5,7 @@ import nodomain.freeyourgadget.gadgetbridge.devices.pebble.PebbleIconID;
|
||||
|
||||
public enum NotificationType {
|
||||
|
||||
// TODO: this this pebbleism needs to be moved somewhere else
|
||||
UNKNOWN(PebbleIconID.NOTIFICATION_GENERIC, PebbleColor.Red),
|
||||
|
||||
CONVERSATIONS(PebbleIconID.NOTIFICATION_HIPCHAT, PebbleColor.Inchworm),
|
||||
@ -19,6 +20,7 @@ public enum NotificationType {
|
||||
TELEGRAM(PebbleIconID.NOTIFICATION_TELEGRAM, PebbleColor.PictonBlue),
|
||||
WHATSAPP(PebbleIconID.NOTIFICATION_WHATSAPP, PebbleColor.MayGreen),
|
||||
GENERIC_ALARM_CLOCK(PebbleIconID.ALARM_CLOCK, PebbleColor.Red);
|
||||
// Note: if you add any more constants, update all clients as well
|
||||
|
||||
public int icon;
|
||||
public byte color;
|
||||
|
@ -1,10 +1,13 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.btle;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Calendar;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandCoordinator;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.NotificationType;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.alertnotification.AlertCategory;
|
||||
|
||||
/**
|
||||
* Provides methods to convert standard BLE units to byte sequences and vice versa.
|
||||
@ -233,4 +236,33 @@ public class BLETypeConversions {
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static byte[] toUtf8s(String message) {
|
||||
return message.getBytes(StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
public static AlertCategory toAlertCategory(NotificationType type) {
|
||||
switch (type) {
|
||||
case GENERIC_ALARM_CLOCK:
|
||||
return AlertCategory.HighPriorityAlert;
|
||||
case GENERIC_SMS:
|
||||
return AlertCategory.SMS;
|
||||
case GENERIC_EMAIL:
|
||||
return AlertCategory.Email;
|
||||
case GENERIC_NAVIGATION:
|
||||
return AlertCategory.Simple;
|
||||
case RIOT:
|
||||
case SIGNAL:
|
||||
case TELEGRAM:
|
||||
case WHATSAPP:
|
||||
case CONVERSATIONS:
|
||||
case FACEBOOK:
|
||||
case FACEBOOK_MESSENGER:
|
||||
case TWITTER:
|
||||
return AlertCategory.InstantMessage;
|
||||
case UNKNOWN:
|
||||
return AlertCategory.Simple;
|
||||
}
|
||||
return AlertCategory.Simple;
|
||||
}
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ public class GattCharacteristic {
|
||||
public static final UUID UUID_CHARACTERISTIC_ALERT_CATEGORY_ID = UUID.fromString((String.format(AbstractBTLEDeviceSupport.BASE_UUID, "2A43")));
|
||||
public static final UUID UUID_CHARACTERISTIC_ALERT_CATEGORY_ID_BIT_MASK = UUID.fromString((String.format(AbstractBTLEDeviceSupport.BASE_UUID, "2A42")));
|
||||
public static final UUID UUID_CHARACTERISTIC_ALERT_LEVEL = UUID.fromString((String.format(AbstractBTLEDeviceSupport.BASE_UUID, "2A06")));
|
||||
public static final UUID UUID_CHARACTERISTIC_CLIENT_CHARACTERISTIC_CONFIG = UUID.fromString((String.format(AbstractBTLEDeviceSupport.BASE_UUID, "2902")));
|
||||
|
||||
public static final byte NO_ALERT = 0x0;
|
||||
public static final byte MILD_ALERT = 0x1;
|
||||
|
@ -1,12 +1,66 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.alertnotification;
|
||||
|
||||
import android.bluetooth.BluetoothGattCharacteristic;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.AbstractBTLEDeviceSupport;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.BLETypeConversions;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.GattCharacteristic;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.AbstractBleProfile;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.StringUtils;
|
||||
|
||||
public class AlertNotificationProfile<T extends AbstractBTLEDeviceSupport> extends AbstractBleProfile<T> {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(AlertNotificationProfile.class);
|
||||
private static final int MAX_MSG_LENGTH = 18;
|
||||
|
||||
public AlertNotificationProfile(T support) {
|
||||
super(support);
|
||||
}
|
||||
|
||||
public void newAlert(TransactionBuilder builder, NewAlert alert, OverflowStrategy strategy) {
|
||||
BluetoothGattCharacteristic characteristic = getCharacteristic(GattCharacteristic.UUID_CHARACTERISTIC_NEW_ALERT);
|
||||
if (characteristic != null) {
|
||||
String message = alert.getMessage();
|
||||
if (message.length() > MAX_MSG_LENGTH && strategy == OverflowStrategy.TRUNCATE) {
|
||||
message = StringUtils.truncate(message, MAX_MSG_LENGTH);
|
||||
}
|
||||
|
||||
int numChunks = message.length() / MAX_MSG_LENGTH;
|
||||
if (message.length() % MAX_MSG_LENGTH > 0) {
|
||||
numChunks++;
|
||||
}
|
||||
|
||||
for (int i = 0; i < numChunks; i++) {
|
||||
int offset = i * MAX_MSG_LENGTH;
|
||||
int restLength = message.length() - offset;
|
||||
message = message.substring(offset, offset + Math.min(MAX_MSG_LENGTH, restLength));
|
||||
if (message.length() == 0) {
|
||||
break;
|
||||
}
|
||||
writeAlertMessage(builder, characteristic, alert, message, i);
|
||||
}
|
||||
} else {
|
||||
LOG.warn("NEW_ALERT characteristic not available");
|
||||
}
|
||||
}
|
||||
|
||||
protected void writeAlertMessage(TransactionBuilder builder, BluetoothGattCharacteristic characteristic, NewAlert alert, String message, int chunk) {
|
||||
try {
|
||||
ByteArrayOutputStream stream = new ByteArrayOutputStream(100);
|
||||
stream.write(alert.getCategory().getId());
|
||||
stream.write(alert.getNumAlerts());
|
||||
stream.write(BLETypeConversions.toUtf8s(message));
|
||||
|
||||
builder.write(characteristic, stream.toByteArray());
|
||||
} catch (IOException ex) {
|
||||
// aint gonna happen
|
||||
LOG.error("Error writing alert message to ByteArrayOutputStream");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,52 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.alertnotification;
|
||||
|
||||
/**
|
||||
* https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.new_alert.xml&u=org.bluetooth.characteristic.new_alert.xml
|
||||
*
|
||||
Recommended Usage for Text String Information Field in New Incoming Alert:
|
||||
|
||||
The usage of this text is up to the implementation, but the recommended text for the category is defined as following for best user experience:
|
||||
|
||||
Category: Simple Alert - The title of the alert
|
||||
|
||||
Category: Email - Sender name
|
||||
|
||||
Category: News - Title of the news feed
|
||||
|
||||
Category: Call - Caller name or caller ID
|
||||
|
||||
Category: Missed call - Caller name or caller ID
|
||||
|
||||
Category: SMS - Sender name or caller ID
|
||||
|
||||
Category: Voice mail - Sender name or caller ID
|
||||
|
||||
Category: Schedule - Title of the schedule
|
||||
|
||||
Category Hig:h Prioritized Aler - Title of the alert
|
||||
|
||||
Category: Instant Messaging - Sender name
|
||||
*/
|
||||
public class NewAlert {
|
||||
private final AlertCategory category;
|
||||
private final int numAlerts;
|
||||
private final String message;
|
||||
|
||||
public NewAlert(AlertCategory category, int /*uint8*/ numAlerts, String /*utf8s*/ message) {
|
||||
this.category = category;
|
||||
this.numAlerts = numAlerts;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public AlertCategory getCategory() {
|
||||
return category;
|
||||
}
|
||||
|
||||
public int getNumAlerts() {
|
||||
return numAlerts;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.alertnotification;
|
||||
|
||||
public enum OverflowStrategy {
|
||||
TRUNCATE,
|
||||
MAKE_MULTIPLE
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.common;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.alertnotification.AlertCategory;
|
||||
|
||||
public class SimpleNotification {
|
||||
private final String message;
|
||||
private final AlertCategory alertCategory;
|
||||
|
||||
public SimpleNotification(String message, AlertCategory alertCategory) {
|
||||
this.message = message;
|
||||
this.alertCategory = alertCategory;
|
||||
}
|
||||
|
||||
public AlertCategory getAlertCategory() {
|
||||
return alertCategory;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
}
|
@ -53,6 +53,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.NotificationType;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.AbstractBTLEDeviceSupport;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.BLETypeConversions;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.BtLEAction;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.GattCharacteristic;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.GattService;
|
||||
@ -61,10 +62,13 @@ import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.AbortTransactio
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.ConditionalWriteAction;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.SetDeviceStateAction;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.WriteAction;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.alertnotification.AlertCategory;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.common.SimpleNotification;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.miband.operations.FetchActivityOperation;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.miband.operations.UpdateFirmwareOperation;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.DateTimeUtils;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.NotificationUtils;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
|
||||
|
||||
import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.DEFAULT_VALUE_FLASH_COLOUR;
|
||||
@ -205,19 +209,19 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport {
|
||||
return mDeviceInfo;
|
||||
}
|
||||
|
||||
private MiBandSupport sendDefaultNotification(TransactionBuilder builder, short repeat, BtLEAction extraAction) {
|
||||
private MiBandSupport sendDefaultNotification(TransactionBuilder builder, SimpleNotification simpleNotification, short repeat, BtLEAction extraAction) {
|
||||
LOG.info("Sending notification to MiBand: (" + repeat + " times)");
|
||||
NotificationStrategy strategy = getNotificationStrategy();
|
||||
for (short i = 0; i < repeat; i++) {
|
||||
strategy.sendDefaultNotification(builder, extraAction);
|
||||
strategy.sendDefaultNotification(builder, simpleNotification, extraAction);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a custom notification to the given transaction builder
|
||||
*
|
||||
* @param vibrationProfile specifies how and how often the Band shall vibrate.
|
||||
* @param vibrationProfile specifies how and how often the Band shall vibrate.
|
||||
* @param simpleNotification
|
||||
* @param flashTimes
|
||||
* @param flashColour
|
||||
* @param originalColour
|
||||
@ -225,8 +229,8 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport {
|
||||
* @param extraAction an extra action to be executed after every vibration and flash sequence. Allows to abort the repetition, for example.
|
||||
* @param builder
|
||||
*/
|
||||
private MiBandSupport sendCustomNotification(VibrationProfile vibrationProfile, int flashTimes, int flashColour, int originalColour, long flashDuration, BtLEAction extraAction, TransactionBuilder builder) {
|
||||
getNotificationStrategy().sendCustomNotification(vibrationProfile, flashTimes, flashColour, originalColour, flashDuration, extraAction, builder);
|
||||
private MiBandSupport sendCustomNotification(VibrationProfile vibrationProfile, SimpleNotification simpleNotification, int flashTimes, int flashColour, int originalColour, long flashDuration, BtLEAction extraAction, TransactionBuilder builder) {
|
||||
getNotificationStrategy().sendCustomNotification(vibrationProfile, simpleNotification, flashTimes, flashColour, originalColour, flashDuration, extraAction, builder);
|
||||
LOG.info("Sending notification to MiBand");
|
||||
return this;
|
||||
}
|
||||
@ -454,17 +458,17 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport {
|
||||
return this;
|
||||
}
|
||||
|
||||
private void performDefaultNotification(String task, short repeat, BtLEAction extraAction) {
|
||||
private void performDefaultNotification(String task, SimpleNotification simpleNotification, short repeat, BtLEAction extraAction) {
|
||||
try {
|
||||
TransactionBuilder builder = performInitialized(task);
|
||||
sendDefaultNotification(builder, repeat, extraAction);
|
||||
sendDefaultNotification(builder, simpleNotification, repeat, extraAction);
|
||||
builder.queue(getQueue());
|
||||
} catch (IOException ex) {
|
||||
LOG.error("Unable to send notification to MI device", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void performPreferredNotification(String task, String notificationOrigin, BtLEAction extraAction) {
|
||||
private void performPreferredNotification(String task, SimpleNotification simpleNotification, String notificationOrigin, BtLEAction extraAction) {
|
||||
try {
|
||||
TransactionBuilder builder = performInitialized(task);
|
||||
Prefs prefs = GBApplication.getPrefs();
|
||||
@ -479,7 +483,7 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport {
|
||||
int flashDuration = getPreferredFlashDuration(notificationOrigin, prefs);
|
||||
|
||||
// setLowLatency(builder);
|
||||
sendCustomNotification(profile, flashTimes, flashColour, originalColour, flashDuration, extraAction, builder);
|
||||
sendCustomNotification(profile, simpleNotification, flashTimes, flashColour, originalColour, flashDuration, extraAction, builder);
|
||||
// setHighLatency(builder);
|
||||
// sendCustomNotification(vibrateDuration, vibrateTimes, vibratePause, flashTimes, flashColour, originalColour, flashDuration, builder);
|
||||
builder.queue(getQueue());
|
||||
@ -549,8 +553,11 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport {
|
||||
return;
|
||||
}
|
||||
|
||||
String message = NotificationUtils.getPreferredTextFor(notificationSpec, 40, 40, getContext()).trim();
|
||||
SimpleNotification simpleNotification = new SimpleNotification(message, BLETypeConversions.toAlertCategory(notificationSpec.type));
|
||||
|
||||
String origin = notificationSpec.type.getGenericType();
|
||||
performPreferredNotification(origin + " received", origin, null);
|
||||
performPreferredNotification(origin + " received", simpleNotification, origin, null);
|
||||
}
|
||||
|
||||
private void onAlarmClock(NotificationSpec notificationSpec) {
|
||||
@ -561,7 +568,9 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport {
|
||||
return !isAlarmClockRinging();
|
||||
}
|
||||
};
|
||||
performPreferredNotification("alarm clock ringing", MiBandConst.ORIGIN_ALARM_CLOCK, abortAction);
|
||||
String message = NotificationUtils.getPreferredTextFor(notificationSpec, 40, 40, getContext());
|
||||
SimpleNotification simpleNotification = new SimpleNotification(message, AlertCategory.HighPriorityAlert);
|
||||
performPreferredNotification("alarm clock ringing", simpleNotification, MiBandConst.ORIGIN_ALARM_CLOCK, abortAction);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -625,7 +634,9 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport {
|
||||
return !isTelephoneRinging();
|
||||
}
|
||||
};
|
||||
performPreferredNotification("incoming call", MiBandConst.ORIGIN_INCOMING_CALL, abortAction);
|
||||
String message = NotificationUtils.getPreferredTextFor(callSpec);
|
||||
SimpleNotification simpleNotification = new SimpleNotification(message, AlertCategory.IncomingCall);
|
||||
performPreferredNotification("incoming call", simpleNotification, MiBandConst.ORIGIN_INCOMING_CALL, abortAction);
|
||||
} else if ((callSpec.command == CallSpec.CALL_START) || (callSpec.command == CallSpec.CALL_END)) {
|
||||
telephoneRinging = false;
|
||||
}
|
||||
@ -716,7 +727,8 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport {
|
||||
return !isLocatingDevice;
|
||||
}
|
||||
};
|
||||
performDefaultNotification("locating device", (short) 255, abortAction);
|
||||
SimpleNotification simpleNotification = new SimpleNotification(getContext().getString(R.string.find_device_you_found_it), AlertCategory.HighPriorityAlert);
|
||||
performDefaultNotification("locating device", simpleNotification, (short) 255, abortAction);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,7 @@ import org.slf4j.LoggerFactory;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.miband.VibrationProfile;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.BtLEAction;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.common.SimpleNotification;
|
||||
|
||||
/**
|
||||
* Does not do anything.
|
||||
@ -14,12 +15,12 @@ public class NoNotificationStrategy implements NotificationStrategy {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(NoNotificationStrategy.class);
|
||||
|
||||
@Override
|
||||
public void sendDefaultNotification(TransactionBuilder builder, BtLEAction extraAction) {
|
||||
public void sendDefaultNotification(TransactionBuilder builder, SimpleNotification simpleNotification, BtLEAction extraAction) {
|
||||
LOG.info("dummy notification stragegy: default notification");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendCustomNotification(VibrationProfile vibrationProfile, int flashTimes, int flashColour, int originalColour, long flashDuration, BtLEAction extraAction, TransactionBuilder builder) {
|
||||
LOG.info("dummy notification stragegy: custom notification");
|
||||
public void sendCustomNotification(VibrationProfile vibrationProfile, SimpleNotification simpleNotification, int flashTimes, int flashColour, int originalColour, long flashDuration, BtLEAction extraAction, TransactionBuilder builder) {
|
||||
LOG.info("dummy notification stragegy: custom notification: " + simpleNotification);
|
||||
}
|
||||
}
|
||||
|
@ -3,14 +3,15 @@ package nodomain.freeyourgadget.gadgetbridge.service.devices.miband;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.miband.VibrationProfile;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.BtLEAction;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.common.SimpleNotification;
|
||||
|
||||
public interface NotificationStrategy {
|
||||
void sendDefaultNotification(TransactionBuilder builder, BtLEAction extraAction);
|
||||
void sendDefaultNotification(TransactionBuilder builder, SimpleNotification simpleNotification, BtLEAction extraAction);
|
||||
|
||||
/**
|
||||
* Adds a custom notification to the given transaction builder
|
||||
*
|
||||
* @param vibrationProfile specifies how and how often the Band shall vibrate.
|
||||
* @param simpleNotification
|
||||
* @param flashTimes
|
||||
* @param flashColour
|
||||
* @param originalColour
|
||||
@ -18,5 +19,5 @@ public interface NotificationStrategy {
|
||||
* @param extraAction an extra action to be executed after every vibration and flash sequence. Allows to abort the repetition, for example.
|
||||
* @param builder
|
||||
*/
|
||||
void sendCustomNotification(VibrationProfile vibrationProfile, int flashTimes, int flashColour, int originalColour, long flashDuration, BtLEAction extraAction, TransactionBuilder builder);
|
||||
void sendCustomNotification(VibrationProfile vibrationProfile, SimpleNotification simpleNotification, int flashTimes, int flashColour, int originalColour, long flashDuration, BtLEAction extraAction, TransactionBuilder builder);
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ import nodomain.freeyourgadget.gadgetbridge.devices.miband.VibrationProfile;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.AbstractBTLEDeviceSupport;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.BtLEAction;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.common.SimpleNotification;
|
||||
|
||||
public class V1NotificationStrategy implements NotificationStrategy {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(V1NotificationStrategy.class);
|
||||
@ -24,7 +25,7 @@ public class V1NotificationStrategy implements NotificationStrategy {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendDefaultNotification(TransactionBuilder builder, BtLEAction extraAction) {
|
||||
public void sendDefaultNotification(TransactionBuilder builder, SimpleNotification simpleNotification, BtLEAction extraAction) {
|
||||
BluetoothGattCharacteristic characteristic = support.getCharacteristic(MiBandService.UUID_CHARACTERISTIC_CONTROL_POINT);
|
||||
builder.write(characteristic, getDefaultNotification());
|
||||
builder.add(extraAction);
|
||||
@ -53,8 +54,8 @@ public class V1NotificationStrategy implements NotificationStrategy {
|
||||
|
||||
/**
|
||||
* Adds a custom notification to the given transaction builder
|
||||
*
|
||||
* @param vibrationProfile specifies how and how often the Band shall vibrate.
|
||||
* @param simpleNotification
|
||||
* @param flashTimes
|
||||
* @param flashColour
|
||||
* @param originalColour
|
||||
@ -63,7 +64,7 @@ public class V1NotificationStrategy implements NotificationStrategy {
|
||||
* @param builder
|
||||
*/
|
||||
@Override
|
||||
public void sendCustomNotification(VibrationProfile vibrationProfile, int flashTimes, int flashColour, int originalColour, long flashDuration, BtLEAction extraAction, TransactionBuilder builder) {
|
||||
public void sendCustomNotification(VibrationProfile vibrationProfile, SimpleNotification simpleNotification, int flashTimes, int flashColour, int originalColour, long flashDuration, BtLEAction extraAction, TransactionBuilder builder) {
|
||||
BluetoothGattCharacteristic controlPoint = support.getCharacteristic(MiBandService.UUID_CHARACTERISTIC_CONTROL_POINT);
|
||||
for (short i = 0; i < vibrationProfile.getRepeat(); i++) {
|
||||
int[] onOffSequence = vibrationProfile.getOnOffSequence();
|
||||
|
@ -7,6 +7,10 @@ import nodomain.freeyourgadget.gadgetbridge.service.btle.AbstractBTLEDeviceSuppo
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.BtLEAction;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.GattCharacteristic;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.alertnotification.AlertNotificationProfile;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.alertnotification.NewAlert;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.alertnotification.OverflowStrategy;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.common.SimpleNotification;
|
||||
|
||||
public class V2NotificationStrategy implements NotificationStrategy {
|
||||
private final AbstractBTLEDeviceSupport support;
|
||||
@ -20,12 +24,12 @@ public class V2NotificationStrategy implements NotificationStrategy {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendDefaultNotification(TransactionBuilder builder, BtLEAction extraAction) {
|
||||
public void sendDefaultNotification(TransactionBuilder builder, SimpleNotification simpleNotification, BtLEAction extraAction) {
|
||||
VibrationProfile profile = VibrationProfile.getProfile(VibrationProfile.ID_MEDIUM, (short) 3);
|
||||
sendCustomNotification(profile, extraAction, builder);
|
||||
sendCustomNotification(profile, simpleNotification, extraAction, builder);
|
||||
}
|
||||
|
||||
protected void sendCustomNotification(VibrationProfile vibrationProfile, BtLEAction extraAction, TransactionBuilder builder) {
|
||||
protected void sendCustomNotification(VibrationProfile vibrationProfile, SimpleNotification simpleNotification, BtLEAction extraAction, TransactionBuilder builder) {
|
||||
//use the new alert characteristic
|
||||
BluetoothGattCharacteristic alert = support.getCharacteristic(GattCharacteristic.UUID_CHARACTERISTIC_ALERT_LEVEL);
|
||||
for (short i = 0; i < vibrationProfile.getRepeat(); i++) {
|
||||
@ -49,11 +53,18 @@ public class V2NotificationStrategy implements NotificationStrategy {
|
||||
}
|
||||
}
|
||||
}
|
||||
sendAlert(simpleNotification, builder);
|
||||
}
|
||||
|
||||
protected void sendAlert(SimpleNotification simpleNotification, TransactionBuilder builder) {
|
||||
AlertNotificationProfile<?> profile = new AlertNotificationProfile<>(getSupport());
|
||||
NewAlert alert = new NewAlert(simpleNotification.getAlertCategory(), 1, simpleNotification.getMessage());
|
||||
profile.newAlert(builder, alert, OverflowStrategy.MAKE_MULTIPLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendCustomNotification(VibrationProfile vibrationProfile, int flashTimes, int flashColour, int originalColour, long flashDuration, BtLEAction extraAction, TransactionBuilder builder) {
|
||||
public void sendCustomNotification(VibrationProfile vibrationProfile, SimpleNotification simpleNotification, int flashTimes, int flashColour, int originalColour, long flashDuration, BtLEAction extraAction, TransactionBuilder builder) {
|
||||
// all other parameters are unfortunately not supported anymore ;-(
|
||||
sendCustomNotification(vibrationProfile, extraAction, builder);
|
||||
sendCustomNotification(vibrationProfile, simpleNotification, extraAction, builder);
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,8 @@ import nodomain.freeyourgadget.gadgetbridge.service.btle.AbstractBTLEDeviceSuppo
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.BtLEAction;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.GattCharacteristic;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.alertnotification.AlertNotificationProfile;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.common.SimpleNotification;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.miband.V2NotificationStrategy;
|
||||
|
||||
public class Mi2NotificationStrategy extends V2NotificationStrategy {
|
||||
@ -16,7 +18,7 @@ public class Mi2NotificationStrategy extends V2NotificationStrategy {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void sendCustomNotification(VibrationProfile vibrationProfile, BtLEAction extraAction, TransactionBuilder builder) {
|
||||
protected void sendCustomNotification(VibrationProfile vibrationProfile, SimpleNotification simpleNotification, BtLEAction extraAction, TransactionBuilder builder) {
|
||||
//use the new alert characteristic
|
||||
BluetoothGattCharacteristic alert = getSupport().getCharacteristic(GattCharacteristic.UUID_CHARACTERISTIC_ALERT_LEVEL);
|
||||
for (short i = 0; i < vibrationProfile.getRepeat(); i++) {
|
||||
@ -38,11 +40,13 @@ public class Mi2NotificationStrategy extends V2NotificationStrategy {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendCustomNotification(VibrationProfile vibrationProfile, int flashTimes, int flashColour, int originalColour, long flashDuration, BtLEAction extraAction, TransactionBuilder builder) {
|
||||
public void sendCustomNotification(VibrationProfile vibrationProfile, SimpleNotification simpleNotification, int flashTimes, int flashColour, int originalColour, long flashDuration, BtLEAction extraAction, TransactionBuilder builder) {
|
||||
// all other parameters are unfortunately not supported anymore ;-(
|
||||
sendCustomNotification(vibrationProfile, extraAction, builder);
|
||||
sendCustomNotification(vibrationProfile, simpleNotification, extraAction, builder);
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.net.Uri;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.content.LocalBroadcastManager;
|
||||
import android.widget.Toast;
|
||||
|
||||
@ -67,8 +68,10 @@ import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.AbortTransactionAction;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.SetDeviceStateAction;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.WriteAction;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.alertnotification.AlertCategory;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.deviceinfo.DeviceInfoProfile;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.heartrate.HeartRateProfile;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.common.SimpleNotification;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.miband.CheckAuthenticationNeededAction;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.miband.DeviceInfo;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.miband.NotificationStrategy;
|
||||
@ -79,7 +82,9 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.miband2.operations.I
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.miband2.operations.UpdateFirmwareOperation;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.DateTimeUtils;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.NotificationUtils;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.StringUtils;
|
||||
|
||||
import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.DEFAULT_VALUE_FLASH_COLOUR;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.DEFAULT_VALUE_FLASH_COUNT;
|
||||
@ -301,19 +306,19 @@ public class MiBand2Support extends AbstractBTLEDeviceSupport {
|
||||
return mDeviceInfo;
|
||||
}
|
||||
|
||||
private MiBand2Support sendDefaultNotification(TransactionBuilder builder, short repeat, BtLEAction extraAction) {
|
||||
private MiBand2Support sendDefaultNotification(TransactionBuilder builder, SimpleNotification simpleNotification, short repeat, BtLEAction extraAction) {
|
||||
LOG.info("Sending notification to MiBand: (" + repeat + " times)");
|
||||
NotificationStrategy strategy = getNotificationStrategy();
|
||||
for (short i = 0; i < repeat; i++) {
|
||||
strategy.sendDefaultNotification(builder, extraAction);
|
||||
strategy.sendDefaultNotification(builder, simpleNotification, extraAction);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a custom notification to the given transaction builder
|
||||
*
|
||||
* @param vibrationProfile specifies how and how often the Band shall vibrate.
|
||||
* @param simpleNotification
|
||||
* @param flashTimes
|
||||
* @param flashColour
|
||||
* @param originalColour
|
||||
@ -321,8 +326,8 @@ public class MiBand2Support extends AbstractBTLEDeviceSupport {
|
||||
* @param extraAction an extra action to be executed after every vibration and flash sequence. Allows to abort the repetition, for example.
|
||||
* @param builder
|
||||
*/
|
||||
private MiBand2Support sendCustomNotification(VibrationProfile vibrationProfile, int flashTimes, int flashColour, int originalColour, long flashDuration, BtLEAction extraAction, TransactionBuilder builder) {
|
||||
getNotificationStrategy().sendCustomNotification(vibrationProfile, flashTimes, flashColour, originalColour, flashDuration, extraAction, builder);
|
||||
private MiBand2Support sendCustomNotification(VibrationProfile vibrationProfile, SimpleNotification simpleNotification, int flashTimes, int flashColour, int originalColour, long flashDuration, BtLEAction extraAction, TransactionBuilder builder) {
|
||||
getNotificationStrategy().sendCustomNotification(vibrationProfile, simpleNotification, flashTimes, flashColour, originalColour, flashDuration, extraAction, builder);
|
||||
LOG.info("Sending notification to MiBand");
|
||||
return this;
|
||||
}
|
||||
@ -500,17 +505,17 @@ public class MiBand2Support extends AbstractBTLEDeviceSupport {
|
||||
return this;
|
||||
}
|
||||
|
||||
private void performDefaultNotification(String task, short repeat, BtLEAction extraAction) {
|
||||
private void performDefaultNotification(String task, SimpleNotification simpleNotification, short repeat, BtLEAction extraAction) {
|
||||
try {
|
||||
TransactionBuilder builder = performInitialized(task);
|
||||
sendDefaultNotification(builder, repeat, extraAction);
|
||||
sendDefaultNotification(builder, simpleNotification, repeat, extraAction);
|
||||
builder.queue(getQueue());
|
||||
} catch (IOException ex) {
|
||||
LOG.error("Unable to send notification to MI device", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void performPreferredNotification(String task, String notificationOrigin, int alertLevel, BtLEAction extraAction) {
|
||||
private void performPreferredNotification(String task, String notificationOrigin, SimpleNotification simpleNotification, int alertLevel, BtLEAction extraAction) {
|
||||
try {
|
||||
TransactionBuilder builder = performInitialized(task);
|
||||
Prefs prefs = GBApplication.getPrefs();
|
||||
@ -525,7 +530,7 @@ public class MiBand2Support extends AbstractBTLEDeviceSupport {
|
||||
int originalColour = getPreferredOriginalColour(notificationOrigin, prefs);
|
||||
int flashDuration = getPreferredFlashDuration(notificationOrigin, prefs);
|
||||
|
||||
sendCustomNotification(profile, flashTimes, flashColour, originalColour, flashDuration, extraAction, builder);
|
||||
sendCustomNotification(profile, simpleNotification, flashTimes, flashColour, originalColour, flashDuration, extraAction, builder);
|
||||
// sendCustomNotification(vibrateDuration, vibrateTimes, vibratePause, flashTimes, flashColour, originalColour, flashDuration, builder);
|
||||
builder.queue(getQueue());
|
||||
} catch (IOException ex) {
|
||||
@ -597,8 +602,10 @@ public class MiBand2Support extends AbstractBTLEDeviceSupport {
|
||||
if (notificationSpec.type == NotificationType.UNKNOWN) {
|
||||
alertLevel = MiBand2Service.ALERT_LEVEL_VIBRATE_ONLY;
|
||||
}
|
||||
String message = NotificationUtils.getPreferredTextFor(notificationSpec, 40, 40, getContext()).trim();
|
||||
String origin = notificationSpec.type.getGenericType();
|
||||
performPreferredNotification(origin + " received", origin, alertLevel, null);
|
||||
SimpleNotification simpleNotification = new SimpleNotification(message, BLETypeConversions.toAlertCategory(notificationSpec.type));
|
||||
performPreferredNotification(origin + " received", origin, simpleNotification, alertLevel, null);
|
||||
}
|
||||
|
||||
private void onAlarmClock(NotificationSpec notificationSpec) {
|
||||
@ -609,7 +616,9 @@ public class MiBand2Support extends AbstractBTLEDeviceSupport {
|
||||
return !isAlarmClockRinging();
|
||||
}
|
||||
};
|
||||
performPreferredNotification("alarm clock ringing", MiBandConst.ORIGIN_ALARM_CLOCK, MiBand2Service.ALERT_LEVEL_VIBRATE_ONLY, abortAction);
|
||||
String message = NotificationUtils.getPreferredTextFor(notificationSpec, 40, 40, getContext());
|
||||
SimpleNotification simpleNotification = new SimpleNotification(message, AlertCategory.HighPriorityAlert);
|
||||
performPreferredNotification("alarm clock ringing", MiBandConst.ORIGIN_ALARM_CLOCK, simpleNotification, MiBand2Service.ALERT_LEVEL_VIBRATE_ONLY, abortAction);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -640,7 +649,9 @@ public class MiBand2Support extends AbstractBTLEDeviceSupport {
|
||||
return !isTelephoneRinging();
|
||||
}
|
||||
};
|
||||
performPreferredNotification("incoming call", MiBandConst.ORIGIN_INCOMING_CALL, MiBand2Service.ALERT_LEVEL_PHONE_CALL, abortAction);
|
||||
String message = NotificationUtils.getPreferredTextFor(callSpec);
|
||||
SimpleNotification simpleNotification = new SimpleNotification(message, AlertCategory.IncomingCall);
|
||||
performPreferredNotification("incoming call", MiBandConst.ORIGIN_INCOMING_CALL, simpleNotification, MiBand2Service.ALERT_LEVEL_PHONE_CALL, abortAction);
|
||||
} else if ((callSpec.command == CallSpec.CALL_START) || (callSpec.command == CallSpec.CALL_END)) {
|
||||
telephoneRinging = false;
|
||||
}
|
||||
@ -722,7 +733,8 @@ public class MiBand2Support extends AbstractBTLEDeviceSupport {
|
||||
return !isLocatingDevice;
|
||||
}
|
||||
};
|
||||
performDefaultNotification("locating device", (short) 255, abortAction);
|
||||
SimpleNotification simpleNotification = new SimpleNotification(getContext().getString(R.string.find_device_you_found_it), AlertCategory.HighPriorityAlert.HighPriorityAlert);
|
||||
performDefaultNotification("locating device", simpleNotification, (short) 255, abortAction);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,46 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.util;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.CallSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
|
||||
|
||||
public class NotificationUtils {
|
||||
@NonNull
|
||||
public static String getPreferredTextFor(NotificationSpec notificationSpec, int lengthBody, int lengthSubject, Context context) {
|
||||
switch (notificationSpec.type) {
|
||||
case GENERIC_ALARM_CLOCK:
|
||||
return StringUtils.getFirstOf(notificationSpec.title, notificationSpec.subject);
|
||||
case GENERIC_SMS:
|
||||
case GENERIC_EMAIL:
|
||||
return formatText(notificationSpec.sender, notificationSpec.subject, notificationSpec.body, lengthBody, lengthSubject, context);
|
||||
case GENERIC_NAVIGATION:
|
||||
return StringUtils.getFirstOf(notificationSpec.title, notificationSpec.body);
|
||||
case RIOT:
|
||||
case SIGNAL:
|
||||
case TELEGRAM:
|
||||
case TWITTER:
|
||||
case WHATSAPP:
|
||||
case CONVERSATIONS:
|
||||
case FACEBOOK:
|
||||
case FACEBOOK_MESSENGER:
|
||||
return notificationSpec.body;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static String formatText(String sender, String subject, String body, int lengthBody, int lengthSubject, Context context) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append(StringUtils.truncate(body, lengthBody));
|
||||
builder.append(StringUtils.truncate(subject, lengthSubject));
|
||||
builder.append(StringUtils.formatSender(sender, context));
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
public static String getPreferredTextFor(CallSpec callSpec) {
|
||||
return StringUtils.getFirstOf(callSpec.name, callSpec.number);
|
||||
}
|
||||
}
|
@ -1,12 +1,21 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.util;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
|
||||
public class StringUtils {
|
||||
|
||||
public static String truncate(String s, int maxLength){
|
||||
int length = Math.min(s.length(), maxLength);
|
||||
|
||||
if(length < 0)
|
||||
if (s == null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
int length = Math.min(s.length(), maxLength);
|
||||
if(length < 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return s.substring(0, length);
|
||||
}
|
||||
@ -16,10 +25,28 @@ public class StringUtils {
|
||||
}
|
||||
|
||||
public static String pad(String s, int length, char padChar){
|
||||
|
||||
while(s.length() < length)
|
||||
while(s.length() < length) {
|
||||
s += padChar;
|
||||
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static String formatSender(String sender, Context context) {
|
||||
if (sender == null || sender.length() == 0) {
|
||||
return "";
|
||||
}
|
||||
return context.getString(R.string.StringUtils_sender, sender);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static String getFirstOf(String first, String second) {
|
||||
if (first != null && first.length() > 0) {
|
||||
return first;
|
||||
}
|
||||
if (second != null) {
|
||||
return second;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
@ -394,4 +394,6 @@
|
||||
<string name="timeformat_24h">24H</string>
|
||||
<string name="timeformat_am_pm">AM/PM</string>
|
||||
<string name="pref_screen_notification_profile_alarm_clock">Alarm Clock</string>
|
||||
<string name="StringUtils_sender"> (%1$s)</string>
|
||||
<string name="find_device_you_found_it">You found it!</string>
|
||||
</resources>
|
||||
|
Loading…
Reference in New Issue
Block a user