mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge.git
synced 2025-01-25 16:15:55 +01:00
Notification actions refatoring and fixes
- Fixes "Mute, Open, Dismiss" to work again on pebble - Greatly reduces complexity in PebbleProtocol, since all logic for adding specific reply actions to notification have been moved to generic code Fixes the rest of #1336 (the part that says "Additionally, dismissing a notification on the watch no longer dismisses it on the Android device")
This commit is contained in:
parent
7626a0d4ec
commit
59f8e72410
@ -21,6 +21,8 @@ import android.content.BroadcastReceiver;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
|
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.NotificationType;
|
import nodomain.freeyourgadget.gadgetbridge.model.NotificationType;
|
||||||
@ -64,13 +66,21 @@ public class AlarmClockReceiver extends BroadcastReceiver {
|
|||||||
private synchronized void sendAlarm(boolean on) {
|
private synchronized void sendAlarm(boolean on) {
|
||||||
dismissLastAlarm();
|
dismissLastAlarm();
|
||||||
if (on) {
|
if (on) {
|
||||||
NotificationSpec spec = new NotificationSpec();
|
NotificationSpec notificationSpec = new NotificationSpec();
|
||||||
//TODO: can we attach a dismiss action to the notification and not use the notification ID explicitly?
|
//TODO: can we attach a dismiss action to the notification and not use the notification ID explicitly?
|
||||||
lastId = spec.getId();
|
lastId = notificationSpec.getId();
|
||||||
spec.type = NotificationType.GENERIC_ALARM_CLOCK;
|
notificationSpec.type = NotificationType.GENERIC_ALARM_CLOCK;
|
||||||
spec.sourceName = "ALARMCLOCKRECEIVER";
|
notificationSpec.sourceName = "ALARMCLOCKRECEIVER";
|
||||||
|
notificationSpec.attachedActions = new ArrayList<>();
|
||||||
|
|
||||||
|
// DISMISS ALL action
|
||||||
|
NotificationSpec.Action dismissAllAction = new NotificationSpec.Action();
|
||||||
|
dismissAllAction.title = "Dismiss All";
|
||||||
|
dismissAllAction.type = NotificationSpec.Action.TYPE_SYNTECTIC_DISMISS_ALL;
|
||||||
|
notificationSpec.attachedActions.add(dismissAllAction);
|
||||||
|
|
||||||
// can we get the alarm title somehow?
|
// can we get the alarm title somehow?
|
||||||
GBApplication.deviceService().onNotification(spec);
|
GBApplication.deviceService().onNotification(notificationSpec);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,7 +86,9 @@ public class NotificationListener extends NotificationListenerService {
|
|||||||
public static final String ACTION_REPLY
|
public static final String ACTION_REPLY
|
||||||
= "nodomain.freeyourgadget.gadgetbridge.notificationlistener.action.reply";
|
= "nodomain.freeyourgadget.gadgetbridge.notificationlistener.action.reply";
|
||||||
|
|
||||||
private LimitedQueue mActionLookup = new LimitedQueue(16);
|
private LimitedQueue mActionLookup = new LimitedQueue(32);
|
||||||
|
private LimitedQueue mPackageLookup = new LimitedQueue(64);
|
||||||
|
private LimitedQueue mNotificationHandleLookup = new LimitedQueue(128);
|
||||||
|
|
||||||
private HashMap<String, Long> notificationBurstPrevention = new HashMap<>();
|
private HashMap<String, Long> notificationBurstPrevention = new HashMap<>();
|
||||||
private HashMap<String, Long> notificationOldRepeatPrevention = new HashMap<>();
|
private HashMap<String, Long> notificationOldRepeatPrevention = new HashMap<>();
|
||||||
@ -96,39 +98,58 @@ public class NotificationListener extends NotificationListenerService {
|
|||||||
@Override
|
@Override
|
||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
String action = intent.getAction();
|
String action = intent.getAction();
|
||||||
|
if (action == null) {
|
||||||
|
LOG.warn("no action");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int handle = (int) intent.getLongExtra("handle", -1);
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case GBApplication.ACTION_QUIT:
|
case GBApplication.ACTION_QUIT:
|
||||||
stopSelf();
|
stopSelf();
|
||||||
break;
|
break;
|
||||||
case ACTION_MUTE:
|
|
||||||
case ACTION_OPEN: {
|
case ACTION_OPEN: {
|
||||||
StatusBarNotification[] sbns = NotificationListener.this.getActiveNotifications();
|
StatusBarNotification[] sbns = NotificationListener.this.getActiveNotifications();
|
||||||
int handle = (int) intent.getLongExtra("handle", -1);
|
Long ts = (Long) mNotificationHandleLookup.lookup(handle);
|
||||||
|
if (ts == null) {
|
||||||
|
LOG.info("could not lookup handle for open action");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
for (StatusBarNotification sbn : sbns) {
|
for (StatusBarNotification sbn : sbns) {
|
||||||
if ((int) sbn.getPostTime() == handle) {
|
if (sbn.getPostTime() == ts) {
|
||||||
if (action.equals(ACTION_OPEN)) {
|
try {
|
||||||
try {
|
PendingIntent pi = sbn.getNotification().contentIntent;
|
||||||
PendingIntent pi = sbn.getNotification().contentIntent;
|
if (pi != null) {
|
||||||
if (pi != null) {
|
pi.send();
|
||||||
pi.send();
|
|
||||||
}
|
|
||||||
} catch (PendingIntent.CanceledException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
} else {
|
} catch (PendingIntent.CanceledException e) {
|
||||||
// ACTION_MUTE
|
e.printStackTrace();
|
||||||
LOG.info("going to mute " + sbn.getPackageName());
|
|
||||||
GBApplication.addAppToNotifBlacklist(sbn.getPackageName());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case ACTION_MUTE:
|
||||||
|
String packageName = (String) mPackageLookup.lookup(handle);
|
||||||
|
if (packageName == null) {
|
||||||
|
LOG.info("could not lookup handle for mute action");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG.info("going to mute " + packageName);
|
||||||
|
GBApplication.addAppToNotifBlacklist(packageName);
|
||||||
|
break;
|
||||||
case ACTION_DISMISS: {
|
case ACTION_DISMISS: {
|
||||||
StatusBarNotification[] sbns = NotificationListener.this.getActiveNotifications();
|
StatusBarNotification[] sbns = NotificationListener.this.getActiveNotifications();
|
||||||
int handle = (int) intent.getLongExtra("handle", -1);
|
Long ts = (Long) mNotificationHandleLookup.lookup(handle);
|
||||||
|
if (ts == null) {
|
||||||
|
LOG.info("could not lookup handle for dismiss action");
|
||||||
|
break;
|
||||||
|
}
|
||||||
for (StatusBarNotification sbn : sbns) {
|
for (StatusBarNotification sbn : sbns) {
|
||||||
if ((int) sbn.getPostTime() == handle) {
|
if (sbn.getPostTime() == ts) {
|
||||||
if (GBApplication.isRunningLollipopOrLater()) {
|
if (GBApplication.isRunningLollipopOrLater()) {
|
||||||
String key = sbn.getKey();
|
String key = sbn.getKey();
|
||||||
NotificationListener.this.cancelNotification(key);
|
NotificationListener.this.cancelNotification(key);
|
||||||
@ -146,8 +167,7 @@ public class NotificationListener extends NotificationListenerService {
|
|||||||
NotificationListener.this.cancelAllNotifications();
|
NotificationListener.this.cancelAllNotifications();
|
||||||
break;
|
break;
|
||||||
case ACTION_REPLY:
|
case ACTION_REPLY:
|
||||||
int id = (int)intent.getLongExtra("handle", -1);
|
NotificationCompat.Action wearableAction = (NotificationCompat.Action) mActionLookup.lookup(handle);
|
||||||
NotificationCompat.Action wearableAction = (NotificationCompat.Action) mActionLookup.lookup(id);
|
|
||||||
String reply = intent.getStringExtra("reply");
|
String reply = intent.getStringExtra("reply");
|
||||||
if (wearableAction != null) {
|
if (wearableAction != null) {
|
||||||
PendingIntent actionIntent = wearableAction.getActionIntent();
|
PendingIntent actionIntent = wearableAction.getActionIntent();
|
||||||
@ -162,14 +182,13 @@ public class NotificationListener extends NotificationListenerService {
|
|||||||
try {
|
try {
|
||||||
LOG.info("will send exec intent to remote application");
|
LOG.info("will send exec intent to remote application");
|
||||||
actionIntent.send(context, 0, localIntent);
|
actionIntent.send(context, 0, localIntent);
|
||||||
mActionLookup.remove(id);
|
mActionLookup.remove(handle);
|
||||||
} catch (PendingIntent.CanceledException e) {
|
} catch (PendingIntent.CanceledException e) {
|
||||||
LOG.warn("replyToLastNotification error: " + e.getLocalizedMessage());
|
LOG.warn("replyToLastNotification error: " + e.getLocalizedMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -218,6 +237,18 @@ public class NotificationListener extends NotificationListenerService {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ignore too frequent notifications, according to user preference
|
||||||
|
long min_timeout = prefs.getInt("notifications_timeout", 0) * 1000;
|
||||||
|
long cur_time = System.currentTimeMillis();
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
NotificationSpec notificationSpec = new NotificationSpec();
|
NotificationSpec notificationSpec = new NotificationSpec();
|
||||||
|
|
||||||
// determinate Source App Name ("Label")
|
// determinate Source App Name ("Label")
|
||||||
@ -269,37 +300,51 @@ public class NotificationListener extends NotificationListenerService {
|
|||||||
NotificationCompat.WearableExtender wearableExtender = new NotificationCompat.WearableExtender(notification);
|
NotificationCompat.WearableExtender wearableExtender = new NotificationCompat.WearableExtender(notification);
|
||||||
List<NotificationCompat.Action> actions = wearableExtender.getActions();
|
List<NotificationCompat.Action> actions = wearableExtender.getActions();
|
||||||
|
|
||||||
|
|
||||||
|
if (actions.size() == 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;
|
||||||
|
}
|
||||||
|
|
||||||
notificationSpec.attachedActions = new ArrayList<>();
|
notificationSpec.attachedActions = new ArrayList<>();
|
||||||
|
|
||||||
|
// DISMISS action
|
||||||
|
NotificationSpec.Action dismissAction = new NotificationSpec.Action();
|
||||||
|
dismissAction.title = "Dismiss";
|
||||||
|
dismissAction.type = NotificationSpec.Action.TYPE_SYNTECTIC_DISMISS;
|
||||||
|
notificationSpec.attachedActions.add(dismissAction);
|
||||||
|
|
||||||
for (NotificationCompat.Action act : actions) {
|
for (NotificationCompat.Action act : actions) {
|
||||||
if (act != null) {
|
if (act != null) {
|
||||||
NotificationSpec.Action wearableAction = new NotificationSpec.Action();
|
NotificationSpec.Action wearableAction = new NotificationSpec.Action();
|
||||||
wearableAction.title = act.getTitle().toString();
|
wearableAction.title = act.getTitle().toString();
|
||||||
if(act.getRemoteInputs()!=null) {
|
if(act.getRemoteInputs()!=null) {
|
||||||
wearableAction.isReply = true;
|
wearableAction.type = NotificationSpec.Action.TYPE_WEARABLE_REPLY;
|
||||||
|
} else {
|
||||||
|
wearableAction.type = NotificationSpec.Action.TYPE_WEARABLE_SIMPLE;
|
||||||
}
|
}
|
||||||
notificationSpec.flags |= NotificationSpec.FLAG_WEARABLE_ACTIONS;
|
|
||||||
notificationSpec.attachedActions.add(wearableAction);
|
notificationSpec.attachedActions.add(wearableAction);
|
||||||
mActionLookup.add((notificationSpec.getId()<<4) + notificationSpec.attachedActions.size(), act);
|
mActionLookup.add((notificationSpec.getId()<<4) + notificationSpec.attachedActions.size(), act);
|
||||||
LOG.info("found wearable action: " + notificationSpec.attachedActions.size() + " - "+ act.getTitle() + " " + sbn.getTag());
|
LOG.info("found wearable action: " + notificationSpec.attachedActions.size() + " - "+ act.getTitle() + " " + sbn.getTag());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// OPEN action
|
||||||
|
NotificationSpec.Action openAction = new NotificationSpec.Action();
|
||||||
|
openAction.title = getString(R.string._pebble_watch_open_on_phone);
|
||||||
|
openAction.type = NotificationSpec.Action.TYPE_SYNTECTIC_OPEN;
|
||||||
|
notificationSpec.attachedActions.add(openAction);
|
||||||
|
|
||||||
if ((notificationSpec.flags & NotificationSpec.FLAG_WEARABLE_ACTIONS) == 0 && NotificationCompat.isGroupSummary(notification)) { //this could cause #395 to come back
|
// MUTE action
|
||||||
LOG.info("Not forwarding notification, FLAG_GROUP_SUMMARY is set and no wearable action present. Notification flags: " + notification.flags);
|
NotificationSpec.Action muteAction = new NotificationSpec.Action();
|
||||||
return;
|
muteAction.title = getString(R.string._pebble_watch_mute);
|
||||||
}
|
muteAction.type = NotificationSpec.Action.TYPE_SYNTECTIC_MUTE;
|
||||||
|
notificationSpec.attachedActions.add(muteAction);
|
||||||
|
|
||||||
|
mNotificationHandleLookup.add(notificationSpec.getId(), sbn.getPostTime()); // for both DISMISS and OPEN
|
||||||
|
mPackageLookup.add(notificationSpec.getId(), sbn.getPackageName()); // for MUTE
|
||||||
|
|
||||||
// Ignore too frequent notifications, according to user preference
|
|
||||||
long min_timeout = prefs.getInt("notifications_timeout", 0) * 1000;
|
|
||||||
long cur_time = System.currentTimeMillis();
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
notificationBurstPrevention.put(source, cur_time);
|
notificationBurstPrevention.put(source, cur_time);
|
||||||
notificationOldRepeatPrevention.put(source, notification.when);
|
notificationOldRepeatPrevention.put(source, notification.when);
|
||||||
|
|
||||||
@ -331,6 +376,9 @@ public class NotificationListener extends NotificationListenerService {
|
|||||||
|
|
||||||
private boolean isServiceRunning() {
|
private boolean isServiceRunning() {
|
||||||
ActivityManager manager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
|
ActivityManager manager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
|
||||||
|
if (manager == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
|
for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
|
||||||
if (DeviceCommunicationService.class.getName().equals(service.service.getClassName())) {
|
if (DeviceCommunicationService.class.getName().equals(service.service.getClassName())) {
|
||||||
return true;
|
return true;
|
||||||
@ -401,7 +449,9 @@ public class NotificationListener extends NotificationListenerService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onNotificationRemoved(StatusBarNotification sbn) {
|
public void onNotificationRemoved(StatusBarNotification sbn) {
|
||||||
if (shouldIgnore(sbn) || true) // FIXME: DISABLED for now
|
// FIXME: DISABLED for now
|
||||||
|
/*
|
||||||
|
if (shouldIgnore(sbn))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Prefs prefs = GBApplication.getPrefs();
|
Prefs prefs = GBApplication.getPrefs();
|
||||||
@ -409,8 +459,10 @@ public class NotificationListener extends NotificationListenerService {
|
|||||||
LOG.info("notification removed, will ask device to delete it");
|
LOG.info("notification removed, will ask device to delete it");
|
||||||
GBApplication.deviceService().onDeleteNotification((int) sbn.getPostTime());
|
GBApplication.deviceService().onDeleteNotification((int) sbn.getPostTime());
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
private void dumpExtras(Bundle bundle) {
|
private void dumpExtras(Bundle bundle) {
|
||||||
for (String key : bundle.keySet()) {
|
for (String key : bundle.keySet()) {
|
||||||
Object value = bundle.get(key);
|
Object value = bundle.get(key);
|
||||||
@ -420,6 +472,7 @@ public class NotificationListener extends NotificationListenerService {
|
|||||||
LOG.debug(String.format("Notification extra: %s %s (%s)", key, value.toString(), value.getClass().getName()));
|
LOG.debug(String.format("Notification extra: %s %s (%s)", key, value.toString(), value.getClass().getName()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
private boolean shouldIgnore(StatusBarNotification sbn) {
|
private boolean shouldIgnore(StatusBarNotification sbn) {
|
||||||
/*
|
/*
|
||||||
@ -492,7 +545,7 @@ public class NotificationListener extends NotificationListenerService {
|
|||||||
Prefs prefs = GBApplication.getPrefs();
|
Prefs prefs = GBApplication.getPrefs();
|
||||||
if (!prefs.getBoolean("notifications_generic_whenscreenon", false)) {
|
if (!prefs.getBoolean("notifications_generic_whenscreenon", false)) {
|
||||||
PowerManager powermanager = (PowerManager) getSystemService(POWER_SERVICE);
|
PowerManager powermanager = (PowerManager) getSystemService(POWER_SERVICE);
|
||||||
if (powermanager.isScreenOn()) {
|
if (powermanager != null && powermanager.isScreenOn()) {
|
||||||
// LOG.info("Not forwarding notification, screen seems to be on and settings do not allow this");
|
// LOG.info("Not forwarding notification, screen seems to be on and settings do not allow this");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -45,7 +45,7 @@ public class SMSReceiver extends BroadcastReceiver {
|
|||||||
}
|
}
|
||||||
if ("when_screen_off".equals(prefs.getString("notification_mode_sms", "when_screen_off"))) {
|
if ("when_screen_off".equals(prefs.getString("notification_mode_sms", "when_screen_off"))) {
|
||||||
PowerManager powermanager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
|
PowerManager powermanager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
|
||||||
if (powermanager.isScreenOn()) {
|
if (powermanager != null && powermanager.isScreenOn()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -74,11 +74,19 @@ public class SMSReceiver extends BroadcastReceiver {
|
|||||||
notificationSpec.body = entry.getValue().toString();
|
notificationSpec.body = entry.getValue().toString();
|
||||||
notificationSpec.phoneNumber = originatingAddress;
|
notificationSpec.phoneNumber = originatingAddress;
|
||||||
notificationSpec.attachedActions = new ArrayList<>();
|
notificationSpec.attachedActions = new ArrayList<>();
|
||||||
|
|
||||||
|
// REPLY action
|
||||||
NotificationSpec.Action replyAction = new NotificationSpec.Action();
|
NotificationSpec.Action replyAction = new NotificationSpec.Action();
|
||||||
replyAction.title = "Reply";
|
replyAction.title = "Reply";
|
||||||
replyAction.isReply = true;
|
replyAction.type = NotificationSpec.Action.TYPE_SYNTECTIC_REPLY_PHONENR;
|
||||||
notificationSpec.attachedActions.add(replyAction);
|
notificationSpec.attachedActions.add(replyAction);
|
||||||
|
|
||||||
|
// DISMISS ALL action
|
||||||
|
NotificationSpec.Action dismissAllAction = new NotificationSpec.Action();
|
||||||
|
dismissAllAction.title = "Dismiss All";
|
||||||
|
dismissAllAction.type = NotificationSpec.Action.TYPE_SYNTECTIC_DISMISS_ALL;
|
||||||
|
notificationSpec.attachedActions.add(dismissAllAction);
|
||||||
|
|
||||||
switch (GBApplication.getGrantedInterruptionFilter()) {
|
switch (GBApplication.getGrantedInterruptionFilter()) {
|
||||||
case NotificationManager.INTERRUPTION_FILTER_ALL:
|
case NotificationManager.INTERRUPTION_FILTER_ALL:
|
||||||
break;
|
break;
|
||||||
|
@ -21,8 +21,6 @@ import java.util.ArrayList;
|
|||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
public class NotificationSpec {
|
public class NotificationSpec {
|
||||||
public static final int FLAG_WEARABLE_ACTIONS = 0x00000001;
|
|
||||||
|
|
||||||
public int flags;
|
public int flags;
|
||||||
private static final AtomicInteger c = new AtomicInteger((int) (System.currentTimeMillis()/1000));
|
private static final AtomicInteger c = new AtomicInteger((int) (System.currentTimeMillis()/1000));
|
||||||
private int id;
|
private int id;
|
||||||
@ -64,7 +62,17 @@ public class NotificationSpec {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static class Action implements Serializable {
|
public static class Action implements Serializable {
|
||||||
public boolean isReply = false;
|
static final int TYPE_UNDEFINED = -1;
|
||||||
|
public static final int TYPE_WEARABLE_SIMPLE = 0;
|
||||||
|
public static final int TYPE_WEARABLE_REPLY = 1;
|
||||||
|
public static final int TYPE_SYNTECTIC_REPLY_PHONENR = 2;
|
||||||
|
public static final int TYPE_SYNTECTIC_DISMISS = 3;
|
||||||
|
public static final int TYPE_SYNTECTIC_DISMISS_ALL = 4;
|
||||||
|
public static final int TYPE_SYNTECTIC_MUTE = 5;
|
||||||
|
public static final int TYPE_SYNTECTIC_OPEN = 6;
|
||||||
|
|
||||||
|
public int type = TYPE_UNDEFINED;
|
||||||
|
public long handle;
|
||||||
public String title;
|
public String title;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -376,7 +376,7 @@ public class DeviceCommunicationService extends Service implements SharedPrefere
|
|||||||
}
|
}
|
||||||
|
|
||||||
//TODO: check if at least one of the attached actions is a reply action instead?
|
//TODO: check if at least one of the attached actions is a reply action instead?
|
||||||
if (((notificationSpec.flags & NotificationSpec.FLAG_WEARABLE_ACTIONS) > 0)
|
if ((notificationSpec.attachedActions != null && notificationSpec.attachedActions.size() > 0)
|
||||||
|| (notificationSpec.type == NotificationType.GENERIC_SMS && notificationSpec.phoneNumber != null)) {
|
|| (notificationSpec.type == NotificationType.GENERIC_SMS && notificationSpec.phoneNumber != null)) {
|
||||||
// NOTE: maybe not where it belongs
|
// NOTE: maybe not where it belongs
|
||||||
// I would rather like to save that as an array in SharedPreferences
|
// I would rather like to save that as an array in SharedPreferences
|
||||||
|
@ -485,7 +485,6 @@ public class PebbleProtocol extends GBDeviceProtocol {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte[] encodeNotification(NotificationSpec notificationSpec) {
|
public byte[] encodeNotification(NotificationSpec notificationSpec) {
|
||||||
boolean hasHandle = notificationSpec.sourceAppId != null;
|
|
||||||
int id = notificationSpec.getId() != -1 ? notificationSpec.getId() : mRandom.nextInt();
|
int id = notificationSpec.getId() != -1 ? notificationSpec.getId() : mRandom.nextInt();
|
||||||
String title;
|
String title;
|
||||||
String subtitle = null;
|
String subtitle = null;
|
||||||
@ -507,7 +506,7 @@ public class PebbleProtocol extends GBDeviceProtocol {
|
|||||||
if (mFwMajor >= 3 || mForceProtocol || notificationSpec.type != NotificationType.GENERIC_EMAIL) {
|
if (mFwMajor >= 3 || mForceProtocol || notificationSpec.type != NotificationType.GENERIC_EMAIL) {
|
||||||
// 3.x notification
|
// 3.x notification
|
||||||
return encodeNotification(id, (int) (ts & 0xffffffffL), title, subtitle, notificationSpec.body,
|
return encodeNotification(id, (int) (ts & 0xffffffffL), title, subtitle, notificationSpec.body,
|
||||||
notificationSpec.sourceName, hasHandle, notificationSpec.type, notificationSpec.pebbleColor,
|
notificationSpec.type, notificationSpec.pebbleColor,
|
||||||
notificationSpec.cannedReplies, notificationSpec.attachedActions);
|
notificationSpec.cannedReplies, notificationSpec.attachedActions);
|
||||||
} else {
|
} else {
|
||||||
// 1.x notification on FW 2.X
|
// 1.x notification on FW 2.X
|
||||||
@ -794,9 +793,8 @@ public class PebbleProtocol extends GBDeviceProtocol {
|
|||||||
return encodeBlobdb(uuid, BLOBDB_INSERT, BLOBDB_PIN, buf.array());
|
return encodeBlobdb(uuid, BLOBDB_INSERT, BLOBDB_PIN, buf.array());
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte[] encodeNotification(int id, int timestamp, String title, String subtitle, String body, String sourceName,
|
private byte[] encodeNotification(int id, int timestamp, String title, String subtitle, String body,
|
||||||
boolean hasHandle, NotificationType notificationType, byte backgroundColor,
|
NotificationType notificationType, byte backgroundColor, String[] cannedReplies, ArrayList<Action> attachedActions) {
|
||||||
String[] cannedReplies, ArrayList<Action> attachedActions) {
|
|
||||||
final short NOTIFICATION_PIN_LENGTH = 46;
|
final short NOTIFICATION_PIN_LENGTH = 46;
|
||||||
final short ACTION_LENGTH_MIN = 6;
|
final short ACTION_LENGTH_MIN = 6;
|
||||||
|
|
||||||
@ -811,25 +809,6 @@ public class PebbleProtocol extends GBDeviceProtocol {
|
|||||||
// Calculate length first
|
// Calculate length first
|
||||||
int actions_count = 0;
|
int actions_count = 0;
|
||||||
short actions_length = 0;
|
short actions_length = 0;
|
||||||
String dismiss_string;
|
|
||||||
String open_string = GBApplication.getContext().getString(R.string._pebble_watch_open_on_phone);
|
|
||||||
String mute_string = GBApplication.getContext().getString(R.string._pebble_watch_mute);
|
|
||||||
if (sourceName != null) {
|
|
||||||
mute_string += " " + sourceName;
|
|
||||||
}
|
|
||||||
|
|
||||||
byte dismiss_action_id;
|
|
||||||
if (hasHandle && !"ALARMCLOCKRECEIVER".equals(sourceName)) {
|
|
||||||
actions_count += 3;
|
|
||||||
dismiss_string = "Dismiss";
|
|
||||||
dismiss_action_id = 0x02;
|
|
||||||
actions_length += (short) (ACTION_LENGTH_MIN * 3 + dismiss_string.getBytes().length + open_string.getBytes().length + mute_string.getBytes().length);
|
|
||||||
} else {
|
|
||||||
actions_count += 1;
|
|
||||||
dismiss_string = "Dismiss all";
|
|
||||||
dismiss_action_id = 0x03;
|
|
||||||
actions_length += (short) (ACTION_LENGTH_MIN + dismiss_string.getBytes().length);
|
|
||||||
}
|
|
||||||
|
|
||||||
int replies_length = 0;
|
int replies_length = 0;
|
||||||
if (cannedReplies != null && cannedReplies.length > 0) {
|
if (cannedReplies != null && cannedReplies.length > 0) {
|
||||||
@ -846,7 +825,7 @@ public class PebbleProtocol extends GBDeviceProtocol {
|
|||||||
for (Action act : attachedActions) {
|
for (Action act : attachedActions) {
|
||||||
actions_count++;
|
actions_count++;
|
||||||
actions_length += (short) (ACTION_LENGTH_MIN + act.title.getBytes().length);
|
actions_length += (short) (ACTION_LENGTH_MIN + act.title.getBytes().length);
|
||||||
if (act.isReply) {
|
if (act.type == Action.TYPE_WEARABLE_REPLY || act.type == Action.TYPE_SYNTECTIC_REPLY_PHONENR) {
|
||||||
actions_length += (short) replies_length + 3; // 3 = attribute id (byte) + length(short)
|
actions_length += (short) replies_length + 3; // 3 = attribute id (byte) + length(short)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -941,46 +920,42 @@ public class PebbleProtocol extends GBDeviceProtocol {
|
|||||||
buf.put(backgroundColor);
|
buf.put(backgroundColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
// dismiss action
|
|
||||||
buf.put(dismiss_action_id);
|
|
||||||
buf.put(dismiss_action_type);
|
|
||||||
buf.put((byte) 0x01); // number attributes
|
|
||||||
buf.put((byte) 0x01); // attribute id (title)
|
|
||||||
buf.putShort((short) dismiss_string.getBytes().length);
|
|
||||||
buf.put(dismiss_string.getBytes());
|
|
||||||
|
|
||||||
// open and mute actions
|
|
||||||
if (hasHandle && !"ALARMCLOCKRECEIVER".equals(sourceName)) {
|
|
||||||
buf.put((byte) 0x01);
|
|
||||||
buf.put((byte) 0x02); // generic action
|
|
||||||
buf.put((byte) 0x01); // number attributes
|
|
||||||
buf.put((byte) 0x01); // attribute id (title)
|
|
||||||
buf.putShort((short) open_string.getBytes().length);
|
|
||||||
buf.put(open_string.getBytes());
|
|
||||||
|
|
||||||
buf.put((byte) 0x04);
|
|
||||||
buf.put((byte) 0x02); // generic action
|
|
||||||
buf.put((byte) 0x01); // number attributes
|
|
||||||
buf.put((byte) 0x01); // attribute id (title)
|
|
||||||
buf.putShort((short) mute_string.getBytes().length);
|
|
||||||
buf.put(mute_string.getBytes());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (attachedActions != null && attachedActions.size() > 0) {
|
if (attachedActions != null && attachedActions.size() > 0) {
|
||||||
for (int ai = 0 ; ai<attachedActions.size(); ai++) {
|
for (int ai = 0 ; ai<attachedActions.size(); ai++) {
|
||||||
Action act = attachedActions.get(ai);
|
Action act = attachedActions.get(ai);
|
||||||
buf.put((byte) (0x05 + ai));
|
switch (act.type) {
|
||||||
if(act.isReply) {
|
case Action.TYPE_SYNTECTIC_OPEN:
|
||||||
|
buf.put((byte) 0x01);
|
||||||
|
break;
|
||||||
|
case Action.TYPE_SYNTECTIC_DISMISS:
|
||||||
|
buf.put((byte) 0x02);
|
||||||
|
break;
|
||||||
|
case Action.TYPE_SYNTECTIC_DISMISS_ALL:
|
||||||
|
buf.put((byte) 0x03);
|
||||||
|
break;
|
||||||
|
case Action.TYPE_SYNTECTIC_MUTE:
|
||||||
|
buf.put((byte) 0x04);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
buf.put((byte) (0x05 + ai));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (act.type == Action.TYPE_WEARABLE_REPLY || act.type == Action.TYPE_SYNTECTIC_REPLY_PHONENR) {
|
||||||
buf.put((byte) 0x03); // reply action
|
buf.put((byte) 0x03); // reply action
|
||||||
buf.put((byte) 0x02); // number attributes
|
buf.put((byte) 0x02); // number attributes
|
||||||
} else {
|
} else {
|
||||||
buf.put((byte) 0x02); // generic action
|
if (act.type == Action.TYPE_SYNTECTIC_DISMISS) {
|
||||||
|
buf.put(dismiss_action_type);
|
||||||
|
} else {
|
||||||
|
buf.put((byte) 0x02); // generic action
|
||||||
|
}
|
||||||
buf.put((byte) 0x01); // number attributes
|
buf.put((byte) 0x01); // number attributes
|
||||||
}
|
}
|
||||||
|
|
||||||
buf.put((byte) 0x01); // attribute id (title)
|
buf.put((byte) 0x01); // attribute id (title)
|
||||||
buf.putShort((short) act.title.getBytes().length);
|
buf.putShort((short) act.title.getBytes().length);
|
||||||
buf.put(act.title.getBytes());
|
buf.put(act.title.getBytes());
|
||||||
if (act.isReply) {
|
if (act.type == Action.TYPE_WEARABLE_REPLY || act.type == Action.TYPE_SYNTECTIC_REPLY_PHONENR) {
|
||||||
buf.put((byte) 0x08); // canned replies
|
buf.put((byte) 0x08); // canned replies
|
||||||
buf.putShort((short) replies_length);
|
buf.putShort((short) replies_length);
|
||||||
if (cannedReplies != null && cannedReplies.length > 0) {
|
if (cannedReplies != null && cannedReplies.length > 0) {
|
||||||
|
Loading…
Reference in New Issue
Block a user