1
0
mirror of https://codeberg.org/Freeyourgadget/Gadgetbridge synced 2024-11-28 12:56:49 +01:00

Various improvements and bugfixes to notification handling

Prevent duplicate notifications with a dedicated data structure (not reusing
the anti-burst one) #1062, #657
Pebble: Forward the actions attached to notifications (not only reply)
inspired by the work of dnastase #705
This commit is contained in:
Daniele Gobbetti 2018-10-31 21:47:12 +01:00
parent b9999edf2a
commit eede85a9c9
12 changed files with 145 additions and 74 deletions

View File

@ -122,7 +122,6 @@ public class DebugActivity extends AbstractGBActivity {
notificationSpec.subject = testString;
notificationSpec.type = NotificationType.values()[sendTypeSpinner.getSelectedItemPosition()];
notificationSpec.pebbleColor = notificationSpec.type.color;
notificationSpec.id = -1;
GBApplication.deviceService().onNotification(notificationSpec);
}
});

View File

@ -20,6 +20,7 @@ public class GBDeviceEventNotificationControl extends GBDeviceEvent {
public int handle;
public String phoneNumber;
public String reply;
public String title;
public Event event = Event.UNKNOWN;
public enum Event {

View File

@ -64,10 +64,10 @@ public class AlarmClockReceiver extends BroadcastReceiver {
private synchronized void sendAlarm(boolean on) {
dismissLastAlarm();
if (on) {
lastId = generateId();
NotificationSpec spec = new NotificationSpec();
//TODO: can we attach a dismiss action to the notification and not use the notification ID explicitly?
lastId = spec.getId();
spec.type = NotificationType.GENERIC_ALARM_CLOCK;
spec.id = lastId;
spec.sourceName = "ALARMCLOCKRECEIVER";
// can we get the alarm title somehow?
GBApplication.deviceService().onNotification(spec);
@ -81,8 +81,4 @@ public class AlarmClockReceiver extends BroadcastReceiver {
}
}
private int generateId() {
// lacks negative values, but should be sufficient
return (int) (Math.random() * Integer.MAX_VALUE);
}
}

View File

@ -50,6 +50,7 @@ import android.support.v7.graphics.Palette;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Objects;
@ -87,7 +88,8 @@ public class NotificationListener extends NotificationListenerService {
private LimitedQueue mActionLookup = new LimitedQueue(16);
private HashMap<String, Long> notificationTimes = new HashMap<>();
private HashMap<String, Long> notificationBurstPrevention = new HashMap<>();
private HashMap<String, Long> notificationOldRepeatPrevention = new HashMap<>();
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@ -145,19 +147,20 @@ public class NotificationListener extends NotificationListenerService {
break;
case ACTION_REPLY:
int id = intent.getIntExtra("handle", -1);
NotificationCompat.Action wearableAction = (NotificationCompat.Action) mActionLookup.lookup(id);
String reply = intent.getStringExtra("reply");
NotificationCompat.Action replyAction = (NotificationCompat.Action) mActionLookup.lookup(id);
if (replyAction != null && replyAction.getRemoteInputs() != null) {
RemoteInput[] remoteInputs = replyAction.getRemoteInputs();
PendingIntent actionIntent = replyAction.getActionIntent();
if (wearableAction != null) {
PendingIntent actionIntent = wearableAction.getActionIntent();
Intent localIntent = new Intent();
localIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
if(wearableAction.getRemoteInputs()!=null) {
RemoteInput[] remoteInputs = wearableAction.getRemoteInputs();
Bundle extras = new Bundle();
extras.putCharSequence(remoteInputs[0].getResultKey(), reply);
RemoteInput.addResultsToIntent(remoteInputs, localIntent, extras);
}
try {
LOG.info("will send reply intent to remote application");
LOG.info("will send exec intent to remote application");
actionIntent.send(context, 0, localIntent);
mActionLookup.remove(id);
} catch (PendingIntent.CanceledException e) {
@ -209,15 +212,13 @@ public class NotificationListener extends NotificationListenerService {
String source = sbn.getPackageName().toLowerCase();
Notification notification = sbn.getNotification();
if (notificationTimes.containsKey(source)) {
long last_time = notificationTimes.get(source);
if (notification.when <= last_time) {
LOG.info("NOT processing notification, too old. notification.when: " + notification.when + " last notification for this source: " + last_time);
if (notificationOldRepeatPrevention.containsKey(source)) {
if (notification.when <= notificationOldRepeatPrevention.get(source)) {
LOG.info("NOT processing notification, already sent newer notifications from this source.");
return;
}
}
NotificationSpec notificationSpec = new NotificationSpec();
notificationSpec.id = (int) sbn.getPostTime(); //FIXME: a truly unique id would be better
// determinate Source App Name ("Label")
PackageManager pm = getPackageManager();
@ -249,7 +250,7 @@ public class NotificationListener extends NotificationListenerService {
// Get color
notificationSpec.pebbleColor = getPebbleColorForNotification(notificationSpec);
LOG.info("Processing notification " + notificationSpec.id + " from source " + source + " with flags: " + notification.flags);
LOG.info("Processing notification " + notificationSpec.getId() + " age: " + (System.currentTimeMillis() - notification.when) + " from source " + source + " with flags: " + notification.flags);
dissectNotificationTo(notification, notificationSpec, preferBigText);
@ -263,16 +264,23 @@ public class NotificationListener extends NotificationListenerService {
NotificationCompat.WearableExtender wearableExtender = new NotificationCompat.WearableExtender(notification);
List<NotificationCompat.Action> actions = wearableExtender.getActions();
notificationSpec.attachedActions = new ArrayList<>();
for (NotificationCompat.Action act : actions) {
if (act != null && act.getRemoteInputs() != null) {
LOG.info("found wearable action: " + act.getTitle() + " " + sbn.getTag());
mActionLookup.add(notificationSpec.id, act);
notificationSpec.flags |= NotificationSpec.FLAG_WEARABLE_REPLY;
break;
if (act != null) {
NotificationSpec.Action wearableAction = new NotificationSpec.Action();
wearableAction.title = act.getTitle().toString();
if(act.getRemoteInputs()!=null) {
wearableAction.isReply = true;
}
notificationSpec.flags |= NotificationSpec.FLAG_WEARABLE_ACTIONS;
notificationSpec.attachedActions.add(wearableAction);
mActionLookup.add((notificationSpec.getId()<<4) + notificationSpec.attachedActions.size(), act);
LOG.info("found wearable action: " + notificationSpec.attachedActions.size() + " - "+ act.getTitle() + " " + sbn.getTag());
}
}
if ((notificationSpec.flags & NotificationSpec.FLAG_WEARABLE_REPLY) == 0 && NotificationCompat.isGroupSummary(notification)) { //this could cause #395 to come back
if ((notificationSpec.flags & NotificationSpec.FLAG_WEARABLE_ACTIONS) == 0 && NotificationCompat.isGroupSummary(notification)) { //this could cause #395 to come back
LOG.info("Not forwarding notification, FLAG_GROUP_SUMMARY is set and no wearable action present. Notification flags: " + notification.flags);
return;
}
@ -280,14 +288,15 @@ public class NotificationListener extends NotificationListenerService {
// Ignore too frequent notifications, according to user preference
long min_timeout = prefs.getInt("notifications_timeout", 0) * 1000;
long cur_time = System.currentTimeMillis();
if (notificationTimes.containsKey(source)) {
long last_time = notificationTimes.get(source);
if (notificationBurstPrevention.containsKey(source)) {
long last_time = notificationBurstPrevention.get(source);
if (cur_time - last_time < min_timeout) {
LOG.info("Ignoring frequent notification, last one was " + (cur_time - last_time) + "ms ago");
return;
}
}
notificationTimes.put(source, cur_time);
notificationBurstPrevention.put(source, cur_time);
notificationOldRepeatPrevention.put(source, notification.when);
GBApplication.deviceService().onNotification(notificationSpec);
}

View File

@ -62,7 +62,6 @@ public class PebbleReceiver extends BroadcastReceiver {
}
NotificationSpec notificationSpec = new NotificationSpec();
notificationSpec.id = -1;
String notificationData = intent.getStringExtra("notificationData");
try {

View File

@ -50,7 +50,6 @@ public class SMSReceiver extends BroadcastReceiver {
}
NotificationSpec notificationSpec = new NotificationSpec();
notificationSpec.id = -1;
notificationSpec.type = NotificationType.GENERIC_SMS;
Bundle bundle = intent.getExtras();

View File

@ -150,8 +150,9 @@ public class GBDeviceService implements DeviceService {
.putExtra(EXTRA_NOTIFICATION_SUBJECT, notificationSpec.subject)
.putExtra(EXTRA_NOTIFICATION_TITLE, notificationSpec.title)
.putExtra(EXTRA_NOTIFICATION_BODY, notificationSpec.body)
.putExtra(EXTRA_NOTIFICATION_ID, notificationSpec.id)
.putExtra(EXTRA_NOTIFICATION_ID, notificationSpec.getId())
.putExtra(EXTRA_NOTIFICATION_TYPE, notificationSpec.type)
.putExtra(EXTRA_NOTIFICATION_ACTIONS, notificationSpec.attachedActions)
.putExtra(EXTRA_NOTIFICATION_SOURCENAME, notificationSpec.sourceName)
.putExtra(EXTRA_NOTIFICATION_PEBBLE_COLOR, notificationSpec.pebbleColor)
.putExtra(EXTRA_NOTIFICATION_SOURCEAPPID, notificationSpec.sourceAppId);

View File

@ -77,6 +77,7 @@ public interface DeviceService extends EventHandler {
String EXTRA_NOTIFICATION_SUBJECT = "notification_subject";
String EXTRA_NOTIFICATION_TITLE = "notification_title";
String EXTRA_NOTIFICATION_TYPE = "notification_type";
String EXTRA_NOTIFICATION_ACTIONS = "notification_actions";
String EXTRA_NOTIFICATION_PEBBLE_COLOR = "notification_pebble_color";
String EXTRA_FIND_START = "find_start";
String EXTRA_VIBRATION_INTENSITY = "vibration_intensity";

View File

@ -16,11 +16,16 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. */
package nodomain.freeyourgadget.gadgetbridge.model;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicInteger;
public class NotificationSpec {
public static final int FLAG_WEARABLE_REPLY = 0x00000001;
public static final int FLAG_WEARABLE_ACTIONS = 0x00000001;
public int flags;
public int id;
private static final AtomicInteger c = new AtomicInteger((int) (System.currentTimeMillis()/1000));
private int id;
public String sender;
public String phoneNumber;
public String title;
@ -29,7 +34,10 @@ public class NotificationSpec {
public NotificationType type;
public String sourceName;
public String[] cannedReplies;
/**
* Wearable actions that were attached to the incoming notifications and will be passed to the gadget (includes the "reply" action)
*/
public ArrayList<Action> attachedActions;
/**
* The application that generated the notification.
*/
@ -39,4 +47,24 @@ public class NotificationSpec {
* The color that should be assigned to this notification when displayed on a Pebble
*/
public byte pebbleColor;
public NotificationSpec() {
this.id = c.incrementAndGet();
}
public NotificationSpec(int id) {
if (id != -1)
this.id = id;
else
this.id = c.incrementAndGet();
}
public int getId() {
return id;
}
public static class Action implements Serializable {
public boolean isReply = false;
public String title;
}
}

View File

@ -52,8 +52,8 @@ import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventAppInfo;
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventBatteryInfo;
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventCallControl;
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventDisplayMessage;
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventFmFrequency;
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventFindPhone;
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventFmFrequency;
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventLEDColor;
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventMusicControl;
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventNotificationControl;
@ -337,6 +337,7 @@ public abstract class AbstractDeviceSupport implements DeviceSupport {
if (action != null) {
Intent notificationListenerIntent = new Intent(action);
notificationListenerIntent.putExtra("handle", deviceEvent.handle);
notificationListenerIntent.putExtra("title", deviceEvent.title);
if (deviceEvent.reply != null) {
Prefs prefs = GBApplication.getPrefs();
String suffix = prefs.getString("canned_reply_suffix", null);

View File

@ -147,6 +147,7 @@ import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_MUS
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_MUSIC_TRACK;
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_MUSIC_TRACKCOUNT;
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_MUSIC_TRACKNR;
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_NOTIFICATION_ACTIONS;
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_NOTIFICATION_BODY;
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_NOTIFICATION_FLAGS;
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_NOTIFICATION_ID;
@ -356,7 +357,8 @@ public class DeviceCommunicationService extends Service implements SharedPrefere
mGBDevice.sendDeviceUpdateIntent(this);
break;
case ACTION_NOTIFICATION: {
NotificationSpec notificationSpec = new NotificationSpec();
int desiredId = intent.getIntExtra(EXTRA_NOTIFICATION_ID, -1);
NotificationSpec notificationSpec = new NotificationSpec(desiredId);
notificationSpec.phoneNumber = intent.getStringExtra(EXTRA_NOTIFICATION_PHONENUMBER);
notificationSpec.sender = intent.getStringExtra(EXTRA_NOTIFICATION_SENDER);
notificationSpec.subject = intent.getStringExtra(EXTRA_NOTIFICATION_SUBJECT);
@ -364,17 +366,17 @@ public class DeviceCommunicationService extends Service implements SharedPrefere
notificationSpec.body = intent.getStringExtra(EXTRA_NOTIFICATION_BODY);
notificationSpec.sourceName = intent.getStringExtra(EXTRA_NOTIFICATION_SOURCENAME);
notificationSpec.type = (NotificationType) intent.getSerializableExtra(EXTRA_NOTIFICATION_TYPE);
notificationSpec.attachedActions = (ArrayList<NotificationSpec.Action>) intent.getSerializableExtra(EXTRA_NOTIFICATION_ACTIONS);
notificationSpec.pebbleColor = (byte) intent.getSerializableExtra(EXTRA_NOTIFICATION_PEBBLE_COLOR);
notificationSpec.id = intent.getIntExtra(EXTRA_NOTIFICATION_ID, -1);
notificationSpec.flags = intent.getIntExtra(EXTRA_NOTIFICATION_FLAGS, 0);
notificationSpec.sourceAppId = intent.getStringExtra(EXTRA_NOTIFICATION_SOURCEAPPID);
if (notificationSpec.type == NotificationType.GENERIC_SMS && notificationSpec.phoneNumber != null) {
notificationSpec.id = mRandom.nextInt(); // FIXME: add this in external SMS Receiver?
GBApplication.getIDSenderLookup().add(notificationSpec.id, notificationSpec.phoneNumber);
GBApplication.getIDSenderLookup().add(notificationSpec.getId(), notificationSpec.phoneNumber);
}
if (((notificationSpec.flags & NotificationSpec.FLAG_WEARABLE_REPLY) > 0)
//TODO: check if at least one of the attached actions is a reply action instead?
if (((notificationSpec.flags & NotificationSpec.FLAG_WEARABLE_ACTIONS) > 0)
|| (notificationSpec.type == NotificationType.GENERIC_SMS && notificationSpec.phoneNumber != null)) {
// NOTE: maybe not where it belongs
if (prefs.getBoolean("pebble_force_untested", false)) {

View File

@ -60,6 +60,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.CallSpec;
import nodomain.freeyourgadget.gadgetbridge.model.CannedMessagesSpec;
import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec;
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec.Action;
import nodomain.freeyourgadget.gadgetbridge.model.NotificationType;
import nodomain.freeyourgadget.gadgetbridge.model.Weather;
import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
@ -484,8 +485,9 @@ public class PebbleProtocol extends GBDeviceProtocol {
@Override
public byte[] encodeNotification(NotificationSpec notificationSpec) {
boolean hasHandle = notificationSpec.id != -1 && notificationSpec.phoneNumber == null;
int id = notificationSpec.id != -1 ? notificationSpec.id : mRandom.nextInt();
//TODO: simplify this logic? is hasHandle still needed?
boolean hasHandle = notificationSpec.getId() != -1 && notificationSpec.phoneNumber == null;
int id = notificationSpec.getId() != -1 ? notificationSpec.getId() : mRandom.nextInt();
String title;
String subtitle = null;
@ -507,11 +509,11 @@ public class PebbleProtocol extends GBDeviceProtocol {
// 3.x notification
return encodeBlobdbNotification(id, (int) (ts & 0xffffffffL), title, subtitle, notificationSpec.body,
notificationSpec.sourceName, hasHandle, notificationSpec.type, notificationSpec.pebbleColor,
notificationSpec.cannedReplies);
notificationSpec.cannedReplies, notificationSpec.attachedActions);
} else if (mForceProtocol || notificationSpec.type != NotificationType.GENERIC_EMAIL) {
// 2.x notification
return encodeExtensibleNotification(id, (int) (ts & 0xffffffffL), title, subtitle, notificationSpec.body,
notificationSpec.sourceName, hasHandle, notificationSpec.cannedReplies);
notificationSpec.sourceName, hasHandle, notificationSpec.cannedReplies, notificationSpec.attachedActions);
} else {
// 1.x notification on FW 2.X
String[] parts = {title, notificationSpec.body, String.valueOf(ts), subtitle};
@ -594,7 +596,8 @@ public class PebbleProtocol extends GBDeviceProtocol {
*/
}
private byte[] encodeExtensibleNotification(int id, int timestamp, String title, String subtitle, String body, String sourceName, boolean hasHandle, String[] cannedReplies) {
//TODO: add support for attachedActions
private byte[] encodeExtensibleNotification(int id, int timestamp, String title, String subtitle, String body, String sourceName, boolean hasHandle, String[] cannedReplies, ArrayList attachedActions) {
final short ACTION_LENGTH_MIN = 10;
String[] parts = {title, subtitle, body};
@ -930,7 +933,7 @@ public class PebbleProtocol extends GBDeviceProtocol {
private byte[] encodeBlobdbNotification(int id, int timestamp, String title, String subtitle, String body, String sourceName,
boolean hasHandle, NotificationType notificationType, byte backgroundColor,
String[] cannedReplies) {
String[] cannedReplies, ArrayList<Action> attachedActions) {
final short NOTIFICATION_PIN_LENGTH = 46;
final short ACTION_LENGTH_MIN = 10;
@ -943,36 +946,43 @@ public class PebbleProtocol extends GBDeviceProtocol {
int icon_id = notificationType.icon;
// Calculate length first
byte actions_count;
short actions_length;
byte actions_count = 0;
short actions_length = 0;
String dismiss_string;
String open_string = "Open on phone";
String mute_string = "Mute";
String reply_string = "Reply";
if (sourceName != null) {
mute_string += " " + sourceName;
}
byte dismiss_action_id;
if (hasHandle && !"ALARMCLOCKRECEIVER".equals(sourceName)) {
actions_count = 3;
actions_count += 3;
dismiss_string = "Dismiss";
dismiss_action_id = 0x02;
actions_length = (short) (ACTION_LENGTH_MIN * actions_count + dismiss_string.getBytes().length + open_string.getBytes().length + mute_string.getBytes().length);
//TODO: ACTION_LENGTH_MIN disagrees with my observation of the needed bytes. I used 6 instead of 10
actions_length += (short) (6 * 3 + dismiss_string.getBytes().length + open_string.getBytes().length + mute_string.getBytes().length);
} else {
actions_count = 1;
actions_count += 1;
dismiss_string = "Dismiss all";
dismiss_action_id = 0x03;
actions_length = (short) (ACTION_LENGTH_MIN * actions_count + dismiss_string.getBytes().length);
actions_length += (short) (ACTION_LENGTH_MIN + dismiss_string.getBytes().length);
}
if (attachedActions != null && attachedActions.size() > 0) {
for (Action act : attachedActions) {
actions_count++;
actions_length += (short) (6 + act.title.getBytes().length);
}
}
int replies_length = -1;
if (cannedReplies != null && cannedReplies.length > 0) {
actions_count++;
//do not increment actions_count! reply is an action and was already added above
for (String reply : cannedReplies) {
replies_length += reply.getBytes().length + 1;
}
actions_length += ACTION_LENGTH_MIN + reply_string.getBytes().length + replies_length + 3; // 3 = attribute id (byte) + length(short)
//similarly, only the replies lenght has to be added, the lenght for the bare action was already added above
actions_length += replies_length + 3; // 3 = attribute id (byte) + length(short)
}
byte attributes_count = 2; // icon
@ -1053,13 +1063,21 @@ public class PebbleProtocol extends GBDeviceProtocol {
buf.put(mute_string.getBytes());
}
if (cannedReplies != null && replies_length > 0) {
buf.put((byte) 0x05);
if (attachedActions != null && attachedActions.size() > 0) {
for (int ai = 0 ; ai<attachedActions.size(); ai++) {
Action act = attachedActions.get(ai);
buf.put((byte) (0x05 + ai));
if(act.isReply) {
buf.put((byte) 0x03); // reply action
buf.put((byte) 0x02); // number attributes
buf.put((byte) 0x01); // title
buf.putShort((short) reply_string.getBytes().length);
buf.put(reply_string.getBytes());
} else {
buf.put((byte) 0x02); // generic action, dismiss did not do anything
buf.put((byte) 0x01); // number attributes
}
buf.put((byte) 0x01); // attribute id (title)
buf.putShort((short) act.title.getBytes().length);
buf.put(act.title.getBytes());
if(act.isReply && cannedReplies != null ) {
buf.put((byte) 0x08); // canned replies
buf.putShort((short) replies_length);
for (int i = 0; i < cannedReplies.length - 1; i++) {
@ -1069,6 +1087,8 @@ public class PebbleProtocol extends GBDeviceProtocol {
// last one must not be zero terminated, else we get an additional emply reply
buf.put(cannedReplies[cannedReplies.length - 1].getBytes());
}
}
}
return encodeBlobdb(UUID.randomUUID(), BLOBDB_INSERT, BLOBDB_NOTIFICATION, buf.array());
}
@ -2096,7 +2116,7 @@ public class PebbleProtocol extends GBDeviceProtocol {
id = buf.getInt();
}
byte action = buf.get();
if (action >= 0x00 && action <= 0x05) {
if (action >= 0x00 && action <= 0xf) {
GBDeviceEventNotificationControl devEvtNotificationControl = new GBDeviceEventNotificationControl();
devEvtNotificationControl.handle = id;
String caption = "undefined";
@ -2125,6 +2145,7 @@ public class PebbleProtocol extends GBDeviceProtocol {
caption = "Muted";
icon_id = PebbleIconID.RESULT_MUTE;
break;
//TODO: 0x05 is not a special case anymore, and reply action might have an index that is higher. see default below
case 0x05:
case 0x00:
boolean failed = true;
@ -2145,6 +2166,7 @@ public class PebbleProtocol extends GBDeviceProtocol {
}
devEvtNotificationControl.event = GBDeviceEventNotificationControl.Event.REPLY;
devEvtNotificationControl.reply = new String(reply);
devEvtNotificationControl.handle = (devEvtNotificationControl.handle << 4) + 1;
caption = "SENT";
icon_id = PebbleIconID.RESULT_SENT;
failed = false;
@ -2156,6 +2178,19 @@ public class PebbleProtocol extends GBDeviceProtocol {
devEvtNotificationControl = null; // error
}
break;
default:
if (action > 0x05) {
int simpleActionId = action - 0x05;
caption = "EXECUTED";
devEvtNotificationControl.event = GBDeviceEventNotificationControl.Event.REPLY;
devEvtNotificationControl.handle = (devEvtNotificationControl.handle << 4) + simpleActionId;
LOG.info("detected simple action, subId:" + simpleActionId + " title:" + devEvtNotificationControl.title);
} else {
caption = "FAILED";
icon_id = PebbleIconID.RESULT_FAILED;
devEvtNotificationControl = null; // error
}
break;
}
GBDeviceEventSendBytes sendBytesAck = null;
if (mFwMajor >= 3 || needsAck2x) {